# Reachability Drift Detection - Architecture

Module: Scanner Version: 1.1 Status: Implemented (core drift engine + API; Node Babel integration pending; tier-2 router wiring complete — Sprint 20260512_032). Last Updated: 2026-05-13


1. Overview

Reachability Drift Detection tracks function-level reachability changes between scans. It highlights when code changes create new paths to sensitive sinks or remove existing paths, producing deterministic evidence for triage and VEX workflows.

Key outcomes:


2. Key Concepts

2.1 Call Graph

A directed graph of function calls:

2.2 Reachability Analysis

Multi-source traversal from entrypoints to sinks to determine exploitability.

2.3 Drift Detection

Compares reachability between base and head scans:

2.4 Cause Attribution

Explains why drift happened by correlating code changes with paths.


3. Data Flow

flowchart TD
    A[Source or binary] --> B[Call graph extractor]
    B --> C[CallGraphSnapshot]
    C --> D[Reachability analyzer]
    D --> E[ReachabilityResult]
    C --> F[Code change extractor]
    E --> G[ReachabilityDriftDetector]
    F --> G
    G --> H[ReachabilityDriftResult]
    H --> I[Storage + API]

4. Component Architecture

4.1 Call Graph Extractors

Registered extractors are configured in CallGraphServiceCollectionExtensions. The drift API tier is set by IDriftLanguageRouter (src/Scanner/__Libraries/StellaOps.Scanner.ReachabilityDrift/Routing/DriftLanguageRouter.cs), which is the canonical source of supported languages and alias normalization. Tier-1 aliases: csharp/c#/cs/.net/net -> dotnet, nodejs/javascript/js/typescript/ts -> node, golang -> go, py -> python, jvm -> java. Tier-2 aliases (SPRINT_20260512_032): bunjs -> bun, rb -> ruby, rs -> rust; deno and php have no aliases. The GET /api/v1/scans/{scanId}/drift endpoint returns HTTP 400 for any language outside the union of tier-1 and tier-2 sets (currently cobol, binary, and any unrecognised value).

