Skip to content

Verify the safe-version steer before printing it#104

Merged
juangaitanv merged 2 commits into
install-vuln-gatefrom
ivg/u1-steer-verify
Jun 11, 2026
Merged

Verify the safe-version steer before printing it#104
juangaitanv merged 2 commits into
install-vuln-gatefrom
ivg/u1-steer-verify

Conversation

@juangaitanv

Copy link
Copy Markdown
Contributor

What

The install gate steered blocked installs to the advisories' fixed_version without checking whether that version is itself flagged. Now every proposed → safe version is re-verdicted against vuln-api (through the existing verdict_pool) before anything prints:

  • Verified (clean re-check) → → safe version: <name>@<version> prints, and JSON remediation carries the version.
  • Rejected (re-check flagged) → → advertised fix <v> is also flagged — no safe version to suggest prints; JSON remediation is null.
  • Unverified (request failed) → the steer is suppressed quietly; JSON remediation is null. Counts and exit codes never move — should_block_install is untouched.

How

  • New enum SteerCheck { Verified, Rejected, Unverified } and steers: HashMap<(String, String), SteerCheck> on PrecheckReport, keyed by (normalized name, proposed version).
  • New verify_steers() runs once in run_parsed_install after the verdict/tree passes: collects proposals from named + transitive vulnerable verdicts, dedups by normalized (name, version), and sends requests only when a token is configured and at least one proposal exists.
  • steer_for() resolves a proposal + check at render time; a missing map entry counts as Unverified (suppress).

Tests

  • Unit: verify_steers mapping (clean/flagged/503 → Verified/Rejected/Unverified, named + transitive), tokenless no-op, no-proposal short-circuit, normalized-name dedup.
  • e2e (tests/cli_remediation.rs): rejected fix prints the rejection note and keeps 1 vulnerable, 0 unverifiable; 503 re-check suppresses the steer quietly with unchanged counts/exit; JSON remediation null on rejection; existing verified-path tests still pass (stub default-clean re-check).
  • ./harness check green (clippy strict, fmt, 259 tests, deps-skill drift).
  • Live staging smoke: corgea npm install axios@0.21.0 against cve-worker-staging blocks with exit 1 and prints → safe version: axios@0.21.2 (staging re-verdicts 0.21.2 clean).

Notes

  • Doc drift left in place on purpose: skills/corgea/SKILL.md line ~158 ("remediation … null when any advisory has no known fix") is now incomplete — null also means the fix was rejected or unverified. That paragraph belongs to another unit's section, so it is flagged here instead of edited.
  • Drive-by fix (separate commit): find_available_port overflowed u16 on start_port + 50; the pre-commit hook's test run tripped it when the OS handed the test an ephemeral port above 65485. Saturating add.

start_port + 50 panics in debug builds when the start port is above
65485 — the port-search test binds an ephemeral port and trips this
whenever the OS hands out one near u16::MAX. Saturate instead.
Re-verdict each proposed '→ safe version' against vuln-api through the
existing verdict_pool before any output. A clean re-check prints the
steer; a flagged one prints '→ advertised fix {v} is also flagged — no
safe version to suggest'; a failed re-check suppresses the steer quietly
and never moves counts or exit codes. JSON 'remediation' now emits only
on a Verified steer. Proposals dedup by normalized (name, version) and
requests fire only when a vulnerable verdict exists with a token
configured.

@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.

  • src/precheck/mod.rs:220 / src/lib.rs:2: Adding pub steers: HashMap<(String, String), SteerCheck> to PrecheckReport is a source-breaking public API change. precheck is exported from the library (pub mod precheck), and PrecheckReport is a public struct with public fields, so any downstream Rust consumer or integration test constructing PrecheckReport { ... } now fails to compile unless it knows about this internal render-only cache. Impact: a patch/minor CLI release can break library consumers even though the new state is only needed while rendering. Fix: keep steer verification state out of PrecheckReport's public shape, e.g. have verify_steers return a local HashMap/sidecar passed into print_text, print_json, steer_for, and verdict_json, or introduce a constructor/builder as part of an intentional breaking API change.

  • skills/corgea/SKILL.md:161: The documented JSON contract is now stale. It still says vulnerable verdict remediation is "the certified safe version, or null when any advisory has no known fix," but the new renderer sets remediation to null for rejected and unverified steer re-checks too (src/precheck/mod.rs:975 and src/precheck/mod.rs:982). Impact: agents or other machine consumers following this skill can misinterpret null as "no known fixed version" even when every advisory did advertise a fix but the re-check failed or found that fix vulnerable. Fix: update the JSON documentation to state that remediation is non-null only after the proposed fix re-verdicts clean, and is null when no fix is known, the fix is also flagged, or the re-check cannot be verified.

Open in Web View Automation 

Sent by Cursor Automation: pr-flow

@juangaitanv juangaitanv merged commit 0a485ec into install-vuln-gate Jun 11, 2026
17 checks passed
@juangaitanv juangaitanv deleted the ivg/u1-steer-verify branch June 11, 2026 07:40
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