Repository navigation
fix(advisories): unversioned matches are never grounded; uncovered ecosystems say so (audit A2/E4) - #974
Merged
Conversation
runyourempire
force-pushed
the
fix/e4-unversioned-not-covered
branch
3 times, most recently
from
October 17, 2026 16:50
76c0b20 to
f77a2f9
Compare
runyourempire
enabled auto-merge
October 17, 2026 16:50
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 17, 2026
runyourempire
force-pushed
the
fix/e4-unversioned-not-covered
branch
from
October 17, 2026 18:15
f77a2f9 to
c5df05c
Compare
runyourempire
enabled auto-merge
October 17, 2026 18:16
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 17, 2026
…osystems say so (audit A2/E4)
A fresh profile with one Maven pom.xml showed 15 GHSA advisories as grounded
"Affects You" items (14 did not apply), and Maven/Gradle/.NET projects read
as clean because nothing reported them as unchecked.
Signal (scoring v42, scoped epoch on source_type cve/osv):
- A registry advisory naming a dependency with no known installed version
(manifest-only, no lockfile, or an unresolved ecosystem) takes the
confirmed-not-affected tier: no critical fast path, the registry-ungrounded
ceiling, never feed-relevant, never strongly grounded or a dependency
event. Applicability is `version_unknown`; the reason and explanation say
"unconfirmed: no installed version known" instead of "affects".
- The evidence pool never puts `version_unknown` in Affects You.
Bypasses closed:
- Preemption Tier 2 (LLM-judged) no longer matches a cve/osv item to a
direct dependency without a resolved version.
- The background CVE scan no longer notifies on unversioned dependencies
(the matcher "conservatively assumes affected" without a version).
Not covered (reuses the MCP server's `not_covered` concept):
- AdvisorySync carries `not_covered`: the lockfile walk's unsupported files
({path, ecosystem}) and its unreadable lockfiles ({path, reason}).
- A .NET project with only a .csproj/.fsproj/.vbproj is now reported as
unsupported (it was not reported at all).
- Preemption names those files, and its empty state no longer says "Your
stack is clean" while they exist.
- Conformance: new synthetic case synth-dotnet-csproj, and a test that every
declared-unsupported corpus file comes back from the reader as Unsupported.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
… stored verdict, lockfile pin before "unknown" - SF1: Tier 2's grounding set reads installed versions from the shared resolver (temporal::included_dependencies_resolved, extracted from get_inventory_dependencies): same project + ecosystem family, then the same active root. The name-only join could give a Cargo crate an npm row's version. Test: tier2_version_never_crosses_ecosystems. - SF2: a cve/osv row becomes a Tier 2 alert only when the scorer's stored verdict saw an installed version and did not find it outside the range (not_affected and version_unknown are rejected; unscored rows fail closed). Test: tier2_respects_the_stored_version_verdict. - SF3: before an advisory is "version unknown", the scorer looks for a lockfile pin of the package (same family, same or enclosing project) via temporal::installed_version_nearby. Test: a_lockfile_pin_rescues_a_versionless_grounding_row. - Nits: empty-state tests for the partial all-clear; a not-covered-only project shows the not-covered note instead of "scan your projects"; the CVE scan logs how many unversioned deps it skipped; NotCovered's doc says it extends the MCP shape with `unreadable`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
…ier 2; locale keys (round-3 review) - SF1: temporal::installed_versions_nearby (temporal_versions.rs) replaces the first-row lookup that could take a stray parent lockfile or a nested sub-project's pin and suppress a real advisory. Scope: the project's own lockfile, else the NEAREST ancestor inside its active repo root (never above it), else a unique nested pin only when the project has no lockfile of its own. Every distinct version in scope is returned and the scorer treats the advisory as affected if ANY copy is (the affected copy is shown). Name lookup uses the package index (exact + lowercase forms). - SF2: Preemption Tier 2 fills a missing version from the same lookup, so Tier 2 and the scorer agree; a test proves it on one fixture. - SF3: the 9 new UI keys are translated into all 13 locales. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
…merge-queue ejection) Both fixtures modelled lockfile dependencies with `version: None` and no `user_dependencies` rows, i.e. genuinely unversioned, which v42 (audit E4) correctly treats as "version unknown". Neither test is about that case: - direct_dep_cve_clears_the_direct_dep_floor: the direct `hyper` dep now carries a pin (1.4.0); the test still proves the direct-dep floor. - serde_derive_advisory_engages_fast_path_for_serde_user: the bench profile's lockfile-only family children carry their Cargo.lock pins (serde_derive 1.0.200, below the 1.0.205 fix; tokio-util 0.7.11); the test still proves the family-child fast path. The unversioned case stays covered by advisory_against_an_unknown_installed_version_is_unconfirmed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
…ts (v42, real-embedding ratchet) The real-embedding calibration ratchet (queue run 39057765993) failed at 93.0%: four security scenarios (sec_hyper_vuln, sec_react_xss, sec_pytorch_rce, reg_cve_reqwest) scored exactly 0.370, the v42 version-unknown ceiling. The benchmark profiles install every dependency with `version: None` and the bench DB has no lockfile rows, so these were genuinely unversioned fixtures, not a resolver regression. The profiles now carry lockfile pins inside each advisory's affected range, so the scenarios still test the confirmed-exposure security path: hyper 1.4.0 (< 1.4.2), reqwest 0.12.10 (< 0.12.15), react 19.1.0 (< 19.1.2), pytorch/torch 2.4.0 (< 2.4.1). Local run, `FOURDA_REQUIRE_REAL_EMBEDDINGS=1 cargo test --lib --features calibrated-sim scoring::` (committed real-model embedding fixtures): score-range 97.0% (97/100), security 12/12, TP 17/20, TN 20/20, quality gate PASSED. The three remaining failures (tp_systems_programming, reg_tauri_title_boost, reg_desktop_packaging) are the documented residuals in quality_gate.rs and fail identically on main. No floor was changed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
runyourempire
force-pushed
the
fix/e4-unversioned-not-covered
branch
from
October 18, 2026 04:52
c5df05c to
afb5767
Compare
runyourempire
added a commit
that referenced
this pull request
Oct 18, 2026
… what it did not check (W5a, follow-ups to #974) - Readiness counts an ecosystem only when an auditable row carries an installed version. The manifest scanner registers pom.xml / build.gradle dependencies with no version, a versionless dependency is never matched (#974), and those rows made "Maven" a required ecosystem: its sync succeeded and readiness said Ready for a project nothing was checked in. Now a Maven-only project reads NoInventory with its pom.xml named, and an npm + Maven machine reads Ready for npm with the Maven files named. The scanner keeps those rows for ACE context; the sync is unchanged. (Live DB: every versioned row is lockfile-backed npm/Rust, so the operator's readiness does not change.) - BriefFacts carries #974's not-covered report. The deterministic brief's all-clear reads "Nothing new touches the code 4DA checked today." and a "Not checked: ..." line names the files 4DA does not read and the lockfiles it could not read (three named, then "and N more"). A narrated brief's all-clear is rewritten the same way (idempotent), and the prompt tells the model the facts are complete only for the files read. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adversarial audit 2026-10-12, findings E4 and A2 (app side). A fresh profile with one Maven
pom.xmlshowed 15 GHSA advisories under Signal's "Affects You: Grounded in your dependencies", marked CORE and red. 14 of the 15 did not apply. Maven, Gradle and .NET projects also read as clean, because nothing reported that their versions were never checked.1. Unversioned matches are never grounded (scoring v42, scoped epoch)
A registry advisory (
cve/osvrow) that names a dependency with no known installed version (manifest-only, no lockfile, or an ecosystem 4DA does not resolve) now gets the same treatment as a confirmed not-affected row (version_unknowninpipeline_v2::score_item):strongly_groundedand never adependency_event;applicability = "version_unknown";On the frontend,
evidence-pool::isGroundedrefusesversion_unknowneven if a stale breakdown still claims grounding. The expanded row labels it "Unconfirmed: no installed version known".Display choice: drop from the promoted surfaces, label it everywhere else. I did not show these as a low-confidence "unconfirmed" card.
PIPELINE_VERSION41 → 42, registered inepochs::SCOPED_EPOCHSassource_type IN ('osv','cve')(AD-034).version_unknownrequiresregistry_advisory, which is exactly that predicate.2. Two bypasses closed
llm_judged_to_alerts) matched cve/osv items to direct dependencies by name only. Two checks now apply:temporal::included_dependencies_resolved, extracted fromget_inventory_dependencies: the same project and ecosystem family, then the same active root. Dormant projects are still admitted.project_dependencies.versionalone is NULL on all 593 live rows, and a name-only join could give a Cargo crate an npm row's version.scoring_explanations) must not be not-affected or version-unknown. An unscored row fails closed; Tier 1 still lists every version-confirmed match.monitoring_jobs) no longer passes unversioned dependencies tocross_reference_advisories. That function "conservatively assumes affected" without a version, which would have sent Critical/Highsecurity-alertnotifications for a pom.xml.version_is_affecteditself is unchanged, becausedependency_healthlegitimately relies on it.3. "Not covered" is reported, never treated as clean
This reuses the MCP server's
not_coveredconcept (project-tree.ts,{path, ecosystem}) rather than adding a new type.AdvisorySync.not_covered?: NotCoveredis built from the lockfile walk's saved report (ace.lockfile_report.v1) and has two parts:{path, ecosystem};{path, reason}. An all-clear must not rest on rows a failed read left stale (recovery-lead's parity finding).*.csproj/*.fsproj/*.vbproj(nopackages.lock.json) is now reported as unsupported. Before this it was not reported at all.PreemptionNotCoveredNotenames the files (5 listed, the rest counted). While any file is not covered, the empty state reads "No known vulnerabilities in the dependencies 4DA could check" instead of "Your stack is clean". The copy uses the coverage qualifier from CLAUDE.md verbatim.synth-dotnet-csproj;every_declared_unsupported_file_is_reported_not_covered, which requires every declared-unsupported corpus file (Mavenpom.xml,bun.lockb,.csproj) to come back from the reader as an explicitUnsupported;is_lockfile_likeis updated in both the Rust harness andscripts/conformance-corpus.mjs.4. Review fixes (second commit)
The scorer looks for a lockfile pin before declaring "version unknown", through the bounded lookup
temporal::installed_versions_nearby(temporal_versions.rs, round 3). The scope is, in order:Every distinct version in scope is returned, and the advisory is affected if ANY copy is; the affected copy's version is the one shown. The name lookup uses
idx_user_deps_package(exact and lowercase forms). Tests:a_stray_parent_lockfile_never_overrides_the_projects_own_pin;a_nested_sub_project_pin_never_replaces_the_own_pin;any_affected_copy_makes_the_advisory_affected;a_lockfile_pin_rescues_a_versionless_grounding_row;Preemption Tier 2 fills a missing installed version from the same lookup, so Tier 2 and the scorer cannot disagree.
tier2_and_the_scorer_agree_on_the_installed_versionasserts both see 4.17.1 on one fixture.The 9 new UI keys are translated into all 13 locales.
When the only files are ones 4DA cannot read (for example an
.fsproj-only repo withtotal_tracked == 0), Preemption shows the not-covered note instead of "No dependencies are known yet, scan your projects".The CVE scan logs how many unversioned dependencies it skipped.
The
NotCovereddoc now says it is the MCP shape plusunreadable. The MCP side has not adoptedunreadableyet.Not done / follow-ups
ace/scanner.rs(t2's file) still stores Maven coordinates with no version and offers them to the OSV sync. That is harmless now that unversioned matches are unconfirmed everywhere, but readiness can still say "ready" for the Maven ecosystem. Suggested change for t2: skip versionless manifest rows inosv/sync::auditable_packages_by_ecosystem, or have the scanner not register Maven deps at all.brief_facts_copies.rs, t2's file) does not yet mention not-covered files.AdvisorySync.not_coveredis available for it.Evidence
tier2_version_never_crosses_ecosystems,tier2_respects_the_stored_version_verdict(an installed version past the fix is rejected; an unscored row fails closed) anda_lockfile_pin_rescues_a_versionless_grounding_row. Frontend:PreemptionWorklist.emptyStategains the partial all-clear and the not-covered-only project; 95 preemption tests pass.advisory_against_an_unknown_installed_version_is_unconfirmed, end to end throughscore_item, with a pinned control that still confirms;an_advisory_against_an_unknown_version_is_unconfirmed_not_affecting;tier2_never_matches_a_registry_advisory_to_an_unversioned_dep;readiness_names_the_files_4da_does_not_read;readiness_has_no_not_covered_when_every_file_was_read, which includes back-compat with an older snapshot;read_dir_reports_a_csproj_only_project_as_unsupported;every_declared_unsupported_file_is_reported_not_covered.evidence-pool(version_unknownis never grounded) andPreemptionNotCoveredNote(2 tests).🤖 Generated with Claude Code
https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7