---
name: generate-security-report
description: Run all applicable gemma-deployment-security audit skills against a repo and produce a unified Markdown security report. Use when auditing a client deployment end-to-end, preparing a security review, or generating a deliverable for a client.
argument-hint: "[path-to-repo-root]"
disable-model-invocation: true
---

# Generate Security Report

Orchestrate all applicable audit skills against a deployment repo and write a unified security report to `security-audit-report-YYYY-MM-DD.md` in the current working directory.

The report template is at `${CLAUDE_SKILL_DIR}/assets/report-template.md`. Read it before producing output.

## Arguments

`$ARGUMENTS` — optional path to the repo root to audit. Defaults to the current working directory.

```
/generate-security-report /path/to/client-airflow-repo
/generate-security-report                               # audits cwd
```

## Step 1 — Resolve paths

- **Audit target** (`$AUDIT_ROOT`): use `$ARGUMENTS` if provided, otherwise current working directory. Verify the path exists.
- **Report output**: current working directory (where the skill was invoked from), not the audited repo. The filename is `security-audit-report-YYYY-MM-DD.md` using today's date.
- **Template**: read `${CLAUDE_SKILL_DIR}/assets/report-template.md` now.

Announce the audit target and output path before proceeding.

## Step 2 — Auto-detect which skills to run

Scan `$AUDIT_ROOT` for the following indicators. Record each skill as "will run" or "skipped — reason":

| 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` |

For `audit-server-config`: if no SSH host is provided in `$ARGUMENTS`, note it as "guided checklist mode — no SSH target provided" and run the guided checklist interactively after file-based audits are complete.

Print the detection results as a table before running any audits:

```
## Audit Scope — Detection Results

| Skill | Status | Trigger |
|---|---|---|
| audit-docker-compose | Will run | docker-compose.yml found at repo root |
| audit-dockerfile | Will run | Dockerfile found at repo root |
| audit-cicd-workflows | Skipped | No .github/workflows/ directory |
| audit-infrastructure-as-code | Skipped | No .tf files or ansible/ directory |
| audit-airflow-config | Will run | Dockerfile references apache/airflow |
| audit-pre-commit | Will run | .pre-commit-config.yaml found at repo root |
| audit-server-config | Guided checklist | No SSH target — manual verification |
```

## Step 3 — Run each applicable skill

Run each skill that was marked "will run" in sequence. For each skill:

1. State which skill is running: `## Running: audit-<name>`
2. Follow the skill's SKILL.md instructions using `$AUDIT_ROOT` as the repo root path.
3. Collect all findings (severity, ID, title, location, issue, risk, remediation).
4. Collect all passed checks.

Assign globally unique finding IDs across all skills using the domain prefix:
- `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-pre-commit` → `PC-N`
- `audit-server-config` → `SRV-N`

If a skill is skipped, record its skipped status with a brief reason for the Audit Scope table in the report.

## Step 4 — Run guided server checklist (if no SSH target)

If `audit-server-config` is in guided checklist mode, present the checklist from that skill's `references/guided-checklist.md` as a series of yes/no questions. Record responses and convert them to findings or passed checks using the same format.

If the user prefers to skip the server checklist for now, note it as "Server config audit deferred — run audit-server-config separately with SSH access or guided mode."

## Step 5 — Compile all findings

Aggregate findings from all skills into four severity buckets:
- **Critical**: any finding that could lead to immediate compromise (exposed secrets, default credentials, unauthenticated access, public ports)
- **Important**: findings that materially increase attack surface or reduce containment
- **Recommended**: hardening improvements that reduce risk but are not acute
- **Note**: observations without a clear security impact (informational)

Count findings per severity for the executive summary table.

Write a 2–3 sentence `<overall_assessment>` based on the Critical count:
- 0 Critical: "No critical issues found. The deployment demonstrates good baseline security hygiene. Address the Important findings before the next production change."
- 1–2 Critical: "The deployment has N critical issue(s) that require immediate attention before the next release. ..."
- 3+ Critical: "The deployment has N critical issues indicating systemic security gaps. Immediate remediation is strongly recommended."

## Step 6 — Fill in the report template

Read `${CLAUDE_SKILL_DIR}/assets/report-template.md`. Replace each `<placeholder>` token as follows:

| Placeholder | Value |
|---|---|
| `<repo_name>` | Basename of `$AUDIT_ROOT` |
| `<date>` | Today's date (YYYY-MM-DD) |
| `<auditor>` | "gemma-deployment-security plugin (Claude Code)" |
| `<critical_count>` | Count of Critical findings |
| `<important_count>` | Count of Important findings |
| `<recommended_count>` | Count of Recommended findings |
| `<note_count>` | Count of Notes |
| `<overall_assessment>` | 2–3 sentence assessment from Step 5 |
| `<critical_findings_or_"None found.">` | Full Critical findings block, or "None found." |
| `<important_findings>` | Full Important findings block, or "None found." |
| `<recommended_findings>` | Full Recommended findings block, or "None found." |
| `<notes>` | Notes block, or "None." |
| `<passed_check_N>` | Each passed check as a bullet: "`[Domain] Check name — brief note`" |
| Audit Scope table rows | Actual status and trigger/reason for each skill |

Each finding block uses this structure (consistent with the template):

```markdown
### [ID] Finding Title
- **Domain**: Docker Compose / Dockerfile / CI/CD / Infrastructure / Airflow / Pre-Commit / Server
- **Location**: `filename:line` or `filename — environment block`
- **Issue**: One-sentence description of what was found.
- **Risk**: What an attacker could do if this is exploited.
- **Remediation**:
  ```
  # Before (insecure)
  <bad pattern>

  # After (secure)
  <good pattern>
  ```
```

**Critical rule**: Never include actual secret values in any part of the report — only patterns, placeholder names, and whether a value is hardcoded vs referenced from a secret manager.

## Step 7 — Write the report

Write the completed report to `security-audit-report-YYYY-MM-DD.md` in the **invoking working directory** (not `$AUDIT_ROOT`, unless they are the same).

After writing, print:

```
Report written to: /absolute/path/to/security-audit-report-YYYY-MM-DD.md

Summary:
- Critical: N  ← fix before next deploy
- Important: N
- Recommended: N
- Checks passed: N

Top priority findings:
1. [ID] <title> — <one-liner>
2. [ID] <title> — <one-liner>
3. [ID] <title> — <one-liner>
```

List up to 3 top-priority findings (all Criticals, then Importants, up to 3 total).

## Rules

- Never display actual secret values — only locations, patterns, and whether values are hardcoded.
- The "Checks Passed" section is as important as the findings — it shows what is correctly configured and should not be omitted.
- The Audit Scope table must list every skill with its status (ran / skipped / guided) and a brief reason. This documents what was and was not reviewed.
- If a file cannot be read, note it as "not found — skipped" and continue. Do not abort the entire audit.
- Do not auto-fix anything. This is a read-only audit.
- The report date in the filename comes from today's actual date, so multiple audits of the same repo do not overwrite each other.
