Repo Hardening
Audit and fix GitHub repository security settings using the bundled scripts/harden.sh.
Prerequisites
Before running the script, ensure:
gh CLI is installed and authenticated (gh auth login)
jq is installed
- The user has sufficient access to the target repository:
audit can run with read access, with inaccessible endpoints reported as skip
fix requires admin access
The script checks prerequisites and exits with a clear error if required tools, authentication, or fix permissions are missing.
Workflow
Always follow this sequence:
Resolve the script path — run the bundled script via the path to this skill directory, not the current project directory:
SKILL_DIR="/path/to/repo-hardening" # directory containing this SKILL.md
HARDEN_SCRIPT="$SKILL_DIR/scripts/harden.sh"
Audit first — run the audit to see current state:
bash "$HARDEN_SCRIPT" audit --repo OWNER/REPO
Present findings — summarise the audit results to the user, highlighting fail and warn items grouped by severity (critical > high > medium > low).
Dry-run before fixing — ask the user which categories to fix. Use explicit --checks to scope fixes to the confirmed categories, then run --dry-run before any mutation:
bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches,security --dry-run
If branch protection has no existing required status checks, pass each CI context explicitly:
bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches --required-check "test" --dry-run
Apply the exact approved plan — once confirmed, rerun the exact dry-run command with only --dry-run removed. Keep the same scoped --checks and any --required-check options from the preview:
bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches,security
# If the approved dry-run included required checks:
bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches --required-check "test"
Verify — run audit again to confirm all checks pass.
Check Categories
| Category |
Flag |
What it covers |
repo |
--checks repo |
Auto-delete branches, suggest PR updates, wiki/projects |
branches |
--checks branches |
Branch protection: require PRs, reviews, code owners, checks |
security |
--checks security |
Dependabot, secret scanning, push protection |
merge |
--checks merge |
Merge strategy enforcement (rebase by default) |
actions |
--checks actions |
Actions permissions, workflow token, PR approval restrictions |
access |
--checks access |
CODEOWNERS, deploy keys, outside collaborators (report only) |
Audits run all categories by default. Fixes require an explicit --checks value; use --checks all only when the user has approved changing every category.
Key Options
--merge-strategy rebase|squash|any — which merge method to enforce (default: rebase)
--min-reviewers N — minimum required PR reviewers, 1-6 (default: 1)
--branch BRANCH — branch to protect (default: repo's default branch)
--required-check NAME — required status check context to add for branch protection; repeat for multiple checks. Existing required contexts and app-backed checks are preserved.
--format json|text — output format (default: json)
Interpreting Results
Audit statuses:
pass — meets the hardened policy
fail — does not meet policy; fixable by the script
warn — informational; needs human review (e.g. deploy keys, wiki)
skip — not applicable or insufficient permissions (e.g. GHAS features on private repos)
Severity levels: critical > high > medium > low
For detailed documentation of each check, see references/checks.md.
Multi-Repo Hardening
To audit all repos in an org:
gh repo list ORGNAME --limit 1000 --json nameWithOwner -q '.[].nameWithOwner' | \
while read -r repo; do bash "$HARDEN_SCRIPT" audit --repo "$repo"; done
Limitations
- GHAS features: Secret scanning push protection requires GitHub Advanced Security on private repos. The script skips these gracefully.
- Org-level overrides: Some settings (Actions policies, required workflows) can be locked at the org level and cannot be changed per-repo.
- CODEOWNERS content: The script checks for the file's existence but does not validate its contents.
- Access checks: Deploy keys and outside collaborators are reported but not modified — they require human judgement.
1---2name: repo-hardening3description: Audit and harden GitHub repository security settings using the gh CLI. Use when the user wants to review or improve repository security posture, enforce branch protection, enable secret scanning, configure merge policies, lock down GitHub Actions permissions, or apply security best practices. Triggers on requests to "harden", "secure", "lock down", or "audit" a GitHub repository, even if they just say "make this repo more secure".4---56# Repo Hardening78Audit and fix GitHub repository security settings using the bundled `scripts/harden.sh`.910## Prerequisites1112Before running the script, ensure:131. `gh` CLI is installed and authenticated (`gh auth login`)142. `jq` is installed153. The user has sufficient access to the target repository:16 - `audit` can run with read access, with inaccessible endpoints reported as `skip`17 - `fix` requires **admin access**1819The script checks prerequisites and exits with a clear error if required tools, authentication, or fix permissions are missing.2021## Workflow2223Always follow this sequence:24251. **Resolve the script path** — run the bundled script via the path to this skill directory, not the current project directory:26 ```bash27 SKILL_DIR="/path/to/repo-hardening" # directory containing this SKILL.md28 HARDEN_SCRIPT="$SKILL_DIR/scripts/harden.sh"29 ```30312. **Audit first** — run the audit to see current state:32 ```bash33 bash "$HARDEN_SCRIPT" audit --repo OWNER/REPO34 ```35363. **Present findings** — summarise the audit results to the user, highlighting `fail` and `warn` items grouped by severity (critical > high > medium > low).37384. **Dry-run before fixing** — ask the user which categories to fix. Use explicit `--checks` to scope fixes to the confirmed categories, then run `--dry-run` before any mutation:39 ```bash40 bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches,security --dry-run41 ```4243 If branch protection has no existing required status checks, pass each CI context explicitly:44 ```bash45 bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches --required-check "test" --dry-run46 ```47485. **Apply the exact approved plan** — once confirmed, rerun the exact dry-run command with only `--dry-run` removed. Keep the same scoped `--checks` and any `--required-check` options from the preview:49 ```bash50 bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches,security5152 # If the approved dry-run included required checks:53 bash "$HARDEN_SCRIPT" fix --repo OWNER/REPO --checks branches --required-check "test"54 ```55566. **Verify** — run audit again to confirm all checks pass.5758## Check Categories5960| Category | Flag | What it covers |61|------------|--------------------|-----------------------------------------------------------------|62| `repo` | `--checks repo` | Auto-delete branches, suggest PR updates, wiki/projects |63| `branches` | `--checks branches`| Branch protection: require PRs, reviews, code owners, checks |64| `security` | `--checks security`| Dependabot, secret scanning, push protection |65| `merge` | `--checks merge` | Merge strategy enforcement (rebase by default) |66| `actions` | `--checks actions` | Actions permissions, workflow token, PR approval restrictions |67| `access` | `--checks access` | CODEOWNERS, deploy keys, outside collaborators (report only) |6869Audits run all categories by default. Fixes require an explicit `--checks` value; use `--checks all` only when the user has approved changing every category.7071## Key Options7273- `--merge-strategy rebase|squash|any` — which merge method to enforce (default: rebase)74- `--min-reviewers N` — minimum required PR reviewers, 1-6 (default: 1)75- `--branch BRANCH` — branch to protect (default: repo's default branch)76- `--required-check NAME` — required status check context to add for branch protection; repeat for multiple checks. Existing required contexts and app-backed checks are preserved.77- `--format json|text` — output format (default: json)7879## Interpreting Results8081**Audit statuses:**82- `pass` — meets the hardened policy83- `fail` — does not meet policy; fixable by the script84- `warn` — informational; needs human review (e.g. deploy keys, wiki)85- `skip` — not applicable or insufficient permissions (e.g. GHAS features on private repos)8687**Severity levels:** `critical` > `high` > `medium` > `low`8889For detailed documentation of each check, see [references/checks.md](references/checks.md).9091## Multi-Repo Hardening9293To audit all repos in an org:94```bash95gh repo list ORGNAME --limit 1000 --json nameWithOwner -q '.[].nameWithOwner' | \96 while read -r repo; do bash "$HARDEN_SCRIPT" audit --repo "$repo"; done97```9899## Limitations100101- **GHAS features**: Secret scanning push protection requires GitHub Advanced Security on private repos. The script skips these gracefully.102- **Org-level overrides**: Some settings (Actions policies, required workflows) can be locked at the org level and cannot be changed per-repo.103- **CODEOWNERS content**: The script checks for the file's existence but does not validate its contents.104- **Access checks**: Deploy keys and outside collaborators are reported but not modified — they require human judgement.