Swazee mark Product (type slug) Tool (chevron-wrench) Experiment (4-point star) Active (filled diamond) Shipped (hollow diamond) Shelved (diamond + slash) External link (↗) Search (angular magnifier) Filter (funnel) Close / Esc (chunky X) Move down (j) Move up (k) Return / Enter
SWAZEENET
VOL. I · NO. 01 · EST. MCMLXXXVII
BROADSIDE 12 active · 2026·05·14
№ 02 · tool · Rust 1.76+ · 2026—

xiphos,
a security engine with rules of its own.

A Rust security engine for OSS supply chains. SAST, SCA/SBOM, secrets, IaC, WASM plugins, SARIF 2.1 out, CWE/OWASP/CVSS on every finding.

rust sast supply-chain

Xiphos is a single-binary scanner that fans out to AST-based static analysis (tree-sitter), SCA + SPDX/CycloneDX SBOM, secret detection, IaC misconfig, and a Wasmtime-hosted plugin surface for community rules. Output is SARIF 2.1.0 with CWE / OWASP / CVSS metadata on every finding. As of writing, the workspace is an architectural skeleton --- the layering rules and RFCs exist before the crates do, on purpose.

ITech scope

IIArchitecture

The pipeline runs in one direction. xiphos-cli builds a ScanRequest from flags + config; xiphos-scanner walks the source tree using the ignore crate for .gitignore / .xiphosignore semantics, classifies files by language and content sniff, and schedules AnalysisUnits onto a Rayon pool sized to min(num_cpus, --jobs). Capability scanners consume units and produce Vec<Finding> into a deduplicating FindingSet; the WASM plugin host runs after that and may add or decorate findings but never delete them; the LLM decorator runs last and may downgrade severity with justification; finally, xiphos-sarif emits canonical SARIF 2.1 with the CWE / OWASP / CVSS metadata attached.

Determinism is a hard contract. Same inputs → byte-identical canonical JSON, regardless of thread count, OS, or wall-clock time. Finding.id is a content hash over (rule_id, location_fingerprint, message_template) only — time, env vars, machine identifiers, and absolute paths are explicitly excluded by the schema. tests/determinism.rs runs every scanner twice and byte-diffs the output; CI rejects any change that breaks the diff. The canonical-JSON encoder sorts object keys, freezes float formatting to 17-digit shortest-round-trip, and rejects NaN / Infinity, so the contract holds across serde versions.

Layering is enforced, not aspirational. xiphos-core has zero I/O, zero async, zero workspace-internal deps, and zero std::time calls. cargo xtask check-layers walks Cargo.toml across the workspace and refuses a violation; CI runs it on every PR. Crates above core in the layering DAG can use I/O and async freely, which is what allows the scanner orchestrator and the plugin host to stay readable while the core remains a pure library.

IIIThreat model and constraints

IVLayering and crate map

The 12-crate workspace exists today as Cargo.toml declarations and three accepted RFCs — the architectural skeleton on top of which the implementation will be poured. Every crate has a written purpose statement and a layering position before any code lands, which is the only way to keep determinism and the layering rule honest once contributors arrive.

Fig. I.
01CLI 02scanner 03capabilities 04FindingSet 05WASM plugins 06LLM decorate 07SARIF 2.1
as of 2026-04-26
Fig. II.
scanner 800 16% sast 700 14% core 600 12% sca · 500 plugin · 450 secrets · 400 iac · 350 heuristic · 300 llm sarif rules cli
12 crates declared in Cargo.toml workspace · 0 LOC implemented as of 2026-04-26

VSurface

Today the surface is the workspace and the architecture document — the crates declared in Cargo.toml are intent, not yet implementation. The eventual end-user binary is xiphos-cli, the only crate that will carry a bin target. xiphos scan, xiphos sbom, and xiphos plugin compose into one binary; capability scanners (sast, sca, secrets, iac, heuristic) live in their own crates and only see the work the orchestrator hands them. Plugins are WebAssembly components against the xiphos:plugin@0.1.0 WIT world; capabilities are default-deny and per-call enforced inside the host, not in the scanner that called the plugin — which is what makes a “the plugin asked for HTTP egress” finding traceable to a specific grant rather than buried in a transitive dependency.

VINumbers

The numbers above are honest about the stage. 12 crates declared, 0 implemented — the workspace is the architectural skeleton on top of which the code will be poured, and the layering rules and RFCs exist before the crates do, on purpose. MSRV 1.76 is firm; cargo features that landed in 1.77+ are not available, which keeps the toolchain story compatible with corporate Rust toolchains that lag a few releases. unsafe_code = "deny" applies workspace-wide with one fenced exception in the Wasmtime glue, where the component-model FFI requires it. Determinism is the load-bearing contract: same inputs → byte-identical canonical SARIF, regardless of thread count, OS, or wall-clock time. Finding.id is a content hash over (rule_id, location_fingerprint, message_template) only; time, env vars, machine identifiers, and absolute paths are excluded by schema, and tests/determinism.rs byte-diffs every scanner’s output across two runs to keep that contract honest.

:/ ESC