Repository navigation
feat(adk): a secret-free bash environment with the turn's git identity #290
Description
Problem
The bash tool runs a model-written command on an allowlisted environment (commandEnvNames in go/adk/pkg/tools/shell.go, carried as fix(adk): run bash tool commands on an allowlisted environment, #303): PATH, HOME, USER, LOGNAME, LANG, LC_*, TERM, TZ, TMPDIR and the CA-bundle variables. The model keys, the controller token and every KAGENT_* variable stay in the runtime (kagent-dev#3002; the open kagent-dev#3014 strips by name instead). The allowlist admits neither GH_TOKEN nor a git identity, so the Harness images' gh (#288) runs gh --version but every authenticated call fails on the kagent Harness. A coding agent working as the person needs two things in that environment and nothing else secret:
- An inert placeholder token for the provider's CLI.
ghrefuses every API call withoutGH_TOKEN; in a Session with caller credentials (feat(egress): caller credentials per Session through Substrate's actor-JWT exchange #297) the egress gateway replaces the headerghsends with the person's token, so the placeholder only has to exist. Nothing sets it today, the allowlist withholds it, and a strip by name (TOKEN) would remove it. - git's author and committer identity. Without one
git commitfails ("Please tell me who you are") or records the sandbox's user, so nothing the agent commits is attributed to the person. The runtime knows the person of the turn: the identity the a2a gateway forwards asx-kagent-user, which the Go ADK already sets on every model call.
Proposed solution
The carried allowlist gains, per turn, GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL from the turn's user identity (the email; the name the forwarded identity carries, otherwise the email), and GH_TOKEN set to the translator's inert placeholder value (kagent-credential-injected) in a turn whose dispatch names a workspace directory (#296's working-directory header), so the CLI runs and the gateway does the authentication. The allowlist admits the inert placeholder only: a real token in the runtime's environment never reaches the command. A session without claims (unsecure mode, an agent's propagated caller id) gets no identity variables, so git's own error stands rather than a stand-in author. Built on kagent-dev#3014: the allow-list is proposed there as the shape that keeps a placeholder, and carried on the fork line until upstream settles it.
Acceptance criteria
-
envthrough the bash tool shows no model key, controller token orKAGENT_*variable; in a Session with a workspace it showsGH_TOKEN=kagent-credential-injected, in one without it shows noGH_TOKEN(unit test; fork e2e on thekagentHarness) -
git committhrough the bash tool in a turn sent byalice@example.comcarries author and committeralice@example.com; the next turn, sent bybob@example.com, commits as bob (unit test on the executor's per-turn environment) -
gh api userthrough the bash tool reaches the git host fixture with the exchanged token, never the placeholder (fork e2e on test(e2e): snapshotted workspace volume and grant signer fixtures #293's fixture and feat(egress): caller credentials per Session through Substrate's actor-JWT exchange #297's fake broker) -
FORK.mdrow; the upstream exit is the allow-list proposed on fix(adk): strip secret env vars from the Go bash tool kagent-dev/kagent#3014's thread
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog 📦
Activity
teemow commentedon Oct 18, 2026
Checked against the criteria: #598 (merged) delivers the first two (unit tests
TestExecuteCommand_TurnEnvironment,TestExecuteCommand_CommitsAsThePersonOfEachTurn), now ticked. Left open: thegh api userfork e2e is #292 (still open) and #297 (blocker) is still open; the FORK.md row is unconfirmed here.