Scanner Analyzer Determinism & Completion (Group F closure)
Sprint: SPRINT_20260430_012_Scanner_analyzer_determinism_and_completion Audit reference: docs-archive/qa/audits/microservice-audit-pass2-2026-04-29.md (Section F)
This release closes the four findings in pass-2 audit Group F.
F2 — Node.js: deterministic runtime-evidence component key
RuntimeEvidenceLoader no longer falls back to Guid.NewGuid() when an incoming runtime-evidence record carries no path. The fallback now derives a stable runtime-component:<sha256-lower-hex> key over the scrubbed (reason, loaderId, from, to) tuple, so two analyzer runs over identical evidence files produce byte-equal SBOM output.
F3 — Secrets: deterministic SecretFinding.Id
SecretFinding.Create no longer falls back to Guid.NewGuid(). The fallback derives a deterministic Guid via HMAC-SHA256(pepper, ruleId|filePath|lineNumber|columnNumber|artifactDigest) packing the first 16 bytes into the Id. This restores chain-hashing, dedupe, and replay invariants in the findings ledger. Caller-supplied Guid? id values continue to be honored unchanged.
F1a — Deno: SBOM emission paths
The Deno analyzer now emits SBOM components from three streams that were previously held back behind // Task 5+ placeholders:
- npm purls (
pkg:npm/<name>@<version>) collapsed to one component per(name, version)pair fromcompatibility.NpmResolutions. Specifiers, conditions, source nodes, targets, and resolved paths are aggregated into deduped metadata lists. - Remote modules (
type: deno:remote, keydeno-remote::<sha256(specifier)>) forhttps://...module-graph nodes that are not also covered by an npm resolution. - Bundle components (
type: deno:bundle, keydeno-bundle::<relativePath>) for eachDenoBundleObservation.
The existing observation::deno summary record and DenoContainerEmitter output are unchanged.
F1b — Rust: declared-deps, workspace, status lift
RustLanguageAnalyzer.DisplayName is now Rust Analyzer (previously Rust Analyzer (preview)). The plug-in manifest carries org.stellaops.analyzer.status = production.
New plumbing:
RustCargoTomlParser(Tomlyn-backed, BSD-2-Clause) reads[package],[dependencies],[dev-dependencies],[build-dependencies],[target.<cfg>.dependencies], and[workspace](members, default-members, dependencies).RustWorkspaceResolverdiscovers allCargo.tomlfiles under the scan root and expandscrates/*-style member globs.RustAnalyzerCollector.CollectCargoManifestsperforms declared-vs-installed merge: declared crates with aCargo.lockmatch appenddeclared.versionSpec / declared.scope / declared.targetCfg / declared.manifestPathsmetadata; declared-only crates emit fresh components withdeclaredOnly = "true". Workspace-member crates with their own[package]section emit components carryingworkspace.member/workspace.rootand (where applicable)workspace.defaultMember = "true".
Dependency added
- Tomlyn (BSD-2-Clause). Recorded in
NOTICE.md, listed indocs/legal/THIRD-PARTY-DEPENDENCIES.md, license vendored atthird-party-licenses/Tomlyn/LICENSE. The sprint plan stated MIT; the upstream NuGet license declaration is BSD-2-Clause. Both are BUSL-1.1 compatible (see the compatibility table in the dependencies doc).
Determinism contract
For each of the four fixes, the analyzer’s output ordering is stable across invocations and the new tests assert byte-equal component-key sequences across two consecutive runs.
