mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-16 19:49:56 +00:00
* [agent-network] Shared proto, OpenAPI schema, and generated types * [agent-network] Management: store, manager, synthesizer, policy engine, provider catalog, HTTP/gRPC API Adds the account-scoped agent-network module: provider/policy/budget CRUD and store, the reverse-proxy service synthesizer, policy selection + limit enforcement, the provider catalog (incl. Vertex AI and AWS Bedrock entries), and the management HTTP + proxy gRPC surfaces. * [management] Fix agent-network proxy-peer fan-out on affected-peer recompute The affected-peers resolver loaded only persisted reverse-proxy services, but agent-network services are synthesized on demand and never persisted. As a result the embedded proxy peer was never folded into the affected set when a client's group changed, so the proxy received no network-map update for a newly authorised client and rejected its handshake until a full resync (restart). loadProxyServices now merges the synthesized agent-network services (injected via a registration hook to avoid an import cycle), so proxy peers learn newly authorised clients immediately. * [proxy] Reverse-proxy middleware framework, chain, and request plumbing The per-target middleware chain (slots, dispatcher, mutation gate, metadata merger), body capture, access-log terminal sink, and the proxy wiring that builds + runs chains for synthesized agent-network services. * [proxy] LLM parsers, pricing, and builtin middlewares (OpenAI, Anthropic, Vertex AI, AWS Bedrock) Request/response parsers and SSE/event-stream metering, the embedded pricing table, and the builtin middleware set: request parser, router, policy limit-check/record, cost meter, guardrail, identity inject, response parser. Includes the path-routed providers — Google Vertex AI (keyfile:: service-account OAuth minting) and AWS Bedrock (bearer auth, invoke/converse/streaming, optional /bedrock prefix) — plus the Models allowlist and unmeterable-publisher deny. * [proxy] IPv6 in-place apply and TCP accept-loop hardening on netstack listeners * [agent-network] End-to-end test suite, module docs, and deployment preset * [agent-network] Fix codespell typos and exclude false positives - labelgen word pool: vermillion -> vermilion, racoon -> raccoon. - codespell ignore list: add flate (Go compress/flate package), recordin (a test-local identifier), and unparseable (a valid alternative spelling used consistently across identifiers + a metadata-value constant). * [management] Set LastSeen on injected proxy peer in realstack test (MySQL strict-mode) The injected embedded proxy peer had a PeerStatus with a zero LastSeen, which serializes to '0000-00-00' and is rejected by MySQL in strict mode (SQLite tolerates it). Set LastSeen to a valid time so SaveAccount succeeds on both engines. * [agent-network] Remove e2e shell-script suite from this branch The end-to-end shell scripts under scripts/e2e/ are maintained in a separate testing suite and are not part of this change set. * [agent-network] Polish module docs: remove internal review scaffolding, fix links, verify diagrams Strip PR-review framing, commit references, absolute paths, and stale internal references from the agent-network module docs; fix broken relative links; verify all diagrams against the current architecture. Remove the internal AI-reviewer prompt file. * [management] Refine session expiration handling to support 3-state encoding for SSO deadlines * [agent-network] Relocate agentnetwork package to internals/modules Move management/server/agentnetwork (and its catalog/, labelgen/, types/ subpackages) to management/internals/modules/agentnetwork, alongside the reverse-proxy module, and rewrite all importers. Pure relocation: package names, the synthesizer + affectedpeers registration hook, and store access (shared store.Store) are unchanged, so no import cycle is introduced (affectedpeers still depends only on the agentnetwork/types leaf). * [agent-network] Co-locate HTTP handlers in the module (RegisterEndpoints) Move the agent-network HTTP handlers from server/http/handlers/agentnetwork into the module at internals/modules/agentnetwork/handlers (package handlers) and rename the entrypoint AddEndpoints -> RegisterEndpoints, matching the reverse-proxy module convention. Wiring in http/handler.go updated accordingly.
307 lines
11 KiB
Go
307 lines
11 KiB
Go
package status
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/netbirdio/netbird/shared/management/operations"
|
|
)
|
|
|
|
const (
|
|
// UserAlreadyExists indicates that user already exists
|
|
UserAlreadyExists Type = 1
|
|
|
|
// PreconditionFailed indicates that some pre-condition for the operation hasn't been fulfilled
|
|
PreconditionFailed Type = 2
|
|
|
|
// PermissionDenied indicates that user has no permissions to view data
|
|
PermissionDenied Type = 3
|
|
|
|
// NotFound indicates that the object wasn't found in the system (or under a given Account)
|
|
NotFound Type = 4
|
|
|
|
// Internal indicates some generic internal error
|
|
Internal Type = 5
|
|
|
|
// InvalidArgument indicates some generic invalid argument error
|
|
InvalidArgument Type = 6
|
|
|
|
// AlreadyExists indicates a generic error when an object already exists in the system
|
|
AlreadyExists Type = 7
|
|
|
|
// Unauthorized indicates that user is not authorized
|
|
Unauthorized Type = 8
|
|
|
|
// BadRequest indicates that user is not authorized
|
|
BadRequest Type = 9
|
|
|
|
// Unauthenticated indicates that user is not authenticated due to absence of valid credentials
|
|
Unauthenticated Type = 10
|
|
|
|
// TooManyRequests indicates that the user has sent too many requests in a given amount of time (rate limiting)
|
|
TooManyRequests Type = 11
|
|
)
|
|
|
|
// Type is a type of the Error
|
|
type Type int32
|
|
|
|
var (
|
|
ErrExtraSettingsNotFound = errors.New("extra settings not found")
|
|
ErrPeerAlreadyLoggedIn = errors.New("peer with the same public key is already logged in")
|
|
|
|
// ErrNoAuthMethodProvided is returned when a peer login attempt carries neither a
|
|
// setup key nor an SSO token. Match it with errors.Is.
|
|
ErrNoAuthMethodProvided = Errorf(Unauthenticated, "no peer auth method provided, please use a setup key or interactive SSO login")
|
|
)
|
|
|
|
// Error is an internal error
|
|
type Error struct {
|
|
ErrorType Type
|
|
Message string
|
|
}
|
|
|
|
// Type returns the Type of the error
|
|
func (e *Error) Type() Type {
|
|
return e.ErrorType
|
|
}
|
|
|
|
// Error is an error string
|
|
func (e *Error) Error() string {
|
|
return e.Message
|
|
}
|
|
|
|
// Is reports whether target is an *Error with the same type and message,
|
|
// enabling matching with errors.Is against sentinel errors.
|
|
func (e *Error) Is(target error) bool {
|
|
var t *Error
|
|
if !errors.As(target, &t) {
|
|
return false
|
|
}
|
|
return e.ErrorType == t.ErrorType && e.Message == t.Message
|
|
}
|
|
|
|
// Errorf returns Error(ErrorType, fmt.Sprintf(format, a...)).
|
|
func Errorf(errorType Type, format string, a ...interface{}) error {
|
|
return &Error{
|
|
ErrorType: errorType,
|
|
Message: fmt.Sprintf(format, a...),
|
|
}
|
|
}
|
|
|
|
// FromError returns Error, true if the provided error is of type of Error. nil, false otherwise
|
|
func FromError(err error) (s *Error, ok bool) {
|
|
if err == nil {
|
|
return nil, true
|
|
}
|
|
var e *Error
|
|
if errors.As(err, &e) {
|
|
return e, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// NewPeerNotFoundError creates a new Error with NotFound type for a missing peer
|
|
func NewPeerNotFoundError(peerKey string) error {
|
|
return Errorf(NotFound, "peer not found: %s", peerKey)
|
|
}
|
|
|
|
// NewAccountNotFoundError creates a new Error with NotFound type for a missing account
|
|
func NewAccountNotFoundError(accountKey string) error {
|
|
return Errorf(NotFound, "account not found: %s", accountKey)
|
|
}
|
|
|
|
// NewAccountOnboardingNotFoundError creates a new Error with NotFound type for a missing account onboarding
|
|
func NewAccountOnboardingNotFoundError(accountKey string) error {
|
|
return Errorf(NotFound, "account onboarding not found: %s", accountKey)
|
|
}
|
|
|
|
// NewPeerNotPartOfAccountError creates a new Error with PermissionDenied type for a peer not being part of an account
|
|
func NewPeerNotPartOfAccountError() error {
|
|
return Errorf(PermissionDenied, "peer is not part of this account")
|
|
}
|
|
|
|
// NewUserNotFoundError creates a new Error with NotFound type for a missing user
|
|
func NewUserNotFoundError(userKey string) error {
|
|
return Errorf(NotFound, "user: %s not found", userKey)
|
|
}
|
|
|
|
// NewUserBlockedError creates a new Error with PermissionDenied type for a blocked user
|
|
func NewUserBlockedError() error {
|
|
return Errorf(PermissionDenied, "user is blocked")
|
|
}
|
|
|
|
// NewUserPendingApprovalError creates a new Error with PermissionDenied type for a blocked user pending approval
|
|
func NewUserPendingApprovalError() error {
|
|
return Errorf(PermissionDenied, "user is pending approval")
|
|
}
|
|
|
|
// NewPeerNotRegisteredError creates a new Error with Unauthenticated type unregistered peer
|
|
func NewPeerNotRegisteredError() error {
|
|
return Errorf(Unauthenticated, "peer is not registered")
|
|
}
|
|
|
|
// NewPeerLoginMismatchError creates a new Error with Unauthenticated type for a peer that is already registered for another user
|
|
func NewPeerLoginMismatchError() error {
|
|
return Errorf(Unauthenticated, "peer is already registered by a different User or a Setup Key")
|
|
}
|
|
|
|
// NewPeerLoginExpiredError creates a new Error with PermissionDenied type for an expired peer
|
|
func NewPeerLoginExpiredError() error {
|
|
return Errorf(PermissionDenied, "peer login has expired, please log in once more")
|
|
}
|
|
|
|
// NewSetupKeyNotFoundError creates a new Error with NotFound type for a missing setup key
|
|
func NewSetupKeyNotFoundError(setupKeyID string) error {
|
|
return Errorf(NotFound, "setup key: %s not found", setupKeyID)
|
|
}
|
|
|
|
func NewGetAccountFromStoreError(err error) error {
|
|
return Errorf(Internal, "issue getting account from store: %s", err)
|
|
}
|
|
|
|
// NewUserNotPartOfAccountError creates a new Error with PermissionDenied type for a user not being part of an account
|
|
func NewUserNotPartOfAccountError() error {
|
|
return Errorf(PermissionDenied, "user is not part of this account")
|
|
}
|
|
|
|
// NewGetUserFromStoreError creates a new Error with Internal type for an issue getting user from store
|
|
func NewGetUserFromStoreError() error {
|
|
return Errorf(Internal, "issue getting user from store")
|
|
}
|
|
|
|
// NewAdminPermissionError creates a new Error with PermissionDenied type for actions requiring admin role.
|
|
func NewAdminPermissionError() error {
|
|
return Errorf(PermissionDenied, "admin role required to perform this action")
|
|
}
|
|
|
|
// NewInvalidKeyIDError creates a new Error with InvalidArgument type for an issue getting a setup key
|
|
func NewInvalidKeyIDError() error {
|
|
return Errorf(InvalidArgument, "invalid key ID")
|
|
}
|
|
|
|
// NewGetAccountError creates a new Error with Internal type for an issue getting account
|
|
func NewGetAccountError(err error) error {
|
|
return Errorf(Internal, "error getting account: %s", err)
|
|
}
|
|
|
|
// NewGroupNotFoundError creates a new Error with NotFound type for a missing group
|
|
func NewGroupNotFoundError(groupID string) error {
|
|
return Errorf(NotFound, "group: %s not found", groupID)
|
|
}
|
|
|
|
// NewPostureChecksNotFoundError creates a new Error with NotFound type for a missing posture checks
|
|
func NewPostureChecksNotFoundError(postureChecksID string) error {
|
|
return Errorf(NotFound, "posture checks: %s not found", postureChecksID)
|
|
}
|
|
|
|
// NewPolicyNotFoundError creates a new Error with NotFound type for a missing policy
|
|
func NewPolicyNotFoundError(policyID string) error {
|
|
return Errorf(NotFound, "policy: %s not found", policyID)
|
|
}
|
|
|
|
// NewNameServerGroupNotFoundError creates a new Error with NotFound type for a missing name server group
|
|
func NewNameServerGroupNotFoundError(nsGroupID string) error {
|
|
return Errorf(NotFound, "nameserver group: %s not found", nsGroupID)
|
|
}
|
|
|
|
// NewNetworkNotFoundError creates a new Error with NotFound type for a missing network.
|
|
func NewNetworkNotFoundError(networkID string) error {
|
|
return Errorf(NotFound, "network: %s not found", networkID)
|
|
}
|
|
|
|
// NewNetworkRouterNotFoundError creates a new Error with NotFound type for a missing network router.
|
|
func NewNetworkRouterNotFoundError(routerID string) error {
|
|
return Errorf(NotFound, "network router: %s not found", routerID)
|
|
}
|
|
|
|
// NewNetworkResourceNotFoundError creates a new Error with NotFound type for a missing network resource.
|
|
func NewNetworkResourceNotFoundError(resourceID string) error {
|
|
return Errorf(NotFound, "network resource: %s not found", resourceID)
|
|
}
|
|
|
|
// NewAgentNetworkProviderNotFoundError creates a new Error with NotFound type for a missing Agent Network provider.
|
|
func NewAgentNetworkProviderNotFoundError(providerID string) error {
|
|
return Errorf(NotFound, "agent network provider: %s not found", providerID)
|
|
}
|
|
|
|
// NewAgentNetworkPolicyNotFoundError creates a new Error with NotFound type for a missing Agent Network policy.
|
|
func NewAgentNetworkPolicyNotFoundError(policyID string) error {
|
|
return Errorf(NotFound, "agent network policy: %s not found", policyID)
|
|
}
|
|
|
|
// NewAgentNetworkGuardrailNotFoundError creates a new Error with NotFound type for a missing Agent Network guardrail.
|
|
func NewAgentNetworkGuardrailNotFoundError(guardrailID string) error {
|
|
return Errorf(NotFound, "agent network guardrail: %s not found", guardrailID)
|
|
}
|
|
|
|
// NewAgentNetworkBudgetRuleNotFoundError creates a new Error with NotFound type for a missing Agent Network budget rule.
|
|
func NewAgentNetworkBudgetRuleNotFoundError(ruleID string) error {
|
|
return Errorf(NotFound, "agent network budget rule: %s not found", ruleID)
|
|
}
|
|
|
|
// NewPermissionDeniedError creates a new Error with PermissionDenied type for a permission denied error.
|
|
func NewPermissionDeniedError() error {
|
|
return Errorf(PermissionDenied, "permission denied")
|
|
}
|
|
|
|
func NewPermissionValidationError(err error) error {
|
|
return Errorf(PermissionDenied, "failed to validate user permissions: %s", err)
|
|
}
|
|
|
|
func NewResourceNotPartOfNetworkError(resourceID, networkID string) error {
|
|
return Errorf(BadRequest, "resource %s is not part of the network %s", resourceID, networkID)
|
|
}
|
|
|
|
func NewRouterNotPartOfNetworkError(routerID, networkID string) error {
|
|
return Errorf(BadRequest, "router %s is not part of the network %s", routerID, networkID)
|
|
}
|
|
|
|
// NewServiceUserRoleInvalidError creates a new Error with InvalidArgument type for creating a service user with owner role
|
|
func NewServiceUserRoleInvalidError() error {
|
|
return Errorf(InvalidArgument, "can't create a service user with owner role")
|
|
}
|
|
|
|
// NewOwnerDeletePermissionError creates a new Error with PermissionDenied type for attempting
|
|
// to delete a user with the owner role.
|
|
func NewOwnerDeletePermissionError() error {
|
|
return Errorf(PermissionDenied, "can't delete a user with the owner role")
|
|
}
|
|
|
|
func NewPATNotFoundError(patID string) error {
|
|
return Errorf(NotFound, "PAT: %s not found", patID)
|
|
}
|
|
|
|
func NewExtraSettingsNotFoundError() error {
|
|
return ErrExtraSettingsNotFound
|
|
}
|
|
|
|
func NewUserRoleNotFoundError(role string) error {
|
|
return Errorf(NotFound, "user role: %s not found", role)
|
|
}
|
|
|
|
func NewOperationNotFoundError(operation operations.Operation) error {
|
|
return Errorf(NotFound, "operation: %s not found", operation)
|
|
}
|
|
|
|
func NewRouteNotFoundError(routeID string) error {
|
|
return Errorf(NotFound, "route: %s not found", routeID)
|
|
}
|
|
|
|
// NewZoneNotFoundError creates a new Error with NotFound type for a missing dns zone.
|
|
func NewZoneNotFoundError(zoneID string) error {
|
|
return Errorf(NotFound, "zone: %s not found", zoneID)
|
|
}
|
|
|
|
// NewDNSRecordNotFoundError creates a new Error with NotFound type for a missing dns record.
|
|
func NewDNSRecordNotFoundError(recordID string) error {
|
|
return Errorf(NotFound, "dns record: %s not found", recordID)
|
|
}
|
|
|
|
func NewResourceInUseError(resourceID string, proxyID string) error {
|
|
return Errorf(PreconditionFailed, "resource %s is in use by proxy %s", resourceID, proxyID)
|
|
}
|
|
|
|
func NewPeerInUseError(peerID string, proxyID string) error {
|
|
return Errorf(PreconditionFailed, "peer %s is in use by proxy %s", peerID, proxyID)
|
|
}
|