contract

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

Documentation

Overview

Package contract defines the cycle-neutral HTTP composition input value types shared by runtimebundle (canonical construction) and stdhttp (canonical and transitional composition). It owns no lifecycle, imports no runtimebundle, and imports no root stdhttp (task 3.4 dependency-direction contract).

Index

Constants

View Source
const CanonicalLegacyBasePath = "/v1"

CanonicalLegacyBasePath is the shared /v1 prefix used by existing frontends.

Variables

View Source
var ErrRouteConflict = errors.New("route registry: conflict")

ErrRouteConflict indicates two enabled owners claim the same normalized route.

Functions

func CloneHTTPAuthProviders

func CloneHTTPAuthProviders(in []httpauth.Provider) []httpauth.Provider

CloneHTTPAuthProviders returns a defensive copy of an auth provider slice.

func ClonePluginConfigs

func ClonePluginConfigs(in []config.PluginConfig) []config.PluginConfig

ClonePluginConfigs returns a deep defensive copy of plugin configuration rows, including their nested YAML config nodes.

func CloneRegistrations

func CloneRegistrations(in []lipsdk.Registration) []lipsdk.Registration

CloneRegistrations returns a deep defensive copy of plugin registrations, including their nested YAML config nodes.

func CloneStrings

func CloneStrings(in []string) []string

CloneStrings returns a defensive copy of a string slice.

func CloneTrafficRedactors

func CloneTrafficRedactors(in []traffic.Redactor) []traffic.Redactor

CloneTrafficRedactors returns a defensive copy of a redactor slice.

func CloneYAMLNode

func CloneYAMLNode(n yaml.Node) yaml.Node

CloneYAMLNode returns a deep defensive copy of a YAML node, including aliases and nested content.

func NormalizeMethod

func NormalizeMethod(method string) (string, error)

NormalizeMethod uppercases and trims an HTTP method.

func NormalizePath

func NormalizePath(path string) (string, error)

NormalizePath canonicalizes a mount path for deterministic ownership checks.

func SourceAddr

func SourceAddr(ctx context.Context) (netip.Addr, bool)

SourceAddr returns the normalized source address attached by WithSourceAddr. The second result reports whether a snapshot is present, so an observer outside a gated handler can fall back without inventing an identity.

func TrafficPortsFromSnapshot

func TrafficPortsFromSnapshot(snap TrafficSnapshot) traffic.PortBundle

TrafficPortsFromSnapshot projects a TrafficSnapshot into an immutable traffic.PortBundle with a defensive redactor-slice copy.

func ValidateOperatorRoutePath

func ValidateOperatorRoutePath(field, p string) error

ValidateOperatorRoutePath rejects an operator-supplied data-plane path that is not a literal route.

The policy is closed on purpose rather than extended metacharacter by metacharacter: an operator path is owned by the router and by the ingress self-defense carve, and both reason about literal paths, so a value that means something else to either of them cannot be supported safely. An operator who wants a literal character writes the literal character.

func WithSourceAddr

func WithSourceAddr(ctx context.Context, addr netip.Addr) context.Context

WithSourceAddr returns ctx carrying the already-resolved, normalized source address for this request.

The value stored is only the resolved netip.Addr: the ingress gate publishes the identity it snapshotted so inner observers (the transport-auth adaptive observer) never reparse mutable forwarding headers and can never disagree with the gate. No header, path, query, credential or principal is retained.

An invalid address is not a snapshot, so the parent context is returned unchanged and an outer gate decision is never silently overwritten.

Types

type CredentialDisposition

type CredentialDisposition uint8

CredentialDisposition is the closed, conservative answer of the credential presence question the ingress self-defense gate asks before it may refuse a quarantined source in front of authentication.

The two members carry no credential material, so the answer can never become a credential-validity oracle, and the ordering is normative: MayAuthenticate is the zero value, so an unprojected probe, an unknown provider and any future member all fail open to the normal transport-auth chain.

const (
	// MayAuthenticate reports that the active provider chain might still
	// authenticate the request as presented, so the request must reach the normal
	// auth chain. It is the safe default and the zero value of the enum.
	MayAuthenticate CredentialDisposition = iota
	// DefinitelyNoCredential reports that the complete active provider chain
	// proves the request carries no credential material it could authenticate
	// with. It is the only license to refuse a quarantined source before
	// authentication.
	DefinitelyNoCredential
)

type CredentialProbe

type CredentialProbe func(r *http.Request) CredentialDisposition

CredentialProbe is the conservative credential-presence probe projected per generation from the same transport-auth provider slice the auth chain runs.

The gate reads it as "this request definitely cannot authenticate": a DefinitelyNoCredential answer licenses a pre-auth refusal, and every other answer, including the nil probe, must reach authentication. The probe answers a question about the request and never discloses, copies or stores any credential.

type FrontendRouteClaims

type FrontendRouteClaims func(instanceID string, cfg yaml.Node) ([]RouteClaim, error)

FrontendRouteClaims computes the normalized owner-aware route claims for one enabled frontend instance. instanceID is the immutable owner identity used for the route-ownership registry; cfg is the plugin-local config subtree.

type GeoIPObserver

type GeoIPObserver interface {
	Decision(coregeoip.Reason, bool)
}

GeoIPObserver receives finite-label decision outcomes only.

type GeoIPResolverConfig

type GeoIPResolverConfig struct {
	Source         config.ClientIPSource
	TrustedProxies []netip.Prefix
}

GeoIPResolverConfig carries only generation-scoped address-source policy. Fixed parser bounds are owned by the HTTP adapter and are not caller knobs.

type GeoIPSecurityInput

type GeoIPSecurityInput struct {
	Policy   *coregeoip.Policy
	Lookup   coregeoip.CountryLookup
	Resolver GeoIPResolverConfig
	Observer GeoIPObserver
}

GeoIPSecurityInput is a non-owning projection of the process lookup service and immutable generation policy into the standard data-plane handler graph.

type HTTPCoreInput

type HTTPCoreInput struct {
	Executor *runtime.Executor
}

type HTTPFrontendInput

type HTTPFrontendInput struct {
	Executor             *runtime.Executor
	Registry             *pluginreg.Registry
	DefaultRouteSelector string
	RoutePrefixes        []string
	Plugins              []config.PluginConfig
	MaxRequestBodyBytes  int64
	DecodeAdmission      lipsdk.DecodeAdmission
	TrafficPorts         traffic.PortBundle
	PreRequestKeepalive  lipsdk.FrontendKeepaliveConfig
	// HTTPHeaders is the resolved inbound header-name set for this generation.
	HTTPHeaders lipsdk.HTTPHeaders
	// StreamKeepaliveInterval is the recovery SSE keepalive interval.
	StreamKeepaliveInterval time.Duration
	// GenerationContext is the runtime-owned generation lifecycle context. It
	// cancels when the generation begins shutdown (quiesce/drain) and is passed
	// to every mounted frontend through [lipsdk.FrontendMountOptions] so
	// long-lived transports (WebSocket sessions) close exactly once on retire.
	GenerationContext context.Context
	// ContinuationWiringFactory creates composition-root-owned continuation
	// state for each frontend mount generation.
	ContinuationWiringFactory lipsdk.ContinuationMountWiringFactory
	// FrontendRouteClaims optionally maps a frontend factory id to a provider
	// that computes the normalized owner-aware route claims for one frontend
	// instance. When set, [stdhttp.MountBundledFrontends] validates route
	// ownership (owner-aware claims + canonical path takeover) in a
	// generation-scoped RouteRegistry BEFORE any ServeMux handler is mounted; a
	// conflict fails the candidate atomically with both-owner diagnostics.
	// Frontends without a provider participate in no route-ownership
	// validation, so the seam stays fully generic plugin architecture.
	FrontendRouteClaims map[string]FrontendRouteClaims
	// LargePayload carries optional large-payload fast-path candidate configuration
	// for supported frontends.
	LargePayload LargePayloadInput
}

type HTTPModelInput

type HTTPModelInput struct {
	CatalogRuntime       *modelcatalog.CatalogRuntime
	ModelRegistryRuntime *modelregistry.Runtime
}

type HTTPOperationsInput

type HTTPOperationsInput struct {
	BillingReports          billing.ReportingStore
	BillingReportsPath      string
	BillingProvisioner      billing.AccountProvisioner
	BillingExposureRecovery billing.ExposureRecovery
	// BillingOperatorReports carries the optional 16.2A operator readers
	// for the protected reports mount. The zero value leaves every new
	// operator route reporting disabled; stock startup never opts into
	// the normalized statement import.
	BillingOperatorReports billingadmin.OperatorReports
	Metrics                *metrics.Bundle
	Store                  diag.AttemptLoader
	SecretGuardInventory   *diag.InventoryExtras
	ControlPlaneQueries    lipcp.Queries
	ReadinessReport        lipcp.ReadinessReportReader
	TokenAccountingAdmin   adminaccounting.Service
	RouteOverrideAdmin     http.Handler
	KeepwarmAdmin          adminkeepwarm.Options
	KeepwarmAdminEnabled   bool
	Registrations          []lipsdk.Registration
	TerminalDecisionPolicy TerminalDecisionPolicyInput
}

