Documentation
¶
Overview ¶
Package server implements the gRPC RegistryService.
The server is the public entry point to a running protoregistry. It validates and rate-limits incoming requests, applies the configured Authenticator (defaulting to NoAuth), gates privileged operations (writes to the __builtins__ namespace, Publish with Force=true) on Identity.Admin, and sanitizes errors so that backend implementation detail (raw PostgreSQL errors, unwrapped wrap chains) does not leak to clients.
Index ¶
- Variables
- func ParseTokenFile(r io.Reader) (map[string]Identity, error)
- func UnaryAuthInterceptor(a Authenticator) grpc.UnaryServerInterceptor
- type Authenticator
- type Identity
- type Limits
- type NoAuth
- type Option
- type Options
- type Server
- func (s *Server) CreateNamespace(ctx context.Context, req *registrypb.CreateNamespaceRequest) (*registrypb.CreateNamespaceResponse, error)
- func (s *Server) DiscardStaging(ctx context.Context, req *registrypb.DiscardStagingRequest) (*registrypb.DiscardStagingResponse, error)
- func (s *Server) GetDescriptor(ctx context.Context, req *registrypb.GetDescriptorRequest) (*registrypb.GetDescriptorResponse, error)
- func (s *Server) GetSchema(ctx context.Context, req *registrypb.GetSchemaRequest) (*registrypb.GetSchemaResponse, error)
- func (s *Server) GetSource(ctx context.Context, req *registrypb.GetSourceRequest) (*registrypb.GetSourceResponse, error)
- func (s *Server) ListNamespaces(ctx context.Context, req *registrypb.ListNamespacesRequest) (*registrypb.ListNamespacesResponse, error)
- func (s *Server) ListSchemas(ctx context.Context, req *registrypb.ListSchemasRequest) (*registrypb.ListSchemasResponse, error)
- func (s *Server) Promote(ctx context.Context, req *registrypb.PromoteRequest) (*registrypb.PromoteResponse, error)
- func (s *Server) Publish(ctx context.Context, req *registrypb.PublishRequest) (*registrypb.PublishResponse, error)
- func (s *Server) Rollback(ctx context.Context, req *registrypb.RollbackRequest) (*registrypb.RollbackResponse, error)
- type TokenAuth
Constants ¶
This section is empty.
Variables ¶
var AnonymousIdentity = Identity{Subject: "anonymous", Admin: false}
AnonymousIdentity is the placeholder returned by NoAuth and used when no authentication metadata accompanies a request.
Functions ¶
func ParseTokenFile ¶
ParseTokenFile reads the TokenAuth file format described on the TokenAuth type. It returns the parsed token map suitable for NewTokenAuth.
func UnaryAuthInterceptor ¶
func UnaryAuthInterceptor(a Authenticator) grpc.UnaryServerInterceptor
UnaryAuthInterceptor returns a grpc.UnaryServerInterceptor that runs the configured Authenticator and stashes the resulting Identity on the request context. Handlers retrieve it via IdentityFromContext.
Types ¶
type Authenticator ¶
type Authenticator interface {
Authenticate(ctx context.Context, fullMethod string) (Identity, error)
}
Authenticator extracts an Identity from incoming RPC metadata. Implementations may consult bearer tokens, mTLS client certs, JWT claims, or any other transport-supplied data.
Returning a non-nil error rejects the RPC; the error should be a gRPC status (e.g. codes.Unauthenticated) so the caller sees a meaningful failure rather than codes.Internal.
type Identity ¶
Identity is the authenticated principal behind an RPC. It is attached to the request context by the auth interceptor; handlers retrieve it via IdentityFromContext.
Subject is the human/service name (used in audit logs). Admin grants the bearer the ability to perform privileged operations: writes to the __builtins__ namespace, Publish with Force=true, and (in a future patch) rollbacks that bypass dependent compat checks.
func IdentityFromContext ¶
IdentityFromContext returns the Identity attached by the auth interceptor, or AnonymousIdentity if none is present.
type Limits ¶
type Limits struct {
// MaxIDLength is the maximum length, in bytes, of a namespace ID,
// schema ID, or token cursor. Applied to user-supplied identifiers only.
MaxIDLength int
// MaxFilenameLength is the maximum length, in bytes, of a source
// filename inside a Publish request.
MaxFilenameLength int
// MaxSourcesPerRequest caps the number of source files in a single
// Publish request. Each file allocates AST nodes during normalization,
// so this cap bounds compile-time memory.
MaxSourcesPerRequest int
// MaxTotalSourceBytes caps the sum of all source file sizes in a
// single Publish request.
MaxTotalSourceBytes int64
// MaxFileSourceBytes caps the size of any individual source file.
MaxFileSourceBytes int64
// DefaultListPageSize is used when a List* RPC sends page_size = 0.
DefaultListPageSize int
// MaxListPageSize is the upper bound the server will honour even if a
// caller asks for more.
MaxListPageSize int
}
Limits caps the size and shape of incoming RPC payloads. Every limit is expressed in user units (bytes, count, length) so operators can reason about them directly. Limits are enforced at the RPC boundary before any expensive work (compilation, blob storage, descriptor materialization) happens — they are the first line of defence against DoS via crafted inputs.
The compile-time wall-clock cap lives on the compiler (see compiler.WithTimeout). It is enforced where the cost is paid, and so applies whether the compiler is invoked from the server, a CLI command, or an embedded library caller.
func DefaultLimits ¶
func DefaultLimits() Limits
DefaultLimits returns the default Limits used when the server is constructed without WithLimits. The numbers are chosen to be permissive enough for normal use (multi-megabyte schemas, hundreds of files) while still bounding worst-case server memory.
type NoAuth ¶
type NoAuth struct{}
NoAuth permits every request, returning AnonymousIdentity. It is the default when the server is constructed without WithAuth and is intended for local development and trusted-network deployments. Combined with AllowAnonymousWrites=false it allows reads but rejects writes; combined with AllowAnonymousWrites=true (the back-compat default) it preserves the pre-auth-seam behaviour and emits a startup warning instead.
type Option ¶
type Option func(*Options)
Option mutates an Options. Apply via New(reg, store, WithAuth(...), ...).
func WithAllowAnonymousWrites ¶
WithAllowAnonymousWrites controls whether anonymous callers may invoke write RPCs. The default is true; pass false to require authentication for any state-mutating call.
func WithAuth ¶
func WithAuth(a Authenticator) Option
WithAuth installs an Authenticator. The Authenticator's result is available on the request context via IdentityFromContext.
func WithLogger ¶
WithLogger replaces the default slog.Logger used for audit lines.
type Options ¶
type Options struct {
// Limits caps incoming RPC payload sizes. Defaults to DefaultLimits().
Limits Limits
// Auth runs on every RPC and produces the Identity on the request
// context. Defaults to NoAuth (anonymous, non-admin).
Auth Authenticator
// Logger receives audit and warning lines. Defaults to slog.Default().
Logger *slog.Logger
// AllowAnonymousWrites controls whether write RPCs (Publish, Promote,
// Rollback, DiscardStaging, CreateNamespace) accept callers whose
// Identity is AnonymousIdentity. Defaults to true to preserve the
// pre-auth-seam behaviour; operators who want to lock the server down
// should set this to false and configure WithAuth.
AllowAnonymousWrites bool
}
Options configures a Server. Use the With* helpers rather than mutating directly; the zero Options is not a valid configuration.
func DefaultOptions ¶
func DefaultOptions() Options
DefaultOptions returns the Options used when no With* options are passed to New. The defaults are permissive enough to keep existing local-dev setups working (anonymous reads, anonymous writes, no auth) but the server emits a startup warning in this configuration so the operator knows it is unprotected.
type Server ¶
type Server struct {
registrypb.UnimplementedRegistryServiceServer
// contains filtered or unexported fields
}
Server implements the RegistryService gRPC server.
func New ¶
New creates a new gRPC server backed by the given registry and store. The variadic options replace fields on DefaultOptions.
func (*Server) CreateNamespace ¶
func (s *Server) CreateNamespace(ctx context.Context, req *registrypb.CreateNamespaceRequest) (*registrypb.CreateNamespaceResponse, error)
func (*Server) DiscardStaging ¶
func (s *Server) DiscardStaging(ctx context.Context, req *registrypb.DiscardStagingRequest) (*registrypb.DiscardStagingResponse, error)
func (*Server) GetDescriptor ¶
func (s *Server) GetDescriptor(ctx context.Context, req *registrypb.GetDescriptorRequest) (*registrypb.GetDescriptorResponse, error)
func (*Server) GetSchema ¶
func (s *Server) GetSchema(ctx context.Context, req *registrypb.GetSchemaRequest) (*registrypb.GetSchemaResponse, error)
func (*Server) GetSource ¶
func (s *Server) GetSource(ctx context.Context, req *registrypb.GetSourceRequest) (*registrypb.GetSourceResponse, error)
func (*Server) ListNamespaces ¶
func (s *Server) ListNamespaces(ctx context.Context, req *registrypb.ListNamespacesRequest) (*registrypb.ListNamespacesResponse, error)
func (*Server) ListSchemas ¶
func (s *Server) ListSchemas(ctx context.Context, req *registrypb.ListSchemasRequest) (*registrypb.ListSchemasResponse, error)
func (*Server) Promote ¶
func (s *Server) Promote(ctx context.Context, req *registrypb.PromoteRequest) (*registrypb.PromoteResponse, error)
func (*Server) Publish ¶
func (s *Server) Publish(ctx context.Context, req *registrypb.PublishRequest) (*registrypb.PublishResponse, error)
func (*Server) Rollback ¶
func (s *Server) Rollback(ctx context.Context, req *registrypb.RollbackRequest) (*registrypb.RollbackResponse, error)
type TokenAuth ¶
type TokenAuth struct {
// contains filtered or unexported fields
}
TokenAuth authenticates bearer tokens against a static map loaded from a file or constructed in code. Tokens are presented in the standard `authorization: Bearer <token>` metadata header.
File format (one entry per line, tab-separated; `#` starts a comment):
# token subject role abc123def456 alice admin 0123456789ab ci-bot user
`role` is `admin` or `user` (default `user`). Tokens with role `admin` receive Identity.Admin = true.
func NewTokenAuth ¶
NewTokenAuth constructs a TokenAuth over the given token→identity map. Callers wanting a file loader should use ParseTokenFile.