Skip to content

feat(sdk): add extension auth for middleware E2E - #2784

Open
pimlock wants to merge 11 commits into
mainfrom
1733-supervisor-middleware-e2e-sdk/pimlock
Open

feat(sdk): add extension auth for middleware E2E#2784
pimlock wants to merge 11 commits into
mainfrom
1733-supervisor-middleware-e2e-sdk/pimlock

Conversation

@pimlock

@pimlock pimlock commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Establish the first Rust SDK surface for building OpenShell extension services and add authenticated supervisor middleware end-to-end coverage.

This PR intentionally starts with a narrow foundation: the opt-in openshell-sdk extension feature provides service-side caller verification, and one Docker E2E proves the complete gateway → sandbox supervisor → authenticated middleware → upstream HTTP path. The middleware replaces sensitive content and adds a header before the request reaches the upstream.

Related Issue

Related to #1733.

Follow-up coverage and SDK adoption are tracked in #2794.

SDK Direction

The extension module is intended to become the Rust SDK for implementing extension services. As it grows, the SDK should own common lifecycle concerns such as service interfaces, authentication before handler dispatch, key caching and refresh after trusted bootstrap, protocol lifecycle validation, consistent errors, and observability. Extension authors should primarily implement manifests, configuration validation, and request or message business logic.

Rust is the initial proving ground, not a Rust-only extension model. OpenShell's other language SDKs should provide equivalent extension support within their existing packages rather than introducing a separate family of extension packages. The cross-language API shape still needs dedicated design work so each SDK remains idiomatic while sharing the same lifecycle, trust, and interoperability guarantees.

The deployment must continue to provide cold-start trust configuration, including the trusted gateway identity, issuer, audience, and CA or initial verification keys. Extension-specific authorization also remains application-owned. In this initial PR, key refresh remains deployment-owned and middleware protobuf interfaces still come from the existing core surface.

Alternative Considered

We considered publishing a dedicated extension SDK, separate from the existing API SDK in each language. Keeping extension support in the regular SDKs gives OpenShell fewer packages, release paths, and dependency surfaces to maintain. It also reflects the expected usage model: extensions will likely call OpenShell APIs in addition to implementing service interfaces.

A unified SDK can eventually provide an extension-oriented API client wrapper with the appropriate authentication configured for extension-to-OpenShell calls. This avoids requiring extension authors to combine and configure two SDK families themselves. Cargo features and language-appropriate modules can preserve an opt-in boundary without introducing separate packages.

Changes

  • Extension SDK: Add the opt-in openshell-sdk extension feature with self-contained caller authentication from trusted Ed25519 keys or JWKS, strict token and identity validation, and typed authenticated caller information without a direct openshell-extension-core dependency.
  • Authenticated middleware E2E: Add a TLS fixture built against the new SDK feature and one Docker happy path covering gateway and supervisor authentication, request transformation, local upstream verification, ephemeral trust setup, a dedicated mise task, and a GitHub Actions E2E lane.

Follow-up

Issue #2794 tracks the next layer of work:

  • migrate examples/supervisor-middleware-content-guard to the SDK and use it as the behavioral E2E fixture
  • add HTTP and WebSocket redact/deny coverage, invalid configuration, failure modes, chaining, and payload-limit scenarios
  • add direct negative verifier tests for issuer, audience, signing key, kid, algorithm, time bounds, claim shape, and JWKS validation
  • require authentication even on unsupported fixture RPC stubs

Testing

  • mise run pre-commit passes
  • SDK extension authentication unit tests pass
  • Standalone middleware fixture builds with its locked dependency graph
  • mise run e2e:supervisor-middleware passes against a Docker-backed gateway

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)

@copy-pr-bot

copy-pr-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

@pimlock pimlock self-assigned this Aug 18, 2026
@pimlock pimlock added the test:e2e Requires end-to-end coverage label Aug 18, 2026
@pimlock

pimlock commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 3128169

@github-actions

Copy link
Copy Markdown

Label test:e2e applied for 3128169. Open the existing run and click Re-run all jobs to execute with the label set. The run will execute the standard E2E suite after building the required gateway and supervisor images once. The matching required CI gate status on this PR will flip green automatically once the run finishes.

@pimlock
pimlock marked this pull request as ready for review August 18, 2026 23:22
@pimlock

This comment was marked as outdated.

