Skip to content

VC policy hardening — diagnostic prompt

Use this prompt when running a version-control policy audit. Read ../SKILL.md first for orientation questions and guardrails.

Inputs

Collect from the user before scanning:

Input Required Default
host No github
org Yes (GitHub/Bitbucket) or project (ADO)
repo If single-repo scope
scope Yes single-repo or all-org-repos
policy_level_preference Ask repo-first or org-wide
target_branch No main (or repo default branch)
large_file_limit_mb No 3

Metadata block (top of every report)

Last updated by: <agent or reviewer name>
Run date: <ISO date>
Host: GitHub | Azure DevOps | Bitbucket
Scope: <OWNER/REPO | org ORG — N repos>
Policy level assessed: repo | org | both
Target branch: main
Evidence source: gh CLI | UI screenshots | mixed

Phase 0 — Tooling gate

  1. Confirm gh availability (gh --version, gh auth status) for GitHub.
  2. If unavailable, direct the user to gh-cli-install.md (Windows/winget, Git Bash PATH, macOS, Linux) or switch to UI audit mode.
  3. Ask user to paste or screenshot:
  4. Rules / rulesets list
  5. Pull request merge settings
  6. Default branch name

Do not proceed to remediation commands until tooling path is clear.

Phase 1 — Scope question (mandatory)

Ask exactly one of:

Should I audit a single repository (you'll name OWNER/REPO) or scan all
repositories in the org/project and summarise gaps across them?

If all-org-repos, warn that runtime grows with repo count; offer to filter by team, naming prefix, or "active in last 90 days" if the list is large.

Phase 2 — Policy level question (mandatory)

Ask:

Do you want recommendations for repo-specific policies first (pilot on one
repo), or org/project-wide rules that apply to every repository?

Record the answer. Tailor remediation steps accordingly.

Phase 3 — GitHub scan (single repo)

Run and capture output for each:

# Identity and default branch
gh repo view OWNER/REPO --json name,defaultBranchRef,mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed,deleteBranchOnMerge

# Rulesets (org + repo)
gh api repos/OWNER/REPO/rulesets --jq '.[] | {id, name, source_type, enforcement, target}'

# Ruleset detail (for each active ruleset affecting main)
gh api repos/OWNER/REPO/rulesets/RULESET_ID --jq '{name, rules, conditions}'

# Legacy branch protection (may 404 if rulesets-only)
gh api repos/OWNER/REPO/branches/main/protection 2>&1 || true

Checklist — map evidence to controls

Control What to look for Golden path
Main protected Ruleset targets main / default branch Active ruleset
No force-push non_fast_forward rule Present
No branch deletion deletion rule Present
Linear history required_linear_history Present (blocks merge commits)
Rebase-only merges Repo flags + optional pull_request merge method rule squash=false, merge=false, rebase=true
Auto-delete head branches deleteBranchOnMerge true
Update branch button allow_update_branch on repo true (recommended)
Large file block Push ruleset with max file size e.g. 3 MB active
CI on main Required status checks in ruleset or workflow runs on PR/push Validate workflow exists

Ghost-branch diagnostic (optional)

If user reports "branch still 1 commit ahead after merge":

git fetch origin
git log --oneline origin/main..origin/FEATURE_BRANCH | head -5
git log --oneline origin/FEATURE_BRANCH..origin/main | head -5

Explain: squash merge creates a new commit on main; branch tip is not an ancestor → GitHub shows "ahead". Not missing work if PR merged. Fix: rebase merge + auto-delete branches.

Large-file diagnostic (optional)

git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
  | awk '/^blob/ && $3 > LIMIT_BYTES {printf "%.2f MB %s\n", $3/1024/1024, $4}' | sort -rn | head -20

Replace LIMIT_BYTES with e.g. 3145728 for 3 MiB.

Phase 4 — GitHub scan (all org repos)

ORG=wiresuncrossed  # example

gh repo list "$ORG" --limit 200 --json name,defaultBranchRef,isArchived,updatedAt \
  --jq '.[] | select(.isArchived == false) | .name'

# Per repo (script or loop) — collect merge flags + ruleset names only
for repo in $(gh repo list "$ORG" --limit 200 --json name -q '.[].name'); do
  echo "=== $repo ==="
  gh repo view "$ORG/$repo" --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed,deleteBranchOnMerge
  gh api "repos/$ORG/$repo/rulesets" --jq '.[].name' 2>/dev/null || echo "(no rulesets or no access)"
done

Produce a summary table plus drill-down on repos that fail golden path.

Phase 5 — Gap analysis

For each control: ✅ Present | ⚠️ Partial | ❌ Missing | 🔶 Org-only (not repo)

Prioritise:

  • P0 — main unprotected, direct push allowed, or merge commits allowed
  • P1 — squash enabled (ghost branches), no large-file push rule
  • P2 — no auto-delete branches, no update-branch, no local dev guidance
  • P3 — documentation, commitlint, pre-commit alignment

Phase 6 — Recommendations (do not apply without approval)

Present repo-first and org-wide variants where relevant.

GitHub repo-first golden path (reference only):

gh repo edit OWNER/REPO \
  --enable-merge-commit=false \
  --enable-squash-merge=false \
  --enable-rebase-merge=true \
  --delete-branch-on-merge=true \
  --allow-update-branch

Rulesets (UI or API) — see github-controls.md.

Ask: "Shall I apply these changes, or do you want the report only?"

Phase 7 — Local dev recommendations

Always include a short local dev section in the report:

  1. git-hygiene skill — branch from fresh main, never commit to main.
  2. New branch per PR — avoid reusing merged branch names without reset.
  3. Large artifacts — R2 / Git LFS / release assets; never commit >limit MB.
  4. History scrub — if large file was pushed: git filter-repo on feature branch, force-push with lease; coordinate before rewriting shared branches.
  5. Pre-commit — optional local gates; server push rules remain authoritative.

Phase 8 — Non-GitHub hosts

If host is Azure DevOps or Bitbucket, follow other-platforms.md. Do not invent policy names or API commands — use documented UI paths and ask for screenshots.

Output

Write the report using gap-report-template.md. Attach raw command output or screenshot references as an appendix when helpful.