# audit-pre-commit Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add a read-only `audit-pre-commit` skill to `gemma-deployment-security` that checks `.pre-commit-config.yaml` for mandatory gitleaks, recommended ruff, and pinned `rev` values — and wire it into `generate-security-report`.

**Architecture:** Two new files (SKILL.md + references/checklist.md) following the reference-checklist architecture established by the plugin constitution. One modification to `generate-security-report` to auto-detect and run the new skill. No code, no tests — validation is running the skill against a known fixture.

**Tech Stack:** Markdown, YAML. No dependencies beyond Claude Code skill runtime.

---

## File map

```
plugins/gemma-deployment-security/
  skills/
    audit-pre-commit/               ← CREATE
      SKILL.md                      ← CREATE
      references/
        checklist.md                ← CREATE
    generate-security-report/
      SKILL.md                      ← MODIFY (3 additions)
```

---

### Task 1: Write the checklist

The checklist is the single source of truth for all checks (constitution Principle II). It must be written first — SKILL.md references it.

**Files:**
- Create: `plugins/gemma-deployment-security/skills/audit-pre-commit/references/checklist.md`

- [ ] **Step 1: Create the references directory and write checklist.md**

Create `plugins/gemma-deployment-security/skills/audit-pre-commit/references/checklist.md` with this exact content:

```markdown
# Pre-Commit Hooks Security Checklist

Security checks for pre-commit hook configuration. Ensures mandatory
secret-scanning and recommended linting hooks are present and version-pinned.

---

## Check: .pre-commit-config.yaml present

- **Priority**: Critical
- **What to look for**: Absence of `.pre-commit-config.yaml` at the repository root.
- **Pass condition**: `.pre-commit-config.yaml` exists at the repo root.
- **Fail example**:
  ```
  # No .pre-commit-config.yaml file at repo root
  ```
- **Remediation**: Create `.pre-commit-config.yaml` at the repo root. Install
  pre-commit (`uv add --dev pre-commit`) and activate hooks (`pre-commit install`).
  ```yaml
  # .pre-commit-config.yaml (minimal secure baseline)
  repos:
    - repo: https://github.com/gitleaks/gitleaks
      rev: v8.21.2
      hooks:
        - id: gitleaks

    - repo: https://github.com/astral-sh/ruff-pre-commit
      rev: v0.15.1
      hooks:
        - id: ruff
          args: [--fix]
        - id: ruff-format
  ```
- **Source**: Gemma internal standard (2026-04-16)

---

## Check: gitleaks hook configured

- **Priority**: Critical
- **What to look for**: No hook with `id: gitleaks` in any `repos` entry of
  `.pre-commit-config.yaml`.
- **Pass condition**: At least one hook entry with `id: gitleaks` is present and
  its parent repo points to `github.com/gitleaks/gitleaks`.
- **Fail example**:
  ```yaml
  repos:
    - repo: https://github.com/astral-sh/ruff-pre-commit
      rev: v0.15.1
      hooks:
        - id: ruff
  # gitleaks hook is absent
  ```
- **Remediation**: Add gitleaks to `.pre-commit-config.yaml`.
  ```yaml
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.21.2
    hooks:
      - id: gitleaks
  ```
- **Source**: Gemma internal standard (2026-04-16)

---

## Check: ruff hook configured

- **Priority**: Recommended
- **What to look for**: No hook with `id: ruff` or `id: ruff-format` in any
  `repos` entry of `.pre-commit-config.yaml`.
- **Pass condition**: At least one hook entry with `id: ruff` or `id: ruff-format`
  is present.
- **Fail example**:
  ```yaml
  repos:
    - repo: https://github.com/gitleaks/gitleaks
      rev: v8.21.2
      hooks:
        - id: gitleaks
  # ruff hook is absent
  ```
- **Remediation**: Add ruff to `.pre-commit-config.yaml`.
  ```yaml
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.15.1
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format
  ```
- **Source**: Gemma internal standard (2026-04-16)

---

## Check: All rev values pinned to specific versions

- **Priority**: Important
- **What to look for**: Any `rev:` field set to a floating reference: `main`,
  `master`, `HEAD`, `latest`, or an empty string.
- **Pass condition**: Every `rev:` field uses a specific version tag (e.g.
  `v8.21.2`) or a full SHA digest. No floating references.
- **Fail example**:
  ```yaml
  repos:
    - repo: https://github.com/gitleaks/gitleaks
      rev: main   # floating — pulls latest silently on next autoupdate
      hooks:
        - id: gitleaks
  ```
- **Remediation**: Replace floating refs with the latest stable tag. Run
  `pre-commit autoupdate` to find current versions, then pin.
  ```yaml
  # Before (insecure — floating ref)
  - repo: https://github.com/gitleaks/gitleaks
    rev: main

  # After (secure — pinned)
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.21.2
  ```
- **Source**: Gemma internal standard (2026-04-16); mirrors SHA-pinning
  rationale from CI/CD security research §07
```

- [ ] **Step 2: Commit**

```bash
git add plugins/gemma-deployment-security/skills/audit-pre-commit/references/checklist.md
git commit -m "feat(gemma-deployment-security): add audit-pre-commit checklist"
```