@pimlock pimlock added the gator:blocked Gator is blocked by process or repository gates label Aug 20, 2026
@pimlock
pimlock force-pushed the 1733-supervisor-middleware-e2e-sdk/pimlock branch from eb6130a to 02ab41b Compare August 20, 2026 23:26
@pimlock pimlock added gator:watch-pipeline Gator is monitoring PR CI/CD status and removed gator:blocked Gator is blocked by process or repository gates labels Aug 20, 2026
@pimlock

This comment was marked as outdated.

@pimlock pimlock added gator:blocked Gator is blocked by process or repository gates and removed gator:watch-pipeline Gator is monitoring PR CI/CD status labels Aug 21, 2026
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
@pimlock
pimlock force-pushed the 1733-supervisor-middleware-e2e-sdk/pimlock branch from 02ab41b to 79f4857 Compare August 21, 2026 16:29
@pimlock

This comment was marked as outdated.

@pimlock pimlock added gator:watch-pipeline Gator is monitoring PR CI/CD status gator:blocked Gator is blocked by process or repository gates and removed gator:blocked Gator is blocked by process or repository gates gator:watch-pipeline Gator is monitoring PR CI/CD status labels Aug 21, 2026
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
@pimlock

This comment was marked as outdated.

@pimlock pimlock added gator:watch-pipeline Gator is monitoring PR CI/CD status gator:approval-needed Gator completed review; maintainer approval needed and removed gator:blocked Gator is blocked by process or repository gates gator:watch-pipeline Gator is monitoring PR CI/CD status labels Aug 21, 2026
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
@copy-pr-bot

This comment was marked as outdated.

Make the public `extension` surface safe to extend before anything
depends on it:

- Mark `ExtensionCallerKind`, `AuthenticatedCaller`, and
  `VerificationError` `#[non_exhaustive]` so new caller kinds, claims,
  and failure modes are not breaking changes.
- Stop exposing `jsonwebtoken` and `serde_json` error types in the
  public API; wrap them as opaque error sources.
- Replace the positional constructors with a builder that accepts one
  or more trusted key sources and an optional SPIFFE trust domain
  instead of hard-coding `openshell` in the supervisor subject check.
- Log the verification failure at `warn` before mapping it to the
  stable `Unauthenticated` status, since the extension is the only place
  an issuer or audience mismatch is observable.
- Drop `required_spec_claims` entries that jsonwebtoken ignores and the
  redundant algorithm assignment.

Add a drift test in `openshell-server` that mints gateway and supervisor
extension tokens and verifies them with the SDK from both PEM and the
published JWKS, and rejects a sandbox bootstrap token. The SDK keeps its
own copy of the wire contract so it does not depend on the internal
`openshell-extension-core` crate; this test is what enforces that the
two stay aligned.

Add the E2E middleware fixture to the fmt and check gates so its
standalone lockfile is validated on every branch, and refresh the
lockfile that had already drifted after merging main.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
jsonwebtoken 10 panics on first use when the host binary's feature
unification enables both `aws_lc_rs` and `rust_crypto` and no provider
was installed. In the workspace, `spiffe` enables `rust_crypto`, so the
SDK verifier tests panicked under the workspace-wide test run while
passing in isolation. Install the AWS-LC provider best-effort when the
verifier is built, mirroring the gateway, so extension binaries work
regardless of their own dependency graph.

Move the E2E middleware fixture from `tls-ring` to `tls-aws-lc`. Since
main replaced ring with AWS-LC (#3243), `openshell-core` enables the
AWS-LC rustls backend, and the fixture's ring feature left rustls with
two backends and no process default, so it panicked at startup.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
The gateway crate is not the right home for a test of the public SDK verifier. The SDK keeps its own unit coverage; where a mint-to-verify contract test belongs is decided separately.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
@pimlock
pimlock force-pushed the 1733-supervisor-middleware-e2e-sdk/pimlock branch from 30b3794 to 8857761 Compare September 11, 2026 02:03
The extension SDK keeps its own copy of the gateway's trust contract
rather than depending on internal crates, so something outside both
must fail when they drift. In the supervisor-middleware lane, fetch the
running gateway's OIDC-shaped discovery document and JWKS over mTLS,
assert the issuer matches the SDK's expected `openshell-gateway:<id>`
shape and EdDSA is the only algorithm, and build an SDK verifier from
the published JWKS. Claim shape is already covered by the fixture in
the same lane, which verifies real gateway and supervisor tokens.

The e2e crate gains `openshell-sdk` with the `extension` feature and a
provider-less rustls reqwest client that installs the AWS-LC provider
shared by the rest of its graph. The Docker wrapper exports the gateway
endpoint and the e2e client identity, which the gateway requires.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gator:approval-needed Gator completed review; maintainer approval needed test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant