Source: BLOCKING #2 from @scottschreckengaust's review of #665 — #665 (review) (agent/src/registry/loader.py:157)
Parent: #246 · Sibling blockers: #758 (symlink), and the skip-worktree data-loss issue
Problem
_protect_mcp_json_from_commit logs and continues when git update-index --skip-worktree fails — but by then the unredacted MCP runtime is already written to .mcp.json, so the full git add -u → commit → push chain is live and will exfiltrate the secret to the PR. The guard trusts the command exit code rather than verifying the flag actually took.
Two non-attacker triggers reproduced against the real loader:
index.lock contention — concurrent git (prek hooks, a parallel agent tool call, a crashed prior git) → fatal: Unable to create '.git/index.lock': File exists; guard WARNs, then git add -u stages the secret.
- Unmerged index entry for
.mcp.json — a conflicted predecessor merge (repo.py:656 does exactly this for merge_branches; the --abort window exists) → fatal: Unable to mark file .mcp.json; same result.
Both WARNs are followed by TASK Registry: merged 1 MCP server(s), so an operator reading logs sees success.
Fix
Verify the observed flag and fail closed once bytes are on disk:
verify = _git("ls-files", "-v", "--", ".mcp.json").stdout
if not verify.startswith(("S", "h")):
raise RegistryAssetLoadError(
"could not make .mcp.json unstageable; refusing to run with a "
"secret-bearing config in a committable tree"
)
Checking the observed flag also covers the symlink case (#758) for free. If adopted, the "best-effort … not fatal" docstring and the fail-closed list in the loader need updating to match.
Scott's recommended durable fix (in-process mcp_servers, no disk write) subsumes this.
Acceptance
- A failed/ineffective skip-worktree (lock contention, unmerged index) causes
apply_mcp_assets to raise rather than proceed with a committable secret
- Regression test: monkeypatch the git call to fail, assert the raise
Source: BLOCKING #2 from @scottschreckengaust's review of #665 — #665 (review) (
agent/src/registry/loader.py:157)Parent: #246 · Sibling blockers: #758 (symlink), and the skip-worktree data-loss issue
Problem
_protect_mcp_json_from_commitlogs and continues whengit update-index --skip-worktreefails — but by then the unredacted MCP runtime is already written to.mcp.json, so the fullgit add -u→ commit → push chain is live and will exfiltrate the secret to the PR. The guard trusts the command exit code rather than verifying the flag actually took.Two non-attacker triggers reproduced against the real loader:
index.lockcontention — concurrent git (prek hooks, a parallel agent tool call, a crashed prior git) →fatal: Unable to create '.git/index.lock': File exists; guard WARNs, thengit add -ustages the secret..mcp.json— a conflicted predecessor merge (repo.py:656does exactly this formerge_branches; the--abortwindow exists) →fatal: Unable to mark file .mcp.json; same result.Both WARNs are followed by
TASK Registry: merged 1 MCP server(s), so an operator reading logs sees success.Fix
Verify the observed flag and fail closed once bytes are on disk:
Checking the observed flag also covers the symlink case (#758) for free. If adopted, the "best-effort … not fatal" docstring and the fail-closed list in the loader need updating to match.
Acceptance
apply_mcp_assetsto raise rather than proceed with a committable secret