Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,72 @@

## Unreleased

- Second review round (PR#29 delta findings): custom package sources
(`--registry`, `--index-url`, `--find-links`, `--no-index`, composer
`--repository`) now floor the verdict at WARN for every ecosystem — exact
versions included — because public advisory data cannot vouch for a
private artifact of the same name@version; the operator lifts the floor
per source via `install.trusted_registries` (or per version via a pinned
host-allow). `safe install` and the uv wrapper thread the same selectors.
OSV pagination rejects non-string/repeated tokens (a malformed
completeness token no longer reads as zero advisories). SemVer prerelease
identifiers compare per spec (identifier-by-identifier, numeric before
alphanumeric) instead of lexically, and version-qualified `overrides` keys
(`"pkg@^2.0.0"`) degrade resolution like bare ones. An adverse advisory
result revokes recorded clean install-known evidence even when a pinned
host-allow permits the current invocation, and the stale readers use the
canonical ecosystem key (cargo/composer entries are findable again).

- Orthogonal-review hardening of the version-aware gate (PR#29 findings):
version-scoped OSV results are server-authoritative — the local range
comparator annotates but can never downgrade a hit to GO; OSV pagination is
followed (a token-only page no longer reads as zero advisories, anomalies
fail closed); target-altering selectors are threaded into the audit
(`--tag` → dist-tag resolution, `--registry` → packument source,
`--prefix`/`--working-dir` → project dir; custom pip/uv/cargo/composer
indexes degrade to the unresolved refusal instead of auditing the default
registry); the npm resolver follows npm-pick-manifest's latest-tag
preference, no longer globs range tokens against cwd files, and degrades
when root `overrides` mention the package; a WARN/BLOCK check revokes any
stale install-known entry for that version and the timeout fallback only
accepts verdict-GO evidence; severity now normalizes from qualitative
labels AND standard CVSS v3 vectors (computed base score, most severe
wins; v4-only floors at high); `cargo`/`composer` ecosystem labels map to
their resolvers and OSV names, and `cargo install --version X` audits the
pinned crate.

- Version-aware install verdicts: `safe audit check` now resolves the version
the package manager would actually install (exact spec as-is; npm dist-tag
for installs; the **in-range** target from `package.json`/lockfile ranges
for `--op update`; registry latest for pip/uv, cargo, composer, go) and
matches OSV advisories against that exact version's affected ranges.
Previously the query sent `version:"latest"`, OSV returned every advisory
ever filed, and the verdict was a version-blind count — which WARN-blocked
the very bumps that remediate a CVE (inbox 2026-07-31, third occurrence).
Advisories are classified `affecting`/`remediated`/`unfixed`/`ambiguous`;
only affecting ones drive the verdict, with `install.block_severities`
(default critical) escalating to BLOCK. Resolution failure degrades to a
package-level audit with a WARN floor (`version_unresolved`), and an OSV
outage now fails closed (it used to count as zero CVEs). Exit codes and
plain `check` semantics are unchanged for consumers.

- New install gate mode (`safe audit check --gate install`), used by the zsh
wrappers and `safe install`: GO proceeds with no operator terminal and
records the pinned resolved version in machine-written
`~/.config/safe/run/install-known.json` (evidence pointing at the check
receipt; consulted only as an offline fallback when the audit times out,
within `install.auto_allow_ttl_days`). WARN proceeds only on a pinned
host-allow entry matching the **resolved** version — fixing the dead end
where `npm update` audited `pkg@latest` and a pinned allow could never
match — or via the opt-in `install.auto_allow_tolerate` causes. Refusal
hints are always pinned (`host-allow add <pkg>@<resolved>`); nothing ever
suggests `@latest`. Socket scoring failures refuse with an explicit
infrastructure-failure message and recovery path (`socket login`,
`safe doctor` now reports the Socket CLI/token wiring), clearly
distinguished from a package finding. Wrapper and `safe install` gate
decisions now leave a persistent record in the safe-run audit log
(`install:<ecosystem> | ... | GATE | ... | PROCEED/REFUSED_*`).

- Add `safe vendor update --preset <vendor>` for claude, gh, op, uv, and
codex: fills `--name`, `--path` (auto-detected on PATH), and `--version-cmd`
so a native vendor update needs only `--reason` and the command; explicit
Expand Down
Loading