keychain: run subcommand injects secrets into a child process's environment - #663
Open
clawdbot-glitch003 wants to merge 2 commits into
Open
clawdbot-glitch003 wants to merge 2 commits into
clawdbot-glitch003 wants to merge 2 commits into
Conversation
…ironment Bitwarden-style handoff for tools that need the raw credential: `keychain run <identity> <config> [--only A,B] [--env SECRET=ENV_VAR]... -- <command>` decrypts the config's export-release secrets, places each in the child's environment under the secret's name, inherits stdio, forwards SIGINT/SIGTERM/SIGHUP, and exits with the child's status. The CLI prints nothing, so the value stays out of agent transcripts, shell history and logs. "Use inside Lit" secrets are skipped with a stderr note (an error under --only), invalid variable names must be mapped with --env, and colliding mappings are rejected. Unit tests cover parsing, planning and the spawn contract with a fake child; the Postgres integration test runs the real CLI against the mock Lit runtime and checks the value reaches only the child. Docs: sdk/README.md, SKILL.md, SECURITY.md (same-user process environments are readable; not a sandbox), and a "How agents use this secret" panel on stored-secret detail cards. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… disk Writes the secret to a new mode-0600 file before the child starts (open with wx, so an existing path is never overwritten), keeps it out of the environment unless --env names it too, and unlinks it when the child exits or fails to start. Multi-line values such as PEM keys are written byte for byte. Mapping a secret outside --only is now an error rather than silently ignored. Tests: parser cases, planner cases (file-only secrets, file+env, path clash, unlisted mapping), spawn contract against a real temp dir (0600 while the child runs, gone after, refuses to overwrite, no spawn on create failure), and the Postgres integration test runs the real CLI with --file. Docs in sdk/README.md, SKILL.md, SECURITY.md and the web stored-secret panel. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bitwarden-style handoff for tools that need the raw credential:
--onlysubset) in parallel and places each in the child's environment under the secret's name.--only. Names that are not valid variable names must be mapped with--env; colliding mappings are rejected.--file SECRET=PATHwrites the secret to a new mode-0600 file (never overwrites) that is unlinked when the child exits, for tools that only read credentials from a path (service-account JSON, kubeconfig, SSH/TLS keys). Such secrets stay out of the environment unless--envnames them too.get. Bad arguments fail before any network call.Nothing changes in the protocol, server, or existing
get/use/MCP paths. No MCP tool forrunon purpose: an MCP tool that runs arbitrary commands with secrets injected is a prompt-injection footgun.Docs
sdk/README.md,SKILL.md: usage and when to preferrunoverget.SECURITY.md: same-user processes can read another process's environment (ps eww,/proc/<pid>/environ);runis a handoff, not a sandbox. JS strings cannot be scrubbed, so plaintext may linger in the CLI heap briefly.runcommand.Test plan
tests/sdk-package.test.ts: parsing, injection planning, spawn contract with a fake child (secrets land only in child env, parent env untouched, client destroyed, exit code propagates, missing executable reported without leaking), CLI rejects bad args before the network.tests/api.test.ts: real CLIrunagainst the mock Lit runtime, both env and--file(0600 while the child runs, absent from env, removed after); value reaches only the child under the--envname, original name absent, child exit code 7 propagates.scripts/test-local.mjsonkeychain_testDB: 3/3 integration, 62/62 unit.tsc --noEmit,prettier --check,vite build..cmdshims and signals untested.🤖 Generated with Claude Code