Skip to content

fix(auth): migrate credential storage to secret: scope#5154

Draft
caohy1988 wants to merge 2 commits intogoogle:mainfrom
caohy1988:feat/secret-state-scope-phase2
Draft

fix(auth): migrate credential storage to secret: scope#5154
caohy1988 wants to merge 2 commits intogoogle:mainfrom
caohy1988:feat/secret-state-scope-phase2

Conversation

@caohy1988
Copy link
Copy Markdown

@caohy1988 caohy1988 commented Apr 4, 2026

Summary

Implements Phase 2 of the RFC in #5112: migrate existing credential writers to use the secret: prefix so that OAuth tokens and credentials are never persisted to session storage backends.

This is the change that actually eliminates the credential persistence bug — Phase 1 (#5132) established the framework, this PR uses it.

  • BIGQUERY_TOKEN_CACHE_KEY: changed from "bigquery_token_cache" to "secret:bigquery_token_cache"
  • SessionStateCredentialService: both save_credential and load_credential now prefix credential_key with State.SECRET_PREFIX
  • _google_credentials.py: token cache read falls back to legacy unprefixed key

Backward compatibility & migration

No re-auth required. Load paths try the secret:-prefixed key first, then fall back to the legacy unprefixed key. On fallback hit:

  1. The credential is copied to the secret: key (process-local, non-persistent)
  2. The legacy key is set to None so it is cleared from persistent storage on the next state delta flush

This ensures pre-existing plaintext credentials are actively removed from session backends, not just left in place.

Key-presence checks (not truthiness) are used so that an explicit None in the secret: key is respected and does not revive stale legacy credentials.

Depends on

Test plan

  • 13/13 SessionStateCredentialService tests pass (10 existing + 3 new)
  • 32/32 Phase 1 secret state tests still pass
  • test_load_falls_back_to_legacy_unprefixed_key — verifies fallback read + migration (secret key populated, legacy key cleared)
  • test_secret_key_takes_precedence_over_legacy — verifies secret-prefixed key wins when both exist
  • test_explicit_none_secret_key_not_revived_by_legacy — verifies explicit None in secret key is not overridden by stale legacy value

Closes #5112

🤖 Generated with Claude Code

Introduce a new `secret:` prefix for session state keys that keeps
sensitive data (tokens, credentials) in process memory only — never
persisted to any storage backend and never logged by BQ Agent Analytics.

- Add `State.SECRET_PREFIX` constant and wire it through
  `extract_state_delta()` so secret keys are excluded from all
  persistence buckets.
- Add process-local cache and lifecycle helpers on
  `BaseSessionService` (_apply, _trim, _seed, _restore, _evict).
- Update all four session services (InMemory, Database, Sqlite,
  VertexAI) to seed/restore/evict secret state on create/get/delete.
- Harden BQ Agent Analytics redaction: redact `secret:*` keys and
  detect JSON-encoded blobs containing sensitive credential keys.
- Accept `secret:` as a valid prefix in instruction template injection.
- 32 new tests (unit + integration across all service types).

Closes google#5112 (Phase 1)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@google-cla
Copy link
Copy Markdown

google-cla bot commented Apr 4, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Apr 4, 2026

Response from ADK Triaging Agent

Hello @caohy1988, thank you for your contribution!

It looks like the Contributor License Agreement (CLA) check has failed. Before we can merge this PR, you'll need to sign the CLA. You can find more information and sign the CLA at https://cla.developers.google.com/.

Thanks!

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Apr 4, 2026
@caohy1988 caohy1988 marked this pull request as draft April 4, 2026 06:07
@caohy1988 caohy1988 force-pushed the feat/secret-state-scope-phase2 branch from 2b46204 to 0f7856d Compare April 4, 2026 06:11
Migrate existing credential writers to use the `secret:` prefix so
that OAuth tokens and credentials are never persisted to session
storage backends.

- Change BIGQUERY_TOKEN_CACHE_KEY to "secret:bigquery_token_cache"
- Update SessionStateCredentialService.save_credential and
  load_credential to prefix credential_key with State.SECRET_PREFIX
- Backward-compatible migration: load paths try the secret-prefixed
  key first, then fall back to the legacy unprefixed key. On fallback
  hit, the value is copied to the secret: key and the legacy key is
  set to None so it is cleared from persistent storage on the next
  state delta flush.
- Use key-presence check (not truthiness) so explicit None in the
  secret-scoped key is respected and does not revive stale legacy
  credentials.

Depends on google#5132 (Phase 1: secret: scope infrastructure)
Closes google#5112

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@caohy1988 caohy1988 force-pushed the feat/secret-state-scope-phase2 branch from 0f7856d to 0d01bf7 Compare April 4, 2026 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Secret" session state scope

2 participants