Problem Statement
Supervisor middleware registration currently gives an external service authority to expose every valid binding returned by Describe. Operators control the service endpoint and body limit, but cannot constrain the binding IDs that the service may register. A service upgrade or compromise can therefore expand its manifest, making a new binding selectable by sandbox policy without a matching operator configuration change.
PR #2005 adds dynamic, allowlist, and exact binding policies for gateway interceptors. The review follow-up in this discussion asks supervisor middleware to share the same operator authority model.
This complements #2217. Manifest digest pinning detects or coordinates manifest drift, while a binding policy expresses which binding authority the operator grants even when the service manifest changes.
Proposed Design
Define shared binding authorization semantics in the common configuration layer and use them for both gateway interceptors and operator-registered supervisor middleware:
dynamic: accept all valid manifest bindings. Keep this as the compatibility default and emit the same explicit warning used for dynamically authorized interceptors.
allowlist: enable only operator-configured binding IDs that the manifest advertises. Fail startup when a configured binding is missing or invalid. Ignore and log additional manifest bindings.
exact: require the configured and manifest binding ID sets to match exactly, and fail startup on either missing or additional bindings.
Extend each [[openshell.gateway.middleware]] registration with binding_policy and an explicit binding list. The config shape should leave room for future per-binding operator overrides instead of encoding the restriction as a one-off boolean. Apply the policy only to operator-registered external services; built-in openshell/ bindings remain unchanged.
Normalize the effective authorized binding set at gateway startup. Use only that set for duplicate binding detection, policy binding validation, ValidateConfig routing, required-service selection, and existing operation, phase, reserved-namespace, and body-limit checks.
Carry the normalized authorized binding set in SupervisorMiddlewareService when the gateway publishes sandbox configuration. The supervisor must enforce that set when it connects to the service and processes its own Describe response, so a binding rejected by the gateway cannot become runnable through supervisor-side manifest discovery. Include the effective set in configuration revision calculation so changes propagate to running sandboxes.
Add automated coverage for:
- compatibility behavior when
binding_policy is omitted
- allowlist handling of matching, missing, additional, malformed, duplicate, and reserved bindings
- exact-mode set mismatches
- gateway policy rejection for unauthorized binding IDs
- supervisor runtime rejection of bindings outside the propagated authorized set
- configuration revision changes when the effective binding set changes
Document the shared semantics and middleware TOML shape in architecture/gateway.md, docs/reference/gateway-config.mdx, and the supervisor middleware documentation.
Alternatives Considered
Relying only on manifest digest pinning from #2217 detects drift but does not express the authority an operator intends to grant.
Adding a middleware-specific allowlist or boolean would solve only one mode and allow the interceptor and middleware security models to drift.
Filtering only in the gateway registry would leave a trust-boundary gap because sandbox supervisors independently connect to the service, call Describe, and build their runtime registries.
Agent Investigation
Reviewed PR #2005 and its discussion, the interceptor binding-policy implementation, current MiddlewareServiceFileConfig, middleware registry validation, policy binding checks, and the sandbox configuration protobuf. External middleware configuration currently contains only name, grpc_endpoint, and max_body_bytes; SupervisorMiddlewareService propagates the same three fields to supervisors. No existing issue was found for operator authorization of middleware manifest binding IDs.
Problem Statement
Supervisor middleware registration currently gives an external service authority to expose every valid binding returned by
Describe. Operators control the service endpoint and body limit, but cannot constrain the binding IDs that the service may register. A service upgrade or compromise can therefore expand its manifest, making a new binding selectable by sandbox policy without a matching operator configuration change.PR #2005 adds
dynamic,allowlist, andexactbinding policies for gateway interceptors. The review follow-up in this discussion asks supervisor middleware to share the same operator authority model.This complements #2217. Manifest digest pinning detects or coordinates manifest drift, while a binding policy expresses which binding authority the operator grants even when the service manifest changes.
Proposed Design
Define shared binding authorization semantics in the common configuration layer and use them for both gateway interceptors and operator-registered supervisor middleware:
dynamic: accept all valid manifest bindings. Keep this as the compatibility default and emit the same explicit warning used for dynamically authorized interceptors.allowlist: enable only operator-configured binding IDs that the manifest advertises. Fail startup when a configured binding is missing or invalid. Ignore and log additional manifest bindings.exact: require the configured and manifest binding ID sets to match exactly, and fail startup on either missing or additional bindings.Extend each
[[openshell.gateway.middleware]]registration withbinding_policyand an explicit binding list. The config shape should leave room for future per-binding operator overrides instead of encoding the restriction as a one-off boolean. Apply the policy only to operator-registered external services; built-inopenshell/bindings remain unchanged.Normalize the effective authorized binding set at gateway startup. Use only that set for duplicate binding detection, policy binding validation,
ValidateConfigrouting, required-service selection, and existing operation, phase, reserved-namespace, and body-limit checks.Carry the normalized authorized binding set in
SupervisorMiddlewareServicewhen the gateway publishes sandbox configuration. The supervisor must enforce that set when it connects to the service and processes its ownDescriberesponse, so a binding rejected by the gateway cannot become runnable through supervisor-side manifest discovery. Include the effective set in configuration revision calculation so changes propagate to running sandboxes.Add automated coverage for:
binding_policyis omittedDocument the shared semantics and middleware TOML shape in
architecture/gateway.md,docs/reference/gateway-config.mdx, and the supervisor middleware documentation.Alternatives Considered
Relying only on manifest digest pinning from #2217 detects drift but does not express the authority an operator intends to grant.
Adding a middleware-specific allowlist or boolean would solve only one mode and allow the interceptor and middleware security models to drift.
Filtering only in the gateway registry would leave a trust-boundary gap because sandbox supervisors independently connect to the service, call
Describe, and build their runtime registries.Agent Investigation
Reviewed PR #2005 and its discussion, the interceptor binding-policy implementation, current
MiddlewareServiceFileConfig, middleware registry validation, policy binding checks, and the sandbox configuration protobuf. External middleware configuration currently contains onlyname,grpc_endpoint, andmax_body_bytes;SupervisorMiddlewareServicepropagates the same three fields to supervisors. No existing issue was found for operator authorization of middleware manifest binding IDs.