fix(agent-team): post-build denied-path check writes scratch outside the checkout (#38)

Live smoke exposed a self-pollution bug (pre-existing from PR #17): the post-build
denied-path check wrote its own _build_diff_z.bin / _build_status_z.bin into the
working tree, then its own `git status --untracked-files=all` flagged them as
out-of-scope writes — failing any run with a narrow declared_scope (the smoke's
docs/**). Write them to $RUNNER_TEMP instead (read via $_DIFF_Z/$_STATUS_Z), so
the check no longer sees its own temp files. The agent-team pytest artifacts were
already correctly gitignored; only the check's own files tripped it. Test harness
updated to pass the env paths. 1044 tests, ruff clean.
This commit is contained in:
Adam Moussa 2026-06-22 19:20:05 -04:00 • committed by GitHub
parent 5756178d62
commit 0a5a78ecf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 23 additions and 7 deletions

View file

@ -742,8 +742,15 @@ jobs:
# mangling is done anywhere. A path that cannot be cleanly decoded is
# treated as a VIOLATION (fail closed).
git config core.quotepath false
git diff -z --name-only HEAD > ./_build_diff_z.bin || true
git status --porcelain=v1 -z --untracked-files=all > ./_build_status_z.bin || true
# Write the scratch capture files OUTSIDE the checkout ($RUNNER_TEMP) so
# the `git status --untracked-files=all` below does not see — and flag —
# the check's OWN temp files as out-of-scope writes (they would otherwise
# appear as untracked and fail a narrow declared_scope).
_DIFF_Z="${RUNNER_TEMP:-/tmp}/_build_diff_z.bin"
_STATUS_Z="${RUNNER_TEMP:-/tmp}/_build_status_z.bin"
export _DIFF_Z _STATUS_Z
git diff -z --name-only HEAD > "$_DIFF_Z" || true
git status --porcelain=v1 -z --untracked-files=all > "$_STATUS_Z" || true
python3 - <<'PY'
from __future__ import annotations
@ -885,7 +892,7 @@ jobs:
"""`git diff -z --name-only` records: each NUL field is one path."""
ok: list[str] = []
bad: list[bytes] = []
for rec in _read_z("./_build_diff_z.bin"):
for rec in _read_z(os.environ["_DIFF_Z"]):
dec = _decode(rec)
(ok if dec is not None else bad).append(dec if dec is not None else rec)
return ok, bad
@ -901,7 +908,7 @@ jobs:
"""
ok: list[str] = []
bad: list[bytes] = []
recs = _read_z("./_build_status_z.bin")
recs = _read_z(os.environ["_STATUS_Z"])
i = 0
while i < len(recs):
rec = recs[i]

View file

@ -390,9 +390,18 @@ def _run_post_build(
script = tmp_path / "post_build.py"
script.write_text(_extract_post_build_script(), encoding="utf-8")
(tmp_path / "_build_diff_z.bin").write_bytes(diff_z)
(tmp_path / "_build_status_z.bin").write_bytes(status_z)
env = dict(os.environ, DECLARED_SCOPE=scope)
diff_z_path = tmp_path / "_build_diff_z.bin"
status_z_path = tmp_path / "_build_status_z.bin"
diff_z_path.write_bytes(diff_z)
status_z_path.write_bytes(status_z)
# The script now reads its capture files from $_DIFF_Z / $_STATUS_Z (written
# outside the checkout in CI so the check's own temp files are not flagged).
env = dict(
os.environ,
DECLARED_SCOPE=scope,
_DIFF_Z=str(diff_z_path),
_STATUS_Z=str(status_z_path),
)
result = subprocess.run(
[sys.executable, str(script)],
env=env,