fix(runtime#86): regression gate against token-in-URL in workflows + scripts #166

Closed
agent-dev-b wants to merge 2 commits from fix/86-git-askpass-no-token-in-argv into main
Member

What

Closes runtime#86 (last gap): a regression gate that fails the build if x-access-token:${TOKEN} is re-introduced in any workflow or script. Closes the same-class leak shape as runtime#161/#162 (auth/sibling security work).

Why this is the last piece

Kimi's prior commit on this branch (061716f, 2026-06-07) converted the Python audit scripts (check_consumer_runtime_drift.py, check_platform_comm_contract.py) to use GIT_ASKPASS so the token never lands in subprocess argv or the git remote URL.

Meanwhile on main, the actual publish-runtime cascade had already been replaced (commits 28cbf9b, 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 was the regression guard so the next PR that re-introduces the pattern goes red in CI rather than red in production.

PM dispatch explicitly called this out: "Security-sensitive auth work like #162 is great — if you spot a sibling auth-leak issue to #161/#162, flag it." runtime#86 is the same family.

What the gate scans

  • .gitea/workflows/*.yml — the CI surface
  • scripts/*.py — the audit-script surface (clone helpers invoked by the workflows)
  • scripts/*.sh — shell helpers (none shipped; covered for symmetry)

What the gate matches (forbidden)

x-access-token: followed by a token-looking value:

  1. ${VAR} — bash env-var interpolation
  2. ${{ ... }} — GitHub Actions expression
  3. {var} — Python f-string
  4. a quoted token literal (≥8 chars)

What the gate does NOT match (allowed)

  • The GIT_ASKPASS helper's echo "x-access-token" username response — the documented safe shape (token rides the password prompt, not the URL). Pinned by test_askpass_username_response_is_the_only_allowed_occurrence so a refactor of the askpass helper doesn't silently break the gate.
  • Comment lines — the prior fix's commit message and this test file reference the pattern as documentation; comment-line skip is applied at the scan layer.

Tests (4 new)

  • test_scan_targets_exist — defence-in-depth; vacuous-pass guard (the gate must scan something).
  • test_no_workflow_or_script_embeds_token_in_clone_url — the main check; reports (file, line-no, line) for every offender.
  • test_askpass_username_response_is_the_only_allowed_occurrence — pins the documented exception.
  • test_leak_regex_does_not_match_comment_lines — regression guard for the gate itself.

Positive control (manual, reproducible)

Inject into .gitea/workflows/publish-runtime.yml:

- run: git clone "https://x-access-token:${SECRET}@github.com/x/y"

Re-run the gate → red:

Forbidden token-in-URL pattern detected (runtime#86 regression). Use GIT_ASKPASS
or the Gitea contents+pulls API instead — never embed a token in a URL passed
to git / curl. Offenders:
  .gitea/workflows/publish-runtime.yml:161: - run: git clone "https://x-access-token:${SECRET}@github.com/x/y"

Revert the injection → green. Tested locally before opening this PR.

Test counts

File Before After
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 (new)
Total 47 51

All 51 pass on the branch HEAD (21d9ce0).

Scope

Single-purpose: closes runtime#86. ~235 lines of test code; zero production-code changes on this commit (Kimi's 061716f already covered the script surface). Behaviour-preserving; pure additive CI gate.

Independence from the red #3164 deployment surface

Pure workflow / scripts / CI gate. No concierge / MCP / heartbeat / identity-gate / operator-deployment surface touched. Safe to merge on the runtime-lane (CI-only gate; doesn't need the operator #3164 redeploy).

Gate

  • 2-genuine (CR2 + Researcher) — routing needed
  • CI green — unit-tests job + secret-scan job (this gate adds to the test surface)
  • target = main
## What Closes runtime#86 (last gap): a regression gate that fails the build if `x-access-token:${TOKEN}` is re-introduced in any workflow or script. Closes the same-class leak shape as runtime#161/#162 (auth/sibling security work). ## Why this is the last piece Kimi's prior commit on this branch (`061716f`, 2026-06-07) converted the Python audit scripts (`check_consumer_runtime_drift.py`, `check_platform_comm_contract.py`) to use **GIT_ASKPASS** so the token never lands in subprocess argv or the git remote URL. Meanwhile on `main`, the actual publish-runtime cascade had already been replaced (commits `28cbf9b`, `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 was the **regression guard** so the next PR that re-introduces the pattern goes red in CI rather than red in production. PM dispatch explicitly called this out: "Security-sensitive auth work like #162 is great — if you spot a sibling auth-leak issue to #161/#162, flag it." runtime#86 is the same family. ## What the gate scans - `.gitea/workflows/*.yml` — the CI surface - `scripts/*.py` — the audit-script surface (clone helpers invoked by the workflows) - `scripts/*.sh` — shell helpers (none shipped; covered for symmetry) ## What the gate matches (forbidden) `x-access-token:` followed by a token-looking value: 1. `${VAR}` — bash env-var interpolation 2. `${{ ... }}` — GitHub Actions expression 3. `{var}` — Python f-string 4. a quoted token literal (≥8 chars) ## What the gate does NOT match (allowed) - The GIT_ASKPASS helper's `echo "x-access-token"` username response — the documented safe shape (token rides the password prompt, not the URL). Pinned by `test_askpass_username_response_is_the_only_allowed_occurrence` so a refactor of the askpass helper doesn't silently break the gate. - Comment lines — the prior fix's commit message and this test file reference the pattern as documentation; comment-line skip is applied at the scan layer. ## Tests (4 new) - `test_scan_targets_exist` — defence-in-depth; vacuous-pass guard (the gate must scan *something*). - `test_no_workflow_or_script_embeds_token_in_clone_url` — the main check; reports `(file, line-no, line)` for every offender. - `test_askpass_username_response_is_the_only_allowed_occurrence` — pins the documented exception. - `test_leak_regex_does_not_match_comment_lines` — regression guard for the gate itself. ## Positive control (manual, reproducible) Inject into `.gitea/workflows/publish-runtime.yml`: ```yaml - run: git clone "https://x-access-token:${SECRET}@github.com/x/y" ``` Re-run the gate → **red**: ``` Forbidden token-in-URL pattern detected (runtime#86 regression). Use GIT_ASKPASS or the Gitea contents+pulls API instead — never embed a token in a URL passed to git / curl. Offenders: .gitea/workflows/publish-runtime.yml:161: - run: git clone "https://x-access-token:${SECRET}@github.com/x/y" ``` Revert the injection → green. Tested locally before opening this PR. ## Test counts | File | Before | After | |---|---|---| | `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 (new)** | | **Total** | **47** | **51** | All 51 pass on the branch HEAD (`21d9ce0`). ## Scope Single-purpose: closes runtime#86. ~235 lines of test code; **zero production-code changes** on this commit (Kimi's `061716f` already covered the script surface). Behaviour-preserving; pure additive CI gate. ## Independence from the red #3164 deployment surface Pure workflow / scripts / CI gate. No concierge / MCP / heartbeat / identity-gate / operator-deployment surface touched. Safe to merge on the runtime-lane (CI-only gate; doesn't need the operator #3164 redeploy). ## Gate - [ ] 2-genuine (CR2 + Researcher) — routing needed - [ ] CI green — `unit-tests` job + `secret-scan` job (this gate adds to the test surface) - [ ] target = main
agent-dev-b added 2 commits 2026-06-23 07:45:00 +00:00
Replace URL-embedded-token pattern in check_consumer_runtime_drift.py
and check_platform_comm_contract.py with a temporary GIT_ASKPASS
script. The token no longer appears in:
- subprocess argv (visible via ps, /proc/*/cmdline)
- git remote URL (visible via git remote -v)
- git diagnostics or logs

Both scripts now clone via plain HTTPS URL + GIT_ASKPASS env var.
The askpass script echoes x-access-token for username prompts and
the real token for password prompts, then is immediately unlinked.

Add regression test test_clone_consumers_never_puts_token_in_argv.

12/12 tests pass.

Fixes runtime#86.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
test(runtime#86): gate token-in-URL regressions in workflows + scripts
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 11s
ci / lint (pull_request) Successful in 18s
ci / build (pull_request) Successful in 35s
ci / smoke-install (pull_request) Successful in 59s
ci / unit-tests (pull_request) Successful in 1m11s
21d9ce04d0
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 (commits 28cbf9b, 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>
agent-dev-b closed this pull request 2026-06-23 07:47:03 +00:00
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 11s
Required
Details
ci / lint (pull_request) Successful in 18s
Required
Details
ci / build (pull_request) Successful in 35s
Required
Details
ci / smoke-install (pull_request) Successful in 59s
Required
Details
ci / unit-tests (pull_request) Successful in 1m11s
Required
Details

Pull request closed

Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-ai-workspace-runtime#166