{ "id": "tier2_leak_prevention_20260620", "title": "Tier 2 Sandbox File Leak Prevention (revert + 3-layer defense)", "type": "fix", "status": "shipped", "priority": "A", "created": "2026-06-20", "shipped": "2026-06-20", "owner": "tier2-tech-lead", "spec": "conductor/tracks/tier2_leak_prevention_20260620/spec.md", "plan": "conductor/tracks/tier2_leak_prevention_20260620/plan.md", "scope": { "new_files": 5, "modified_files": 1, "deleted_files": 0 }, "depends_on": [], "blocks": [], "test_summary": { "default_on_tests": 25, "opt_in_tests_sandbox": 0, "opt_in_tests_smoke": 0 }, "verification_criteria": [ "The 4 tier-2 sandbox-only files from commit 00e5a3f2 are removed/reverted from master (fab2e55b)", "scripts/audit_tier2_leaks.py exits 0 on a clean main repo working tree", "scripts/audit_tier2_leaks.py --strict exits 1 when a forbidden file is present", "conductor/tier2/githooks/pre-commit exists, is shell-executable, and reads from forbidden-files.txt", "Pre-commit hook auto-unstages staged forbidden files (verified by tests/test_tier2_pre_commit_hook.py)", "scripts/tier2/setup_tier2_clone.ps1 installs the pre-commit hook into the clone (.git/hooks/pre-commit)", "All 13 audit tests + 12 hook tests + 21 existing tier-2 tests pass" ], "risk_register": [ { "id": "R1", "title": "Pre-commit hook uses CRLF-stripping that may not handle all line endings", "likelihood": "low", "scope_impact": "minimal; hook is best-effort, fails open", "mitigation": "Tests cover both CRLF and LF configs (test_hook_uses_config_from_project_root writes via Python text mode which produces CRLF on Windows; the test_hook_unstages_modified_opencode_json test covers a real-world config file with CRLF endings)" }, { "id": "R2", "title": "git rm --cached --quiet may exit non-zero on edge cases (staged content diverges from both HEAD and working tree)", "likelihood": "medium", "scope_impact": "minimal", "mitigation": "Hook uses --force flag (required when index content differs from HEAD and working tree). Discovered during TDD; documented in hook source." }, { "id": "R3", "title": "Tier-2 branches (tier2/result_migration_app_controller_phase6_20260619, tier2/test_sandbox_hardening_20260619) still contain the offender commit 00e5a3f2", "likelihood": "high", "scope_impact": "the implementation may be larger than the spec suggests if those branches need rebase before next merge", "mitigation": "Documented in TRACK_COMPLETION §Next Steps. User must rebase these branches on the new master tip (8f54deda) before merging. No automation; explicit user action required because force-push is required." }, { "id": "R4", "title": "Forbidden patterns are substring matches; a future legitimate file path containing 'opencode.json' or 'mcp_paths.toml' as substring would be falsely flagged", "likelihood": "low", "scope_impact": "minimal", "mitigation": "Patterns are in a config file at conductor/tier2/githooks/forbidden-files.txt; edit + reinstall if a future false positive is discovered. The pre-commit hook + audit script are independent and easy to update." }, { "id": "R5", "title": "Pre-commit hook must exit 0 (not block tier-2 mid-flow); tier-2 might miss the warning if stderr is not surfaced", "likelihood": "medium", "scope_impact": "minimal", "mitigation": "Hook writes clear warning to stderr (visible in git commit output). Tier-2 failcount machinery in scripts/tier2/failcount.py does not count hook fires as failures. If tier-2 misses the warning, the audit script catches the leak at the working-tree level." } ], "architecture_reference": { "primary_styleguide": "conductor/code_styleguides/feature_flags.md (file-presence = enabled; the hook is enabled iff the script + config are present in the clone)", "secondary_styleguides": [ "conductor/code_styleguides/workspace_paths.md (audit script uses SKIP_DIRS convention)" ], "related_tracks": [ "conductor/archive/tier2_autonomous_sandbox_20260616/", "conductor/tracks/test_sandbox_hardening_20260619/" ], "pattern_references": [ "conductor/tier2/githooks/pre-push (existing hook pattern, copy template for the new pre-commit hook)", "scripts/audit_exception_handling.py (audit script pattern, copy for audit_tier2_leaks.py)" ] }, "deferred_to_followup_tracks": [ { "title": "CI integration of audit_tier2_leaks.py --strict", "description": "Wire scripts/audit_tier2_leaks.py --strict into the existing 11-tier CI pipeline (or a dedicated pre-commit CI job) so the audit runs on every PR. The script exists; only the wiring is missing.", "track_status": "not yet specced" }, { "title": "Rebase of stale tier-2 branches on the post-revert master", "description": "tier2/result_migration_app_controller_phase6_20260619 and tier2/test_sandbox_hardening_20260619 both contain the offender commit 00e5a3f2. When those branches are next merged to master, the merge will conflict with fab2e55b. User should rebase on origin/master@8f54deda.", "track_status": "user action required" } ], "regressions_and_pre_existing_failures": [], "pre_existing_failures_remaining": [], "user_directives": [ "Tier-2 autonomous must NEVER commit those files again", "Use a pre-commit hook (NOT gitignore) for the enforcement", "Selective revert: only the user-named files (./opencode/*, mcp_paths.toml, opencode.json); leave other 00e5a3f2 changes alone", "Recovery from data loss: do not use git restore or git reset without explicit permission" ] }