Skip to content

feat: add operator-controlled binding policies to supervisor middleware #2282

Description

@pimlock

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:gatewayGateway server and control-plane workarea:supervisorProxy and routing-path work

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions