Skip to content

repo-audit

Plugin: core-standards
Category: Governance
Command: /repo-audit


/vt-c-repo-audit — Deployment Integrity Audit

The "Search & Destroy" skill from the Unified Repo Governance model.

Reference: docs/unified repo approach.md

Purpose

Scans the repository for governance violations that could compromise deployment integrity: - Context artifacts leaking into deployable paths - Oversized files not tracked by Git LFS - Sandbox code that should have been promoted or removed - Build bundles containing non-production files - Missing traceability references - Hook script tampering, unauthorized hooks, and dangerous patterns

When to Use

  • On demand: Run anytime to check governance compliance
  • Before deployment: /vt-c-5-finalize calls this automatically
  • In CI/CD: --ci-mode for non-interactive pipeline use
  • Self-correction: --fix to automatically resolve violations

Prerequisites

.repo-manifest.yaml must exist. If absent, report:

No .repo-manifest.yaml found. Governance is not active.
Run /vt-c-repo-init to initialize unified repo governance.

Invocation

/vt-c-repo-audit              # Interactive audit with full report
/vt-c-repo-audit --fix        # Auto-fix violations where possible
/vt-c-repo-audit --ci-mode    # Non-interactive, exit code 1 on critical failures

Execution Steps

Step 1: Load Manifest

Read .repo-manifest.yaml and parse: - partitions.deployable.paths — production code zones - partitions.context.paths — design/AI context zones - partitions.sandbox.paths — draft code zones - binary_rules — size thresholds and LFS extensions - traceability — SPEC reference requirements

Step 2: Context Bleed Check

Scan all files in deployable paths for context artifacts:

Context indicators in deployable paths (CRITICAL): - .md files with YAML frontmatter containing parent_prd:, personas:, status: draft - Files matching known context patterns: *-persona.md, *-research.md, PRD*.md, PID*.md - .design-state.yaml or .repo-manifest.yaml copies in src/ - Prototype HTML/CSS files in src/ (not component files)

Exceptions (allowed in deployable paths): - README.md, CHANGELOG.md, LICENSE.md - CLAUDE.md, AGENTS.md - Code comments referencing SPEC IDs - API documentation generated from code

Output per finding:

❌ CONTEXT BLEED: src/docs/user-research.md
   Context artifact found in deployable partition (src/)
   Fix: Move to docs/ or 02-Knowledge/

Step 3: File Size Check

Scan all files for oversized objects not tracked by LFS:

# Find files exceeding max_file_size_kb
find . -type f -size +{max_file_size_kb}k \
  -not -path "./.git/*" \
  -not -path "./node_modules/*"