---

### Task 2: Write SKILL.md

**Files:**
- Create: `plugins/gemma-deployment-security/skills/audit-pre-commit/SKILL.md`

- [ ] **Step 1: Write SKILL.md**

Create `plugins/gemma-deployment-security/skills/audit-pre-commit/SKILL.md` with this exact content:

```markdown
---
name: audit-pre-commit
description: Audit a repository's pre-commit hook configuration for security and code quality compliance. Checks that gitleaks (mandatory) and ruff (recommended) hooks are configured, and that all hook rev values are pinned. Use when auditing a repo for missing or misconfigured pre-commit hooks, or as part of a full security audit via generate-security-report.
disable-model-invocation: true
argument-hint: "[path-to-repo-root]"
---

# Audit Pre-Commit Hooks

Scan `.pre-commit-config.yaml` and apply the checklist at
`${CLAUDE_SKILL_DIR}/references/checklist.md`.

**Argument**: `$ARGUMENTS`

---

## Step 1 — Locate .pre-commit-config.yaml

If `$ARGUMENTS` is provided, use it as the repo root. Otherwise use the current
working directory.

Look for `.pre-commit-config.yaml` at the repo root using the Glob tool:
`<repo-root>/.pre-commit-config.yaml`

If the file is absent, emit this finding and stop:

```
## Pre-Commit Hooks Security Audit
Config file: not found

### 🔴 Critical

**[PC-1 — Config absent]** — repo root
No `.pre-commit-config.yaml` found. The repository has no pre-commit hook
configuration — secret scanning (gitleaks) and linting (ruff) are not enforced
at commit time.
Fix: Create `.pre-commit-config.yaml` at the repo root with at minimum a gitleaks
hook. See the checklist for a minimal secure baseline with both gitleaks and ruff.
```

Then output this summary table and stop:

| Check | Status | Findings |
|---|---|---|
| .pre-commit-config.yaml present | FAIL | Config file absent |
| gitleaks configured | SKIP | No config file |
| ruff configured | SKIP | No config file |
| rev pinning | SKIP | No config file |

---

## Step 2 — Read the config file

Read `.pre-commit-config.yaml` using the Read tool.

Also read `${CLAUDE_SKILL_DIR}/references/checklist.md` in full.

---

## Step 3 — Apply the checklist

Apply each check to the config file contents.

### Check PC-2: gitleaks configured

Scan all `hooks:` blocks across all `repos:` entries. Look for any line
containing `id: gitleaks`.

- **PASS**: at least one `id: gitleaks` entry exists
- **FAIL** (Critical): no `id: gitleaks` found anywhere in the file

### Check PC-3: ruff configured

Scan all `hooks:` blocks. Look for any line containing `id: ruff` or
`id: ruff-format`.

- **PASS**: at least one `id: ruff` or `id: ruff-format` entry exists
- **FAIL** (Recommended): neither appears anywhere in the file

### Check PC-4: rev pinning

Scan all `rev:` lines across all `repos:` entries. A rev is floating if its
value matches any of: `main`, `master`, `HEAD`, `latest`, or is an empty string.

For each floating rev found, record the repo URL and the floating value.

- **PASS**: all `rev:` values are specific version tags or SHA digests
- **FAIL** (Important): one or more `rev:` values are floating — list each
  affected repo URL and its current rev value

---

## Step 4 — Output findings

### Header

```
## Pre-Commit Hooks Security Audit
Config file: <path>/.pre-commit-config.yaml
Repos configured: <N>
Total hooks: <N>
```

### Findings by severity

Group findings under these headings (omit a heading if there are no findings
in that tier):

```
### 🔴 Critical
### 🟠 Important
### 🟡 Recommended
```

Each finding entry:

```
**[PC-N — Check name]** — `.pre-commit-config.yaml`
<One-sentence description of what was found and why it is a risk.>
Fix: <concrete remediation — the key change required, with a short YAML snippet.>
```

### Summary table

| Check | Status | Findings |
|---|---|---|
| .pre-commit-config.yaml present | PASS / FAIL | — |
| gitleaks configured | PASS / FAIL / SKIP | — |
| ruff configured | PASS / FAIL / SKIP | — |
| rev pinning | PASS / FAIL / SKIP | N repos with floating revs |

### Passed checks

List all checks that passed (no findings) as a brief bullet list.

---

## Notes

- This skill is read-only. It does not modify any files.
- If `.pre-commit-config.yaml` is absent, checks PC-2 through PC-4 are skipped.
- Finding IDs use the `PC-N` prefix when aggregated in `generate-security-report`.
- Never include actual secret values in output — this skill does not read `.env`
  files or credentials.
```

- [ ] **Step 2: Commit**

```bash
git add plugins/gemma-deployment-security/skills/audit-pre-commit/SKILL.md
git commit -m "feat(gemma-deployment-security): add audit-pre-commit skill"
```

---

### Task 3: Update generate-security-report

Three targeted additions to `generate-security-report/SKILL.md`. Read the current file before editing.

