feat(providers): support proxy-delivered static credentials - #2
Open
johnnygreco wants to merge 4 commits into
Open
feat(providers): support proxy-delivered static credentials#2johnnygreco wants to merge 4 commits into
johnnygreco wants to merge 4 commits into
Conversation
Signed-off-by: Johnny Greco <jogreco@nvidia.com>
Signed-off-by: Johnny Greco <jogreco@nvidia.com>
Make the static credential binding the sandbox's single source of truth for proxy-delivered credentials. The gateway copies the delivery mode, auth style, and header name onto the binding, and the proxy resolves matching proxy-delivered bindings through the request-scoped resolver instead of consulting the dynamic token grant map, which returns to carrying token grants only. Validate proxy-delivered credential values against their declared placement when a provider is created or updated, so a non-token68 bearer value fails with a message that names the credential rather than as a 502 on every request. Emit OCSF HTTP activity events for every successful and failed injection, treat a poisoned credential registry as an error instead of "no credential", and end any open middleware session when forward-proxy injection fails. Add request-level tests through relay_rest, the passthrough relay, and a real handle_forward_proxy round trip, profile validation tests for every proxy-delivery rejection, gateway tests for create/update value validation and binding metadata, and a Docker e2e test that verifies the variable is absent from the sandbox and the upstream receives the injected credential. Document the ambiguity rule, value constraints, and failure modes, and update the sandbox and gateway architecture docs. Signed-off-by: Johnny Greco <jogreco@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add an opt-in
delivery: proxymode for static provider credentials. It keeps both the real credential and OpenShell's endpoint-bound placeholder out of the sandbox environment, then sets the complete authentication header at the last outbound proxy step, after network policy, L7 rules, and middleware have admitted the request.What this does and does not change:
flowchart LR subgraph Sandbox A[Agent or tool] -->|Authorization: public value| B[Inspected HTTP request] C[Environment exploration] --> D[Conversation and session history] E[No credential variable<br/>No OpenShell placeholder] -.-> C end B --> F{Network, L7, and<br/>middleware policy allow?} F -->|No| G[Reject request] F -->|Yes| H[Resolve binding through<br/>request-scoped resolver] H --> I[Replace complete auth header<br/>Emit OCSF event] I --> J[Provider API]environment(default)proxyRelated Issue
No accepted issue is available: this is a fork-only integration PR, and Issues are disabled on
johnnygreco/OpenShell.The motivating integration is OpenShell Research PR #38 on the OpenShell Research branch
johnny/pi-attested-admission. That work combines Pi context admission with post-policy credential delivery so prompt inspection happens before OpenShell authenticates the provider request.Design
The static credential binding is the sandbox's single source of truth. The gateway copies the delivery mode, auth style, and header name onto the
StaticCredentialBindingit already sends for every static credential. The proxy asks the live provider credential state for proxy-delivered bindings that authorize the request's host, port, and path, resolves each through the same request-scoped resolver used for placeholders, and replaces the header. It never consults profile metadata at request time, and proxy-delivered credentials are no longer carried in the dynamic (token grant) credential map, so that map keeps its original meaning.Ambiguity is rejected at attach time, not resolved at request time. Two attached providers cannot bind proxy-delivered credentials to overlapping selectors on the same port, even at different specificity. Token grants allow the more specific selector to win because the request carries no ambiguity the proxy would need to resolve; with proxy delivery the request carries no credential at all, so there is nothing to disambiguate with. The proxy still fails closed if it ever sees two distinct matching credentials. Aliases of one credential (multiple
env_vars) collapse into a single header.Values are validated when the provider is created or updated. A
bearervalue must betoken68; a namedheadervalue must not contain control characters. Previously a stored key with a space would pass creation and fail every request with a misleading "token grant returned a malformed access token" 502. The proxy still validates immediately before injection as a backstop, with a proxy-delivery-specific message.Every injection is auditable. Success and failure emit OCSF HTTP activity events naming the environment key, header, and endpoint, never the value, mirroring the token grant events. Failure also returns
502 provider_authentication_failedand, on the forward-proxy path, ends any open middleware session.Changes
ProviderCredentialDeliveryto the provider profile credential and static credential binding protocol; addauth_styleandheader_nameto the binding. Environment delivery remains the default and leaves the new fields empty.delivery: proxyin custom provider profiles. Validation requires one proxy-delivered credential per profile, at least oneenv_varsentry, inspectedprotocol: restendpoints withouttls: skip,bearerorheaderplacement with a valid non-framing header name, and notoken_grantin the same profile.token68check between the gateway and the proxy.token68value at create time, and verifies from inside a sandbox that the variable is absent and the upstream receives the real credential.Testing
mise run pre-commitpassesUnit and integration coverage added in this PR:
openshell-core: proxy-delivered bindings are listed only for matching endpoints; value validation per auth style.openshell-providers:deliveryround-trips; rejections for missing env vars, multiple proxy credentials, token grant conflicts, non-REST endpoints,tls: skip, unsupported auth styles, framing and invalid header names, and unknown delivery values.openshell-server: resolved bindings carry placement metadata and stay out of the dynamic credential map; environment delivery leaves the fields empty; create and update reject non-token68bearer values without echoing them; overlapping proxy bindings at different specificity are ambiguous.openshell-supervisor-network: header replacement without body change; named header added when absent; passthrough when no binding matches; alias collapse and competing-provider rejection; fail-closed without a resolver and after revocation; bearer value validation. Request-level tests driverelay_rest(allowed path injects, denied path never reaches upstream),relay_passthrough_with_credentials, and a realhandle_forward_proxyround trip against a local upstream.Verification:
cargo test -p openshell-core -p openshell-providers -p openshell-server -p openshell-supervisor-networkhandle_forward_proxyround trip ran (not skipped) on this Linux hostmise run pre-commitmise run go:proto:checkOPENSHELL_E2E_DOCKER_TEST=provider_proxy_delivery e2e/rust/e2e-docker.shagainst an ephemeral Docker gateway with a supervisor image built from this treeproxy_delivered_credential_stays_out_of_sandbox_and_is_injected_upstreampassed: create rejects a non-token68bearer value without echoing it, the sandbox seesTOKEN_ABSENT, and the host upstream receivesAuthorization: Bearer <real secret>in place of the public valueChecklist
architecture/sandbox.md,architecture/gateway.md)