For each oversized file: - If extension matches lfs_extensions but NOT in .gitattributesCRITICAL - If in context paths → WARNING (large but won't deploy) - If in deployable paths → CRITICAL (will bloat production)

Output:

⚠ OVERSIZED: assets/hero-image.png (2.3 MB)
  Not tracked by Git LFS. Extension .png matches binary rules.
  Fix: git lfs track "*.png" && git add .gitattributes

Step 4: LFS Compliance Check

Verify .gitattributes covers all extensions in binary_rules.lfs_extensions:

For each extension in manifest:
  - Check .gitattributes contains matching LFS rule
  - Check any existing files with that extension are LFS-tracked

Output:

❌ LFS MISSING: .sketch files not in .gitattributes
   Manifest requires LFS tracking for .sketch
   Fix: echo "*.sketch filter=lfs diff=lfs merge=lfs -text" >> .gitattributes

Step 5: Build Bundle Audit

If dist/, build/, .next/, or out/ directories exist:

Scan build output for context artifacts:
  - .md files (except README/LICENSE)
  - .yaml/.yml files (except configs)
  - persona documents, research notes
  - prototype files, specs files
  - .design-state.yaml

Output:

❌ BUILD LEAK: dist/docs/PRD.md
   Context artifact found in build output
   Fix: Update build config to exclude docs/ from output

Step 6: Sandbox Status Check

Scan sandbox paths for stale code:

For files in sandbox paths:
  - Last modified > 30 days ago → STALE WARNING
  - Contains TODO/FIXME/HACK markers → NOTE
  - Duplicated in deployable paths → CONFLICT WARNING

Output:

⚠ STALE SANDBOX: 04-prototyp/components/Dashboard.tsx
  Last modified 45 days ago. Consider:
  - /vt-c-promote to move to production
  - Delete if no longer needed

Step 7: Traceability Check

Read traceability.require_spec_reference from manifest:

If true: Scan ALL commits to deployable paths (full enforcement).

If "new-only": Only scan commits AFTER traceability.cutoff_date:

git log --oneline --since="{cutoff_date}" --diff-filter=AM -- {deployable_paths}
Pre-governance commits are exempt. Include a note in output:
ℹ Traceability mode: new-only (adopted {adoption.adopted_at})
  {N} pre-governance commits exempt | Checking {M} post-governance commits

If false or absent: Skip traceability check entirely.

For each checked commit, verify message contains SPEC- prefix reference.

Also scan source files in deployable paths for SPEC- references in comments.

Output (full mode):

⚠ TRACEABILITY: 3 recent commits to src/ lack SPEC- references
  - abc1234 "Add login form"
  - def5678 "Fix button styling"
  - ghi9012 "Update API handler"
  Recommendation: Include SPEC-NNN in commit messages for traceability

Output (new-only mode):

⚠ TRACEABILITY (new-only, cutoff: 2026-02-13):
  15 pre-governance commits — exempt
  5 post-governance commits checked:
    3 reference SPEC- IDs ✅
    2 missing SPEC- references ⚠

  Note: Consider upgrading to require_spec_reference: true
  when all active features have SPEC IDs assigned.

Step 8: Hook Security Audit

Validates hook script integrity, location, permissions, and content against the trusted hooks manifest (configs/security/trusted-hooks.yaml).

Added by SPEC-053. Detects tampered, unauthorized, or dangerous hook scripts.

8a: Load Trusted Hooks Manifest

Read configs/security/trusted-hooks.yaml from the toolkit root (resolve via TOOLKIT_ROOT).

If the manifest file does not exist: - Record finding: [WARN] No trusted hooks manifest found; hook integrity cannot be verified - Continue with sub-steps 8e (network) and 8f (permissions) only — skip 8c (location), 8d (checksum), and 8g (unknown)

If the manifest exists: - Parse approved_locations list - Parse hooks map (keyed by relative path) - Continue with all sub-steps

8b: Discover Hook Scripts

Scan these directories for .sh files and other executables:

  1. plugins/*/scripts/ — all plugin script directories (relative to repo root)
  2. ~/.claude/hooks/ — user-global deployed hooks

For each discovered file: - If it is a symlink: resolve the target using readlink (macOS-compatible; follow chains until a real file is reached) - Record both the symlink path and the resolved target path - If the symlink is broken (target does not exist): record finding [CRITICAL] Broken hook symlink: <symlink> → <target> (target does not exist) - If the file is a directory: skip it silently

Build a set of all discovered scripts with their resolved paths.

8c: Location Validation

For each discovered script (using resolved paths for symlinks): - Check if the resolved path falls under one of the approved_locations entries from the manifest - For ~/.claude/hooks/ symlinks: validate that the resolved target is in an approved location (e.g., plugins/core-standards/scripts/)

Finding for unapproved location:

[CRITICAL] Hook script found in unapproved location: /tmp/.claude-hooks/exfil.sh

8d: Checksum Verification

For each hook entry in the manifest: 1. Check if the file exists on disk 2. If it exists: compute shasum -a 256 <file> and compare against the manifest's sha256 value 3. If the file does not exist on disk: record a WARN finding

Finding for checksum mismatch:

[CRITICAL] Hook checksum mismatch: block-writes.sh (expected abc123..., got def456...)

Finding for missing file:

[WARN] Manifest lists hook not found on disk: plugins/core-standards/scripts/deleted-hook.sh

8e: Network Call Detection

For each discovered script, scan for outbound network call patterns using grep -n:

Patterns to match: - Shell: curl, wget, nc (word boundary), netcat, ncat, socat - Python: python.*http, requests\., urllib, http\.client - Ruby: ruby.*net, Net::HTTP - Node: node.*http, fetch(, XMLHttpRequest

Scan ALL lines including comments (commented-out network calls can be uncommented and are still a risk indicator).

Finding for network call detected:

[CRITICAL] Hook contains network call pattern: secret-scanner.sh (line 42: curl)

If no network patterns are found in a script, no finding is reported for that script.

8f: Permission Audit

For each discovered script, check file permissions using macOS-compatible syntax:

stat -f '%Lp' <file>

Parse the octal permission value: - If the group-write bit is set (second digit is 2, 3, 6, or 7) → WARN - If the other-write bit is set (third digit is 2, 3, 6, or 7) → WARN - Acceptable permissions: 700, 750, 755 - Unacceptable permissions: 775, 776, 777, etc.

Finding for overly permissive:

[WARN] Hook has overly permissive permissions: block-writes.sh (777, expected 755 or stricter)

If a script has 755 or stricter permissions, no finding is reported.

8g: Unknown Hook Detection

Compare the set of discovered scripts against the manifest entries:

  • For scripts in plugins/*/scripts/: use the relative path from repo root as the key
  • For scripts in ~/.claude/hooks/ that are symlinks: validate via their resolved target path (the source script should be in the manifest)
  • For scripts in ~/.claude/hooks/ that are NOT symlinks (real files, not symlinks to plugin scripts): flag as unknown

Finding for unknown hook:

[CRITICAL] Unknown hook script not in manifest: ~/.claude/hooks/sneaky-hook.sh

Step 9: Generate Report

╔══════════════════════════════════════════════════╗
║         REPO GOVERNANCE AUDIT REPORT             ║
╠══════════════════════════════════════════════════╣
║                                                  ║
║  Context Bleed:     ✅ PASS  (0 violations)      ║
║  File Size:         ⚠ WARN  (2 oversized files)  ║
║  LFS Compliance:    ✅ PASS  (all tracked)        ║
║  Build Bundle:      ✅ PASS  (clean)              ║
║  Sandbox Status:    ⚠ WARN  (1 stale file)       ║
║  Traceability:      ⚠ WARN  (3 commits)          ║
║  Hook Security:     ✅ PASS  (all hooks verified) ║
║                                                  ║
║  Overall: ⚠ WARNINGS (no critical failures)      ║
║                                                  ║
╚══════════════════════════════════════════════════╝

Hook Security traffic light logic: - ✅ PASS (green): All hooks pass all checks — checksums match, no unknown hooks, no network calls, permissions OK - ⚠ WARN (yellow): Only WARN-severity findings — permission issues, missing manifest, manifest lists hook not found on disk - ❌ FAIL (red): Any CRITICAL finding — checksum mismatch, unknown hook, unapproved location, network call pattern, broken symlink

Step 10: Self-Correction (--fix mode)

If --fix flag is set, for each fixable violation:

  1. Context bleed: Move file to appropriate context path, update references
  2. Oversized files: Run git lfs track for matching extensions
  3. LFS missing: Add rules to .gitattributes
  4. Build leaks: Suggest build config changes (cannot auto-fix build tools)
  5. Hook permissions: Run chmod 755 <script> to fix overly permissive hooks
  6. Hook checksum mismatch: Cannot auto-fix — report "Manual review required: verify hook content is correct, then update manifest with shasum -a 256 <script>"
  7. Unknown hooks: Cannot auto-fix — report "Manual review required: add to configs/security/trusted-hooks.yaml or remove the script"
  8. Hook network calls: Cannot auto-fix — report "Manual review required: verify the network call is intentional"

Show summary of fixes applied:

Auto-fixed 3 violations:
  ✅ Moved src/research-notes.md → docs/research-notes.md
  ✅ Added *.sketch to .gitattributes (LFS tracking)
  ✅ Added *.psd to .gitattributes (LFS tracking)

Manual action needed:
  ⚠ Update build config to exclude docs/ from dist/
  ⚠ Add SPEC- references to 3 commit messages (cannot retrofix)

Step 11: CI Mode (--ci-mode)

When running in CI/CD pipeline: - No interactive prompts - Exit code 0 = PASS (no critical violations) - Exit code 1 = FAIL (critical violations found) - Warnings are logged but don't cause failure - Output is structured for CI log parsing

[REPO-AUDIT] Context Bleed: PASS
[REPO-AUDIT] File Size: WARN (2 files)
[REPO-AUDIT] LFS Compliance: PASS
[REPO-AUDIT] Build Bundle: PASS
[REPO-AUDIT] Sandbox Status: WARN (1 stale)
[REPO-AUDIT] Traceability: WARN (3 commits)
[REPO-AUDIT] Hook Security: PASS
[REPO-AUDIT] RESULT: PASS (0 critical, 7 warnings)