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
- Variables
- func CloneHTTPAuthProviders(in []httpauth.Provider) []httpauth.Provider
- func ClonePluginConfigs(in []config.PluginConfig) []config.PluginConfig
- func CloneRegistrations(in []lipsdk.Registration) []lipsdk.Registration
- func CloneStrings(in []string) []string
- func CloneTrafficRedactors(in []traffic.Redactor) []traffic.Redactor
- func CloneYAMLNode(n yaml.Node) yaml.Node
- func NormalizeMethod(method string) (string, error)
- func NormalizePath(path string) (string, error)
- func SourceAddr(ctx context.Context) (netip.Addr, bool)
- func TrafficPortsFromSnapshot(snap TrafficSnapshot) traffic.PortBundle
- func ValidateOperatorRoutePath(field, p string) error
- func WithSourceAddr(ctx context.Context, addr netip.Addr) context.Context
- type CredentialDisposition
- type CredentialProbe
- type FrontendRouteClaims
- type GeoIPObserver
- type GeoIPResolverConfig
- type GeoIPSecurityInput
- type HTTPCoreInput
- type HTTPFrontendInput
- type HTTPModelInput
- type HTTPOperationsInput
- type HTTPSecurityInput
- type LargePayloadInput
- type OwnedRoute
- type OwnedRouteCandidate
- type RouteClaim
- type RouteConflictError
- type RouteDiagnostic
- type RouteKind
- type RouteRegistry
- func (r *RouteRegistry) Claims() []RouteClaim
- func (r *RouteRegistry) OwnerOf(method, path string) (RouteClaim, bool)
- func (r *RouteRegistry) Register(claim RouteClaim) error
- func (r *RouteRegistry) RegisterAll(claims []RouteClaim) error
- func (r *RouteRegistry) ValidateCanonicalPathTakeover(basePath string, proposed []RouteClaim) error
- type SelfDefenseObserver
- type SelfDefenseSecurityInput
- type StandardHTTPInput
- type TerminalDecisionPolicyInput
- type TrafficSnapshot
Constants ¶
const CanonicalLegacyBasePath = "/v1"
CanonicalLegacyBasePath is the shared /v1 prefix used by existing frontends.
Variables ¶
var ErrRouteConflict = errors.New("route registry: conflict")
ErrRouteConflict indicates two enabled owners claim the same normalized route.
Functions ¶
func CloneHTTPAuthProviders ¶
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 ¶
CloneStrings returns a defensive copy of a string slice.
func CloneTrafficRedactors ¶
CloneTrafficRedactors returns a defensive copy of a redactor slice.
func CloneYAMLNode ¶
CloneYAMLNode returns a deep defensive copy of a YAML node, including aliases and nested content.
func NormalizeMethod ¶
NormalizeMethod uppercases and trims an HTTP method.
func NormalizePath ¶
NormalizePath canonicalizes a mount path for deterministic ownership checks.
func SourceAddr ¶
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 ¶
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 ¶
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 ¶
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 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 ¶
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 ¶
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 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.