fix(agent): use GIT_AUTHOR/COMMITTER env vars instead of git config --global (#622)#623
Conversation
…-global (#622) run_task() set the bot's git identity via `git config --global user.name/email`, which writes to ~/.gitconfig for whatever OS user runs the process. In the ephemeral ECS container that's intended, but the same code path runs on developer workstations (local agent runs, dry-runs, pytest reaching run_task), permanently clobbering the developer's real identity to `bgagent`. Replace the two `git config --global` subprocess calls with process-scoped GIT_AUTHOR_NAME/EMAIL and GIT_COMMITTER_NAME/EMAIL env vars, set alongside the existing os.environ writes. Git honors these for every commit (inherited by Claude Code and the safety-net commit in post_hooks) without touching any on-disk config, so container commits stay attributed to bgagent while a developer's ~/.gitconfig is never modified. Removes the now-unused `subprocess` import. Adds a regression test asserting the identity env vars are set. The GitHub PAT flow (GITHUB_TOKEN/GH_TOKEN from the blueprint's Secrets Manager secret) is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
theagenticguy
left a comment
There was a problem hiding this comment.
Approve.
Clean, correctly scoped fix for a real destructive bug. The switch from git config --global to GIT_AUTHOR_*/GIT_COMMITTER_* env vars is the right mechanism: git reads these for author and committer on every commit, and they take precedence over on-disk config without writing to it.
I verified the behavior empirically against a sandboxed GIT_CONFIG_GLOBAL:
- With only the four env vars set and an empty global config,
git commitsucceeds and both author and committer resolve tobgagent <bgagent@noreply.github.com>; the global config file stays empty. - With neither the env vars nor any config, git refuses (
Author identity unknown), confirming the env vars are what carry the identity.
Both commit paths inherit the vars correctly. The safety-net commit in post_hooks.py calls subprocess.run with no env= override, and shell.py's _clean_env() strips only OTEL_* and PYTHONPATH, so the Claude Code CLI subprocess and the safety-net commit both see the identity. The subprocess import removal is correct (no remaining subprocess. calls in pipeline.py), ruff passes, and the new regression test passes against the full project env. No existing test depended on the removed git config calls.
Leaving repo.py:153's safe.directory --global untouched is the right call: it is additive and git mandates global scope for it.
Non-blocking notes inline.
…osv-scanner (aws-samples#636) (aws-samples#637) The osv-scanner required check (`Secrets, deps, and workflow scan`) fails on main's yarn.lock, ejecting every PR from the merge queue (observed on aws-samples#623). Advisories were published after PR-open scans, so PR-level checks are green while the merge_group re-scan is red. - astro 7.0.5 -> 7.1.3 (docs/package.json). Fixes GHSA-4g3v-8h47-v7g6 (XSS), GHSA-8mv7-9c27-98vc, GHSA-f48w-9m4c-m7f5. NOTE: intentionally 7.1.3, NOT 7.1.0 — 7.1.0 (the version Dependabot aws-samples#631/aws-samples#630 target, and the "fixed" version GHSA-4g3v cites) is flagged malicious by MAL-2026-10726. 7.1.3 is the current `latest` and is past the single poisoned release. - brace-expansion re-resolved within existing ^1.1.7/^2.0.2 ranges: 1.1.15 -> 1.1.16 and 2.1.1 -> 2.1.2 (GHSA-3jxr-9vmj-r5cp). Transitive-only; no resolutions pin needed. Lockfile-only (+ one version string). Verified: `mise run security:deps` exits 0, `mise //docs:build` builds 68 pages clean, `mise run security:retire` clean. Supersedes Dependabot aws-samples#631/aws-samples#630 (which bump to the malicious 7.1.0). Co-authored-by: bgagent <bgagent@noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Post-merge coherence fixes the conflict-marker resolution alone didn't catch (only the full build/test gate did): - hooks.py: post_tool_use_hook had a DUPLICATE stuck_guard kwarg + a duplicated K7 docstring/record_tool_result block (both sides added stuck_guard to the same signature; git kept both → SyntaxError 'duplicate argument', and the guard was fed twice per tool call). Collapsed to one stuck_guard param + one record block. - pipeline.py: restored 'import subprocess' (main's #623 dropped it when it removed the git-config subprocess calls, but lv's A6 code_changed block still calls subprocess.run → would NameError at runtime). Also the linter's import-order fix. - test_pipeline.py: main's test_git_identity_uses_env_vars_not_global_config mocked verify_build/verify_lint with a bare bool, but the resolved source keeps lv's VerifyOutcome shape (build_outcome.passed) → AttributeError. Fixed both mocks to VerifyOutcome(passed=True), matching every other lv pipeline test. Gates green after: cdk 3207 tests + synth + eslint; agent 1374 tests + ruff + ty (under AGENT_SESSION_ROLE_ARN set — no ECS hang).
Problem
run_task()inagent/src/pipeline.pyset the bot's git identity with:--globalwrites to~/.gitconfigfor whatever OS user runs the process. Inside the ephemeral ECS container that's intended. But the same code path runs on developer workstations (local agent runs, dry-runs, or any pytest that reachesrun_task), permanently clobbering the developer's real identity tobgagent. This was observed in the wild.Fix
Replace the two
git config --globalsubprocess calls with process-scoped env vars set alongside the existingos.environwrites:Git honors
GIT_AUTHOR_*/GIT_COMMITTER_*for every commit (inherited by Claude Code and the safety-net commit inpost_hooks.py) without touching any on-disk config. Container commits stay attributed tobgagent; a developer's~/.gitconfigis never modified.Also removes the now-unused
subprocessimport.Proof (controlled A/B against a sandboxed
GIT_CONFIG_GLOBAL)bgagent?git config --global)Scope notes
repo.py:153'ssafe.directory --globalis left as-is: it's additive and git deliberately mandates global scope forsafe.directory; it does not reset identity.GITHUB_TOKEN/GH_TOKENsourced from the blueprint's Secrets Manager secret viaconfig.py) is unchanged.Testing
test_git_identity_uses_env_vars_not_global_configasserts the identity env vars are set byrun_task.ruffclean.--no-verify(worktree lacksnode_modulesfor the CDK pre-push compile — agent-only change); CI runs the full build.Closes #622
🤖 Generated with Claude Code