Skip to content

feat(auth): add fixed-alias X.509 transport capability - #934

Merged
jbeckwith-oai merged 1 commit into
mainfrom
codex/x509-java-02-transport-capability
Aug 25, 2026
Merged

feat(auth): add fixed-alias X.509 transport capability#934
jbeckwith-oai merged 1 commit into
mainfrom
codex/x509-java-02-transport-capability

Conversation

@jbeckwith-oai

Copy link
Copy Markdown
Contributor

Summary

  • Add a narrow OkHttp X.509 transport capability built from caller-attested JSSE key and trust managers.
  • Pin one eligible certificate alias across the token-exchange and API TLS legs.
  • Bind two direct-only, isolated, non-retrying clients with redirects disabled and native hostname verification intact.

This is PR 2 of the five-PR X.509 WIF stack and follows #929. It establishes transport ownership and TLS invariants without exposing workload-identity metadata or changing top-level clients.

Security and lifecycle invariants

  • One caller-selected certificate alias is the only client identity visible to JSSE on either leg.
  • Alias selection still honors the key types and issuers requested by the peer.
  • Key, certificate-chain, and trust-policy stability are explicitly caller-attested for one capability generation.
  • Identity or trust rotation requires a new capability and SSL context.
  • Production binding is explicitly direct with Proxy.NO_PROXY.
  • Token-exchange and API clients have separate pools, dispatchers, and executors.
  • Redirects, SSL redirects, and OkHttp connection retries are disabled.
  • Native hostname verification and production SNI authorities are preserved.
  • Partial construction and two-client close paths preserve primary and suppressed failures.

Non-goals

  • No token exchange implementation or token response parser.
  • No top-level OpenAIClient integration.
  • No credential cache, refresh, retry, 401 replay, or rotation lifecycle.
  • No custom proxy support.
  • No endpoint customization, data residency, Azure, or Bedrock support.
  • No generated-source changes or custom-code budget increase.

Validation

  • Focused X509TransportTest and X509WireTest: pass.
  • Full openai-java-client-okhttp test suite: pass.
  • Repository-wide build: pass, including artifact compilation, support policy, examples, Bedrock, ProGuard, and runtime compatibility compilation.
  • Repository-wide Kotlin and Java lint: pass.
  • Custom-code budget: 1,610 / 2,000; 390 lines headroom; no increase.
  • Two independent review passes, followed by fixes and two new independent passes: clean.
  • Mandatory thermo-nuclear maintainability re-review of the final staged snapshot: clean.

Documentation alignment

  • Canonical X.509 WIF design and failure-history document reviewed.
  • Canonical live E2E runbook reviewed; protected live validation remains a PR 5 launch gate because this transport-only slice does not yet perform token exchange or API dispatch.

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner August 25, 2026 02:43
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-25T02:44:44.626095Z fb8b27b PR opened
🔒 Security Review Completed 2026-08-25T02:51:03.776081Z fb8b27b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@openai-sdks

openai-sdks Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 17.172s for Java SDK PR #934.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 792ms
tests/chat-completions-create.test.ts ✅ Passed 501ms
tests/chat-completions-stream.test.ts ✅ Passed 393ms
tests/files-content-binary.test.ts ✅ Passed 206ms
tests/files-create-multipart.test.ts ✅ Passed 263ms
tests/files-list-pagination.test.ts ✅ Passed 245ms
tests/initialize-config.test.ts ✅ Passed 369ms
tests/instance-isolation.test.ts ✅ Passed 207ms
tests/models-list.test.ts ✅ Passed 195ms
tests/responses-background-lifecycle.test.ts ✅ Passed 433ms
tests/responses-body-method-errors.test.ts ✅ Passed 553ms
tests/responses-cancel-timeout.test.ts ✅ Passed 234ms
tests/responses-cancel.test.ts ✅ Passed 314ms
tests/responses-compact-retries.test.ts ✅ Passed 350ms
tests/responses-compact.test.ts ✅ Passed 336ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 605ms
tests/responses-create-advanced.test.ts ✅ Passed 1.281s
tests/responses-create-disconnect.test.ts ✅ Passed 1.091s
tests/responses-create-errors.test.ts ✅ Passed 444ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 348ms
tests/responses-create-retries.test.ts ✅ Passed 348ms
tests/responses-create-stream-failures.test.ts ✅ Passed 272ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 209ms
tests/responses-create-stream-wire.test.ts ✅ Passed 6.591s
tests/responses-create-stream.test.ts ✅ Passed 91ms
tests/responses-create-terminal-states.test.ts ✅ Passed 472ms
tests/responses-create-timeout.test.ts ✅ Passed 215ms
tests/responses-create.test.ts ✅ Passed 1.008s
tests/responses-delete.test.ts ✅ Passed 277ms
tests/responses-input-items-errors.test.ts ✅ Passed 292ms
tests/responses-input-items-list.test.ts ✅ Passed 337ms
tests/responses-input-items-options.test.ts ✅ Passed 230ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 222ms
tests/responses-input-tokens-count.test.ts ✅ Passed 421ms
tests/responses-malformed-inputs.test.ts ✅ Passed 5.164s
tests/responses-not-found-errors.test.ts ✅ Passed 442ms
tests/responses-parse.test.ts ✅ Passed 769ms
tests/responses-retrieve-retries.test.ts ✅ Passed 368ms
tests/responses-retrieve.test.ts ✅ Passed 328ms
tests/responses-stored-method-errors.test.ts ✅ Passed 980ms
tests/retry-behavior.test.ts ✅ Passed 3.548s
tests/sdk-error-shape.test.ts ✅ Passed 417ms

