Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

mikronova/modgunn

.nornir/engine-b-analyses.md

Móðguðr — Engine B catalog of advanced analyses (design, post-demo)

Móðguðr guards Gjallarbrú: she watches the whole dependency world and tracks every change to the smallest bit. Engine B is not "a diff" — it is a battery of tripwires, graph algorithms, and anomaly detectors over (the SCIP world × time).

Inputs available to us:

  • SCIP facts — symbol defs/refs, the call graph, monikers (cross-repo symbol identity), per-symbol reference closure. Lifted from nornir's SCIP/knowledge modules.
  • Dep graph — resolved transitive tree per ecosystem (cargo/maven/npm/pip/go…).
  • Registry metadata — publisher, keys, timestamps, download counts, yank state.
  • Provenance — CMS signatures (znippy sign), SLSA/in-toto attestations.
  • Embeddings — the nornir embedder (jina/Qwen) → code/package vectors.
  • Time-travel — Apache Iceberg snapshots via skade (modgunn → skade, leaf; never nornir). Any two world-snapshots are diffable; full history is queryable.

Verdict surface: every analysis emits Finding{severity, kind, subject, evidence} folded into a core::Verdict (Pass/Warn/Block), the SAME shape Engine A uses, plus a Tripwire event stream for the world-delta site.


Build status (2026-07) — what is actually implemented

Authoritative, code-verified. DONE = implemented + unit-tested; PARTIAL = core landed, a piece of the full analysis still design-only; DESIGN = not yet coded. Symbols are in src/scip.rs unless noted provenance.rs / warehouse.rs. 25 / 25 catalog analyses are landed (22 in the Engine-B graph core scip.rs

  • 2 on the provenance surface + the world-time-travel two-point diff verb in warehouse.rs), up from the 5 the old status table claimed — plus a taint-path (source→sink) analysis (taint_path_findings) beyond the numbered catalog (the SAST/dataflow-rival capability, master-plan "A12").
