# pkgaudit — Changelog

## v1.0.0 — 2026-06-25

Initial release. Fourth tool in the "productivity-boost" series.

### Purpose

Every cli.johlem.net engagement walks a third-party stack — Rust /
npm / Python / Go libraries pulled from public registries. pkgaudit
turns the operator's lockfile(s) into a jfind-shaped bill of materials
and (with `--online`) overlays known vulnerabilities from OSV.dev. It
is the supply-chain half of compose-audit's deployment-hardening half:
together they cover DORA Art. 9 + Art. 28 for any container-deployed
service.

### Subcommands

```
pkgaudit scan    <path…>                    # auto-detect every lockfile
pkgaudit cargo   <Cargo.lock>
pkgaudit npm     <package-lock.json | yarn.lock | pnpm-lock.yaml>
pkgaudit python  <requirements.txt | Pipfile.lock | poetry.lock>
pkgaudit go      <go.sum>
```

All accept `-F human|json|jfind`, `-o <file>`, `--fail-on <severity>`,
`--online` (default off), `--timeout <secs>` (default 15).

### Supported lockfile formats (eight)

| Ecosystem | Files |
|---|---|
| Cargo | `Cargo.lock` (v3) |
| npm   | `package-lock.json` (v2/v3 + v1 fallback), `yarn.lock`, `pnpm-lock.yaml`, `npm-shrinkwrap.json` |
| PyPI  | `requirements.txt` (strict `==` pins only), `Pipfile.lock`, `poetry.lock` |
| Go    | `go.sum` |

### Online mode

`--online` queries `https://api.osv.dev/v1/query` once per package.
A failed query (network / 5xx) is logged to stderr but does *not*
abort the scan — the rest of the lockfile still produces an
inventory. Default is offline for determinism (and because the OSV
API rate-limits aggressive clients).

### jfind/v1 output

| Category | Triggers |
|---|---|
| `vulnerability` | OSV returned ≥1 vuln for this package |
| `asset-inventory` | clean package (Info, Confirmed confidence) |

Every emission carries:
- DORA Art. 9 + Art. 28 (ICT third-party risk)
- NIS2 Art. 21(2)(d) (supply chain security)
- ISO/IEC 27001:2022 A.5.21 (managing information security in the ICT supply chain)
- MITRE T1195.001 (Compromise Software Dependencies)

Severity ladder: CVSS numeric → ladder (≥9 Critical, ≥7 High, ≥4
Medium, >0 Low). Falls back to `database_specific.severity` string
("HIGH" / "MODERATE" / …). If nothing parses we land on Medium — a
known vuln of unknown severity is never `Info`.

### Exit codes

```
0  ok        — scan completed, no finding crossed --fail-on
2  usage     — clap parse error
3  runtime   — io, parse, OSV transport failure on init
4  policy    — a vulnerability met or exceeded --fail-on
```

### Build

- Library crate (`pkgaudit`) + thin CLI binary.
- 15 unit + 13 integration tests = 28 tests, all green.
- Zero compiler warnings.
- HTTP via `reqwest` (rustls-tls + blocking; matches notify's stack).
- Offline-by-default; `--online` is the explicit opt-in.
- Suite-standard exit codes + tagline footer.
- NixOS-only platform gate in `install.sh`.

### Suite interop

| Producer | Consumer | Use case |
|---|---|---|
| operator | pkgaudit | enumerate / audit a lockfile or repo |
| pkgaudit | complymap | map vulns → DORA Art. 28 / NIS2 21(2)(d) |
| pkgaudit | dossier   | gap-assessment / pentest report dependencies |
| pkgaudit | notify    | dispatch High+ vulns to Slack / Teams |
| pkgaudit | cmdb link | (planned) attach OSV URLs to a cmdb asset |

### Deferred to v1.1

- `--mirror <path>` — feed a downloaded OSV database export instead of
  hitting the live API (proper offline CVE check).
- `--ignore CVE-…` / `--ignore-osv GHSA-…` suppression flags.
- `composer.lock` (PHP / Packagist) and `Gemfile.lock` (Ruby).
- Batched OSV queries via `/v1/querybatch` (current impl serializes
  one query per package — fine for ≤200 packages, sluggish above).
- Async runtime with bounded concurrency (today: blocking, serial).