View OkTest run #32802472810

SDK merge (3821ba9586a1) · head (fb8b27b78e17) · base (d7ecd271fa2b) · OkTest (2b1bdfd25e98)

@github-actions

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

53 mixed files remain; 0 existing customizations changed.

Compared d7ecd271fa2bfb8b27b78e17. Generated baselines verified.

53 existing customizations unchanged
  • openai-java-core/src/main/kotlin/com/openai/models/audio/AudioResponseFormat.kt
  • openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt
  • openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionMessageFunctionToolCall.kt
  • openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionToolMessageParam.kt
  • openai-java-core/src/main/kotlin/com/openai/models/embeddings/Embedding.kt
  • openai-java-core/src/main/kotlin/com/openai/models/embeddings/EmbeddingCreateParams.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionToolCall.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionWebSearch.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseInputItem.kt
  • openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseTextConfig.kt
  • openai-java-core/src/main/kotlin/com/openai/models/videos/Video.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/BetaServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/BetaServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/WebhookServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/WebhookServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/audio/TranscriptionServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt
  • openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsyncImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/BetaService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/BetaServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/WebhookService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/WebhookServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/audio/TranscriptionServiceImpl.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionService.kt
  • openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionServiceImpl.kt
  • openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponsesServerEventTest.kt
  • openai-java-core/src/test/kotlin/com/openai/models/responses/ResponsesServerEventTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/CompletionServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/ImageServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/ResponseServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/WebhookServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/audio/TranscriptionServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/beta/ResponseServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/beta/ThreadServiceAsyncTest.kt
  • openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncTest.kt

13 more in the full report.

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 32802494142 --repo openai/openai-java \
  --name castiron-custom-code-32802494142-1 --dir /tmp/castiron-custom-code-32802494142-1
git apply --stat /tmp/castiron-custom-code-32802494142-1/custom-code.patch
cat /tmp/castiron-custom-code-32802494142-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin d7ecd271fa2bf0f85ed56e66d009f89b7aecd2a0 fb8b27b78e178fb342c1477229996ba0aad38b96
python3 scripts/castiron/custom_code_report.py report \
  --base d7ecd271fa2bf0f85ed56e66d009f89b7aecd2a0 \
  --head fb8b27b78e178fb342c1477229996ba0aad38b96 --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-fb8b27b78e17
cat /tmp/castiron-custom-code-fb8b27b78e17/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the fixed-alias JSSE key manager, peer key-type/issuer selection, TLS context and trust ownership, direct-only isolated OkHttp clients, disabled redirect/retry paths, and partial-construction/close cleanup. The certificate identity and transport boundaries remain consistently constrained; no actionable issues found.

@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Aug 25, 2026
Merged via the queue into main with commit 2303825 Aug 25, 2026
13 checks passed
@openai-sdks openai-sdks Bot mentioned this pull request Aug 25, 2026
jbeckwith-oai added a commit that referenced this pull request Aug 26, 2026
## Summary

- add public sync and async `x509Builder` entry points backed only by
caller-attested `X509Transport`
- bind isolated exchange and API clients while preserving exact
ownership and close behavior
- enforce fixed X.509 issuer/API origins, bearer-only route eligibility,
and exclusive authentication/provider configuration
- validate the final request boundary before exchanging or dispatching
credentials
- use OkHttp call lifecycle events so client close cancels exchange/API
calls through response-body completion

