Skip to content

Support secret interpolation in streamable HTTP extension URLs#7782

Merged
DOsinga merged 2 commits intomainfrom
jhugo/secret-url-interpolation
Mar 11, 2026
Merged

Support secret interpolation in streamable HTTP extension URLs#7782
DOsinga merged 2 commits intomainfrom
jhugo/secret-url-interpolation

Conversation

@jh-block
Copy link
Collaborator

@jh-block jh-block commented Mar 10, 2026

Summary

Allow users to store secret values (API keys, tokens) in the system keyring and interpolate them into streamable HTTP extension URLs and headers using ${VAR} or $VAR syntax. Addresses the feature request in #4307.

Changes

  • Backend: Apply substitute_env_vars() to the URI (previously only applied to headers) in both the config resolution path and runtime launch path
  • UI: Show the Environment Variables section for streamable HTTP extensions (previously only shown for stdio extensions), enabling users to add and manage keyring-stored secrets
  • Fix recursive expansion: substitute_env_vars() now scans the original input for $VAR patterns instead of the post-substitution output, preventing double-expansion when a secret value contains $OTHER_VAR syntax
  • Detect secret rotation: Store a resolved config snapshot (with secrets substituted) in memory at client-creation time, so that add_extension detects when a secret value has changed even if env_keys and URI are unchanged
  • Tests: Added test cases for URI variable substitution and recursive expansion prevention

Secrets are stored securely in the system keyring (macOS Keychain, Linux Secret Service, Windows Credential Manager) and resolved at runtime — they never appear in plaintext in config.yaml or on disk.

Type of Change

  • Feature
  • Bug fix

AI Assistance

  • This PR was created or reviewed with AI assistance

Testing

All 34 extension-related tests pass, including new tests for URI substitution (http_env_key_uri_substitution) and recursive expansion prevention (test_substitute_env_vars_no_recursive_expansion).

Related Issues

Relates to #4307

Allow users to store secret values (API keys, tokens) in the system keyring
and interpolate them into streamable HTTP extension URLs and headers using
${VAR} or $VAR syntax. The UI now shows the Environment Variables section
for HTTP extensions so users can add and manage secrets, which are stored
securely in the keyring (not in plaintext config). Secrets are resolved
at runtime using the existing merge_environments and substitute_env_vars
infrastructure.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 398a27cea4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@jh-block jh-block force-pushed the jhugo/secret-url-interpolation branch 2 times, most recently from 73c0ef6 to 158d92f Compare March 10, 2026 10:24
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 73c0ef6be7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@jh-block jh-block force-pushed the jhugo/secret-url-interpolation branch from 158d92f to b6ff96e Compare March 10, 2026 10:47
Two improvements to the extension variable substitution system:

1. Fix substitute_env_vars to scan the original input (not post-substitution
   output) for $VAR patterns, preventing recursive expansion when a
   substituted value happens to contain $OTHER_VAR syntax.

2. Resolve extension configs (fetching secrets from keyring) before
   comparing against stored configs in add_extension, so that secret
   rotation is detected even when env_keys and URI remain unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jh-block jh-block force-pushed the jhugo/secret-url-interpolation branch from b6ff96e to c3b10fe Compare March 10, 2026 10:54
@jh-block jh-block requested a review from DOsinga March 10, 2026 13:02
@DOsinga
Copy link
Collaborator

DOsinga commented Mar 11, 2026

not sure we should support two ways for substitutions - or do we do that already elsewhere?

@jh-block
Copy link
Collaborator Author

do you mean ${VAR} vs $VAR? It's just consistent with what the shell does I guess. We're already doing it for env var substitution into headers (which was pre-existing, this just does it in the URL as well)

@DOsinga
Copy link
Collaborator

DOsinga commented Mar 11, 2026

eh, if we use both patterns already for the other thing I guess that ship has sailed

@DOsinga DOsinga added this pull request to the merge queue Mar 11, 2026
Merged via the queue into main with commit 913537d Mar 11, 2026
21 checks passed
@DOsinga DOsinga deleted the jhugo/secret-url-interpolation branch March 11, 2026 13:25
lifeizhou-ap added a commit that referenced this pull request Mar 12, 2026
* main: (270 commits)
  test(acp): align provider and server test parity (#7822)
  fix(acp): register MCP extensions when resuming a session (#7806)
  fix(goose): load .gitignore in prompt_manager for hint file filtering (#7795)
  fix: remap max_completion_tokens to max_tokens for OpenAI-compatible providers (#7765)
  fix(openai): preserve Responses API tool call/output linkage (#7759)
  chore(deps): bump @hono/node-server from 1.19.9 to 1.19.11 in /evals/open-model-gym/mcp-harness (#7687)
  fix: return ContextLengthExceeded when prompt exceeds effective KV cache size (#7815)
  feat: MCP Roots support (#7790)
  fix(google): use `includeThoughts/part.thought` for thinking handling (#7593)
  refactor: simplify tokenizer initialization — remove unnecessary Result wrapper (#7744)
  Fix model selector showing wrong model in tabs (#7784)
  Stop collecting goosed stderr after startup (#7814)
  fix: avoid word splitting by space for windows shell commands (#7781) (#7810)
  Simplify and make it not break on linux (#7813)
  Add preferred microphone selection  (#7805)
  Remove dependency on posthog-rs (#7811)
  feat: load hints in nested subdirs (#7772)
  feat(acp): add read tool and delegate filesystem I/O to ACP clients (#7668)
  Support secret interpolation in streamable HTTP extension URLs (#7782)
  More logging for command injection classifier model training (#7779)
  ...
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.

2 participants