type HTTPSecurityInput

type HTTPSecurityInput struct {
	HTTPAuthProviders    []httpauth.Provider
	SecureSessionStore   ssessiondiag.Store
	UsageAuthority       cpadmin.AccountingAuthorityQueries
	ConcurrencyAuthority cpadmin.ConcurrencyAuthorityQueries
	GeoIP                GeoIPSecurityInput
	SelfDefense          SelfDefenseSecurityInput
}

HTTPSecurityInput uses adapter-owned narrow interfaces (no root core app imports).

type LargePayloadInput

type LargePayloadInput struct {
	// Enabled gates fast-path candidate evaluation. Default false.
	Enabled bool
	// ThresholdBytes is the decoded-size consideration gate. When <= 0,
	// largebody.DefaultThresholdBytes (1 MiB) is used.
	ThresholdBytes int64
	// WireEligibility optionally supplies the generation-frozen WireEligibilitySummary.
	WireEligibility largebody.WireEligibilitySummary
	// SpoolLedger optionally supplies the shared in-flight logical spool ledger.
	SpoolLedger *largebody.SpoolLedger
	// MemorySpoolBytes bounds retained bytes in Go heap per capture before spilling.
	MemorySpoolBytes int64
	// SpoolDir is the directory where temporary spill files are created.
	SpoolDir string
	// CopyBufferSize is the chunk size used for reading from the client body.
	CopyBufferSize int
	// MaxSemanticFactBytes bounds profile-derived metadata such as normalized part shapes.
	MaxSemanticFactBytes int64
	// Diagnostics optionally supplies a diagnostic observer.
	Diagnostics largebody.DiagnosticsObserver
}

LargePayloadInput parameterizes the large-payload fast path for a frontend mount generation (Requirements 1, 2, 20).

func (LargePayloadInput) EffectiveCopyBufferSize

func (c LargePayloadInput) EffectiveCopyBufferSize() int

EffectiveCopyBufferSize returns CopyBufferSize if > 0, else DefaultCopyBufferSize (32 KiB).

func (LargePayloadInput) EffectiveMaxSemanticFactBytes

func (c LargePayloadInput) EffectiveMaxSemanticFactBytes() int64

EffectiveMaxSemanticFactBytes returns MaxSemanticFactBytes if > 0, else DefaultMaxSemanticFactBytes (256 KiB).

func (LargePayloadInput) EffectiveMemorySpoolBytes

func (c LargePayloadInput) EffectiveMemorySpoolBytes() int64

EffectiveMemorySpoolBytes returns MemorySpoolBytes if > 0, else DefaultMemorySpoolBytes (64 KiB).

func (LargePayloadInput) EffectiveSpoolDir

func (c LargePayloadInput) EffectiveSpoolDir() string

EffectiveSpoolDir returns SpoolDir if not empty, else a temporary directory fallback.

func (LargePayloadInput) EffectiveThresholdBytes

func (c LargePayloadInput) EffectiveThresholdBytes() int64

EffectiveThresholdBytes returns ThresholdBytes if > 0, else DefaultThresholdBytes (1 MiB).

type OwnedRoute

type OwnedRoute struct {
	// Method is the HTTP method this route is registered for, or empty when the
	// registration carries no method and therefore answers every method.
	Method string
	// Path is the router's own pattern path, already normalized, and already
	// carrying the trailing separator when Subtree is true.
	Path string
	// Subtree reports whether this route owns its whole subtree. It is true only
	// when the router's pattern ends in a separator, which is exactly the
	// trailing-slash registration form.
	Subtree bool
}

OwnedRoute is one data-plane route the running generation actually owns, with the router's own match semantics.

The deterministic impossible-path families are heuristic probe prefixes, but the data-plane path surface is operator-configurable to any normalized absolute non-root path, so those two spaces overlap and a published route must never be refused. This type exists because a published route is not one concept but two: an EXACT registration, which owns one method/path pair, and a SUBTREE registration, which owns everything below a trailing-slash path. Collapsing both into a plain string is what previously made the carve a case-insensitive subtree and let probes through that the router does not route.

type OwnedRouteCandidate

type OwnedRouteCandidate struct {
	Method string
	Path   string
}

