Skip to content

CI: claude-sdk-oauth binding-lifecycle security test fails only inside the coding-agent 1/3 shard (reproduces on main) #1751

Description

@code-yeongyu

Summary

test/claude-sdk-oauth-binding-lifecycle-security.test.ts > forgets process binding and invalidates/deletes durable state when selecting a non-Claude provider fails inside the Test (coding-agent 1/3) shard while passing in isolation. It reproduces on main itself, so it blocks unrelated PRs whose only red check is that shard.

Evidence

Failure on a main run (no PR involved) — run 35055501202, head fef17495, job Test (coding-agent 1/3):

 FAIL  test/claude-sdk-oauth-binding-lifecycle-security.test.ts > Claude SDK OAuth binding lifecycle security > forgets process binding and invalidates/deletes durable state when selecting a non-Claude provider
AssertionError: expected { …(11) } to be undefined
 ❯ test/claude-sdk-oauth-binding-lifecycle-security.test.ts:200:33
    200|   expect(getBinding(sessionId)).toBeUndefined();

 Test Files  1 failed | 468 passed | 2 skipped (471)
      Tests  1 failed | 3934 passed | 6 skipped (3941)

The received value is a live binding record (sdkSessionId, systemPromptHash, toolsetHash, …) for session id model-select-non-claude, i.e. the model_select handler did not forget the process binding.

Contrast runs I made locally on the same file:

Scope Result
the file alone, at main-derived base 30b5ea8024 Test Files 1 passed, Tests 2 passed
the file alone, at a feature head Test Files 1 passed, Tests 2 passed
the whole test/claude-sdk-oauth-*.test.ts cluster (61 files) Test Files 61 passed, Tests 493 passed | 3 skipped
shard 1/3 in CI fails as above

So the interference comes from a file outside the claude-sdk-oauth cluster that shares this module's process-global state. The suite keeps the binding registry in module scope: the test registers one with registerSessionRegistry(extension.api) and clears it in afterEach via resetSessionRegistryBoundary() — a leftover registration from an earlier file in the shard would leave getBinding and the handler reading different boundaries.

Expected

The test passes in every shard composition, because the binding registry boundary cannot leak across test files. The fix is isolation at the seam (establish the boundary per test rather than trusting the previous file to have cleared it), not a retry, a skip, or a loosened assertion.

Acceptance criteria

  • The exact shard composition that fails today (vitest run --shard=1/3) passes.
  • The cause is named in the PR: which state leaks and which file leaves it.
  • test/claude-sdk-oauth-binding-lifecycle-security.test.ts still fails if the model_select handler stops forgetting the binding (the assertion keeps its teeth).

Related

Found while verifying #1726/#1729 (#1746), whose only red check was this shard.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions