Documentation
¶
Index ¶
- Constants
- Variables
- func AllowApp(ctx context.Context, appName string) bool
- func AppAccessError(ctx context.Context, appName string) error
- func BoundApp(ctx context.Context) string
- func CanBe[T, I any]() bool
- func ContextWithConnectionInfo(ctx context.Context, info *CurrentConnectionInfo) context.Context
- func ContextWithIdentity(ctx context.Context, identity *Identity) context.Context
- func Detach(ctx context.Context) (context.Context, context.CancelFunc)
- func NewResolveDecodeError(name, remote string, err error) error
- func NewResolveError(kind ResolveErrorKind, err error, msg string) error
- func NewResolveHTTPError(err error, format string, args ...any) error
- func NewResolveLookupError(name, remote, msg string) error
- func NewResolveNoAnswerError(name, remote string, elapsed time.Duration, err error) error
- func NewResolveStatusError(name, remote string, statusCode int) error
- func NewResolveStatusErrorWithReason(name, remote string, statusCode int, code, detail string) error
- func NewResolveUnreachableError(name, remote string, elapsed time.Duration, err error) error
- func NewResolveWentSilentError(name, remote string, elapsed time.Duration, err error) error
- func Propagator() propagation.TextMapPropagator
- func RegisterInterface[T any](fn any) bool
- func RegisterREST(mux *http.ServeMux, iface *Interface)
- func SetupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error)
- func SetupTracing(ctx context.Context, attrs ...attribute.KeyValue) (shutdown func(context.Context) error, err error)
- func Tracer() otrace.Tracer
- func WithRequireClientCerts(o *stateOptions)
- func WithSkipVerify(o *stateOptions)
- func Zero[T any]() T
- type ActorCall
- type ActorClient
- func (a *ActorClient) Call(ctx context.Context, name string, arg, ret any) error
- func (a *ActorClient) CallWithCaps(ctx context.Context, method string, args, result any, ...) error
- func (a *ActorClient) Close() error
- func (a *ActorClient) NewClient(capa *Capability) Client
- func (a *ActorClient) NewInlineCapability(i *Interface, lower any) (*InlineCapability, OID, *Capability)
- type ActorRegistry
- type ActorResolver
- type AuthMethod
- type Authenticator
- type Authorizer
- type Call
- type Capability
- type Client
- type Credentials
- type CurrentConnectionInfo
- type DebugAuthResponse
- type DescField
- type DescFile
- type DescHTTPIface
- type DescHTTPMethod
- type DescInterface
- type DescMethods
- type DescParamater
- type DescType
- type DisclosableAuthError
- type Dispatcher
- type ErrorCategory
- type ErrorCode
- type ErrorMessage
- type ForbidRestore
- type Generator
- type HTTPBinding
- type HTTPParam
- type HasReconstructFromState
- type HasRestoreState
- type Identity
- type IfaceReg
- type Import
- type InlineCapability
- type Interface
- type InterfaceCreators
- type InterfaceDescriptor
- type InterfaceState
- type LocalActorRegistry
- type LocalOnlyAuthenticator
- type MessageConn
- type MessageRemote
- type MessageSessionOption
- type Method
- type NetworkCall
- func (c *NetworkCall) Args(v any)
- func (c *NetworkCall) IsAuthenticated() bool
- func (c *NetworkCall) NewCapability(i *Interface) *Capability
- func (c *NetworkCall) NewClient(capa *Capability) Client
- func (c *NetworkCall) RemoteAddr() string
- func (c *NetworkCall) Results(v any)
- func (c *NetworkCall) SkipArgs()
- func (c *NetworkCall) String() string
- type NetworkClient
- func (c *NetworkClient) Call(ctx context.Context, method string, args, result any) error
- func (c *NetworkClient) CallWithCaps(ctx context.Context, method string, args, result any, ...) error
- func (c *NetworkClient) Close() error
- func (c *NetworkClient) HasMethod(ctx context.Context, method string) bool
- func (c *NetworkClient) HasMethodParam(ctx context.Context, method, param string) bool
- func (c *NetworkClient) ListMethods(ctx context.Context) ([]string, error)
- func (c *NetworkClient) NewCapability(i *Interface, lower any) *Capability
- func (c *NetworkClient) NewClient(capa *Capability) Client
- func (c *NetworkClient) NewInlineCapability(i *Interface, lower any) (*InlineCapability, OID, *Capability)
- func (c *NetworkClient) String() string
- type NoOpAuthenticator
- type NoRestore
- type OID
- type ResolveError
- type ResolveErrorKind
- type ResolverFunc
- type Server
- type ServiceID
- type State
- func (s *State) Client(name string) (*NetworkClient, error)
- func (s *State) ClientFromMessageConn(ctx context.Context, conn MessageConn, name string, ...) (*NetworkClient, error)
- func (s *State) Close() error
- func (s *State) Connect(remote string, name string) (*NetworkClient, error)
- func (s *State) ListenAddr() string
- func (s *State) LoopbackAddr() string
- func (s *State) RESTListenAddr() string
- func (s *State) ServeMessageConn(ctx context.Context, conn MessageConn, opts ...MessageSessionOption) error
- func (s *State) Server() *Server
- func (s *State) Shutdown(ctx context.Context) error
- func (s *State) TCPListenAddr() string
- func (s *State) WSListenAddr() string
- type StateCommon
- type StateOption
- func WithAuthenticator(auth Authenticator) StateOption
- func WithAuthorizer(authz Authorizer) StateOption
- func WithBearerToken(token string) StateOption
- func WithBearerTokenFunc(fn func() (string, error)) StateOption
- func WithBindAddr(addr string) StateOption
- func WithCert(certPath, keyPath string) StateOption
- func WithCertPEMs(certData, keyData []byte) StateOption
- func WithCertificateVerification(caCert []byte) StateOption
- func WithEndpoint(endpoint string) StateOption
- func WithHTTPHandler(pattern string, handler http.Handler) StateOption
- func WithLocalConnect(addr string) StateOption
- func WithLocalServer(addr string) StateOption
- func WithLogLevel(level slog.Level) StateOption
- func WithLogger(log *slog.Logger) StateOption
- func WithMemServer(name string) StateOption
- func WithRESTBindAddr(addr string) StateOption
- func WithTCPBindAddr(addr string) StateOption
- func WithTLSServerName(name string) StateOption
- func WithWSBindAddr(addr string) StateOption
- type UnionField
Constants ¶
const ( TypeRW = iota TypeR TypeW )
const AuthErrorOIDCBindingMismatch = "oidc-binding-mismatch"
AuthErrorOIDCBindingMismatch marks a CI token that verified against a configured issuer but matched none of that issuer's bindings.
const BootstrapOID = "!bootstrap"
const InitialPacketSize = 1200
InitialPacketSize pins the QUIC Initial at the 1200-byte spec minimum so the handshake fits a 1280-MTU path (Tailscale/WireGuard tunnels, the IPv6 minimum). quic-go's default of 1280 yields a 1308-byte IPv4 datagram with DF set, which such tunnels silently drop, hanging the handshake in both directions. PMTUD raises the packet size again after the handshake completes, so 1500-MTU paths are unaffected. See quic-go#5573, quic-go#5634, tailscale#2633.
Every quic.Config we hand to a Dial or Listen must set this. quic-go swallows the resulting EMSGSIZE without shrinking the Initial (see sendQueue.Run), so forgetting it costs a silent timeout on tunnelled paths and nothing at all on ordinary ones.
Variables ¶
var ( ErrResolveHTTP = &ResolveError{Kind: ResolveHTTPError, Msg: "http request error"} ErrResolveStatus = &ResolveError{Kind: ResolveStatusError, Msg: "unexpected status code"} ErrResolveDecode = &ResolveError{Kind: ResolveDecodeError, Msg: "decode error"} ErrResolveLookup = &ResolveError{Kind: ResolveLookupError, Msg: "lookup error"} ErrResolveUnreachable = &ResolveError{Kind: ResolveUnreachableError, Msg: "unreachable"} ErrResolveWentSilent = &ResolveError{Kind: ResolveWentSilentError, Msg: "connection went silent"} ErrResolveNoAnswer = &ResolveError{Kind: ResolveNoAnswerError, Msg: "no answer"} )
Exported sentinel errors for common resolve error kinds
var ( DefaultQUICConfig quic.Config DefaultLogLevel = slog.LevelInfo )
ErrUnauthorized is returned when an app-scoped caller attempts to operate on an app they are not bound to.
Functions ¶
func AllowApp ¶ added in v0.5.0
AllowApp checks whether the current caller is permitted to operate on the named app. Callers that are not app-scoped (cert, JWT, anonymous) are always allowed; app-scoped callers are restricted to the app they are bound to.
This is where per-app scoping is enforced. It cannot live in an Authorizer: Authorize only sees the resource and action, never the arguments naming the app, so it can decide whether a caller may ever call a method but not which app it may call it against.
func AppAccessError ¶ added in v0.5.0
AppAccessError returns a descriptive error for an app-scoping denial.
func BoundApp ¶ added in v0.5.0
BoundApp returns the app the current caller is scoped to, or "" if the caller is not app-scoped.
The switch below is the registry of app-scoped auth methods: a method that reports no binding is read by AllowApp as "not app-scoped" and allowed against every app. Every AuthMethod is therefore listed explicitly, and the exhaustive linter keeps it that way — a new method must make its scoping decision here, rather than inheriting cluster-wide access from a default branch.
func ContextWithConnectionInfo ¶ added in v0.10.0
func ContextWithConnectionInfo(ctx context.Context, info *CurrentConnectionInfo) context.Context
ContextWithConnectionInfo returns a copy of ctx carrying the given connection info, as observed by ConnectionInfo. The server populates this from the mTLS handshake; tests use it to exercise handlers that authorize on the peer cert.
func ContextWithIdentity ¶ added in v0.3.1
ContextWithIdentity returns a new context with the Identity stored
func Detach ¶ added in v0.15.0
Detach returns a context that preserves the caller's values but does not end when its transport goes away. When called by an RPC handler, the returned context remains tied to the server process lifetime. Outside RPC dispatch it falls back to context.WithoutCancel, which keeps the helper useful in direct unit tests.
func NewResolveDecodeError ¶
NewResolveDecodeError creates a decode error
func NewResolveError ¶
func NewResolveError(kind ResolveErrorKind, err error, msg string) error
NewResolveError creates a new ResolveError with the specified kind and underlying error
func NewResolveHTTPError ¶
NewResolveHTTPError creates an HTTP request error
func NewResolveLookupError ¶
NewResolveLookupError creates a lookup error: the server answered and told us it doesn't have the capability.
func NewResolveNoAnswerError ¶ added in v0.13.0
NewResolveNoAnswerError reports that remote held a healthy connection open but never answered the lookup.
func NewResolveStatusError ¶
NewResolveStatusError creates a status code error
func NewResolveStatusErrorWithReason ¶ added in v0.13.0
func NewResolveStatusErrorWithReason(name, remote string, statusCode int, code, detail string) error
NewResolveStatusErrorWithReason creates a status code error carrying the server's rpc-status and rpc-error headers: a rejection the server chose to name and explain rather than leave opaque. Both may be empty, which is the normal case, since most failures disclose nothing to an unauthenticated caller.
func NewResolveUnreachableError ¶ added in v0.13.0
NewResolveUnreachableError reports that nothing ever answered at remote.
func NewResolveWentSilentError ¶ added in v0.13.0
NewResolveWentSilentError reports that an established connection to remote stopped responding partway through the lookup.
func Propagator ¶
func Propagator() propagation.TextMapPropagator
func RegisterInterface ¶
func RegisterREST ¶ added in v0.14.0
RegisterREST mounts every HTTP-annotated method of iface onto mux. Route patterns use Go 1.22 method+wildcard syntax ("GET /api/v1/apps/{app}"), so a single mux can host multiple interfaces as long as their paths do not conflict.
Routes mounted this way enforce authentication but consult no authorizer, because a bare mux has no server to take one from. That is the same position as an RPC server with no authorizer configured, and it is why the production path is WithRESTBindAddr, which mounts through the server and applies the full chain. Prefer that unless you are deliberately hosting the gateway on a mux of your own.
func SetupOTelSDK ¶
setupOTelSDK bootstraps the OpenTelemetry pipeline. If it does not return an error, make sure to call shutdown for proper cleanup.
func SetupTracing ¶ added in v0.4.0
func SetupTracing(ctx context.Context, attrs ...attribute.KeyValue) (shutdown func(context.Context) error, err error)
SetupTracing configures OpenTelemetry tracing with an OTLP HTTP exporter. The exporter reads standard OTel env vars (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, etc.) so no explicit configuration is needed. Extra resource attributes (e.g. cluster identity) can be passed in. Returns a shutdown function that flushes pending spans.
func WithRequireClientCerts ¶
func WithRequireClientCerts(o *stateOptions)
func WithSkipVerify ¶
func WithSkipVerify(o *stateOptions)
Types ¶
type ActorCall ¶
type ActorCall struct {
// contains filtered or unexported fields
}
func (*ActorCall) IsAuthenticated ¶ added in v0.3.1
IsAuthenticated returns true for actor calls since they are local and implicitly trusted.
func (*ActorCall) NewCapability ¶
func (a *ActorCall) NewCapability(i *Interface) *Capability
func (*ActorCall) NewClient ¶
func (a *ActorCall) NewClient(capa *Capability) Client
type ActorClient ¶
type ActorClient struct {
// contains filtered or unexported fields
}
func (*ActorClient) CallWithCaps ¶
func (a *ActorClient) CallWithCaps(ctx context.Context, method string, args, result any, caps map[OID]*InlineCapability) error
func (*ActorClient) Close ¶
func (a *ActorClient) Close() error
func (*ActorClient) NewClient ¶
func (a *ActorClient) NewClient(capa *Capability) Client
func (*ActorClient) NewInlineCapability ¶
func (a *ActorClient) NewInlineCapability(i *Interface, lower any) (*InlineCapability, OID, *Capability)
type ActorRegistry ¶
type ActorRegistry interface {
Register(ctx context.Context, name string, iface *Interface) error
Client(ctx context.Context, name string) (Client, error)
Close(ctx context.Context) error
}
func NewLocalActorRegistry ¶
func NewLocalActorRegistry() ActorRegistry
type ActorResolver ¶
type AuthMethod ¶ added in v0.3.1
type AuthMethod string
AuthMethod indicates how a caller was authenticated
const ( AuthMethodCert AuthMethod = "cert" // TLS client certificate AuthMethodJWT AuthMethod = "jwt" // JWT token (e.g., from Miren Cloud) AuthMethodAnonymous AuthMethod = "anonymous" // No authentication (public methods) AuthMethodToken AuthMethod = "token" // Bearer token (e.g., outboard) AuthMethodOIDC AuthMethod = "oidc" // External OIDC token (e.g., GitHub Actions) AuthMethodSystem AuthMethod = "system" // Cluster-issued system workload identity AuthMethodWorkload AuthMethod = "workload" // Workload identity token from a sandbox AuthMethodSigned AuthMethod = "signed" // ed25519-signed request over a message transport )
type Authenticator ¶
type Authenticator interface {
// Authenticate validates the caller's credentials and returns their identity.
// Returns:
// - (*Identity, nil) if credentials are valid
// - (nil, nil) if no credentials present or credentials are invalid
// - (nil, error) if an error occurred during authentication
Authenticate(ctx context.Context, creds *Credentials) (*Identity, error)
}
Authenticator validates credentials and returns caller identity
type Authorizer ¶ added in v0.3.1
type Authorizer interface {
// Authorize checks if the identity is allowed to perform the action on the resource.
// For RPC methods, resource is typically the interface name (lowercase) and
// action is the method name (lowercase).
// Returns nil if allowed, or an error describing why access was denied.
Authorize(ctx context.Context, identity *Identity, resource, action string) error
}
Authorizer checks if an identity is allowed to perform an action on a resource
type Call ¶
type Call interface {
NewClient(capa *Capability) Client
Args(v any)
Results(v any)
NewCapability(i *Interface) *Capability
// IsAuthenticated returns true if the caller presented a valid TLS client certificate.
// This is used by methods that need to distinguish between authenticated and
// unauthenticated callers (e.g., runner registration allows unauthenticated Join
// but requires authentication for admin operations like CreateInvite).
IsAuthenticated() bool
}
type Capability ¶
type Capability struct {
OID OID `cbor:"0,keyasint" json:"oid"`
Address string `cbor:"1,keyasint" json:"address"`
User []byte `cbor:"2,keyasint" json:"owner"`
Issuer []byte `cbor:"3,keyasint" json:"issue"`
RestoreState *InterfaceState `cbor:"4,keyasint" json:"restore-state"`
Inline bool `cbor:"5,keyasint" json:"inline"`
}
type Client ¶
type Client interface {
CallWithCaps(ctx context.Context, method string, args, result any, caps map[OID]*InlineCapability) error
Call(ctx context.Context, method string, args, result any) error
NewInlineCapability(i *Interface, lower any) (*InlineCapability, OID, *Capability)
NewClient(capa *Capability) Client
Close() error
}
type Credentials ¶ added in v0.14.0
type Credentials struct {
// Authorization is the raw Authorization header value, e.g. "Bearer <jwt>".
Authorization string
// Host is the address the caller addressed, used as the expected audience
// when validating a token. Empty on message transports, which are not
// addressed by name.
Host string
// TLS is the connection's handshake state, or nil when the transport has no
// TLS layer of its own — including any connection supplied by a caller,
// whose security is that caller's concern.
TLS *tls.ConnectionState
}
Credentials carries what an authenticator needs to identify a caller, independent of how the call arrived. The HTTP transports fill it from the request; message transports fill it from the operation frame, where there is no request and no TLS handshake to inspect.
func CredentialsFromRequest ¶ added in v0.14.0
func CredentialsFromRequest(r *http.Request) *Credentials
CredentialsFromRequest extracts credentials from an HTTP request, for the HTTP transports and for anything fronting rpc with an HTTP layer of its own.
func (*Credentials) BearerToken ¶ added in v0.14.0
func (c *Credentials) BearerToken() string
BearerToken returns the token from a "Bearer <token>" Authorization value, or an empty string if the credentials carry no bearer token.
func (*Credentials) VerifiedPeerCertificate ¶ added in v0.14.0
func (c *Credentials) VerifiedPeerCertificate() *x509.Certificate
VerifiedPeerCertificate returns the caller's TLS client certificate, but only when the TLS layer verified it against the cluster CA. A presented but unverified certificate must never yield a cert identity, which grants RBAC-bypassing privileges in Authorize.
type CurrentConnectionInfo ¶
type CurrentConnectionInfo struct {
PeerSubject string
// PeerCertificate is the client certificate presented during the mTLS
// handshake, if any. When a CA is configured the server uses
// tls.VerifyClientCertIfGiven, so any cert present here has already been
// verified to chain to the cluster CA (r.TLS.VerifiedChains is non-empty).
PeerCertificate *x509.Certificate
}
func ConnectionInfo ¶
func ConnectionInfo(ctx context.Context) *CurrentConnectionInfo
type DebugAuthResponse ¶
type DebugAuthResponse struct {
Success bool `json:"success"`
ServerVersion string `json:"server_version,omitempty"`
AuthMethod string `json:"auth_method,omitempty"`
Identity string `json:"identity,omitempty"`
UserInfo map[string]string `json:"user_info,omitempty"`
Message string `json:"message,omitempty"`
}
DebugAuthResponse represents the response from the debug-auth endpoint
type DescFile ¶
type DescFile struct {
Imports map[string]Import `yaml:"imports"`
Types []*DescType `yaml:"types"`
Interfaces []*DescInterface `yaml:"interfaces"`
}
type DescHTTPIface ¶ added in v0.14.0
type DescHTTPIface struct {
// Prefix is prepended to every method's path template (e.g. /api/v1).
Prefix string `yaml:"prefix,omitempty"`
}
DescHTTPIface holds interface-level REST configuration from the IDL http: block.
type DescHTTPMethod ¶ added in v0.14.0
type DescHTTPMethod struct {
Get string `yaml:"get,omitempty"`
Post string `yaml:"post,omitempty"`
Put string `yaml:"put,omitempty"`
Delete string `yaml:"delete,omitempty"`
Patch string `yaml:"patch,omitempty"`
// Body designates request-body binding: "*" binds the whole JSON body onto
// the method args; "" means no body and params come from the path and query
// string. When unset, effectiveBody defaults it from the verb.
Body string `yaml:"body,omitempty"`
}
DescHTTPMethod holds method-level REST configuration from the IDL http: block. It accepts two YAML shapes (see UnmarshalYAML): a compact scalar "VERB /path/template" for the common case, or a mapping with an explicit verb key plus an optional body: override. Exactly one verb field ends up set.
func (*DescHTTPMethod) UnmarshalYAML ¶ added in v0.14.0
func (m *DescHTTPMethod) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML accepts either the compact scalar form ("POST /apps") or the mapping form ({post: /apps, body: "*"}). The compact form keeps the common case terse and is backward compatible with the pre-existing http: convention in the IDL.
type DescInterface ¶
type DescInterface struct {
Name string `yaml:"name"`
Method []*DescMethods `yaml:"methods"`
Generic []string `yaml:"generic,omitempty"`
Constraints []string `yaml:"constraints,omitempty"`
HTTP *DescHTTPIface `yaml:"http,omitempty"`
}
type DescMethods ¶
type DescMethods struct {
Name string `yaml:"name"`
Index int `yaml:"index"`
Parameters []*DescParamater `yaml:"parameters"`
Results []*DescParamater `yaml:"results"`
// Public marks this method as accessible without TLS client certificate authentication.
// Public methods still require capability-level auth (Ed25519 signatures) but allow
// unauthenticated callers (e.g., for registration flows where the client doesn't have certs yet).
Public bool `yaml:"public,omitempty"`
// RestOnly marks this method as reachable only through its http: binding.
// It is not dispatched over the RPC transport, not advertised in the
// method list, and no client method is generated for it.
//
// Use it for a method shaped for a URL rather than for a program: flat
// scalars a query string can carry, where the RPC surface offers the same
// answer through grouped arguments. Without it the URL form becomes a
// second, worse way for a Go caller to ask the same question.
//
// A rest_only method with no http: binding is unreachable and is rejected
// at generation time.
RestOnly bool `yaml:"rest_only,omitempty"`
HTTP *DescHTTPMethod `yaml:"http,omitempty"`
}
type DescParamater ¶
type DescType ¶
type DescType struct {
Type string `yaml:"type"`
Fields []*DescField `yaml:"fields"`
Compact bool `yaml:"compact,omitempty"`
Generic []string `yaml:"generic,omitempty"`
Constraints []string `yaml:"constraints,omitempty"`
// contains filtered or unexported fields
}
func (*DescType) CalculateOffsets ¶
type DisclosableAuthError ¶ added in v0.13.0
type DisclosableAuthError interface {
error
// AuthErrorCode returns a short machine-readable code, sent as rpc-status
// so clients can recognize the failure without parsing the message.
AuthErrorCode() string
}
DisclosableAuthError is an authentication failure whose reason is safe to hand back to the caller that triggered it. Authenticators opt in by implementing it; anything else surfaces as a bare 401, because auth failures otherwise make a convenient oracle for probing a cluster's configuration.
type Dispatcher ¶
type ErrorCategory ¶
type ErrorCategory interface {
ErrorCategory() string
}
type ErrorMessage ¶
type ErrorMessage interface {
ErrorMessage() string
}
type ForbidRestore ¶
type ForbidRestore interface {
// contains filtered or unexported methods
}
type Generator ¶
type Generator struct {
Imports map[string]Import
Types []*DescType
Interfaces []*DescInterface
// contains filtered or unexported fields
}
func NewGenerator ¶
type HTTPBinding ¶ added in v0.14.0
type HTTPBinding struct {
// Verb is the HTTP method (GET, POST, PUT, DELETE, PATCH).
Verb string
// Path is the fully-resolved route template, including any interface
// prefix, using Go 1.22 ServeMux wildcards (e.g. /api/v1/apps/{app}/config).
Path string
// Body designates where the request body maps: "*" binds the whole JSON
// body onto the args, "" means no body (params come from path/query).
Body string
// PathParams lists the wildcard names embedded in Path, in order.
PathParams []string
// Query lists the parameters bound from the URL query string, with the type
// info needed to coerce their string values into typed JSON. It is only
// populated for bodyless bindings (Body == ""); when a body is present the
// non-path params ride in the JSON body instead.
Query []HTTPParam
}
HTTPBinding maps an RPC method onto an HTTP route for the REST gateway. It is populated by generated AdaptXxx code from the method's IDL http: annotation.
type HTTPParam ¶ added in v0.14.0
type HTTPParam struct {
// Name is the parameter (and query key) name.
Name string
// Kind selects how the raw string value is coerced into JSON: one of
// "string", "bool", "int", "uint", "float", or "timestamp".
Kind string
}
HTTPParam describes a single query-bound parameter for the REST gateway.
type HasReconstructFromState ¶
type HasReconstructFromState interface {
ReconstructFromState(is *InterfaceState) (*Interface, error)
}
type HasRestoreState ¶
type Identity ¶ added in v0.3.1
type Identity struct {
// Subject is the primary identifier (cert CN, JWT subject, etc.)
Subject string
// Groups contains group memberships (from JWT claims, etc.)
Groups []string
// Method indicates how the caller was authenticated
Method AuthMethod
// Metadata holds auth-method-specific data (e.g., OrganizationID for cloud auth)
Metadata map[string]any
}
Identity represents an authenticated caller
func IdentityFromContext ¶ added in v0.3.1
IdentityFromContext retrieves the Identity from the context, if present
type IfaceReg ¶
type IfaceReg struct {
// contains filtered or unexported fields
}
func NewIfaceReg ¶
func NewIfaceReg() *IfaceReg
type InlineCapability ¶
type InlineCapability struct {
*Capability
*Interface
}
type Interface ¶
type Interface struct {
// contains filtered or unexported fields
}
func NewInterface ¶
func (*Interface) Methods ¶ added in v0.14.0
Methods returns the interface's methods. The order is unspecified. It exists so external packages (notably the REST gateway) can enumerate methods without access to the private method map.
func (*Interface) Name ¶ added in v0.14.0
Name returns the schema name of the interface (e.g. "Crud").
func (*Interface) SetAroundContext ¶
type InterfaceCreators ¶
type InterfaceCreators struct {
// contains filtered or unexported fields
}
func NewInterfaceCreators ¶
func NewInterfaceCreators() *InterfaceCreators
type InterfaceDescriptor ¶
type InterfaceDescriptor struct {
}
type InterfaceState ¶
type InterfaceState struct {
Category string `cbor:"0,keyasint" json:"category"`
Interface string `cbor:"1,keyasint" json:"interface"`
Data any `cbor:"2,keyasint" json:"data"`
}
func (*InterfaceState) Decode ¶
func (i *InterfaceState) Decode(v any) error
type LocalActorRegistry ¶
type LocalActorRegistry struct {
// contains filtered or unexported fields
}
type LocalOnlyAuthenticator ¶ added in v0.2.0
type LocalOnlyAuthenticator struct{}
LocalOnlyAuthenticator requires a valid TLS client certificate. Used when cloud authentication is not enabled.
func (*LocalOnlyAuthenticator) Authenticate ¶ added in v0.3.1
func (l *LocalOnlyAuthenticator) Authenticate(ctx context.Context, creds *Credentials) (*Identity, error)
type MessageConn ¶ added in v0.14.0
MessageConn is the pure message interface a message-oriented backend implements: a reliable, ordered, bidirectional, point-to-point pipe of discrete byte messages between two peers. The framework layers a stream multiplexer (msgmux) on top to recover the rpcSession semantics that callbacks and streaming require.
Recv blocks until a message is available and returns io.EOF once the peer has closed the connection and no buffered messages remain.
type MessageRemote ¶ added in v0.14.0
type MessageRemote interface {
Remote() string
}
MessageRemote is an optional interface a MessageConn may implement to name its far end.
Optional because a MessageConn is a byte pipe and most backends have no address to give. It exists for the audit trail, which records where a call came from and had nothing to record on this transport.
type MessageSessionOption ¶ added in v0.14.0
type MessageSessionOption func(*messageSessionOptions)
MessageSessionOption configures a session built over a MessageConn.
func WithMaxBufferedData ¶ added in v0.14.0
func WithMaxBufferedData(n int) MessageSessionOption
WithMaxBufferedData bounds how much delivered-but-unread stream data one session may hold across all its streams, before the session is torn down.
It exists because the transport's own backpressure does not reach this far. A frame handed to msgmux has already left the backend's accounting, and it sits in a stream's read buffer until a handler reads it — so a peer that sends faster than its handler consumes, or keeps sending after the handler has stopped reading altogether, grows that buffer with nothing to stop it. Any limit the transport advertises is only real if this one backs it.
Zero leaves it at defaultMaxBufferedData.
func WithMaxFrameSize ¶ added in v0.14.0
func WithMaxFrameSize(n int) MessageSessionOption
WithMaxFrameSize bounds the payload rpc places in a single message. Set it below the backend's own message-size limit — an envelope protocol wrapping these messages, or a broker capping message size. Stream writes larger than the bound are split across frames, so the bound costs throughput, never correctness.
type Method ¶
type Method struct {
Name string
InterfaceName string
Index int
Handler func(ctx context.Context, call Call) error
// Public marks this method as accessible without TLS client certificate authentication.
// The RPC layer will reject unauthenticated calls to non-public methods automatically.
Public bool
// RestOnly marks this method as reachable through its HTTP binding and
// nowhere else. The RPC transport reports it as unknown and it is left out
// of the advertised method list, so it is invisible to an RPC caller.
//
// It exists for methods that are shaped for a URL rather than for a
// program: flat scalars a query string can carry, where the RPC surface
// offers the same answer through grouped arguments a caller cannot
// transpose. Marking the URL form rest-only stops it from becoming a second
// way to call the same thing badly.
RestOnly bool
// Params lists the method's parameter names in schema order. It powers
// parameter-level capability detection: a client can ask whether a server
// understands a specific parameter (e.g. one added after the method first
// shipped) instead of only whether the method exists. See HasMethodParam.
Params []string
// HTTP describes how to expose this method over a plain HTTP/JSON REST API.
// It is nil unless the method carries an http: annotation in the IDL. The
// REST gateway (RegisterREST) only mounts routes for methods with a binding.
HTTP *HTTPBinding
}
type NetworkCall ¶
type NetworkCall struct {
// contains filtered or unexported fields
}
func Local ¶
func Local(args ...any) *NetworkCall
func (*NetworkCall) Args ¶
func (c *NetworkCall) Args(v any)
func (*NetworkCall) IsAuthenticated ¶ added in v0.3.1
func (c *NetworkCall) IsAuthenticated() bool
IsAuthenticated returns true if the caller presented a valid TLS client certificate, or if this is a local call (used in tests).
func (*NetworkCall) NewCapability ¶
func (c *NetworkCall) NewCapability(i *Interface) *Capability
func (*NetworkCall) NewClient ¶
func (c *NetworkCall) NewClient(capa *Capability) Client
func (*NetworkCall) RemoteAddr ¶
func (c *NetworkCall) RemoteAddr() string
func (*NetworkCall) Results ¶
func (c *NetworkCall) Results(v any)
func (*NetworkCall) SkipArgs ¶ added in v0.2.0
func (c *NetworkCall) SkipArgs()
SkipArgs consumes and discards args if they haven't been consumed yet. This prevents leftover args data from being misinterpreted as the next request.
func (*NetworkCall) String ¶
func (c *NetworkCall) String() string
type NetworkClient ¶
type NetworkClient struct {
State *State
// contains filtered or unexported fields
}
func LocalClient ¶
func LocalClient(iface *Interface) *NetworkClient
func (*NetworkClient) CallWithCaps ¶
func (c *NetworkClient) CallWithCaps(ctx context.Context, method string, args, result any, caps map[OID]*InlineCapability) error
func (*NetworkClient) Close ¶
func (c *NetworkClient) Close() error
func (*NetworkClient) HasMethod ¶
func (c *NetworkClient) HasMethod(ctx context.Context, method string) bool
HasMethod checks if the remote interface supports a given method. Returns false if the method doesn't exist or if the server doesn't support introspection.
func (*NetworkClient) HasMethodParam ¶ added in v0.11.0
func (c *NetworkClient) HasMethodParam(ctx context.Context, method, param string) bool
HasMethodParam reports whether the remote interface's method accepts a given parameter. This distinguishes servers that have a method from servers that have a newer revision of it with an added parameter. Returns false if the method or parameter is absent, or if the server is too old to report parameters at all (introspection predates this, or the method itself).
func (*NetworkClient) ListMethods ¶
func (c *NetworkClient) ListMethods(ctx context.Context) ([]string, error)
ListMethods returns the list of methods available on this capability. Returns an error if the server doesn't support method introspection (old servers).
func (*NetworkClient) NewCapability ¶
func (c *NetworkClient) NewCapability(i *Interface, lower any) *Capability
func (*NetworkClient) NewClient ¶
func (c *NetworkClient) NewClient(capa *Capability) Client
func (*NetworkClient) NewInlineCapability ¶
func (c *NetworkClient) NewInlineCapability(i *Interface, lower any) (*InlineCapability, OID, *Capability)
func (*NetworkClient) String ¶
func (c *NetworkClient) String() string
type NoOpAuthenticator ¶
type NoOpAuthenticator struct{}
NoOpAuthenticator allows all requests without checking credentials. Used for testing only.
func (*NoOpAuthenticator) Authenticate ¶ added in v0.3.1
func (n *NoOpAuthenticator) Authenticate(ctx context.Context, creds *Credentials) (*Identity, error)
type ResolveError ¶
type ResolveError struct {
Kind ResolveErrorKind
Err error
Msg string
StatusCode int // HTTP status code for ResolveStatusError
// Code is the server's rpc-status header, when it sent one. It names the
// failure so the CLI can recognize it without parsing prose.
Code string
// Detail is the server's rpc-error header: an explanation the server judged
// safe to return to this caller. Empty for most failures.
Detail string
// Name is the capability being resolved, e.g. "entities".
Name string
// Remote is the address we were talking to, e.g. "localhost:8443".
Remote string
// Elapsed is how long we waited before giving up. Zero when the failure
// wasn't a timeout.
Elapsed time.Duration
}
ResolveError represents an error that occurred during capability resolution.
The exported fields carry the structured facts about the failure; turning those into user-facing prose is the CLI's job (see wrapRPCError), which is also where the cluster name and the command the user typed are known.
func (*ResolveError) Error ¶
func (e *ResolveError) Error() string
func (*ResolveError) Is ¶
func (e *ResolveError) Is(target error) bool
Is matches another *ResolveError of the same kind. Comparing kinds (rather than matching any *ResolveError, as this used to) is what makes the exported sentinels below meaningful — otherwise errors.Is(err, ErrResolveLookup) was true for every resolve failure, including transport ones.
func (*ResolveError) Unwrap ¶
func (e *ResolveError) Unwrap() error
type ResolveErrorKind ¶
type ResolveErrorKind int
ResolveErrorKind represents different kinds of capability resolution errors.
The three transport kinds (Unreachable, WentSilent, NoAnswer) exist because they have genuinely different causes and different fixes, even though the underlying transport reports two of them with the same string. quic-go raises its idle-timeout error both for a connection that never completed a handshake and for one that completed and later went quiet, so the error value alone can't tell them apart — see NetworkClient.classifyTransportError.
const ( // ResolveHTTPError is a transport failure we couldn't classify further. ResolveHTTPError ResolveErrorKind = iota // ResolveStatusError is a non-200 response to the lookup. ResolveStatusError // ResolveDecodeError is a response body we couldn't parse. ResolveDecodeError // ResolveLookupError is the server telling us it doesn't have the // capability. The server answered, so it is reachable and healthy. ResolveLookupError // ResolveUnreachableError means nothing ever answered: we gave up before // any connection completed its handshake. The server is down, the address // is wrong, or something is dropping the traffic. ResolveUnreachableError // ResolveWentSilentError means we had an established connection and it // stopped responding mid-request: a crash, a hang, or a lost network path. ResolveWentSilentError // ResolveNoAnswerError means the connection stayed healthy the whole time // but the server never produced a response. The server is running and // reachable but isn't replying — wedged, or too old to serve this lookup. ResolveNoAnswerError )
func (ResolveErrorKind) String ¶ added in v0.13.0
func (k ResolveErrorKind) String() string
type ResolverFunc ¶
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
func (*Server) ExposeValue ¶
type ServiceID ¶ added in v0.3.1
type ServiceID = string
ServiceID represents an RPC service identifier. These are used with RPCClient() and server.ExposeValue() to identify services.
Currently a type alias for incremental adoption. When all call sites use constants, this can become a distinct type (type ServiceID string) and function signatures can be updated for full type safety.
const ( ServiceRunner ServiceID = "dev.miren.runtime/runner" // ServiceSqliteBackup stores LTX transaction files replicated from // SQLite-provider disks on runners. ServiceSqliteBackup ServiceID = "dev.miren.runtime/sqlite-backup" )
Runtime service identifiers. Add new services here to maintain type safety and avoid string typos.
type State ¶
type State struct {
*StateCommon
// contains filtered or unexported fields
}
func (*State) ClientFromMessageConn ¶ added in v0.14.0
func (s *State) ClientFromMessageConn( ctx context.Context, conn MessageConn, name string, opts ...MessageSessionOption, ) (*NetworkClient, error)
ClientFromMessageConn builds a client for the named remote object over a connection the caller owns, the dialing counterpart to ServeMessageConn.
The resulting session serves as well as calls: the peer may invoke objects this State has exposed over the same connection. That is what allows a party that dialled outbound — through a firewall it could not accept through — to still be called back into.
func (*State) ListenAddr ¶
func (*State) LoopbackAddr ¶
func (*State) RESTListenAddr ¶ added in v0.14.0
RESTListenAddr returns the address the REST listener is bound to, or an empty string if no such listener is running.
func (*State) ServeMessageConn ¶ added in v0.14.0
func (s *State) ServeMessageConn(ctx context.Context, conn MessageConn, opts ...MessageSessionOption) error
ServeMessageConn serves RPC over a connection the caller owns, and blocks until the connection fails or ctx is cancelled.
This is the entry point for backends rpc does not manage — most importantly a socket carrying somebody else's envelope protocol, where the caller unwraps inbound payloads into Recv and wraps outbound payloads from Send. rpc never dials, listens, or closes such a connection.
Capabilities minted on this connection are reachable only for its lifetime; they carry no dialable address.
func (*State) Shutdown ¶ added in v0.15.0
Shutdown gracefully stops every network server owned by this State. Unlike cancellation of the context passed to NewState, callers can place Shutdown precisely in an ordered component teardown and give in-flight requests a bounded drain window.
func (*State) TCPListenAddr ¶ added in v0.14.0
TCPListenAddr returns the address the raw TCP message listener is bound to, or an empty string if no such listener is running.
func (*State) WSListenAddr ¶ added in v0.14.0
WSListenAddr returns the address the TCP/WebSocket listener is bound to, or an empty string if no such listener is running.
type StateCommon ¶
type StateCommon struct {
// contains filtered or unexported fields
}
type StateOption ¶
type StateOption func(*stateOptions)
func WithAuthenticator ¶
func WithAuthenticator(auth Authenticator) StateOption
func WithAuthorizer ¶ added in v0.3.1
func WithAuthorizer(authz Authorizer) StateOption
func WithBearerToken ¶
func WithBearerToken(token string) StateOption
func WithBearerTokenFunc ¶ added in v0.14.0
func WithBearerTokenFunc(fn func() (string, error)) StateOption
WithBearerTokenFunc supplies a bearer token per request, for credentials that are refreshed out of band and so cannot be captured once at dial time. The sandbox workload identity token is the motivating case: it expires hourly and is rewritten on disk by the sandbox controller, so a client that read it once would start failing after an hour.
Takes precedence over WithBearerToken.
func WithBindAddr ¶
func WithBindAddr(addr string) StateOption
func WithCert ¶
func WithCert(certPath, keyPath string) StateOption
func WithCertPEMs ¶
func WithCertPEMs(certData, keyData []byte) StateOption
func WithCertificateVerification ¶
func WithCertificateVerification(caCert []byte) StateOption
func WithEndpoint ¶
func WithEndpoint(endpoint string) StateOption
func WithHTTPHandler ¶ added in v0.13.0
func WithHTTPHandler(pattern string, handler http.Handler) StateOption
WithHTTPHandler mounts an additional handler beside the RPC surface, so a cluster-internal service can be reached over the listener that already authenticates callers instead of opening a port of its own.
Pattern uses http.ServeMux syntax. Registration happens before the listener starts serving, so a mounted route is live for the first request.
Two things about what a handler mounted here does and does not inherit. It does inherit authentication: a non-RPC path is refused outright unless the authenticator produced an identity, so an anonymous caller never reaches the handler. It does not inherit authorization, because the authorizer runs only on RPC method dispatch. A handler is responsible for deciding what its caller may do, and should not read an identity off the context and assume the answer, since a cluster certificate authenticates as a superuser.
func WithLocalConnect ¶
func WithLocalConnect(addr string) StateOption
func WithLocalServer ¶
func WithLocalServer(addr string) StateOption
func WithLogLevel ¶
func WithLogLevel(level slog.Level) StateOption
func WithLogger ¶
func WithLogger(log *slog.Logger) StateOption
func WithMemServer ¶ added in v0.14.0
func WithMemServer(name string) StateOption
WithMemServer registers this State as an in-process message server under the given name. Peers connect with State.Connect("mem://name", ...). Used for testing and for bridging RPC onto message-oriented systems.
func WithRESTBindAddr ¶ added in v0.14.0
func WithRESTBindAddr(addr string) StateOption
WithRESTBindAddr enables a TCP listener serving the REST/JSON gateway over TLS, bound to addr. It answers HTTP/2 and HTTP/1.1 (negotiated by ALPN), so an ordinary HTTP client reaches the same handlers the QUIC transport serves. Use "host:0" to bind an ephemeral port; the chosen address is available via State.RESTListenAddr after NewState returns.
Setting this also mounts REST routes for every HTTP-annotated method of the interfaces passed to Server.ExposeValue. Without it no REST route is mounted at all, so a deployment that has not opted in keeps exactly the surface it had before.
func WithTCPBindAddr ¶ added in v0.14.0
func WithTCPBindAddr(addr string) StateOption
WithTCPBindAddr enables a raw TLS-over-TCP listener serving the RPC protocol as a message session, bound to addr. It carries no HTTP layer at all, which makes it the leanest option where a WebSocket handshake buys nothing. Clients reach it with State.Connect("tcp://host:port").
func WithTLSServerName ¶ added in v0.14.0
func WithTLSServerName(name string) StateOption
WithTLSServerName overrides the name the server certificate is verified against, independent of the address dialed. Needed when the dial address cannot appear in the certificate — a sandbox reaches the API through its bridge router address, which is allocated only after the certificate has been issued, and verifies against the API's stable name instead.
This is not a way to skip verification: the certificate must still chain to the configured CA and cover this name.
func WithWSBindAddr ¶ added in v0.14.0
func WithWSBindAddr(addr string) StateOption
WithWSBindAddr enables an additional TCP listener serving the RPC protocol over TLS as a WebSocket message session, bound to addr. Use "host:0" to bind an ephemeral port; the chosen address is available via State.WSListenAddr after NewState returns. Clients reach it with State.Connect("wss://host:port") — this listener is TLS, so "ws://", which means plaintext, will not reach it.
Source Files
¶
- actor.go
- audit.go
- authenticator.go
- call.go
- cert.go
- client.go
- detach.go
- drain.go
- drain_client.go
- error.go
- generator.go
- helper.go
- iface_reg.go
- inline.go
- inline_router.go
- ip_addr.go
- message.go
- message_mem.go
- message_tcp.go
- message_ws.go
- msgmux.go
- oid.go
- otel.go
- registry.go
- rest.go
- server.go
- server_session.go
- service.go
- signing.go
- state.go
- state_local.go
- state_rest.go
- state_ws.go
- test_helpers.go
- timeouts.go
- transport.go
- transport_msg.go
- transport_wt.go