Legacy Scanner SDK
ScannerSdk is the opt-in Legacy facade for applications that compose the
historical ordered phase runner. It is not the Preview deterministic assessment
SDK and is not a v1 compatibility baseline. Hosts supply ScanPhase
implementations; Termivar owns ordering, per-phase timeouts, cancellation context,
lifecycle events, and the typed run-report boundary.
Generate a scanner
cargo install cargo-generate
cargo xtask generate scanner my-scanner
cd my-scanner
cargo test
The generated project contains a complete custom phase and an executable
scanner using this Legacy facade. During alpha it tracks Termivar main; pin and
review an exact commit before distribution. Generating a project does not make
the facade stable or move it into the default deterministic product.
Compose directly
use async_trait::async_trait;
use termivar_scanner::{Result, ScanContext, ScanFinding, ScanPhase, ScannerSdk};
struct Headers;
#[async_trait]
impl ScanPhase for Headers {
fn phase_number(&self) -> u8 { 10 }
fn name(&self) -> &'static str { "headers" }
async fn execute(&self, context: &ScanContext) -> Result<Vec<ScanFinding>> {
Ok(vec![ScanFinding {
phase: self.phase_number(),
module_name: self.name().into(),
severity: "INFO".into(),
description: "Custom phase executed".into(),
evidence: context.target.to_string(),
}])
}
}
# async fn example() -> Result<()> {
let scanner = ScannerSdk::builder().phase(Headers).build();
let report = scanner.scan("https://example.test").await?;
assert_eq!(report.outcomes().len(), 1);
assert_eq!(report.outcomes()[0].confidence().parts_per_million(), 0);
# Ok(())
# }
Boundary
- A phase owns historical heuristic behavior and returns compatibility records.
- The SDK owns execution policy and shared runtime context.
- The public SDK result is
termivar_core::RunReport; phase errors, timeouts, cancellation, and panics while polling phase execution remain visible as typed step state. - Raw phase descriptions/evidence and telemetry do not cross the public report
boundary. Compatibility records become informational
Unknownobservations with zero confidence and no fabricated evidence IDs. Only the built-in, allowlisted SQL-behavior, template-arithmetic, and local-file-canary paths can instead publish verifier-owned, knowledge-onlyNeedsReviewoutcomes. - Whole-run request/byte dimensions are explicitly
Unmeteredbecause custom phases and built-in phase one can retain raw transport authority. The bounded phase-two-to-four discovery and phase-five-to-nine active-verification slices are not complete-run accounting; only elapsed wall time is observed at the report boundary. - A host may provide an event bus, finite
DiscoveryLimitsandVerificationLimitsenvelopes, and a configured raw HTTP client through the builder. The raw client is used only by phase one and custom phases; built-in phases two through four use an isolated passive broker, and built-in phases five through nine use a distinctActive-stage broker. - Product policy, UI, report rendering, and transports remain outside phase implementations.
- New product capabilities belong under the deterministic
StandardWebDecisionRuntime/WebAssessmentRuntimeauthority rather than adding behavior to this Legacy runner.
ScanContext is non-exhaustive and runtime-constructed. Extensions borrow it,
use its methods and documented public handles, and must not depend on struct
literals. Access reasoning state through ScanContext::knowledge(). Consumers
moving from the tagged v0.9 contract or from unreleased main should follow the
ScanContext construction migration.
This is a Legacy source-level facade. The deterministic assessment and typed
report contracts remain Preview, as does the separate host-owned, evidence-only
plugin API 0.2 described by the
Plugin API and SemVer policy. Plugins still cannot
author findings, severities, verifier outcomes, or Confirmed dispositions.
Within compat/current-head/, which has one dedicated lockfile, the separately
invoked Scanner SDK consumer proves only that an empty historical scanner can
be built through the public facade at the same checkout. It is not a
prior-release comparison, accepted v1 baseline, deprecation commitment,
published-crate integration, or external-adoption result. Broader scanner
compatibility remains governed by release notes, accepted ADRs, and the
explicit baseline status in Public API compatibility status
and Repository health.
The ordered runtime boundaries are recorded in ADR 0016 and ADR 0018.