LanguageExtractorStatusNotes
.NETDotNetCallGraphExtractorWired (tier 1)Roslyn semantic model; ASP.NET controllers, minimal APIs, hosted services, CLI main.
JavaJavaCallGraphExtractorWired (tier 1)ASM bytecode parsing; Spring MVC, JAX-RS (javax + jakarta), Servlet, Micronaut, Quarkus, CLI main.
GoGoCallGraphExtractorWired (tier 1)SSA analysis; net/http, gin, echo, chi, fiber, gorilla/mux, gRPC, cobra CLI.
PythonPythonCallGraphExtractorWired (tier 1)AST analysis; Flask, FastAPI, Django, Celery, CLI main.
Node.jsNodeCallGraphExtractorWired (tier 1)Babel AST / trace fallback; Express, Fastify, Next.js, Hapi, Koa, AWS Lambda.
BunBunCallGraphExtractorRouter wired (tier 2, SPRINT_20260512_032)Bun.serve / Elysia / Hono routes, @cron/@scheduled annotations, WebSocket handlers. Extractor registration pending follow-up sprint.
DenoDenoCallGraphExtractorRouter wired (tier 2, SPRINT_20260512_032)Deno.serve, Fresh handler exports, Oak / Hono routes, Deno Deploy handlers, Deno.cron, WebSocket. Extractor registration pending follow-up sprint.
PHPPhpCallGraphExtractorRouter wired (tier 2, SPRINT_20260512_032)Symfony route attributes, Laravel *Controller actions, Job/Listener handle(), Symfony Command::execute, scheduled tasks. Extractor registration pending follow-up sprint.
RubyRubyCallGraphExtractorRouter wired (tier 2, SPRINT_20260512_032)Rails controllers (CRUD + public), Sinatra::Base / Grape::API, Sidekiq/ActiveJob perform/call, rake tasks, *CLI/*Command. Extractor registration pending follow-up sprint.
RustRustCallGraphExtractorRouter wired (tier 2, SPRINT_20260512_032)tokio/async_std main, actix-web / axum / rocket / warp / tonic, AWS Lambda runtime, clap CLI, FFI export. Extractor delivered by Sprint 030; registration pending follow-up sprint.
JavaScriptJavaScriptCallGraphExtractorLibrary present, not router-wired (tier 3)Use node (tier 1) for Node.js code; standalone JS pending.
BinaryBinaryCallGraphExtractorLibrary present, not router-wired (tier 3)Native call edge extraction.

4.2 Reachability Analyzer

Located in src/Scanner/__Libraries/StellaOps.Scanner.CallGraph/Analysis/.

4.3 Drift Detector

ReachabilityDriftDetector compares base and head snapshots and produces ReachabilityDriftResult with compressed paths.

4.4 Path Compressor and Cause Explainer


5. Language Support Matrix

Sprint 20260512_032 (TASK-032-04) extended the drift router to ten canonical languages. Tier-1 has full extractor + classifier + drift wiring. Tier-2 has router recognition (alias normalization + HTTP 200 instead of 400) and an existing classifier source documenting recognised framework patterns; the extractor registration in CallGraphServiceCollectionExtensions is still pending a follow-up sprint.

CapabilityTier-1 (.NET, Java, Go, Python, Node)Tier-2 (Bun, Deno, PHP, Ruby, Rust)Tier-3 (JavaScript-standalone, Binary)
Drift router (IDriftLanguageRouter)Wired (Sprint 031)Wired (Sprint 032)Not wired
Call graph extractionSupportedLibrary present (extractor registration pending)Library present, not router-wired
Entrypoint detectionSupportedSupported (per-language <Lang>EntrypointClassifier.cs)Library present, not router-wired
Sink detectionSupportedSupported (per-language <Lang>SinkMatcher.cs)Library present, not router-wired

Per-tier-2 framework conventions recognised by the existing classifiers (pinned in DriftLanguageRouterTests.Frameworks_<Lang>_Match_..._Conventions):

LanguageAliasesFrameworks (documentation surface)
bunbunjsbun-serve, elysia, hono, scheduled-cron, websocket
deno(none)deno-cron, deno-deploy, deno-serve, fresh, hono, oak, websocket
php(none)laravel-controller, laravel-job, laravel-listener, laravel-scheduled, symfony-command, symfony-route
rubyrbgrape, rails-cli, rails-controller, rake-task, sidekiq, sinatra
rustrsactix-web, aws-lambda, axum, clap-cli, ffi-export, grpc-tonic, rocket, tokio-main, warp

The drift API supported set is the canonical contract; adding a new tier (e.g. JavaScript-standalone) requires a sprint task that:

  1. Extends DriftLanguageRouter.BuildTier2Descriptors() (or a new BuildTier3Descriptors() helper) with the new descriptor + alias list + framework list — matching the patterns already recognised by the corresponding <Lang>EntrypointClassifier.cs source;
  2. Registers the corresponding ICallGraphExtractor in AddCallGraphServices();
  3. Adds tier-2a behavioral coverage to ReachabilityDriftEndpointsTests.

6. Storage Schema

Migrations are in src/Scanner/__Libraries/StellaOps.Scanner.Storage/Postgres/Migrations/.

Core tables:


7. Cache and Determinism

If the call graph cache is enabled (CallGraph:Cache), cached keys follow this pattern:

Determinism is enforced by stable ordering and deterministic IDs (see DeterministicIds).


8. API Endpoints

Base path: /api/v1

MethodPathDescription
GET/scans/{scanId}/driftGet or compute drift results for a scan.
GET/drift/{driftId}/sinksList drifted sinks (paged).
POST/scans/{scanId}/compute-reachabilityTrigger reachability computation.
GET/scans/{scanId}/reachability/componentsList components with reachability.
GET/scans/{scanId}/reachability/findingsList findings with reachability.
GET/scans/{scanId}/reachability/explainExplain reachability for a CVE and PURL.

See docs/api/scanner-drift-api.md for details.


9. Integration Points


10. Performance Characteristics (Targets)

MetricTargetNotes
Call graph extraction (100K LOC)< 60sPer language extractor.
Reachability analysis< 5sBFS traversal on trimmed graphs.
Drift detection< 10sGraph comparison and compression.
Cache hit improvement10xValkey cache vs recompute.

11. References