Skip to content

feat(identity): emit X-Client-ID header on every outbound request (v9)#177

Merged
saurabhjain1592 merged 2 commits into
mainfrom
feat/v9-x-client-id-header
May 19, 2026
Merged

feat(identity): emit X-Client-ID header on every outbound request (v9)#177
saurabhjain1592 merged 2 commits into
mainfrom
feat/v9-x-client-id-header

Conversation

@saurabhjain1592
Copy link
Copy Markdown
Member

Summary

Closes the SDK side of Epic #2230 (v9 identity cleanup), workstream B. Every governed request now carries an X-Client-ID: <effective_client_id> header alongside the existing Basic Auth + X-Axonflow-Client headers.

  • Value matches the SDK's existing Basic Auth username — smart default "community" when no clientId is configured.
  • Set in addAuthHeaders (AxonFlow.java), the canonical funnel for every governed request.
  • The agent's apiAuthMiddleware (PR getaxonflow/axonflow-enterprise#2233) overwrites the header with its auth-derived value, so caller-supplied values are harmless (no spoofing surface).

Bumps to v8.1.0.

Compatibility

  • v8 platform + v8.1 SDK: agent ignores unknown header → backward compatible.
  • v9 platform + v8.0 SDK: agent derives identity from Basic Auth → backward compatible.
  • No SDK config changes. No removed fields. No changed defaults.

R1 — mechanical

  • mvn test clean — 1239 tests passed, 0 failures, 0 errors
  • New file XClientIdHeaderTest.java covers the new code path

R2 — functional (real HTTP transport via WireMock)

Tests in XClientIdHeaderTest.java route a real proxyLLMCall through the SDK's OkHttp client at a WireMock-stubbed endpoint, then assert against headers WireMock captured off the wire. This is not a builder-state assertion in-memory — the test only sees the header if the SDK's HTTP client successfully wrote it to the socket. Mutation evidence below confirms.

Captured outbound headers (WireMock log):

Header community default configured client
Authorization Basic Y29tbXVuaXR5Og== Basic YWNtZS1jb3JwOnNlY3JldA==
X-Axonflow-Client sdk-java/8.1.0 sdk-java/8.1.0
X-Client-ID community acme-corp
X-Tenant-ID (absent) (absent)

R3 — hostile self-review

  • Mutation test (per feedback_mutation_test_to_prove_assertion_not_tautological.md): removed builder.header("X-Client-ID", effectiveClientId); in scratch copy → 2/3 new tests FAILED (communityDefault, configuredClient). Restored. Assertions are not tautological.
  • Anti-spoofing: Java SDK has no extraHeaders config field. Server-side, the agent's apiAuthMiddleware overwrites the header regardless.
  • Cross-SDK coherence: header NAME (X-Client-ID) and value shape (raw effective client_id, no prefix) match Go/Python/TS/Rust PRs in the same release train.
  • Negative test (noLegacyTenantHeader) pins that the SDK does NOT emit X-Tenant-ID — the agent accepts it as an alias through v9 for back-compat, but SDK-side we standardize on X-Client-ID.

Workstream coordination

  • Independent of Phase 5/6/7/8 of #2230 (different repos).
  • Per feedback_sub_sessions_admin_merge_when_ci_green_r3_done.md, this PR admin-merges on green CI + R3 done; no master gating.

Every governed request now carries an X-Client-ID header alongside the
existing Basic Auth + X-Axonflow-Client headers, matching the v9 identity
contract on the platform (Epic getaxonflow/axonflow-enterprise#2230).

The header value mirrors the SDK's Basic Auth username — smart default
"community" when no clientId is configured. The agent's apiAuthMiddleware
overwrites the header with its auth-derived value, so caller-supplied
values are harmless (no spoofing surface). Backward-compatible with v8
agents (they ignore the unknown header).

Bumps to v8.1.0. Tests in XClientIdHeaderTest.java assert header
presence + value across community + configured-client paths, and pin
that the SDK does NOT send legacy X-Tenant-ID.

Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
Per CLAUDE.md HARD RULE #0: gate requires runtime-e2e/<feature>/ test
for user-facing surface changes. Adds the v9 X-Client-ID counterpart
to x-axonflow-client/ runner — spawns an in-process forwarding proxy
(JDK HttpServer + HttpClient) that captures the outbound X-Client-ID
off the wire and forwards to the real agent. Asserts captured value
equals the configured clientId. Prereqs: AXONFLOW_AGENT_URL,
AXONFLOW_TENANT_ID, AXONFLOW_TENANT_SECRET.

Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
@saurabhjain1592 saurabhjain1592 merged commit 318b827 into main May 19, 2026
18 checks passed
@saurabhjain1592 saurabhjain1592 deleted the feat/v9-x-client-id-header branch May 19, 2026 21:33
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.

1 participant