# Analysis State Implementing symbol
1 Call-graph delta ✅ DONE CallGraphDeltaTripwire
2 Capability-surface drift ✅ DONE capability_surface + CapabilityDriftTripwire
3 Silent behavior fingerprint ✅ DONE FingerprintDriftTripwire (FNV-1a over the reachable closure)
4 Reachability-gated vuln ✅ DONE reachability_gated_vulns / unreachable_vulns
5 Sink-newly-reachable ✅ DONE SinkNewlyReachableTripwire
6 Publisher/maintainer anomaly ✅ DONE MaintainerAnomalyTripwire (ownership-transfer delta over DepNode::owners: disjoint owner set → High takeover, partial change → Medium, maintainer-count collapse → Low); signer-change co-signal via provenance::attestation_delta
7 Release-cadence / timeline anomaly ✅ DONE release_cadence_anomalies (per-package inter-arrival z-score; DepNode::release_epochs input)
8 Typosquat & dependency-confusion ✅ DONE typosquat_findings (+ levenshtein)
9 Attestation delta (SLSA/in-toto) ✅ DONE provenance::attestation_delta + ProvenanceRequirement::evaluate
10 Source↔artifact divergence ✅ DONE provenance::verify_sealed_provenance / evaluate_sealed (znippy-sealed build-provenance VERIFY: CMS seal + content-addressing + source-repo, feature provenance-verify)
11 Blast-radius centrality ✅ DONE blast_radius (PageRank) / blast_radius_findings
12 Bus-factor / SPOF ✅ DONE bus_factor_findings (DepNode::maintainers input)
13 Owner-cluster correlation ✅ DONE owner_cluster_findings (label-propagation community detection over the co-ownership graph; DepNode::owners input)
14 Entrypoint→sink path + min-cut ✅ DONE sink_chokepoints (single-vertex cuts)
15 Diamond / multi-version conflict ✅ DONE diamond_conflicts
16 Metric-outlier detection ✅ DONE zscore_outliers primitive + dep_fanin_outliers
17 Obfuscation / entropy spike ✅ DONE shannon_entropy + ObfuscationTripwire
18 Embedding-novelty ✅ DONE embedding_novelty_findings (per-ecosystem centroid + cosine_distance novelty outliers; DepNode::embedding input — producer attaches the nornir embedder's vector, honest-optional)
19 License-transition ✅ DONE license_transition_findings (riskward relicense across version history, ranked by license_risk_tier; DepNode::license_history input) — transitive copyleft-contamination-path cut is a further extension
20 SBOM drift ✅ DONE SbomDriftTripwire (component set-diff over DepNode::key → entered/left Findings; entered-unverified → Low, else Info) — the catalog-surface companion to the raw warehouse::sbom_drift (name,version) helper
21 Policy tripwires ✅ DONE PolicyRule DSL (NoCapabilityGrowth/NoNewNativeCode/NoUnverifiedDependencyAdded/ForbidEcosystem) + PolicyTripwire + default_policy() — declarative boolean assertions firing High on the delta
22 Threshold tripwires ✅ DONE ThresholdRule DSL (UnverifiedCentralityOver/CapabilitySurfaceGrewBy/NewSymbolEntropyOver/FanInAtLeast) + ThresholdTripwire — declarative numeric-bound crossings
23 Honeytoken / canary ✅ DONE Honeytoken (InternalName/CanaryToken) + honeytoken_findings — resolved internal name = dependency-confusion hit, surfaced canary token = exfiltration; every hit Critical, unplanted world never fires
24 World time-travel ✅ DONE warehouse::world_diff(snap_a, snap_b) -> WorldEdgeDiff — the explicit two-point diff verb over persisted snapshots (entered/left dep-graph edges + node sets), atop the capture + CDC seam (capture_world_snapshot/commit_seq/table_delta)
25 Change-velocity baselines ✅ DONE change_velocity_anomalies (trailing-window release-rate burst; z-score over the rolling velocity series; reuses DepNode::release_epochs)

Beyond the numbered catalog — taint-path (source→sink). taint_path_findings flags call-graph paths from an untrusted source ([Symbol::is_taint_source] — a network / IPC / deserialization read) to a sensitive sink (a symbol exercising a capability in default_taint_sinks: process/dynamic-code/filesystem/ ffi/env). This is the SAST/dataflow-rival capability (Semgrep/CodeQL taint) the master-plan lists as "A12"; Critical for code/command-exec sinks, else High. Empty (no source marked) ⇒ doesn't fire.


Family 1 — Behavior-delta (the core "world-delta")

  1. Call-graph delta. New/removed edges between two versions of a symbol's transitive call set. Fires when: a leaf dep grows edges into network/fs/process/FFI it never had. Data: SCIP call graph × 2 snapshots. Algo: graph set-diff + edge classification.
  2. Capability-surface drift. Track the set of dangerous capabilities a package reaches transitively — network, filesystem, process-spawn, env/secret read, dynamic code load, reflection, FFI/unsafe, clock/rng. Alert when the set grows. Algo: reachability closure over the call graph to a labeled sink set; set delta.
  3. Silent behavior fingerprint. Hash/embed a symbol's effective behavior (its transitive reference closure). Fire when the fingerprint changes but the version / public API signature did NOT — the classic "5th-level jar, unchanged for years, suddenly behaves differently." Algo: SCIP closure → stable hash + embedding; compare to the symbol's own history.
  4. Reachability-gated vuln prioritization. Only alert on a CVE if the vulnerable function is call-reachable from your entrypoints (kills the 90% false-positive noise of version-only matchers). Algo: multi-source BFS entrypoints → CVE sink.
  5. Sink-newly-reachable tripwire. A delta that makes any sink (CVE, capability, tainted source) reachable that previously was not — the highest-signal delta event.

Family 2 — Supply-chain integrity & provenance anomalies

  1. Publisher/maintainer anomaly. New signing key, ownership transfer, sudden maintainer change → account-takeover signal. Data: registry + provenance history.
  2. Release-cadence / timeline anomaly. Dormant package (no release in years) suddenly publishes; off-hours/weekend publish; unusual version jump. Algo: per-package inter-arrival baseline + z-score on the warehouse time series.
  3. Typosquat & dependency-confusion. Name edit-distance / homoglyph similarity to popular packages; internal package name now resolvable on a public registry (the dep-confusion attack). Algo: normalized edit distance + homoglyph table + internal-namespace set membership.
  4. Attestation delta (SLSA/in-toto). Attestation appears/disappears, builder identity changes, source-repo URL mismatch vs the artifact's claimed origin.
  5. Source↔artifact divergence. Does the published artifact rebuild from the tagged source (reproducible-build / git-SHA→package linkage)? Flag artifacts that don't.

Family 3 — Graph / structural algorithms (the "government-grade" core)

  1. Blast-radius centrality. Betweenness / PageRank over the dep graph → rank which deps, if compromised, touch the most of your surface. Drives monitoring priority.
  2. Bus-factor / single-point-of-failure. Highly central deps with a single maintainer (correlate centrality × maintainer-count).
  3. Owner-cluster correlation. Community detection over (dep → publisher) to surface clusters controlled by one entity → correlated, not independent, risk.
  4. Entrypoint→sink path analysis + min-cut. All paths from your code to a sink, and the chokepoints (min vertex cut) you could patch/pin to sever the most paths.
  5. Diamond / multi-version conflict. Same crate at N versions in the tree, one of which is vulnerable or unverified.

Family 4 — Statistical & ML anomaly detection

  1. Metric-outlier detection. Size delta, dep-count delta, file-count jump, download-count anomalies → z-score / isolation forest over the warehouse history.
  2. Obfuscation / entropy spike. High-entropy strings, minified/obfuscated regions, base64/hex blobs, eval-like dynamic execution newly introduced. Algo: per-file Shannon entropy + AST/SCIP markers, delta vs prior version.
  3. Embedding-novelty. Embed each package version (nornir embedder) and flag a release whose vector moves far from its own history or from the ecosystem norm (cosine distance > threshold). Catches semantically-novel injected code.

Family 5 — License & legal drift

  1. License-transition tracking. A dep relicenses mid-stream (MIT→AGPL); detect copyleft-contamination paths (transitive license-compatibility cut).
  2. SBOM drift. Full CycloneDX/SPDX SBOM delta between two world snapshots — the auditable record of "what entered/left the world and when."

Family 6 — Tripwires (declarative, active)

  1. Policy tripwires. Declarative rules that fire on delta: "no new native FFI in transitive deps", "no dep added without provenance", "no dep from registry X", "capability surface may not grow without review".
  2. Threshold tripwires. "centrality of an unverified dep crossed T", "entropy spike > σ", "capability set grew by ≥ k".
  3. Honeytoken / canary. Planted markers that fire if a watched internal name or secret-shaped token is exfiltrated/resolved externally.

Family 7 — Temporal (warehouse-backed — where skade/Iceberg earns its keep)

  1. World time-travel. Iceberg snapshot = "what did the dep world look like on date X"; diff any two points; reconstruct the full provenance timeline of any dep.
  2. Change-velocity baselines. Per-dep historical change-rate model; flag deviations (sudden burst, or suspicious freeze-then-spike).

Compute tiers

Recommended first slice (when Engine B starts, post-demo)

  1. WorldSnapshot capture — persist the resolved dep graph + SCIP symbol/edge facts into skade Iceberg tables (world_snapshots, dep_edges, scip_symbols).
  2. diff() → BehaviorDelta — Family-1 #1 (call-graph delta) + #2 (capability drift) as the first two real signals; emit Tripwire events.
  3. #4 reachability-gated vuln prioritization — immediately makes Engine A's CVE verdicts precise (reachable vs merely-present), the highest user-visible win.
  4. Then layer #11 blast-radius centrality (cheap, high value) and #18 embedding-novelty (reuses the existing embedder).

All of the above are leaf-clean: SCIP/knowledge machinery is lifted into modgunn; persistence is modgunn → skade; nornir remains the consumer (viz pane + tripwire feed). See nornir/.nornir/modgunn-security-scanner.md.