## Security and ownership boundaries

- API origin is fixed to `https://mtls.api.openai.com/v1`; the exchange
origin remains `https://mtls.auth.openai.com/oauth/token`
- no custom base URL, data residency, Azure/Bedrock/provider auth,
proxy, arbitrary transport, or organization/project routing can be
combined with X.509 mode
- user-supplied authorization, API-key, proxy-auth, cookie,
host/authority, organization, and project headers are rejected at the
final sink
- the authenticator owns only the exchange client; `ClientOptions` owns
the real API client
- no token caching, shared retry budget, 401 rotation, or long-lived
lifecycle policy in this slice

## Validation

- real loopback CONNECT plus mTLS sync/async Files API coverage verifies
SNI, certificate chain, exact exchange body, bearer placement, and
header separation
- focused construction, Java-visibility, exclusivity, cloning, build
isolation, cancellation, blocked exchange/API close, stalled
response-body close, and retry-after-close tests
- repository lint: passed
- repository scripts/build: passed
- full Gradle test graph through scripts/test: BUILD SUCCESSFUL,
including R8 and ProGuard; the wrapper cleanup trap subsequently
observed its mock-server PID had already exited
- Castiron custom-code budget: 1610 of 2000 lines, unchanged, 390 lines
headroom
- two independent review cycles completed and remediated; final Reviewer
A and Validator B passes clean
- mandatory thermo-nuclear quality review completed, remediated, and
rerun clean

## Stack

1. #929 — executable raw-wire oracle (merged)
2. #934 — fixed-alias direct mTLS transport capability
3. #935 — identity metadata and exact token exchange
4. this PR — minimal sync/async client integration with fixed origins
and exclusive auth
5. planned — lifecycle, cache, single-flight, retry/deadline, 401
rotation, installed-JAR docs, and protected live E2E

Stacked on #935.
jbeckwith-oai added a commit that referenced this pull request Aug 26, 2026
## Summary

- introduce a single retry/authentication orchestrator for X.509
requests while preserving the ordinary-client retry path unchanged
- cache exchanged bearer tokens with expiry skew, single-flight refresh,
rejected-generation invalidation, and one bounded 401 replay
- propagate request deadlines, cancellation, stream close, and client
close through authentication, backoff, transport calls, request bodies,
responses, parsing, and logging
- preserve exact client/pipeline ownership across sync/async views,
reusable builders, generated `Unit` endpoints, and raw-response
continuations
- add installed-JAR documentation, a runnable example/runtime probe, and
a protected opt-in live X.509 smoke workflow

## Compatibility and security boundaries

- ordinary non-X.509 construction and retry/completion behavior remains
on the pre-existing code path
- X.509 remains fixed to the attested transport and fixed auth/API
origins introduced by the earlier stack layers
- credentials remain bearer-only at the API boundary and are never added
to logs, fixtures, examples, or default test output
- cleanup helpers act only on internal pipeline-owned markers; ordinary
raw-response ownership remains unchanged
- public/source compatibility was verified against both baseline and
proposed API manifests

## Validation

- focused sync/async X.509 lifecycle matrix: passed, including token
races, cancellation, deadlines, retries, 401 replay, builder/view
ownership, request/response cleanup, logging, parsing, streams, and
ordinary-client regressions
- repository lint: passed
- full `scripts/test` graph with Steady: passed, including R8 and
ProGuard artifacts
- Java 21 runtime compatibility probe: passed for core, OkHttp, Bedrock,
and runtime providers
- API/source breaking-change detector: passed for baseline and proposed
public APIs
- staged secret-pattern scan and `git diff --check`: passed
- Castiron custom-code budget: 1668 of 2000 lines, 332 lines headroom;
ratchet unchanged
- first review cycle: two independent agents clean after all findings
were fixed; mandatory thermo-nuclear review clean
- second clean-room review cycle: two fresh independent agents clean on
the exact frozen 49-file diff
(`1e5bba26e91a638915bfa509e87adee10b598c5d92bd23ae54a98a504a4e9fe6`)

## Stack

1. #929 — executable raw-wire oracle (merged)
2. #934 — fixed-alias direct mTLS transport capability
3. #935 — identity metadata and exact token exchange
4. #936 — minimal sync/async client integration with fixed origins and
exclusive auth
5. this PR — lifecycle, cache/single-flight, 401 rotation,
deadline/cancellation ownership, installed-JAR docs, and protected live
E2E

Stacked on #936.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants