fix(loop): eliminate tmp script copy and trap leak in delegate_job_safe (P2-1/B-6)

This commit is contained in:
2026-08-15 10:46:39 +09:00
parent af3dc1600c
commit b490713471
4 changed files with 211 additions and 18 deletions
+161 -6
View File
@@ -147,16 +147,171 @@ def test_z8_dead_pid_marker(mam_sandbox):
assert res["decision"] == "allow"
# Z-9: delegate_job_safe restores _mam_release_guard trap
def test_z9_delegate_job_safe_restores_trap():
def _extract_delegate_job_safe():
run_loop = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "run_loop.sh"
content = run_loop.read_text()
# Check inside delegate_job_safe definition that trap - is replaced with trap _mam_release_guard
func_start = content.find("delegate_job_safe() {")
assert func_start != -1
func_body = content[func_start:func_start+400]
assert "trap _mam_release_guard EXIT INT TERM HUP" in func_body
assert "trap - EXIT INT TERM HUP" not in func_body
func_end = content.find("\n}\n", func_start)
assert func_end != -1
return content[func_start:func_end + 3]
# Z-9: delegate_job_safe preserves loop lock across delegations without tmp copies/traps (B-6, D1)
def test_z9_loop_lock_survives_delegation(tmp_path):
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
skill_dir.mkdir(parents=True)
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'JOB_ID: 12345678'\n")
stub_wrapper.chmod(0o755)
extracted_func = _extract_delegate_job_safe()
script = f"""#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="{tmp_path}"
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
source "{loop_lock_sh}"
log_error() {{ echo "ERROR: $@" >&2; }}
log_info() {{ echo "INFO: $@" >&2; }}
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
trap _mam_release_guard EXIT INT TERM HUP
{extracted_func}
PLAN_JOB_OUTPUT=$(delegate_job_safe submit --task test)
if [ -f "$MAM_LOOP_MARKER" ]; then
echo "MARKER: HELD"
else
echo "MARKER: RELEASED"
fi
"""
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
assert res.returncode == 0
assert "MARKER: HELD" in res.stdout
def test_z9_probe_detects_the_defect(tmp_path):
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
skill_dir.mkdir(parents=True)
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'JOB_ID: 12345678'\n")
stub_wrapper.chmod(0o755)
defective_func = """
delegate_job_safe() {
local orig_script="$REPO_ROOT/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job"
local tmp_script
tmp_script="${orig_script}.${RANDOM}_$$.tmp"
cp "$orig_script" "$tmp_script"
trap 'rm -f "$tmp_script"' EXIT INT TERM HUP
local rc=0
bash "$tmp_script" "$@" || rc=$?
rm -f "$tmp_script"
trap _mam_release_guard EXIT INT TERM HUP
return $rc
}
"""
script = f"""#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="{tmp_path}"
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
source "{loop_lock_sh}"
log_error() {{ echo "ERROR: $@" >&2; }}
log_info() {{ echo "INFO: $@" >&2; }}
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
trap _mam_release_guard EXIT INT TERM HUP
{defective_func}
PLAN_JOB_OUTPUT=$(delegate_job_safe submit --task test)
if [ -f "$MAM_LOOP_MARKER" ]; then
echo "MARKER: HELD"
else
echo "MARKER: RELEASED"
fi
"""
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
assert res.returncode == 0
assert "MARKER: RELEASED" in res.stdout
def test_z9_no_tmp_copy_left_in_skill_tree(tmp_path):
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
skill_dir.mkdir(parents=True)
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'JOB_ID: 12345678'\n")
stub_wrapper.chmod(0o755)
extracted_func = _extract_delegate_job_safe()
script = f"""#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="{tmp_path}"
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
source "{loop_lock_sh}"
log_error() {{ echo "ERROR: $@" >&2; }}
log_info() {{ echo "INFO: $@" >&2; }}
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
trap _mam_release_guard EXIT INT TERM HUP
{extracted_func}
PLAN_JOB_OUTPUT=$(delegate_job_safe submit --task test)
"""
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
assert res.returncode == 0
tmp_files = list(skill_dir.glob("*.tmp"))
assert tmp_files == []
def test_z9_exit_code_and_diagnostics_propagation(tmp_path):
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
skill_dir.mkdir(parents=True)
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'syntax error' >&2\nexit 7\n")
stub_wrapper.chmod(0o755)
extracted_func = _extract_delegate_job_safe()
script = f"""#!/usr/bin/env bash
REPO_ROOT="{tmp_path}"
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
source "{loop_lock_sh}"
log_error() {{ echo "ERROR: $@" >&2; }}
log_info() {{ echo "INFO: $@" >&2; }}
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
trap _mam_release_guard EXIT INT TERM HUP
{extracted_func}
rc=0
delegate_job_safe submit --task test || rc=$?
echo "DELEGATE_RC: $rc"
"""
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
assert "DELEGATE_RC: 7" in res.stdout
assert "delegate_job_safe failed (exit 7):" in res.stderr
assert "bash -n" in res.stderr
# Z-10: Reused PID with stale lstart is NOT blocked