Skip to content

fix(vex): honest machine diagnostics, stale-doc removal, out-of-sync disclosure; offline proxy-notice suppression - #208

Open
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/vex-diagnostics-offline-notice
Open

fix(vex): honest machine diagnostics, stale-doc removal, out-of-sync disclosure; offline proxy-notice suppression#208
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/vex-diagnostics-offline-notice

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Problems (found by the 2026-08-18 pnpm e2e campaign's vex/offline probes; all ecosystem-independent)

  1. Machine-invisible Property-7 drops: a byte-verified applied patch omitted from the VEX doc only because its ecosystem has no install hook (and no setup.manual) made vex --json exit 1 with events: [] and the factually wrong error "No applied patches with vulnerability metadata to attest." — indistinguishable from "not patched". The explanatory note was human-mode-only.
  2. Stale attestations: a failed vex run left the previous run's fully-valid document byte-untouched at --output — a pipeline reusing one path could ship yesterday's attestation for a now-unpatched tree.
  3. --output write failures reported a bare OS error with no path; --product accepted arbitrary non-IRI strings verbatim into the OpenVEX product @id; a healthy vendored attestation said nothing when the live installed tree was out of sync with the patched bytes.
  4. apply/vendor/rollback --offline runs printed the "using the public patch API proxy" notice — network-implying output under strict airgap — and the SOCKET_OFFLINE parse was duplicated between the client and telemetry.

Fixes

  • Setup-filter drops now emit per-purl skipped events with errorCode ecosystem_not_setup; when all omissions are filter drops, the error message names the filter and both remediations.
  • Failed runs remove a recognizably-OpenVEX file at the output path (JSON @context naming openvex.dev) — unrelated files are never touched; the contract is pinned by tests both ways.
  • write_failed names the path; a non-purl/non-IRI product override warns (product_not_iri, honored verbatim); vendored attestations gain a vendored_tree_out_of_sync warning when the present installed tree hash-mismatches (attestation basis unchanged — the committed artifact is the product; the warning says to reinstall).
  • The offline gate suppresses the proxy notice; is_offline_env() is hoisted to utils/env_compat and shared by the client (both gates) and telemetry.

The core attestation invariant is untouched and was verified healthy throughout the probes: verified: true only ever appears when on-disk bytes hash to afterHash; every tamper flipped the attestation. The stable (vendored)/(redirected) impact-marker strings are unchanged (contract-pinned).

Verification

New tests: stale-doc removal + non-OpenVEX preservation, write-failure path naming, setup-filter skipped events + specific message, product_not_iri warn + purl control, out-of-sync warn with absent-tree and pristine controls (core), offline proxy-notice suppression. Suites: cli_parse_vex 7, e2e_embedded_vex 12, e2e_vex_vendor 13, cli_apply_silent 5, core vex 241 — all green; verified against main in an isolated worktree before opening.

🤖 Generated with Claude Code


Note

Medium Risk
Changes VEX JSON contracts, failure cleanup at output paths, and offline messaging—high impact for CI pipelines consuming envelopes, but core attestation rules (hash-to-afterHash, vendored precedence) are preserved and heavily tested.

Overview
VEX --json and envelopes now expose ecosystem-setup (Property 7) drops as per-purl skipped events with errorCode ecosystem_not_setup, with clearer top-level errors when every omission is that filter—not the generic “nothing to attest.” Run-level warnings[] covers non-IRI --product overrides (product_not_iri, still emitted verbatim) and vendored patches whose live node_modules tree hash-mismatches the committed artifact (vendored_tree_out_of_sync; attestation still based on .socket/vendor).

Failed runs delete a recognizably OpenVEX file at --output/--vex so CI cannot ship a prior not_affected doc; unrelated paths are untouched. write_failed names the path and operation.

Core verification adds VerifyOutcome.vendored_out_of_sync when a healthy vendored attestation sees a present installed tree with wrong bytes.

Offline / airgap: tokenless “public patch API proxy” stderr is suppressed when SOCKET_OFFLINE is set; is_offline_env() is shared across API client and telemetry instead of duplicated parses.

Reviewed by Cursor Bugbot for commit dfdc94b. Configure here.

…disclosure; suppress the proxy notice under --offline

Findings from the 2026-08-18 pnpm e2e campaign's vex probe (real-pnpm
projects; the core attestation invariant — verified:true only on matching
bytes — was healthy throughout and is untouched):

- Property-7 setup-filter drops were invisible in --json: a byte-verified
  applied patch omitted only because its ecosystem has no install hook
  (and no setup.manual) produced events:[] and the factually wrong
  "No applied patches with vulnerability metadata to attest." Drops now
  emit per-purl skipped events (errorCode ecosystem_not_setup) and the
  all-drops error message names the filter and both remediations.
- A failed vex run left a stale prior attestation byte-untouched at
  --output. Failed runs now remove a recognizably-OpenVEX file at the
  path (JSON @context naming openvex.dev — unrelated files never touched).
- write_failed errors now name the path; a non-IRI --product override
  warns (product_not_iri) instead of silently landing in the OpenVEX
  product @id; the vendored attestation gains a vendored_tree_out_of_sync
  warning when the PRESENT installed tree hash-mismatches the patched
  bytes (attestation basis — the committed artifact — unchanged).
- apply/vendor/rollback --offline runs no longer print the
  "using the public patch API proxy" notice (network-implying under
  strict airgap); the SOCKET_OFFLINE parse is hoisted to a shared
  is_offline_env() used by the client and telemetry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit dfdc94b. Configure here.

code: code.to_string(),
detail,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedded JSON drops VEX warnings

Medium Severity

note_warning skips stderr under --json and stores advisories in VexWriteSummary.warnings, but only standalone emit_envelope_success copies that field into the envelope. Embedded apply/scan --json --vex share generate_vex and also silence stderr, so product_not_iri and vendored_tree_out_of_sync stay machine-invisible on the channel this PR aimed to fix.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit dfdc94b. Configure here.

fn apply_offline_suppresses_public_proxy_notice() {
// No .socket dir at all: apply exits 0 ("nothing to apply") either way,
// so the only stderr difference is the advisory under test.
let tmp = tempfile::tempdir().unwrap();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New tests use bare unwrap

Low Severity

Newly added test fixtures call bare .unwrap() on tempfile::tempdir(), fs::write, and similar Results. On failure CI only reports a generic unwrap panic, with no indication which setup step broke.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by learned rule: Prefer .expect("context") over bare .unwrap() in test code

Reviewed by Cursor Bugbot for commit dfdc94b. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant