weft
MIT · foundryside-dev GitHub

Wardline · trust-boundary analysis · Python

Is the data each trust-annotated function works with as trusted as it claims?

A semantic-tainting static analyzer with zero runtime dependencies. It propagates a taint lattice across the call graph and flags untrusted data reaching a trusted producer with no validation between. It reads your Python statically — it never runs your code.

Python madder v1.0.3 · snapshot; see repo
exit 0· clean exit 1· gate tripped exit 2· error
$ wardline dossier service.build_record
one entity → typed trust facts; absent peers shown as absent, never as clean…
loomweave:eid:7f3a9c2e1b… wardlinepresent loomweavepresent warplinepresent filigreeabsent legisunavailable

What it is · the honesty mechanic

Silent until you decorate. Silence is not a clean bill.

Wardline asks one question of every function: is the data it works with as trusted as it claims to be? It answers that by tracking a trust level — a taint — for every value and propagating it across the whole project. But it says nothing until you mark a trust boundary.

absent ≠ clean — the rule this whole page exists to teach.
Code with no trust decorators sits in the developer-freedom zone: the engine treats it as unknown-trust and raises no policy findings about it. An empty result is not a clean bill of health — it means you have not yet told Wardline what to guard. You declare trust on the functions that matter, and only then does it enforce. That is what lets it scan a large untouched codebase, including its own source, with zero noise — and it is why a quiet scan must never be read as a pass.

You declare trust with three marker decorators (the only three you write):

@external_boundary marks a source — its return carries raw, untrusted data (EXTERNAL_RAW).
@trust_boundary(to_level=…) marks a validator — it takes raw input and raises its trust on the way out (to GUARDED or ASSURED).
@trusted(level=…) marks a trusted producer — it works on and returns trusted data (INTEGRAL by default).

The full eight-state lattice — INTEGRAL → ASSURED → GUARDED → UNKNOWN_ASSURED → UNKNOWN_GUARDED → EXTERNAL_RAW → UNKNOWN_RAW → MIXED_RAW — runs most-trusted to least-trusted; less-trusted always wins. You write only three levels; the UNKNOWN_* and MIXED_RAW states are the engine's honest record of what it could and could not prove. The states, the decorator vocabulary, and the rule IDs are Wardline's authority — see the model and rules in the repo.

Key capabilities

Scan, gate, explain, attest — and hand the verdict off.

Propagate taint across the call graph

A function is only as trusted as the least-trusted value it returns — and that flows transitively across files. Decorate your boundaries and producers; the engine works out everything in between by following the calls. The boundary-integrity rule family holds a validator to actually being able to reject input — a boundary that cannot say "no" is just relabelling untrusted data.

Gate a build, deterministically

wardline scan . --fail-on ERROR exits non-zero when a finding at or above a level is present. The exit convention is a contract: 0 clean, 1 gate tripped, 2 error.

exit 0· clean exit 1· gate tripped exit 2· error

Explain a finding's provenance

wardline explain-taint (or the MCP explain_taint tool) walks why the gate tripped — the path the taint took from a source to the trusted producer that declared more than it returns.

Many emitters, one engine

JSONL, SARIF 2.1.0, agent summaries, native Filigree emission, and signed Legis governance artifacts all compose with the same scanner path. The rule family PY-WL-1xx and the decorator vocabulary are the repo's authority — pointers, not restated here.

Usage snapshot

From install to a gated build.

The wardline scan CLI lives in the scanner extra. This is the curated quick-start — the deep CLI and MCP reference live under this site's own docs paths.

# install the scanner CLI
pip install "wardline[scanner]"

# mark a boundary, then scan and gate
wardline scan . --format jsonl --fail-on ERROR

# scanned 2 file(s); 4 finding(s) — 1 active -> findings.jsonl
#   PY-WL-101  service.current_user  declares INTEGRAL, returns EXTERNAL_RAW

# ask why the gate tripped
wardline explain-taint --rule PY-WL-101 service.current_user

# agents run the same loop over MCP — no terminal scraping
wardline mcp

The product loop: mark the boundary (@external_boundary / @trust_boundary / @trusted) → wardline scan --fail-on ERRORexplain-taint → fix the validation at the boundary and rescan. See the getting-started guide and the CLI reference for the full surface.

How it composes · value is the weave

Each pairing lights up a capability Wardline does not have alone.

Wardline analyses; it does not enforce — Legis governs. Every pairing's status is honest on its face; a partial or planned pair is never rendered as live. The partner mark links to that tool's site.

Wardline Loomweave live

Structure + trust posture in one view — the dossier.

Wardline Filigree live

Findings become tracked work.

A-1: native emitter shipped; asterisk stays live until the Loomweave-absent path is proven end-to-end (currently unit/server-wiring tier).

Wardline Legis live

Agent-defined policy enforced at the CI/git boundary.

Wardline Warpline partial

Change-impact enriched with trust posture (risk-weighted blast radius).

Enrichment shipped: warpline annotates the change-impact worklist with wardline trust findings (advisory). The risk-weighted re-ranking of the blast radius is not yet built.

Status & honest limits

What it is, and what it is not.

  • Silence is opt-in, not clean. Undecorated code is unknown-trust by design; an empty result means you have not declared a boundary yet, not that the code is safe.
  • Exit codes are a contract. 0 clean · 1 gate tripped · 2 error. A clean run is earned, never the default.
  • Findings → work (A-1 asterisk). The native Wardline→Filigree emitter has shipped, but the asterisk stays live until the Loomweave-absent path is proven end-to-end (currently unit/server-wiring tier) — see the matrix note above.
  • Identity is consumed, never minted. Wardline keys its facts on the SEI, treats it as opaque, and never mints one — Loomweave is the identity authority (the SEI spine).
  • Rust support is a preview. The command-injection frontend is an early preview; Python is the supported surface.

Want to see it actually run?

Lacuna, the demonstration specimen, seeds PY-WL-101..126 for exactly this — watch Wardline analyze a small app with catalogued flaws.

See it on the specimen → Read the doctrine →