**Files:**
- Modify: `plugins/gemma-deployment-security/skills/generate-security-report/SKILL.md`

The file currently has (around lines 33–42) this detection table:

```markdown
| Indicator to look for | Skill to run |
|---|---|
| `docker-compose.yml` or `docker-compose.yaml` at repo root or in a subdirectory | `audit-docker-compose` |
| `Dockerfile` or `Dockerfile.*` at any depth | `audit-dockerfile` |
| `.github/workflows/` directory containing `.yml` files | `audit-cicd-workflows` |
| Any `*.tf` file or an `ansible/` or `playbooks/` directory | `audit-infrastructure-as-code` |
| Airflow indicator: `Dockerfile` containing `apache/airflow`, OR compose file referencing `apache/airflow` image, OR `airflow.cfg` present | `audit-airflow-config` |
| Always — offer guided checklist mode | `audit-server-config` |
```

And around lines 68–77 this finding ID table:

```markdown
- `audit-docker-compose` → `DC-N`
- `audit-dockerfile` → `DF-N`
- `audit-cicd-workflows` → `CI-N`
- `audit-infrastructure-as-code` → `IAC-N`
- `audit-airflow-config` → `AIRFLOW-N`
- `audit-server-config` → `SRV-N`
```

- [ ] **Step 1: Add detection row**

In the detection table, add a new row immediately before the `Always — offer guided checklist mode` row:

```
| `.pre-commit-config.yaml` at repo root | `audit-pre-commit` |
```

The table should read:

```markdown
| Indicator to look for | Skill to run |
|---|---|
| `docker-compose.yml` or `docker-compose.yaml` at repo root or in a subdirectory | `audit-docker-compose` |
| `Dockerfile` or `Dockerfile.*` at any depth | `audit-dockerfile` |
| `.github/workflows/` directory containing `.yml` files | `audit-cicd-workflows` |
| Any `*.tf` file or an `ansible/` or `playbooks/` directory | `audit-infrastructure-as-code` |
| Airflow indicator: `Dockerfile` containing `apache/airflow`, OR compose file referencing `apache/airflow` image, OR `airflow.cfg` present | `audit-airflow-config` |
| `.pre-commit-config.yaml` at repo root | `audit-pre-commit` |
| Always — offer guided checklist mode | `audit-server-config` |
```

- [ ] **Step 2: Add finding ID prefix**

In the finding ID prefix list, add after the `audit-server-config` line:

```
- `audit-pre-commit` → `PC-N`
```

The list should read:

```markdown
- `audit-docker-compose` → `DC-N`
- `audit-dockerfile` → `DF-N`
- `audit-cicd-workflows` → `CI-N`
- `audit-infrastructure-as-code` → `IAC-N`
- `audit-airflow-config` → `AIRFLOW-N`
- `audit-server-config` → `SRV-N`
- `audit-pre-commit` → `PC-N`
```

- [ ] **Step 3: Add audit-pre-commit to the example Audit Scope table**

The example table (around lines 48–58) currently ends with:

```markdown
| audit-server-config | Guided checklist | No SSH target — manual verification |
```

Add a row after `audit-airflow-config` and before `audit-server-config`:

```markdown
| audit-pre-commit | Will run | .pre-commit-config.yaml found at repo root |
```

- [ ] **Step 4: Commit**

```bash
git add plugins/gemma-deployment-security/skills/generate-security-report/SKILL.md
git commit -m "feat(gemma-deployment-security): wire audit-pre-commit into generate-security-report"
```

---

### Task 4: Validate

No automated test runner — validate by invoking the skill mentally against two scenarios.

- [ ] **Scenario A — Config absent (airflow3-demo)**

The `security-audit-report-2026-04-15.md` confirms `airflow3-demo` has no `.pre-commit-config.yaml` (audit-pre-commit was not in scope at that time). Expected output when skill is run against that repo:

```
## Pre-Commit Hooks Security Audit
Config file: not found

### 🔴 Critical
**[PC-1 — Config absent]** — repo root
No `.pre-commit-config.yaml` found...

| Check | Status | Findings |
|---|---|---|
| .pre-commit-config.yaml present | FAIL | Config file absent |
| gitleaks configured | SKIP | No config file |
| ruff configured | SKIP | No config file |
| rev pinning | SKIP | No config file |
```

Verify: SKILL.md Step 1 short-circuit logic matches this output.

- [ ] **Scenario B — Config present with floating rev (mental model)**

Given a `.pre-commit-config.yaml` with gitleaks (`rev: main`) and no ruff:

```yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: main
    hooks:
      - id: gitleaks
```

Expected:
- PC-1: PASS (file present)
- PC-2: PASS (gitleaks present)
- PC-3: FAIL Recommended (no ruff)
- PC-4: FAIL Important (`rev: main` on gitleaks repo)

Verify SKILL.md Step 3 logic handles this correctly — both PC-3 and PC-4 fire independently.

- [ ] **Step: Commit plan as complete**

```bash
git add docs/superpowers/plans/2026-04-16-audit-pre-commit.md
git commit -m "docs(gemma-deployment-security): add audit-pre-commit implementation plan"
```
