fix(runtime#86): re-apply GIT_ASKPASS + add workflow URL-embedding regression gate #167
Reference in New Issue
Block a user
Delete Branch "fix/86-git-askpass-no-token-in-argv"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Closes runtime#86 end-to-end. Two commits:
Re-applies the GIT_ASKPASS conversion for the audit scripts (
check_consumer_runtime_drift.py,check_platform_comm_contract.py). Kimi's prior attempt (commit061716f, 2026-06-07) was reverted twice on main (2ae28eb,480045a— both baregit revertoutputs with no commit-body explanation); the URL-embedded token pattern is back onmain @ 924c0fdatscripts/check_consumer_runtime_drift.py:308+scripts/check_platform_comm_contract.py:290. This commit puts the fix back and adds back thetest_clone_consumers_never_puts_token_in_argvregression test.Adds a workflow-file grep gate (
tests/test_workflow_no_token_in_url.py) that fails CI if thex-access-token:${TOKEN}URL-embedding pattern is re-introduced in any.gitea/workflows/*.ymlorscripts/*.{py,sh}. The gate distinguishes the leak shape from the documented safeecho "x-access-token"username response in the GIT_ASKPASS helper body, and skips comment lines so the docstring of this file + future commit messages don't false-positive.Why both pieces
The leak surface is two scripts (Python) plus two workflow files (CI). Re-applying the GIT_ASKPASS fix closes the live leak. The gate makes the closure durable — without it, the next PR that re-introduces the URL-embedded pattern passes CI and ships the leak back to production.
This is the same auth-leak family as runtime#161 (
CLAUDE_CODE_OAUTH_TOKENdrain) and runtime#162 (ANTHROPIC_AUTH_TOKENdrain, just shipped as PR#165). Same shape: a secret ends up in a place where an attacker with log-read / process-inspection access can read it.Diligence on the Kimi revert history (PM asked)
PM asked for a why-check before re-applying. Findings:
2ae28eb,480045a) are baregit revertoutputs with no commit-body explanation.credential_helperwork (runtime#104, commitfd2051d) setsgit config --global credential.helper— a different mechanism, no overlap with GIT_ASKPASS. No conflict.061716fimplementation in full: standard GIT_ASKPASS pattern (subprocess.runwith env override, 0o700 askpass,os.unlinkinfinally,shlex.quoteon the token). Looks correct.GIT_ASKPASSenv, does not leak token or username into subprocess argv, and unlinks the file in thefinallyclause.Verdict: the reverts appear to be accidental state-management (
git revertthengit revert <revert>thengit revertagain) rather than a discovered bug. The implementation is correct; the live leak was the worse outcome.What the gate matches (forbidden)
x-access-token:followed by a token-looking value:${VAR}— bash env-var interpolation${{ ... }}— GitHub Actions expression{var}— Python f-stringWhat the gate does NOT match (allowed)
echo "x-access-token"username response — the documented safe shape (the token rides the password prompt, not the URL). Pinned bytest_askpass_username_response_is_the_only_allowed_occurrenceso a refactor of the askpass helper doesn't silently break the gate.Tests
tests/test_llm_auth.pytests/test_consumer_runtime_drift_guard.pytests/test_platform_comm_contract_guard.pytests/test_workflow_no_token_in_url.pyPositive control (manual, reproducible)
Inject into
.gitea/workflows/publish-runtime.yml:Re-run
pytest tests/test_workflow_no_token_in_url.py::test_no_workflow_or_script_embeds_token_in_clone_url -v→ red, with a file:line-cited failure:Revert the injection → green.
Smoke test for the helper
Result: askpass file created with
0o700, body contains the expectedecho "x-access-token"+echo 's3cr3t-t0k3n'(single-quoted viashlex.quote), token/username absent from subprocess argv, file unlinked infinally. ✓Independence from the red #3164 deployment surface
Pure scripts + test surface. No concierge / MCP / heartbeat / identity-gate / operator-deployment touched. Safe to merge on the runtime-lane (CI-only gate; doesn't need the operator #3164 redeploy).
Gate
unit-testsjob +secret-scanjob (this gate adds to the test surface)Closes the remaining acceptance-criteria gap from runtime#86: a regression test that fails the build if the x-access-token-in-clone-URL pattern is re-introduced in .gitea/workflows/*.yml or scripts/*.{py,sh}. Why this is the last piece -------------------------- Kimi's prior commit (061716f) on this branch converted the Python audit scripts to use GIT_ASKPASS so the token never lands in subprocess argv or the git remote URL. The publish-runtime.yml cascade had ALREADY been replaced (commits28cbf9b,7154e15) with a Gitea contents+pulls API approach — no git clone, no on-disk remote URL with a token. So the practical leak surface is closed; the missing piece is the regression guard so the next PR that re-introduces the pattern goes red in CI rather than red in production. What the gate scans ------------------- * .gitea/workflows/*.yml — the CI surface * scripts/*.py — the audit-script surface (clone helpers used by CI) * scripts/*.sh — shell helpers (none shipped; covered for symmetry) What the gate matches --------------------- x-access-token: followed by a token-looking value: 1. bash ${VAR} 2. GitHub Actions ${{ ... }} 3. Python f-string {var} 4. a quoted token literal (>=8 chars) What the gate does NOT match ---------------------------- * The GIT_ASKPASS helper's 'echo "x-access-token"' username response (the token rides the password prompt, not the URL — the documented safe shape). * Comment lines (the prior fix's commit message + this test file reference the pattern as documentation; the comment-line skip is applied at the scan layer). Tests ----- * test_scan_targets_exist — defence-in-depth, the gate scans something (vacuous-pass guard). * test_no_workflow_or_script_embeds_token_in_clone_url — the main check. * test_askpass_username_response_is_the_only_allowed_occurrence — pins the documented exception so a refactor of the askpass helper doesn't silently break the gate. * test_leak_regex_does_not_match_comment_lines — regression guard for the gate itself (verifies the comment-skip is wired up). Positive control (manual): injecting - run: git clone "https://x-access-token:${SECRET}@github.com/x/y" into .gitea/workflows/publish-runtime.yml and re-running the test produces a clear, file:line-cited failure: Forbidden token-in-URL pattern detected (runtime#86 regression). ... Offenders: .gitea/workflows/publish-runtime.yml:161: - run: git clone ... Existing tests still pass: tests/test_llm_auth.py — 35/35 tests/test_consumer_runtime_drift_guard.py — 6/6 tests/test_platform_comm_contract_guard.py — 6/6 tests/test_workflow_no_token_in_url.py — 4/4 Total 51/51. Closes: runtime#86 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>APPROVE on
4e01b29336(target=main).Security/RCA review: the GIT_ASKPASS re-application closes the runtime#86 leak shape in the two audit clone paths. The clone URL is now token-free (https://host/molecule-ai/repo.git), the token is supplied only through a temporary 0700 askpass script as the password response, and subprocess argv / persisted remote URL no longer contain DISPATCH_TOKEN or x-access-token credentials. Error redaction still strips the raw token.
I do not see a reintroduced breakage explaining the prior accidental reverts: clone retry behavior is preserved, tokenless config still fails loudly, invalid Gitea URL validation remains, and the askpass env is scoped to the git clone subprocess. The only x-access-token command occurrence is the safe askpass username response.
Regression gate: robust enough for this class. It scans .gitea/workflows plus scripts/.py/.sh, asserts scan targets/non-vacuous candidates, fails on x-access-token: URL patterns, skips comment-only documentation, and pins the allowed askpass username occurrences to exactly the two clone helpers.
CI on this head is green: secret scan, lint, build, smoke-install, unit-tests, responsiveness-e2e. Local focused check passed: tests/test_consumer_runtime_drift_guard.py, tests/test_platform_comm_contract.py, tests/test_workflow_no_token_in_url.py (32/32).
APPROVE on
4e01b29336(target=main).Security review:
CI: own-head CI green (secret scan, lint, build, unit-tests, smoke-install, responsiveness-e2e).