feat(sdk): add OAuth Client Credentials support to SDKs - #2907
Conversation
Implement lazy OAuth client-credentials acquisition and renewal for the Python, TypeScript, and Go SDK clients, with shared security conformance coverage and service-account documentation.\n\nCloses NVIDIA#2803 Signed-off-by: Seth Jennings <sjenning@redhat.com>
E2E Test AttestationLocal E2E tests passed. CI does not currently run this OIDC E2E lane, so this comment serves as the verification record.
Test SummaryTests Executed
|
Signed-off-by: Seth Jennings <sjenning@redhat.com>
Addressed the review concerns in
E2E Test Attestation
Additional verification passed: |
|
/ok to test 81a2817 |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Thanks @sjenning. I reviewed current head 81a2817bdf09fee56be33ff112f16b7d95e30667 in light of your update: the timeout, async interceptor, scope-defaulting, active-gateway TLS-setting, example, and architecture adjustments are present. Two separate blocking issues remain in the existing Go one-shot API and the new Python credential transport path.
Action required: please address both inline Warnings and push an updated head for a focused follow-up review.
Blocking findings:
GATOR-81a2817b-01: preserve the existing Go one-shot exchange behavior whenexpires_inis omitted while keeping renewable auth fail-closed.GATOR-81a2817b-02: prevent renewable Python bearer credentials from being sent to remote gateways over plaintext without an explicit opt-in.
Carried findings:
- None
Non-blocking suggestions:
- None
Gator metadata
- Validation: Project-valid through accepted issue #2803.
- Docs: Fern and SDK documentation are updated for the direct UX change.
- Checks: Current Branch Checks and Helm Lint are green; required E2E dispatch is deferred until review blockers are resolved.
- E2E:
test:e2erequired for provider credential flow; not yet applied because review remains blocked. - Head SHA:
81a2817bdf09fee56be33ff112f16b7d95e30667 - Base SHA:
905e99aa2a960c17d5672b11cf64f10ff7d18b41 - Merge base SHA:
905e99aa2a960c17d5672b11cf64f10ff7d18b41 - Patch ID:
3ec4bd6a7f52fb4d6c8b81922b7d2bc827207fe5 - Gator payload:
7 - Review mode:
initial - Previous reviewed SHA: none
- Review budget exhausted: no
- Maintainer decision required: no
- Next state:
gator:in-review
Signed-off-by: Seth Jennings <sjenning@redhat.com>
|
Label |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Thanks @sjenning. I checked the focused update on current head 15f8f4b3c5d13a5da0a6fca16cf367223b2d8944: the Go one-shot API again accepts a missing expires_in while renewable auth still fails closed, and Python now rejects renewable credentials on remote plaintext gateways while retaining loopback support. Both prior findings are resolved, and the follow-up review found no new blockers.
Blocking findings:
- No blocking findings remain
Carried findings:
GATOR-81a2817b-01: resolved by the current Go compatibility split and regression test.GATOR-81a2817b-02: resolved by the current Python transport guard and regression tests.
Gator metadata
- Validation: Project-valid through accepted issue #2803.
- Docs: Fern and architecture documentation describe the remote TLS requirement.
- Checks: Branch Checks and Helm Lint are pending for the current head.
- E2E:
test:e2eapplied; E2E Label Help is queued and actual E2E dispatch is not yet confirmed. - Head SHA:
15f8f4b3c5d13a5da0a6fca16cf367223b2d8944 - Base SHA:
905e99aa2a960c17d5672b11cf64f10ff7d18b41 - Merge base SHA:
905e99aa2a960c17d5672b11cf64f10ff7d18b41 - Patch ID:
1f1b63f8e8d89f0420df14fc76d86f3d7f65762b - Gator payload:
7 - Review mode:
follow_up - Previous reviewed SHA:
81a2817bdf09fee56be33ff112f16b7d95e30667 - Review budget exhausted: no
- Maintainer decision required: no
- Next state:
gator:in-review
|
/ok to test 15f8f4b |
Monitoring CompleteMonitoring is complete because this PR has merged. Final status: Gator review completed with no remaining code-review blockers, and maintainer approval was present. Branch Checks and Helm Lint passed, but the required E2E gate remained failed after one infrastructure-related Kubernetes failure and one unrelated sandbox-lifecycle failure; an authorized rerun could not be dispatched because the sandbox GitHub policy denied the workflow-rerun endpoint. I removed the active Gator metadata
|
Summary
Add first-class renewable OAuth 2.0 client-credentials authentication to the Python, TypeScript, and Go SDK clients. All three implementations lazily acquire and renew in-memory access tokens, coalesce concurrent exchanges, preserve existing auth APIs, and share a security-focused conformance fixture.
Related Issue
Closes #2803
Changes
ClientCredentialsAuth, supports direct and active-gateway construction, and forwards the provider through the high-levelSandboxAPI.clientCredentials()andOidcTokenProvider, with async bearer attachment through the Connect transport.oidc.NewClientCredentialsAuth, supports literal or callback secrets, and resolves audience/scopes from gateway metadata.Deviations from Plan
None — implemented as planned. TypeScript remains explicit-only because it has no registered-gateway abstraction.
Testing
mise run test:python— 108 passedmise run sdk:ts:ci— 91 passed; lint, typecheck, coverage, and build passedmise run go:ci— race tests, lint, build, proto, and docs checks passedmise run e2e:oidc-python:docker— 84 passedmise run pre-commitpassedenv -u OPENSHELL_NO_BROWSER mise run cipassedTests added:
e2e/python/oidc/oidc_auth_test.pyexercises public Python client-credentials authentication against Keycloak and a Docker gateway.Checklist
Documentation updated:
docs/reference/gateway-auth.mdxanddocs/sandboxes/manage-sandboxes.mdx: service-account workflows and authorization prerequisites.sdk/typescript/README.md,sdk/go/README.md, and Go OIDC API docs: language-specific usage.architecture/gateway.md: stable in-memory SDK token lifecycle boundary.