OwnedRouteCandidate is a method/path pair that MIGHT be published by this generation. It is an input to ownership resolution, not a statement of ownership: whether the router really owns the pair, and with which match semantics, is decided by the router.

type RouteClaim

type RouteClaim struct {
	OwnerID string
	Method  string
	Path    string
	Kind    RouteKind
}

RouteClaim registers one normalized HTTP route owner before serving.

func ClaimsForBasePath

func ClaimsForBasePath(ownerID, basePath string, operations ...RouteClaim) ([]RouteClaim, error)

ClaimsForBasePath builds claims for a frontend-owned operation set. The contract validates and normalizes generic ownership data; protocol packages own operation identifiers and route paths.

func RemapBasePath

func RemapBasePath(claims []RouteClaim, fromBase, toBase string) ([]RouteClaim, error)

RemapBasePath rewrites OpenResponses default claims onto another base path.

func (RouteClaim) NormalizedClaim

func (c RouteClaim) NormalizedClaim() (RouteClaim, error)

NormalizedClaim returns a copy with normalized method and path.

type RouteConflictError

type RouteConflictError struct {
	Method        string
	Path          string
	ExistingOwner string
	NewOwner      string
	ExistingKind  RouteKind
	NewKind       RouteKind
}

RouteConflictError names both owners for deterministic composition failure.

func (RouteConflictError) Error

func (d RouteConflictError) Error() string

type RouteDiagnostic

type RouteDiagnostic struct {
	OwnerID   string `json:"owner_id"`
	Method    string `json:"method"`
	Path      string `json:"path"`
	Kind      string `json:"kind"`
	Transport string `json:"transport,omitempty"`
}

RouteDiagnostic is a sanitized route ownership snapshot for operator diagnostics.

func RouteDiagnosticsFromRegistry

func RouteDiagnosticsFromRegistry(reg *RouteRegistry) []RouteDiagnostic

RouteDiagnosticsFromRegistry projects registered claims into sanitized diagnostics.

type RouteKind

type RouteKind string

RouteKind is an opaque extension-owned operation identifier.

func (RouteKind) Validate

func (k RouteKind) Validate() error

type RouteRegistry

type RouteRegistry struct {
	// contains filtered or unexported fields
}

RouteRegistry validates normalized route ownership before serving.

func NewRouteRegistry

func NewRouteRegistry() *RouteRegistry

NewRouteRegistry returns an empty registry.

func (*RouteRegistry) Claims

func (r *RouteRegistry) Claims() []RouteClaim

Claims returns a sorted copy of registered claims.

func (*RouteRegistry) OwnerOf

func (r *RouteRegistry) OwnerOf(method, path string) (RouteClaim, bool)

OwnerOf returns the registered owner for a normalized method/path pair.

func (*RouteRegistry) Register

func (r *RouteRegistry) Register(claim RouteClaim) error

Register adds one normalized claim or returns a deterministic conflict.

func (*RouteRegistry) RegisterAll

func (r *RouteRegistry) RegisterAll(claims []RouteClaim) error

RegisterAll registers claims in order, failing on the first conflict. The operation is atomic at the candidate level: every claim is validated against a staged copy before the registry is mutated, so a conflict leaves the registry unchanged (no partial registration).

func (*RouteRegistry) ValidateCanonicalPathTakeover

func (r *RouteRegistry) ValidateCanonicalPathTakeover(basePath string, proposed []RouteClaim) error

ValidateCanonicalPathTakeover rejects base_path=/v1 when any registered claim would collide with an already-owned method/path pair.

type SelfDefenseObserver

type SelfDefenseObserver interface {
	// Denial records one generic refusal for a finite reason.
	Denial(reason ingressdefense.Reason)
	// QuarantineTransition records one started or escalated quarantine for a
	// finite reason. entryCount is the bounded number of tracked source entries
	// after the transition.
	QuarantineTransition(reason ingressdefense.Reason, entryCount int)
}

SelfDefenseObserver receives bounded self-defense observations. Every reason is a member of the closed ingressdefense.AllReasons vocabulary; no request path, source address, prefix text, query, header, User-Agent, credential or principal ever reaches it, so it can only produce finite metric labels. Observer absence is not authoritative: metrics never decide or change a security outcome.

type SelfDefenseSecurityInput

type SelfDefenseSecurityInput struct {
	// Policy is the immutable, reloadable request policy of this generation.
	Policy *ingressdefense.Policy
	// State is the process-owned bounded adaptive state, borrowed for the
	// lifetime of this generation.
	State *ingressdefense.State
	// Resolver is the shared client-address trust configuration.
	Resolver GeoIPResolverConfig
	// ImpossiblePaths toggles the fixed impossible-path matcher. Disabling it
	// bypasses only the matcher and retains adaptive quarantine behavior.
	ImpossiblePaths bool
	// OwnedRouteCandidates are the method/path pairs this configuration could
	// publish: the operator-configured diagnostics, metrics and operator-mount
	// paths, plus every enabled frontend's claimed route paths.
	//
	// They are deliberately CANDIDATES, not an inventory. Reading a configured
	// value does not mean the router owns it: a diagnostics block with
	// enabled=false mounts nothing, and a path shape does not tell you whether the
	// registration was exact or a trailing-slash subtree. Composition therefore
	// resolves these against the real router, and the resolved owned routes are
	// what the gate receives.
	OwnedRouteCandidates []OwnedRouteCandidate
	// OwnedRoutes is the resolved inventory: what the router that was just built
	// actually owns, with the router's own match semantics. Composition fills it
	// after the last mount and before the stack; it is deliberately not derivable
	// from the candidates alone, because ownership and match semantics are
	// properties of the router.
	OwnedRoutes []OwnedRoute
	// Probe is the optional conservative credential-presence probe.
	Probe CredentialProbe
	// Observer is the optional bounded metrics seam.
	Observer SelfDefenseObserver
	// Now supplies the request-time instant passed to the adaptive state, so the
	// gate and its paired auth observer share one time base. A nil Now uses
	// time.Now; tests inject a fake clock.
	Now func() time.Time
}

SelfDefenseSecurityInput is the cycle-neutral, non-owning generation projection of ingress self-defense into the standard data-plane handler graph.

A nil Policy, or a policy with Enabled false, is the structural fast path: the gate wrapper is absent and the auth chain runs unobserved, so a disabled generation performs zero self-defense request-side work.

State is a borrowed capability on the process-lifetime adaptive store shared by every generation. It is never owned, closed or resized here: a generation borrows it and the owning ProcessServices lifetime disposes of it. Resolver is the already compiled GeoIP client-address trust configuration, reused verbatim so self-defense creates no second forwarding parser and no second trust boundary, and it needs no GeoIP country database.

Process-state capacity and inactivity TTL are deliberately absent: they size process-owned state, they are restart-required, and no per-request projection may carry them.

func (SelfDefenseSecurityInput) CredentialGateProbe

func (s SelfDefenseSecurityInput) CredentialGateProbe() func(r *http.Request) bool

CredentialGateProbe returns the gate-side view of the conservative probe: it reports whether the request might still authenticate, which is the inverse of the gate's refusal rule `!probe(r)`. A nil projection yields a nil probe, and the gate treats a nil probe as fail open.

func (SelfDefenseSecurityInput) SelfDefenseEnabled

func (s SelfDefenseSecurityInput) SelfDefenseEnabled() bool

SelfDefenseEnabled reports whether this projection installs the gate and the auth observation. It is the single structural switch both wiring sites use, so the disabled posture cannot differ between them.

type StandardHTTPInput

type StandardHTTPInput struct {
	Core       HTTPCoreInput
	Security   HTTPSecurityInput
	Operations HTTPOperationsInput
	Models     HTTPModelInput
	Frontends  HTTPFrontendInput
}

StandardHTTPInput is the focused, lifecycle-free HTTP composition projection.

type TerminalDecisionPolicyInput

type TerminalDecisionPolicyInput struct {
	Store                   *sessionpolicy.Store
	FeatureStatus           func(context.Context, string) (known, available bool, err error)
	ResolveClientScope      func(context.Context, *http.Request, string) (sessionpolicy.Key, sessionpolicy.Authority, error)
	AuthorizeOperatorTarget func(context.Context, *http.Request, string, string) (sessionpolicy.Key, sessionpolicy.Authority, error)
	GenerationDefault       func(string) bool
	MaxBodyBytes            int64
}

TerminalDecisionPolicyInput is the explicit composition projection for the provider-neutral client/operator policy routes.

type TrafficSnapshot

type TrafficSnapshot interface {
	RawCapture() traffic.RawCaptureSink
	TrafficObserver() traffic.Observer
	TrafficRedactors() []traffic.Redactor
}

TrafficSnapshot is the narrow capability a generation extension snapshot exposes for traffic-port projection. Both runtimebundle's frozen extension snapshot and stdhttp test fixtures satisfy it structurally.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL