Skip to main content
ClaudeWave
Skill440 repo starsupdated today

phx:deps-vet

# phx:deps-vet This Claude Code skill manages a project-level audit ledger for Hex package security reviews in Elixir Phoenix applications. It records vetted package versions in hex_vet.exs after manual security assessment, then downgrades flagged packages to informational status on subsequent audit runs. Use it after /phx:deps-audit findings to approve dependencies, before merging mix.lock changes to certify new versions, or to seed an initial baseline of trusted packages.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/oliver-kriska/claude-elixir-phoenix /tmp/phx-deps-vet && cp -r /tmp/phx-deps-vet/plugins/elixir-phoenix/skills/deps-vet ~/.claude/skills/phx-deps-vet
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Deps Vet — Hex package audit ledger

Review a Hex package version, run Phase 1 supply-chain rules against it,
prompt the user for a verdict, append the result to `hex_vet.exs`
(project-root audit ledger). Vetted versions get downgraded to `INFO`
on subsequent `/phx:deps-audit` runs.

Run this AFTER `/phx:deps-audit` to clear findings.
Run this BEFORE merging a `mix.lock` PR to certify new versions.

## Usage

```text
/phx:deps-vet phoenix 1.7.21      # vet a single package version
/phx:deps-vet --seed              # import curated baseline seed (~30 pkgs)
/phx:deps-vet --list              # show existing ledger entries
/phx:deps-vet --check             # cross-check mix.lock vs ledger
```

## Iron Laws

1. **NEVER auto-approve.** Every entry MUST come from an `AskUserQuestion`
   confirmation. Drive-by trust ruins the ledger's value.
2. **Lock wins on disagreement.** If `mix.lock` has version X and the
   ledger vets X-1, emit INFO and treat X as unvetted. Don't silently
   trust the older entry.
3. **Ledger lives at project root.** `hex_vet.exs` is a first-class
   security artifact, visible in PR review. Don't move it into `.claude/`.
4. **Round-trip via `inspect/2`.** When appending, read the file with
   `Code.eval_file/1`, mutate the map, and write back via
   `inspect(term, pretty: true, limit: :infinity)`. Hand-rolled string
   appends drift over time.
5. **Always show findings before prompting.** The user must see what's
   being vetted. No silent `:safe_to_deploy` defaults.
6. **Confirmation counts are COMPUTED, never estimated.** Any number in
   an `AskUserQuestion` (criteria split, new/overwrite/no-op) MUST be
   derived from the loaded data *before* prompting — e.g.
   `Enum.frequencies_by(seed.audits, & &1.criteria)`. Eyeballing the
   file and approving on wrong numbers corrupts the consent.

## Execution flow

### Step 1: Locate or seed `hex_vet.exs`

```text
If hex_vet.exs exists at project root:
    Read it via Code.eval_file/1
Else:
    Write the empty-ledger stub (see references/hex-vet.md §"Empty ledger")
    Inform user: "Created hex_vet.exs at project root."
```

### Step 2: Branch by mode

- **`<pkg> <version>`** → single-vet path (Step 3-7).
- **`--seed`** → import `priv/hex_vet_seed.exs`. Before prompting,
  `Code.eval_file/1` the seed and **compute** (Iron Law #6): the
  `criteria` split (`Enum.frequencies_by(seed.audits, & &1.criteria)`)
  and, against any existing ledger, exact new / overwrite / no-op
  counts. Put those computed numbers in the `AskUserQuestion`. Also
  state up front that the seed is a **provenance baseline, not
  certification of your current `mix.lock`** (per Iron Law #2, seed
  versions older than the locked ones stay unvetted). Ask before
  overwriting existing entries.
- **`--list`** → render the audits table; exit.
- **`--check`** → compare ledger entries with `mix.lock`; warn on
  drift. Read the lock via `Code.eval_file("mix.lock")` with
  **`2>/dev/null`** — modern locks have quoted keys and emit a
  `found quoted keyword` warning per package (tens of KB of noise that
  gets persisted as an oversized tool result otherwise).

### Step 3: Fetch the tarball (single-vet)

Run the deps-audit corpus loader. Cache lives at
`~/.cache/phx-deps-audit/corpus/<pkg>/<version>/contents/`. Use:

```text
bash plugins/elixir-phoenix/skills/deps-audit/smoke-test/corpus.d/fetch.sh \
    <pkg> <version>
```

### Step 4: Run Phase 1 rules

Source the rules from `../deps-audit/references/rules-impl.md`.
Run `run_all_rules` over the cached dir. Write findings to a temp
`vet-findings.jsonl`. Set `FINDINGS_FILE` to override default path.

### Step 5: Present findings

Print the findings table per `../deps-audit/references/output-renderer.md`.
On zero findings: say "No findings — vet from a clean baseline."
On any finding: show severity, file, line, snippet inline.

### Step 6: Prompt for verdict

Call `AskUserQuestion` with these 4 options:

- **`:safe_to_deploy`** — full trust; findings investigated and cleared.
- **`:safe_to_run`** — trust in non-production envs only (test deps).
- **`:does_not_implement_crypto`** — Mozilla-style sub-criterion.
- **`Skip`** — defer decision; don't write an entry.

If any finding is BLOCK severity: default-highlight `Skip`. Require
explicit override before writing `:safe_to_deploy` over a BLOCK.

### Step 7: Append to ledger

Read existing `hex_vet.exs` via `Code.eval_file/1`. Append the audit
map below to `:audits`. Write back via
`Code.format_string!(inspect(...))`.

```elixir
%{
  package: "<pkg>",
  version: "<version>",
  criteria: <verdict_atom>,
  reviewer: "<git config user.email>",
  notes: "<user-provided one-liner OR findings summary>",
  reviewed_at: ~D[<today>]
}
```

Write back via `Code.format_string!(inspect(term, pretty: true))`.
Confirm to user: "Added `<pkg>` `<version>` to hex_vet.exs."

## Integration

- **Run after** `/phx:deps-audit` to clear vetted findings.
- **Run before** merging a `mix.lock` PR to certify new versions.
- **Run `/phx:deps-vet --check`** to detect ledger drift vs `mix.lock`.
- **`/phx:deps-audit`** auto-downgrades vetted findings to INFO.

## References

- `${CLAUDE_SKILL_DIR}/references/hex-vet.md` — schema, parser, lookup
- `${CLAUDE_SKILL_DIR}/references/seed.md` — `--seed` flag, curated baseline
- `${CLAUDE_SKILL_DIR}/../deps-audit/references/rules-impl.md` — the
  same rules `/phx:deps-audit` runs

## Out of scope (Phase 3+)

- **Mix task surface** — defer `mix phx.deps_vet` to a separate Hex
  package `phx_deps_vet` for non-CC users.
- **Block-on-unvetted enforcement** — defer to a PreToolUse hook
  that gates `mix deps.get`.
- **Distributed imports** — defer cargo-vet `imports:` until
  trust-chain semantics are designed.