Skip to content

test(proxy): fence the LLM upstream against member identity#9

Merged
damonleelcx merged 1 commit into
develop-v1.0.4from
feature/feishu-first-login-no-email-verify
Jul 21, 2026
Merged

test(proxy): fence the LLM upstream against member identity#9
damonleelcx merged 1 commit into
develop-v1.0.4from
feature/feishu-first-login-no-email-verify

Conversation

@damonleelcx

Copy link
Copy Markdown
Edition Affected Why
Personal Y One forwarding path for every edition.
Trial Y Same.
Production Y Same.
Cluster Y Same.

Test-only. No production code changed. Companion to aikey-control-master#14.

Why

The first-login change gives every SSO member three new identifying values — the Feishu union_id, the tenant_key, and a synthetic account handle. All three live in the control plane and have no business on the wire to a model provider.

Anthropic's OAuth WAF answers an unrecognized header with a 429 carrying no X-RateLimit-Reset — a business rejection that reads as rate limiting and gets diagnosed as such for days. And quite apart from the WAF, shipping a customer's employee identifiers to a third party is a data-collection surface nobody authorized.

Two fences, because they fail differently

  • TestUpstreamRequest_CarriesNoMemberIdentity — the namespace stripper removes identity-shaped annotations that do not exist yet, and leaves the headers the upstream needs.
  • TestProxySource_DoesNotReferenceMemberIdentityFields — the data plane must not reference union_id / tenant_key / sso.local at all. A stripper removes what someone put on; this asserts nobody has the vocabulary to put it on. If it ever fails, the answer is not another entry in the stripper.

Proved red by narrowing the stripper to the single header known today.

T8 of feishu-first-login-no-email-verify. The first-login change gives every SSO
member three new identifying values — the Feishu union_id, the tenant_key, and a
synthetic account handle — all of which live in the control plane and have no
business on the wire to a model provider.

Two fences, because they fail differently:
- TestUpstreamRequest_CarriesNoMemberIdentity: the namespace stripper removes
  identity-shaped annotations that do not exist yet, and leaves the headers the
  upstream actually needs. Anthropic's OAuth WAF answers an unrecognized header
  with a 429 carrying no X-RateLimit-Reset — a business rejection that reads as
  rate limiting and gets diagnosed as such for days.
- TestProxySource_DoesNotReferenceMemberIdentityFields: the data plane must not
  reference union_id / tenant_key / sso.local at all. A stripper removes what
  someone put on; this asserts nobody has the vocabulary to put it on. If it
  ever fails, the answer is not another entry in the stripper.

Fence proved red: narrowing the stripper to the one header known today ->
  "identity header \"X-Aikey-Union-Id\" survived and would reach the model provider"
  "header \"X-Aikey-Union-Id\" carries \"on_stub_union\" to the upstream"

Test-only; no production code changed.

Edition impact: Personal Y / Trial Y / Production Y / Cluster Y — one proxy
forwarding path for all four.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@damonleelcx
damonleelcx merged commit e3931a7 into develop-v1.0.4 Jul 21, 2026
0 of 2 checks passed
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