"""Exercise reviewed hook activation/rollback in disposable repositories only.""" import hashlib import json import os from pathlib import Path import shutil import subprocess import sys import pytest ROOT = Path(__file__).resolve().parents[1] SCRIPT = ROOT / 'docs/changes/CUST-WP-0080/activate_secret_hooks.py' def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() @pytest.fixture def proposal(tmp_path): binary_source = Path('/tmp/netkingdom-secret-detection/gitleaks') if not binary_source.exists(): pytest.skip('reviewed disposable scanner not installed') repo = tmp_path / 'scoped'; repo.mkdir() def git(*args): return subprocess.check_output(['git', '-C', str(repo), *args], stderr=subprocess.DEVNULL) git('init', '-q') hooks = repo / '.git/hooks' git('config', 'core.hooksPath', str(hooks)) git('config', 'user.name', 'Synthetic Probe'); git('config', 'user.email', 'probe@example.test') (repo / 'source.py').write_text('print("clean")\n') git('add', 'source.py'); git('commit', '-qm', 'clean baseline') before = hooks / 'pre-commit'; before.write_text('#!/bin/sh\nexit 0\n'); before.chmod(0o755) backup = tmp_path / 'backup'; shutil.copyfile(before, backup) binary = tmp_path / 'tools/gitleaks' candidate = tmp_path / 'candidate' candidate.write_text('#!/bin/sh\nset -eu\npython3 '+str(ROOT/'scripts/check_generated_only_commit.py')+' --staged\n' 'case "$(git rev-parse --show-toplevel)" in\n'+str(repo)+')\n' 'exec python3 /home/worsch/repo-manager/src/repo_manager/secret_scan.py --path . --binary ' +str(binary)+'\n;;\nesac\n') data = {'proposal_id':'disposable-activation-probe','scope_roots':[str(repo)], 'binary':{'source':str(binary_source),'target':str(binary),'sha256':sha(binary_source)}, 'hook_source':str(candidate),'hooks':[{'path':str(before),'before_sha256':sha(before), 'before_mode':0o755,'backup':str(backup),'after_sha256':sha(candidate)}], 'original_routes':[{'repo':repo.name,'effective_pre_commit':str(before)}], 'protected_files':[], 'executor_sha256':sha(SCRIPT)} path = tmp_path / 'proposal.json'; path.write_text(json.dumps(data)) return path, data, tmp_path / 'receipt.json', repo, git('rev-parse','HEAD') def invoke(proposal, *args): path, _, receipt, _, _ = proposal return subprocess.run([sys.executable, str(SCRIPT), '--proposal', str(path), '--receipt', str(receipt), *args], capture_output=True, text=True, check=False, timeout=60) def test_activation_native_probes_restore_tool_and_preserve_repository(proposal): _, data, receipt, repo, head = proposal before_index = (repo/'.git/index').read_bytes() assert invoke(proposal, '--apply').returncode == 0 observed = json.loads(receipt.read_text()) assert observed['result'] == 'verified' assert observed['verification']['repositories'][0]['scanner_failure_exit'] == 2 assert observed['verification']['scanner_mode_restored'] assert (repo/'.git/index').read_bytes() == before_index assert subprocess.check_output(['git','-C',str(repo),'rev-parse','HEAD']) == head assert invoke(proposal, '--rollback').returncode == 0 assert sha(Path(data['hooks'][0]['path'])) == data['hooks'][0]['before_sha256'] def test_unknown_hook_is_refused_before_install(proposal): _, data, _, _, _ = proposal Path(data['hooks'][0]['path']).write_text('unreviewed hook\n') assert invoke(proposal, '--apply').returncode != 0 assert not Path(data['binary']['target']).exists() def test_failed_probe_rolls_back_exact_hook(proposal): path, data, receipt, _, _ = proposal candidate = Path(data['hook_source']); candidate.write_text('#!/bin/sh\nexit 0\n') data['hooks'][0]['after_sha256'] = sha(candidate); path.write_text(json.dumps(data)) assert invoke(proposal, '--apply').returncode != 0 observed = json.loads(receipt.read_text()) assert observed['result'] == 'unverified' assert observed['rollback'] == 'prior hooks restored' assert sha(Path(data['hooks'][0]['path'])) == data['hooks'][0]['before_sha256']