Skip to content

Fix: honor the credentialKey override in the OpenAPI tool credential cache slot (stacked on #864) - #953

Open
AmaadMartin wants to merge 3 commits into
fix/openapi-credential-key-identityfrom
fix/openapi-credential-key-cache-slot
Open

Fix: honor the credentialKey override in the OpenAPI tool credential cache slot (stacked on #864)#953
AmaadMartin wants to merge 3 commits into
fix/openapi-credential-key-identityfrom
fix/openapi-credential-key-cache-slot

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Stacked on #864 (fix/openapi-credential-key-identity). Review and merge that one first; this PR targets its branch.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):

N/A

  1. Or, if no issue exists, describe the change:

Problem: The credentialKey option reaches only the auth request slot (temp:<key>), never the exchanged-credential cache slot. ToolContextCredentialStore derives the cache key from the scheme and credential digests alone, so a developer who sets credentialKey cannot choose the cache slot, share one credential across tools, or keep two tools apart. The adk-python docstrings promise the option covers "interactive auth and credential caching", so the option does half of what it says.

Solution: The store now takes the override on its constructor and returns it verbatim ahead of the digest. The constructor is the single site both the read path and the write path derive their key from, so the two cannot disagree. An absent or empty key still derives the scheme+credential digest key from #864.

Notes for the reviewer:

Testing Plan

CI does not run on this PR. validation.yaml, license-check.yml and cross-language-integration.yml all trigger on pull_request: branches: [main], and this PR's base is fix/openapi-credential-key-identity. Only auto-assign ran. Everything below was run locally on the pushed commit 1b76b82.

Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.

Four cases added at the end of core/test/tools/openapi_tool/tool_auth_handler_test.ts. No existing test was edited.

npx vitest run --project unit:core \
  core/test/tools/openapi_tool/tool_auth_handler_test.ts \
  core/test/tools/openapi_tool/rest_api_tool_test.ts \
  core/test/tools/openapi_tool/openapi_toolset_test.ts \
  core/test/utils/hash_utils_test.ts
# Test Files 4 passed (4) / Tests 76 passed (76)

npx vitest run --project integration tests/integration/tools/openapi_credential_cache_test.ts
# Test Files 1 passed (1) / Tests 2 passed (2)

Coverage of tool_auth_handler.ts over the two suites that exercise it is 100% of statements, branches, functions and lines.

Mutation proof. I deleted the if (this.credentialKeyOverride) { return ...; } early return and re-ran the file. Three of the four new tests failed:

AssertionError: expected [ 'temp:my_tool_tokens', …(1) ] to deeply equal [ 'temp:my_tool_tokens', …(1) ]
  [
    "temp:my_tool_tokens",
-   "my_tool_tokens",
+   "apiKey_ab718306e1907ce2__existing_exchanged_credential",
  ]

AssertionError: expected [ …(2) ] to deeply equal [ 'shared_tool_tokens' ]
-   "shared_tool_tokens",
+   "apiKey_ab718306e1907ce2_apiKey_ba7390300e46243a_existing_exchanged_credential",
+   "http_178204f758fb78d5_apiKey_ba7390300e46243a_existing_exchanged_credential",

AssertionError: expected [ Array(1) ] to deeply equal [ 'tool_a_tokens', 'tool_b_tokens' ]
-   "tool_a_tokens",
-   "tool_b_tokens",
+   "apiKey_ab718306e1907ce2_apiKey_ba7390300e46243a_existing_exchanged_credential",

The fourth case pins the empty-string fall-through, which that mutation does not change. I proved it separately by widening the guard to if (this.credentialKeyOverride !== undefined):

AssertionError: expected [] to deeply equal [ '' ]

Manual End-to-End (E2E) Tests:

I built one OpenAPIToolset with two operations and a toolset-wide credentialKey, seeded temp:shared_toolset_tokens, and ran both tools against a real local HTTP server that echoes its headers.

tools: echo_one, echo_two
x-api-key sent: ["shared-key","shared-key"]
session state keys: ["temp:shared_toolset_tokens","shared_toolset_tokens"]

Before the fix, the same run ends with ["temp:shared_toolset_tokens","apiKey_ab718306e1907ce2__existing_exchanged_credential"].

No new integration test is needed. tests/integration/tools/openapi_credential_cache_test.ts from #864 already drives real OpenAPIToolset tools over HTTP through the slot this change moves, and it stays green.

Pre-submit:

npx eslint <the four changed files>   # clean
npx prettier --check <the four changed files>   # clean
npm run ts:check   # 5 pre-existing errors in this test file, unchanged by this PR

The five {type: 'apiKey'} errors in tool_auth_handler_test.ts are on lines 80, 97, 139, 167 and 179, all in tests that predate this branch. I confirmed the count is identical with my test hunk stashed.

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.

Amaad Martin added 3 commits August 11, 2026 12:20
…e slot

ToolAuthHandler passed credentialKey only to the auth request slot, so a
developer who set it could not choose the exchanged-credential cache slot.
The store now takes the override on its constructor, which is the single
site both the read path and the write path derive their key from.
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