diff --git a/skills/nix-review/LENSES.md b/skills/nix-review/LENSES.md new file mode 100644 index 0000000..40888a4 --- /dev/null +++ b/skills/nix-review/LENSES.md @@ -0,0 +1,59 @@ +# Nix Review Lenses + +This document describes the recommended format for Nix review lenses stored in `~/.config/lenses/nix/`. + +## Lens File Layout + +Each lens is a Markdown file named after the lens (e.g., `determinism.md`). Keep lenses focused, actionable, and low-noise. + +**Recommended sections:** + +1. **Purpose** + - What the lens checks and why it matters. + +2. **Checks** + - Bullet list of specific patterns or rules. + - Keep checks concrete (e.g., “`import ` in flake-based repos”). + +3. **Severity Guidance** + - Map checks to default severities (HIGH/MED/LOW). + +4. **Examples** + - Brief “bad” and “good” snippets. + +## Finding Format + +Findings should use the standard format: +``` +[TAG] +Issue: +Suggest: +Evidence: +``` + +## Lens Tags + +Use a stable, uppercase tag per lens (e.g., `DETERMINISM`, `SECRETS`, `MODULE-SAFETY`). + +## Suggested Lens List + +Phase 1: +- determinism +- secrets +- closure-hygiene + +Phase 2: +- flake-hygiene +- module-safety +- systemd-hardening + +Phase 3: +- derivation-diff +- closure-impact +- supply-chain + +## Tips + +- Prefer explicit, actionable checks over style opinions. +- Avoid duplicate checks across lenses; rely on root-cause grouping instead. +- Keep severity consistent to reduce alert fatigue. diff --git a/skills/nix-review/README.md b/skills/nix-review/README.md new file mode 100644 index 0000000..c33db0a --- /dev/null +++ b/skills/nix-review/README.md @@ -0,0 +1,120 @@ +# Nix Review Skill + +Nix-focused infrastructure review for flakes, NixOS/Home Manager modules, overlays, and packaging. Linter-first (statix/deadnix/format) plus optional deep lenses for derivation diffs, closure impact, and supply-chain scanning. + +## Quick Start + +**Claude Code / OpenCode:** +The agent will invoke this skill when you ask to review Nix configs. + +**Manual invocation:** +``` +/nix-review +/nix-review path/to/module.nix +/nix-review --eval +/nix-review --quick +/nix-review --deep +``` + +## What It Does + +- Runs Nix linting and unused-binding checks (statix/deadnix) +- Runs formatter check only when the repo declares one (treefmt, flake formatter, or `nix fmt`) +- Runs `nix flake check` when `flake.nix`/`flake.lock` changed or with `--eval` (may build; skip with `--quick`) +- Runs secrets pre-check before any eval; skips eval if a potential secret is detected +- If NixOS modules changed, prompts for `nixosConfigurations` to evaluate (or uses `NIX_REVIEW_TARGETS`) +- Applies Nix-specific lenses (determinism, secrets, module safety, strict flake hygiene) +- Optionally runs deep analysis (nix-diff/nvd, closure impact, sbomnix+grype) +- Summarizes findings (grouped by root cause) and asks which to file as issues (default: file all non-lint) + +## Prerequisites + +- `nix` CLI +- `statix` +- `deadnix` +- Nix formatter installed if the repo declares one +- Optional deep tools: `nix-diff`, `nvd`, `sbomnix`, `grype`, `nix-tree` + +## Example Usage + +### Scenario: Default review with eval +**User request:** +``` +/nix-review +``` +**Agent actions:** +1. Collects changed Nix files +2. Runs statix/deadnix/formatter checks +3. Runs `nix flake check` if `flake.nix`/`flake.lock` changed or `--eval` is set +4. If NixOS modules changed, prompts for `nixosConfigurations` (or uses `NIX_REVIEW_TARGETS`) +5. Applies Phase 1–2 lenses +6. Summarizes findings and asks what to file + +### Scenario: Quick lint-only review +**User request:** +``` +/nix-review --quick +``` +**Agent actions:** +1. Collects changed Nix files +2. Runs statix/deadnix/formatter checks +3. Skips `nix flake check` +4. Applies Phase 1–2 lenses +5. Summarizes findings and asks what to file + +### Scenario: Deep supply-chain + impact analysis +**User request:** +``` +/nix-review --deep +``` +**Agent actions:** +1. Runs default lint checks +2. Adds derivation diff + closure impact +3. Generates SBOM and scans with grype +4. Summarizes findings (all severities) and asks what to file + +**Note:** Closure impact runs when `flake.lock` changes; it will prompt before running unless `--deep` is set. + +## Configuration + +No configuration required by default. Lenses are loaded from: +``` +~/.config/lenses/nix/ +``` + +Starter lens templates are available in: +``` +skills/nix-review/lenses/ +``` + +### Optional repo config: `.nix-review.toml` +```toml +formatter = "alejandra" # or "nixfmt-rfc-style" +eval = "auto" # auto|always|never +closure_impact = "auto" # auto|always|never +issue_filing = "non-lint" # all|non-lint|high-only +nixos_targets = ["nixosConfigurations.laptop", "nixosConfigurations.server"] +``` + +Notes: +- `eval = auto` runs `nix flake check` when `flake.nix` or `flake.lock` changes. +- `closure_impact = auto` runs when `flake.lock` changes (prompts unless `--deep`). +- `nixos_targets` overrides `NIX_REVIEW_TARGETS` and avoids prompts. +- Precedence: CLI flags > `.nix-review.toml` > environment variables. + +Optional: set `NIX_REVIEW_TARGETS` to a comma-separated list of `nixosConfigurations` to evaluate (avoids prompts). + +## Troubleshooting + +### Problem: Missing tool errors +**Cause:** Tool not installed or not in PATH. +**Solution:** The review skips missing tools and reports a warning. Install via nix or system package manager for full coverage. + +### Problem: Deep scan is slow +**Cause:** sbomnix/grype or closure diff can be expensive. +**Solution:** Run without `--deep` or narrow the target path. + +## See Also + +- [ops-review](../ops-review/README.md) +- [code-review](../code-review/README.md) diff --git a/skills/nix-review/SKILL.md b/skills/nix-review/SKILL.md new file mode 100644 index 0000000..0494137 --- /dev/null +++ b/skills/nix-review/SKILL.md @@ -0,0 +1,148 @@ +--- +name: nix-review +description: Nix-focused infrastructure review. Linter-first workflow for flakes, NixOS modules, packages, and Nix CI with eval-aware lenses and actionable fixes. +--- + +# Nix Review Skill + +Run a Nix-specific review across flakes, NixOS/Home Manager modules, overlays, and packaging. Uses a linter-first approach, then applies Nix-centric lenses with optional evaluation checks. Findings are summarized and presented for approval before filing issues. + +## When to Use + +Invoke this skill when the user requests: +- "Review my Nix configs" +- "Check my flake for issues" +- "Audit NixOS modules" +- "Run nix review" +- `/nix-review` + +## Arguments + +- `/nix-review` - Runs Phase 1–2 lenses; runs `nix flake check` if `flake.nix` or `flake.lock` changed +- `/nix-review path/` - Targets a file or directory +- `/nix-review --eval` - Forces `nix flake check` +- `/nix-review --quick` - Skips eval steps (even if `flake.lock` changed) +- `/nix-review --deep` - Includes Phase 3 lenses (derivation diff, closure impact, supply-chain scan) + +## Scope + +**Primary targets** +- `*.nix`, `flake.nix`, `flake.lock` +- NixOS/Home Manager modules +- Nix packaging (pkgs/, overlays) +- Flake check/eval workflows +- Secrets management (`sops-nix`, `agenix`) + +**Default target** +- Git diff of uncommitted changes, unless a file/dir is specified + +## Process + +1. **Target Selection** + - Parse optional target; default to git diff + - Confirm scope if >10 files + +2. **Static Tools (Linter-First)** + - `statix check` (lint) + - `deadnix --fail` (unused bindings) + - Formatter check only when repo config exists (treefmt, `nix fmt`, or flake formatter) + +3. **Secrets Pre-Check** + - Run `secrets` lens before any eval + - If a potential secret is detected, warn and skip eval steps + +4. **Eval Checks (Default)** + - Run `nix flake check` when `flake.nix` or `flake.lock` changed, or when `--eval` is set (may build; use `--quick` to skip) + - Skip with `--quick` + - Optional: `nix flake metadata` / `nix flake show --json` + - Optional: targeted `nix eval` for critical outputs + - When NixOS modules change, evaluate selected `nixosConfigurations` (prompt to choose, or use `NIX_REVIEW_TARGETS`) + +5. **Lens Execution** + - Apply Phase 1–2 lenses by default (skip lens steps if lens directory is missing) + - Apply Phase 3 lenses when `--deep` is set + - Also run closure-impact when `flake.lock` changes (prompt before running unless `--deep`) + - Collect findings in standard format + +6. **Synthesis + Review** + - Deduplicate and rank findings (group by root cause) + - Show summary + top issues + - Ask which findings to file (default recommendation: file all non-lint findings) + +## Available Lenses + +Lenses live in `~/.config/lenses/nix/`. + +### Phase 1: Core Safety (Fast) + +| Lens | Focus | +|------|-------| +| `determinism.md` | Unpinned fetchers, `import `, impure builtins (`getEnv`, `currentTime`) | +| `secrets.md` | Secrets embedded in Nix store or configs; sops/agenix misuse | +| `closure-hygiene.md` | Runtime vs build inputs, obvious bloat patterns | + +### Phase 2: Reliability + +| Lens | Focus | +|------|-------| +| `flake-hygiene.md` | Strict governance: duplicate inputs, missing `follows`, stale lockfiles | +| `module-safety.md` | Risky defaults, missing `mkIf`, missing assertions (pair with targeted eval) | +| `systemd-hardening.md` | Root services, missing hardening knobs | + +### Phase 3: Architecture / Impact + +| Lens | Focus | +|------|-------| +| `derivation-diff.md` | `nix-diff`/`nvd` explain what actually changed | +| `closure-impact.md` | Closure size deltas and dependency attribution (runs on `--deep` or when `flake.lock` changes) | +| `supply-chain.md` | Vulnerability scanning (sbomnix + grype) and input provenance | + +## Static Tools + +- **Lint**: `statix` +- **Unused**: `deadnix` +- **Format**: run only when repo declares formatter (treefmt/flake formatter/`nix fmt`) +- **Optional**: `flake-checker`, `nix-diff`, `nvd`, `sbomnix`, `grype`, `nix-tree`, `nix-du` + +## Output + +1. **Console summary** of findings by severity +2. **Interactive prompt** for issue filing (default: file all non-lint findings; lint findings recommend fix/skip) +3. **Beads issues** (if approved) +4. **Lens provenance** (note custom lenses if applicable) + +## Auto-Fix Policy + +No automatic fixes. Provide suggested commands for safe fixes (formatting, deadnix/statix). + +## Configuration + +Optional repo config file: `.nix-review.toml` (repo root). + +```toml +# Example .nix-review.toml +formatter = "alejandra" # or "nixfmt-rfc-style" +eval = "auto" # auto|always|never +closure_impact = "auto" # auto|always|never +issue_filing = "non-lint" # all|non-lint|high-only +nixos_targets = ["nixosConfigurations.laptop", "nixosConfigurations.server"] +``` + +Notes: +- `eval = auto` runs `nix flake check` when `flake.nix` or `flake.lock` changes. +- `closure_impact = auto` runs when `flake.lock` changes (prompts unless `--deep`). +- `nixos_targets` overrides `NIX_REVIEW_TARGETS` and avoids prompts. +- Precedence: CLI flags > `.nix-review.toml` > environment variables. + +## Lens Documentation + +Lens files live in `~/.config/lenses/nix/`. Starter templates are in `skills/nix-review/lenses/`. See `skills/nix-review/LENSES.md` for the lens format and guidance. + +## Requirements + +- `statix`, `deadnix`, and a Nix formatter installed when the repo declares one +- `nix` CLI available +- Optional: `flake-checker`, `nix-diff`, `nvd`, `sbomnix`, `grype`, `nix-tree` + +Tooling notes: +- Missing tools are skipped with a warning; the review continues with available checks. diff --git a/skills/nix-review/lenses/README.md b/skills/nix-review/lenses/README.md new file mode 100644 index 0000000..2625a13 --- /dev/null +++ b/skills/nix-review/lenses/README.md @@ -0,0 +1,27 @@ +# Nix Review Lenses + +Starter lens templates for the nix-review skill. + +## Available Lenses + +| Lens | Focus | +|------|-------| +| `determinism.md` | Unpinned fetchers, impure builtins, `` imports | +| `secrets.md` | Plaintext secrets and unsafe secret handling | +| `closure-hygiene.md` | Runtime/build input hygiene, obvious bloat | +| `flake-hygiene.md` | Strict flake input governance | +| `module-safety.md` | NixOS/Home Manager module safety | +| `systemd-hardening.md` | Systemd hardening defaults | +| `derivation-diff.md` | Derivation/semantic change summaries | +| `closure-impact.md` | Closure size deltas and attribution | +| `supply-chain.md` | SBOM scan + CVE reporting | + +## Output Convention + +All lenses emit findings in the standard format: +``` +[TAG] +Issue: +Suggest: +Evidence: +``` diff --git a/skills/nix-review/lenses/closure-hygiene.md b/skills/nix-review/lenses/closure-hygiene.md new file mode 100644 index 0000000..516febe --- /dev/null +++ b/skills/nix-review/lenses/closure-hygiene.md @@ -0,0 +1,23 @@ +# Closure Hygiene Lens + +## Purpose +Catch obvious dependency bloat and runtime/build input mistakes. + +## Checks +- Heavy build tools in runtime closures (prefer `nativeBuildInputs` when possible). +- Runtime scripts calling host binaries instead of store paths. +- Large language/runtime toolchains pulled into minimal packages. + +## Severity Guidance +- **MED**: runtime closure includes heavy toolchains. +- **LOW**: minor bloat or unclear tool placement. + +## Examples +**Bad** +```nix +buildInputs = [ pkgs.gcc pkgs.python3 ]; +``` +**Good** +```nix +nativeBuildInputs = [ pkgs.gcc pkgs.python3 ]; +``` diff --git a/skills/nix-review/lenses/closure-impact.md b/skills/nix-review/lenses/closure-impact.md new file mode 100644 index 0000000..3267ba1 --- /dev/null +++ b/skills/nix-review/lenses/closure-impact.md @@ -0,0 +1,22 @@ +# Closure Impact Lens + +## Purpose +Measure closure size deltas and identify bloat sources. + +## Checks +- `nix path-info -S` or `nix store diff-closures` on relevant outputs. +- Identify top contributors to growth. + +## Severity Guidance +- **MED**: >10% closure growth or large absolute increases. +- **LOW**: small deltas with clear justification. + +## Examples +**Bad** +```text +Closure grew by 120MB due to Python runtime +``` +**Good** +```text +Closure grew by 5MB (expected) due to added locale data +``` diff --git a/skills/nix-review/lenses/derivation-diff.md b/skills/nix-review/lenses/derivation-diff.md new file mode 100644 index 0000000..961bc3b --- /dev/null +++ b/skills/nix-review/lenses/derivation-diff.md @@ -0,0 +1,22 @@ +# Derivation Diff Lens + +## Purpose +Explain what actually changed in derivations or outputs. + +## Checks +- Use `nix-diff` or `nvd` to summarize changes. +- Identify rebuild cascades or version bumps. + +## Severity Guidance +- **MED**: unexpected rebuilds or large dependency changes. +- **LOW**: expected version bumps. + +## Examples +**Bad** +```text +Rebuilds 300 derivations without explanation +``` +**Good** +```text +nvd: openssl 3.0.12 -> 3.0.13; rebuilds 12 derivations +``` diff --git a/skills/nix-review/lenses/determinism.md b/skills/nix-review/lenses/determinism.md new file mode 100644 index 0000000..c3dce43 --- /dev/null +++ b/skills/nix-review/lenses/determinism.md @@ -0,0 +1,25 @@ +# Determinism Lens + +## Purpose +Detect sources of impurity and unpinned inputs that break reproducibility. + +## Checks +- `import ` in flake-based repos. +- Unpinned fetchers (`fetchTarball`, `fetchGit`, `builtins.fetchTarball`) without hashes. +- Impure builtins (`builtins.getEnv`, `builtins.currentTime`, `builtins.currentSystem`) in non-dev contexts. +- Flake inputs using floating refs without lockfile updates. + +## Severity Guidance +- **HIGH**: unpinned fetchers or `import ` in production paths. +- **MED**: impure builtins in non-dev modules. +- **LOW**: devShell-only impurity. + +## Examples +**Bad** +```nix +pkgs = import {}; +``` +**Good** +```nix +pkgs = inputs.nixpkgs.legacyPackages.${system}; +``` diff --git a/skills/nix-review/lenses/flake-hygiene.md b/skills/nix-review/lenses/flake-hygiene.md new file mode 100644 index 0000000..9e41e3b --- /dev/null +++ b/skills/nix-review/lenses/flake-hygiene.md @@ -0,0 +1,25 @@ +# Flake Hygiene Lens + +## Purpose +Enforce input governance and prevent dependency graph drift. + +## Checks +- Duplicate `nixpkgs` inputs without `follows`. +- Missing `follows` for shared inputs. +- `flake.lock` out of sync with `flake.nix` changes. + +## Severity Guidance +- **HIGH**: lockfile drift that changes inputs. +- **MED**: duplicate inputs without justification. +- **LOW**: minor governance drift. + +## Examples +**Bad** +```nix +inputs.nixpkgs.url = "github:NixOS/nixpkgs"; +inputs.nixpkgs-unstable.url = "github:NixOS/nixpkgs"; +``` +**Good** +```nix +inputs.nixpkgs-unstable.follows = "nixpkgs"; +``` diff --git a/skills/nix-review/lenses/module-safety.md b/skills/nix-review/lenses/module-safety.md new file mode 100644 index 0000000..e9af3a7 --- /dev/null +++ b/skills/nix-review/lenses/module-safety.md @@ -0,0 +1,24 @@ +# Module Safety Lens + +## Purpose +Ensure NixOS/Home Manager modules are safe, scoped, and guarded. + +## Checks +- Enable flags that should be gated with `mkIf`. +- Missing `assertions` for critical invariants. +- Unscoped defaults that override user config without `mkDefault`. + +## Severity Guidance +- **HIGH**: unsafe defaults that change system security. +- **MED**: missing `mkIf` guards. +- **LOW**: missing assertions or docs. + +## Examples +**Bad** +```nix +config.services.nginx.enable = true; +``` +**Good** +```nix +config = lib.mkIf cfg.enable { services.nginx.enable = true; }; +``` diff --git a/skills/nix-review/lenses/secrets.md b/skills/nix-review/lenses/secrets.md new file mode 100644 index 0000000..16209cf --- /dev/null +++ b/skills/nix-review/lenses/secrets.md @@ -0,0 +1,25 @@ +# Secrets Lens + +## Purpose +Prevent secrets from being embedded in Nix expressions or the Nix store. + +## Checks +- Plaintext secrets in `environment.etc.*.text` or `systemd.services.*.environment`. +- `builtins.readFile` of secret paths that could be copied into the store. +- `sops-nix`/`agenix` misuse (unencrypted files referenced as secrets). +- Hardcoded tokens, passwords, or private keys in Nix files. + +## Severity Guidance +- **HIGH**: plaintext secrets or keys in Nix expressions. +- **MED**: secrets in environment variables without restricted access. +- **LOW**: suspicious strings that need confirmation. + +## Examples +**Bad** +```nix +environment.etc."api.key".text = "supersecret"; +``` +**Good** +```nix +sops.secrets."api.key" = {}; +``` diff --git a/skills/nix-review/lenses/supply-chain.md b/skills/nix-review/lenses/supply-chain.md new file mode 100644 index 0000000..3b86793 --- /dev/null +++ b/skills/nix-review/lenses/supply-chain.md @@ -0,0 +1,24 @@ +# Supply Chain Lens + +## Purpose +Scan for known vulnerabilities and input provenance risks. + +## Checks +- Generate SBOM with `sbomnix` and scan with `grype`. +- Identify CVEs across runtime closures. +- Flag untrusted or unexpected input sources. + +## Severity Guidance +- **HIGH**: critical vulnerabilities without available fixes. +- **MED**: known CVEs with available fixes. +- **LOW**: informational advisories. + +## Examples +**Bad** +```text +CVE-2025-1234 in openssl (no patch applied) +``` +**Good** +```text +CVE-2025-1234 mitigated via nixpkgs patch; note in report +``` diff --git a/skills/nix-review/lenses/systemd-hardening.md b/skills/nix-review/lenses/systemd-hardening.md new file mode 100644 index 0000000..0b767bb --- /dev/null +++ b/skills/nix-review/lenses/systemd-hardening.md @@ -0,0 +1,24 @@ +# Systemd Hardening Lens + +## Purpose +Ensure systemd services are hardened where possible. + +## Checks +- Services running as root without justification. +- Missing hardening options where applicable (`NoNewPrivileges`, `ProtectSystem`, `PrivateTmp`). +- Broad `CapabilityBoundingSet` or `AmbientCapabilities` usage. + +## Severity Guidance +- **HIGH**: root services with network exposure. +- **MED**: missing hardening for services with file/network access. +- **LOW**: optional hardening improvements. + +## Examples +**Bad** +```nix +serviceConfig.User = "root"; +``` +**Good** +```nix +serviceConfig = { User = "nginx"; NoNewPrivileges = true; }; +```