Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Plugins](https://img.shields.io/badge/plugins-4-purple)](plugins/)
[![Skills](https://img.shields.io/badge/skills-31-green)](plugins/)
[![Agents](https://img.shields.io/badge/agents-7-orange)](plugins/)
[![Skills](https://img.shields.io/badge/skills-30-green)](plugins/)
[![Agents](https://img.shields.io/badge/agents-6-orange)](plugins/)
[![.NET 10](https://img.shields.io/badge/.NET-10-512BD4)](https://dotnet.microsoft.com/)
[![React 19](https://img.shields.io/badge/React-19-61DAFB)](https://react.dev/)
[![Terraform](https://img.shields.io/badge/Terraform-IaC-7B42BC)](https://www.terraform.io/)

> AI-powered full-stack cloud engineer for Claude Code. 31 skills, 7 agents, 14 rules across 4 plugins.
> AI-powered full-stack cloud engineer for Claude Code. 30 skills, 6 agents, 14 rules across 4 plugins.

```
/plugin marketplace add makigjuro/cloudstack-ai-plugins
Expand Down
4 changes: 2 additions & 2 deletions plugins/cloud-infra/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "cloud-infra",
"description": "Terraform + Helm infrastructure scaffolding, linting, and review — module scaffolding, chart templates, validation pipelines, and infrastructure-specific code review.",
"description": "Terraform + Helm infrastructure scaffolding, linting, and review — module scaffolding, chart templates, validation pipelines, security scanning (trivy), and infrastructure-specific code review.",
"version": "0.2.0",
"author": {
"name": "Marjan Gjuroski"
},
"license": "MIT",
"homepage": "https://github.com/makigjuro/cloudstack-ai-plugins#cloud-infrastructure",
"repository": "https://github.com/makigjuro/cloudstack-ai-plugins",
"keywords": ["terraform", "helm", "azure", "kubernetes", "aks", "infrastructure-as-code", "terragrunt"]
"keywords": ["terraform", "helm", "azure", "kubernetes", "aks", "infrastructure-as-code", "terragrunt", "trivy", "security-scanning"]
}
5 changes: 3 additions & 2 deletions plugins/cloud-infra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ A Claude Code plugin for cloud infrastructure management — Terraform modules,
|-------|-------------|
| `/add-terraform-module` | Scaffold a new Terraform module with variables, main, outputs, and optional IaC wrapper wiring |
| `/add-helm-chart` | Scaffold a new Helm chart with standard Kubernetes templates and values |
| `/infra-lint` | Lint Terraform and Helm charts only — fast, skips application/frontend checks |
| `/infra-lint` | Lint Terraform and Helm charts only — fast, skips application/frontend checks. Runs `/trivy-scan` as its final step |
| `/trivy-scan` | Scan Terraform and Helm charts with [trivy](https://trivy.dev) for security misconfigurations (public access defaults, weak TLS, over-broad IAM). Honours `.trivyignore` with justifying comments |
| `/infra-apply` | Run `terraform plan` for review and optionally apply infrastructure changes |
| `/infra-plan` | Plan infrastructure changes with dependency analysis and risk assessment |
| `/complete-infra` | Full infrastructure completion workflow — lint, validate, review agent, and PR creation |
| `/complete-infra` | Full infrastructure completion workflow — parallel lint + security scan, review agent, and PR creation |

### Rules

Expand Down
12 changes: 12 additions & 0 deletions plugins/cloud-infra/agents/infra-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Ignore all other changes — the general `reviewer` agent handles application co
1. Get the diff against the base branch for infrastructure files
2. Get changed file list for infrastructure directories
3. Review each changed file against the checklists below
4. If a `.trivyignore` is present at `{TF_PARENT}/.trivyignore`, read it and correlate its suppressions with the current diff (see **Scanner Correlation** below)

## Terraform Checklist

Expand Down Expand Up @@ -82,6 +83,17 @@ Ignore all other changes — the general `reviewer` agent handles application co
- `runAsNonRoot: true` where possible
- No secrets in plain `values.yaml` — use sealed secrets or external secrets

## Scanner Correlation (trivy)

The `/complete-infra` and `/infra-lint` skills run `/trivy-scan` as a separate gate, so your job here is NOT to re-run trivy — it's to sanity-check the human decisions captured in the ignore file.

If `{TF_PARENT}/.trivyignore` exists, read it and confirm:

- **Every suppression has a justifying comment.** An uncommented rule ID is a red flag — either the justification was never written, or the ignore was added reflexively to silence CI. Flag these as warnings.
- **The justification is consistent with the current diff.** If a comment says "deferred until VNet integration" but the current diff *adds* VNet integration, the suppression is now obsolete — flag it.
- **The rule is still relevant.** Some trivy rules target deprecated resource types (e.g. `AZU-0026` was written for Azure PostgreSQL Single Server; it misfires on Flexible Server). Confirm the justification actually matches the current resource usage.
- **Don't re-raise suppressed findings as blockers** — the team has already made a conscious decision on them.

## CI/CD Checklist

### Secrets
Expand Down
16 changes: 15 additions & 1 deletion plugins/cloud-infra/skills/complete-infra/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ These scripts read `TF_PATH` and `CHARTS_PATH` from environment variables. Expor
export TF_PATH="..." CHARTS_PATH="..."
```

The security scan (Track D below) reuses the script from the `trivy-scan` skill rather than duplicating it:
```bash
bash {plugin-skills-path}/trivy-scan/scripts/scan-trivy.sh
```

## Process

### Phase 0: Pre-flight
Expand Down Expand Up @@ -85,7 +90,15 @@ export CHARTS_PATH="{CHARTS_PATH}"
bash {plugin-skills-path}/complete-infra/scripts/lint-helm.sh
```

If any lint track fails, STOP and report.
**Track D: Security scan (trivy)**
```bash
export TF_PARENT="{TF_PARENT}" CHARTS_PATH="{CHARTS_PATH}"
bash {plugin-skills-path}/trivy-scan/scripts/scan-trivy.sh
```

Honours `.trivyignore` at `{TF_PARENT}/.trivyignore`. Every suppression must carry a justifying comment — see the `trivy-scan` skill for conventions.

If any lint or scan track fails, STOP and report. Treat `trivy` missing as a FAIL and print the install hint so the user can remediate.

### Phase 2: Infrastructure Review (Parallel Agents)

Expand Down Expand Up @@ -119,6 +132,7 @@ Run `/create-pr {issue}`.
- Terraform Format: PASS
- Terraform Validate: PASS
- Helm Lint: PASS / SKIP (no chart changes)
- Security Scan (trivy): PASS / WARN (findings in .trivyignore only) / FAIL
- Infra Review: PASS

PR is ready for human review.
Expand Down
13 changes: 13 additions & 0 deletions plugins/cloud-infra/skills/infra-lint/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ done

If `{CHARTS_PATH}/` doesn't exist, skip Helm linting and note it.

## Security Scan

After lint passes, invoke the `trivy-scan` skill as the final verification step. This catches security misconfigurations that `terraform validate` and `helm lint` don't see (public access defaults, weak TLS, over-broad IAM, missing encryption).

```
Skill(skill="cloud-infra:trivy-scan")
```

Findings suppressed by a committed `.trivyignore` (with justifying comments) don't block — only unsuppressed CRITICAL/HIGH/MEDIUM fail the gate.

If trivy isn't installed, the skill prints the install command and exits non-zero. Treat that as a FAIL for this skill's output but print the install hint so the user can remediate.

## Output

Report pass/fail per category:
Expand All @@ -75,4 +87,5 @@ Report pass/fail per category:
- Terragrunt Validate: PASS/FAIL (or SKIPPED if IAC_WRAPPER != terragrunt)
- Helm Lint: PASS/FAIL (or SKIPPED)
- Helm Template: PASS/FAIL (or SKIPPED)
- Security Scan (trivy): PASS/FAIL (or SKIPPED if trivy missing)
```
148 changes: 148 additions & 0 deletions plugins/cloud-infra/skills/trivy-scan/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
name: trivy-scan
description: Scan Terraform and Helm charts for security misconfigurations using trivy. Use for a fast IaC security check — catches issues that `/infra-lint` doesn't (secrets, public-access defaults, missing encryption, weak TLS, over-broad IAM). Invoked automatically by `/infra-lint` and `/complete-infra`.
allowed-tools: Bash, Read
user-invocable: true
---

# Trivy Security Scan

Run Aqua Security's trivy against the infrastructure tree to catch misconfigurations that `terraform validate` and `helm lint` miss — things like publicly exposed storage, missing encryption, weak TLS, over-broad IAM role assignments, and container image vulnerabilities.

## When to Use

- **Directly (`/trivy-scan`)** — manual scan, e.g. while iterating on a module or before a PR.
- **Indirectly** — invoked from `/infra-lint` (fast check) and `/complete-infra` (pre-PR verification gate).

## Arguments

- `--strict` — Fail on any finding, including `LOW`. Default: fail on `CRITICAL`, `HIGH`, `MEDIUM`; `LOW` is advisory.
- `--warn-only` — Never exit non-zero; just report. Useful for CI `continue-on-error` style gating.
- `--severity HIGH,CRITICAL` — Comma-separated list to override the default severity filter.

## Configuration

Read `cloudstack.json` from the project root at start of execution. Extract:
- `TF_PATH` = `infrastructure.terraformPath` (default: `infra/terraform/modules`)
- `CHARTS_PATH` = `infrastructure.chartsPath` (default: `deploy/charts`)

Derive `TF_PARENT` as the parent directory of `TF_PATH` (e.g., `infra/terraform/modules` → `infra/terraform`). If `cloudstack.json` is missing, auto-detect by scanning the project.

## Prerequisites

`trivy` must be installed locally. The skill does NOT auto-install — be explicit about system changes.

```bash
# macOS
brew install trivy

# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
```

If `trivy` is missing, the skill prints the install command and exits non-zero (unless `--warn-only`).

## Suppressing findings — `.trivyignore`

Project-local exemptions go in `deploy/terraform/.trivyignore` (or the parent of `TF_PATH`). One rule ID per line, with a comment explaining **why**:

```
# Deferred until VNet integration (see deploy/terraform/README.md "Known limitations")
AZU-0013
AZU-0022

# Trivy check written for deprecated Single Server; we run Flexible Server
# and set TLS via `require_secure_transport` + `ssl_min_protocol_version`
AZU-0026
```

Every ignore entry MUST carry a justification comment. The comment is what a future reviewer uses to decide whether the suppression is still valid.

## Scripts

| Script | Purpose |
|--------|---------|
| `scripts/scan-trivy.sh` | Runs trivy against `TF_PARENT` and `CHARTS_PATH`, honouring `.trivyignore` |

The script reads `TF_PARENT` and `CHARTS_PATH` from environment variables. Export them before calling:

```bash
export TF_PARENT="..." CHARTS_PATH="..."
bash {plugin-skills-path}/trivy-scan/scripts/scan-trivy.sh
```

## Process

### Step 1: Pre-flight

Verify `trivy` is available:

```bash
if ! command -v trivy >/dev/null 2>&1; then
echo "trivy is not installed. Install it and re-run:"
echo " brew install trivy # macOS"
echo " curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin # Linux"
exit 1
fi
```

### Step 2: Run the scan

```bash
export TF_PARENT="{TF_PARENT}" CHARTS_PATH="{CHARTS_PATH}"
bash {plugin-skills-path}/trivy-scan/scripts/scan-trivy.sh
```

### Step 3: Report

Group findings by severity. For each finding, include:
- Rule ID (e.g. `AZU-0013`)
- Severity
- Title
- File:line reference
- Remediation link (trivy provides this)

If findings exist that are NOT in `.trivyignore`, STOP with FAIL. If all remaining findings are suppressed by `.trivyignore`, PASS with a summary of the suppressed count.

## Output

```
## Trivy Scan: {branch-name}

**Scanned:** {TF_PARENT}, {CHARTS_PATH}

### Findings (excluding .trivyignore suppressions)

| Severity | Rule | Title | File |
|----------|------|-------|------|
| CRITICAL | AZU-0041 | Storage account uses outdated TLS version | modules/storage/main.tf |

### Suppressed (.trivyignore)

| Rule | Justification |
|------|---------------|
| AZU-0013 | Deferred until VNet integration |

### Summary

| Severity | Count |
|----------|-------|
| CRITICAL | 1 |
| HIGH | 0 |
| MEDIUM | 0 |
| LOW | 0 (not shown; pass --strict to include) |

**Overall: PASS / FAIL**
```

## When NOT to Use

- **Runtime container scanning** — `/trivy-scan` only does IaC (`trivy config`). For image scanning (`trivy image`) use a separate CI step.
- **Policy-as-code beyond trivy's built-in rules** — for custom OPA/Rego checks, use a dedicated tool.

## Guidelines

- Never commit a `.trivyignore` entry without a justification comment.
- Periodically review `.trivyignore` — deferred items should either be resolved or have an issue tracking the work.
- Treat `CRITICAL`/`HIGH` findings as PR blockers; `MEDIUM` as must-fix-before-merge; `LOW` as advisory.
- Trivy rules occasionally target deprecated resource types (e.g. AZU-0026 is Single-Server only). Verify before suppressing — and document the reason.
110 changes: 110 additions & 0 deletions plugins/cloud-infra/skills/trivy-scan/scripts/scan-trivy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Scan Terraform + Helm charts for security misconfigurations using trivy.
#
# Reads:
# TF_PARENT — Terraform tree root (default: infra/terraform)
# CHARTS_PATH — Helm charts root (default: deploy/charts)
# TRIVY_SEVERITY — comma-list of severities to fail on
# (default: CRITICAL,HIGH,MEDIUM)
# TRIVY_STRICT — "1" to include LOW in the fail set
# TRIVY_WARN_ONLY — "1" to never exit non-zero
# TRIVY_IGNOREFILE — path to .trivyignore (default: {TF_PARENT}/.trivyignore
# if present, else {CHARTS_PATH}/../.trivyignore)
#
# Usage:
# TF_PARENT=infra/terraform CHARTS_PATH=deploy/charts bash scan-trivy.sh
#
# Exit codes:
# 0 clean (or --warn-only) — PR can proceed
# 1 findings at failing severity — PR blocked
# 2 trivy not installed / invocation error

set -uo pipefail

TF_PARENT="${TF_PARENT:-infra/terraform}"
CHARTS_PATH="${CHARTS_PATH:-deploy/charts}"
TRIVY_SEVERITY="${TRIVY_SEVERITY:-CRITICAL,HIGH,MEDIUM}"
TRIVY_STRICT="${TRIVY_STRICT:-0}"
TRIVY_WARN_ONLY="${TRIVY_WARN_ONLY:-0}"

if [ "$TRIVY_STRICT" = "1" ]; then
TRIVY_SEVERITY="CRITICAL,HIGH,MEDIUM,LOW"
fi

# --- preflight ---
if ! command -v trivy >/dev/null 2>&1; then
cat >&2 <<EOF
ERROR: trivy is not installed.

Install it and re-run:
brew install trivy # macOS
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin # Linux
EOF
exit 2
fi

# --- resolve ignorefile ---
pick_ignorefile() {
if [ -n "${TRIVY_IGNOREFILE:-}" ] && [ -f "$TRIVY_IGNOREFILE" ]; then
echo "$TRIVY_IGNOREFILE"
return
fi
for candidate in \
"$TF_PARENT/.trivyignore" \
"$(dirname "$CHARTS_PATH")/.trivyignore" \
".trivyignore"; do
if [ -f "$candidate" ]; then
echo "$candidate"
return
fi
done
echo ""
}

IGNOREFILE="$(pick_ignorefile)"
IGNORE_ARGS=()
if [ -n "$IGNOREFILE" ]; then
echo "Using .trivyignore: $IGNOREFILE"
IGNORE_ARGS+=("--ignorefile" "$IGNOREFILE")
fi

# --- scan targets ---
TARGETS=()
if [ -d "$TF_PARENT" ]; then
TARGETS+=("$TF_PARENT")
fi
if [ -d "$CHARTS_PATH" ]; then
TARGETS+=("$CHARTS_PATH")
fi

if [ "${#TARGETS[@]}" -eq 0 ]; then
echo "No TF_PARENT ($TF_PARENT) or CHARTS_PATH ($CHARTS_PATH) found — nothing to scan."
exit 0
fi

# --- run scan ---
FAILED=0
for target in "${TARGETS[@]}"; do
echo "=== Scanning $target (severity: $TRIVY_SEVERITY) ==="
if ! trivy config "$target" \
--severity "$TRIVY_SEVERITY" \
--exit-code 1 \
--quiet \
--cache-dir /tmp/trivy-cache \
"${IGNORE_ARGS[@]}"; then
FAILED=1
fi
done

if [ "$FAILED" -eq 0 ]; then
echo "Trivy scan: PASS (no findings at severity $TRIVY_SEVERITY)"
exit 0
fi

if [ "$TRIVY_WARN_ONLY" = "1" ]; then
echo "Trivy scan: WARN (findings present, --warn-only set)"
exit 0
fi

echo "Trivy scan: FAIL (findings at severity $TRIVY_SEVERITY)"
exit 1
Loading