tools capa

tools-boundary-scan

Taint-shape scanner: finds functions where a value reaches a sink (SQL, shell, file write, ...) without evidence that the security boundary the sink implies (tenant, auth, privilege, filesystem, process) was checked at the sink itself, as opposed to only upstream. Emits deidentified JSON (file/function/line/category, no source or SQL text) so findings can be handed to a fix pass without shipping code off-box. Candidates for manual review, per Gate 1.5, same discipline as confinement-scan/stub-scan.

Taint-shape scanner: finds functions where a value reaches a sink (SQL, shell, file write, ...) without evidence that the security boundary the sink implies (tenant, auth, privilege, filesystem, process) was checked at the sink itself, as opposed to only upstream. Emits deidentified JSON (file/function/line/category, no source or SQL text) so findings can be handed to a fix pass without shipping code off-box. Candidates for manual review, per Gate 1.5, same discipline as confinement-scan/stub-scan.

Tiertools
Roleunclassified (baselined)
Pathcrates/tools/boundary-scan
Edition2021
Targetstools-boundary-scan, tools_boundary_scan
Public items42 across 4 modules
Tests24

What it is for

Taint-shape scanner.

Models a request's path as Source -> Transformation* -> SecurityBoundary* -> Sink and looks for functions where a Sink is reached without evidence that the SecurityBoundary a caller-controlled value implies was checked AT THE SINK, as opposed to only somewhere upstream in the same function. That gap — a boundary asserted once, then not re-checked where the dangerous operation actually happens — is what let list_relationships_for_party_for_tenant (crates/identity/parties/src/repo.rs) read across tenants until it was fixed this session: party_belongs_to_tenant checked the ANCHOR party in code, but the paginated SQL itself never mentioned tenant_id, so the OTHER endpoint of the relationship was never constrained. Now fixed (a parties join on the other endpoint); see the_relationships_list_gap_stays_fixed below.

Only one concrete rule is implemented: Sink::Sql + SecurityBoundary::Tenant, triggered when a function's signature declares a tenant_id-shaped parameter and its body calls sqlx::query*. The rest of the taxonomy below is modeled as data (so findings from a future rule slot into the same shape) but has no detector yet — do not read a variant's presence in the enum as a claim that this scanner checks it.

# Deidentified output

A Finding carries file/function/line and taxonomy tags — never source text or SQL text. The scanner is meant to hand findings to a fix pass (human or model) that re-reads the named function from the file itself; nothing about the code needs to leave the box in the finding.

Candidate list for manual review, like tools-confinement-scan/tools-stub-scan — not a hard gate.

Capabilities

Finding

Taint-shape scanner.

Item
pub struct Finding
Finding :: fn to_envelope(& self) -> report::Envelope
fn scan_file(path : & Path, rel : & str) -> Result <Vec <Finding>>
fn scan(root : & Path) -> Result <Vec <Finding>>

FnSpan

Taint-shape scanner.

Item
pub struct FnSpan
fn find_functions(chars : & char, code : & str) -> Vec <FnSpan>

Kind

Taint-shape scanner.

Item
pub enum Kind
fn classify(src : & str) -> Vec <Kind>
fn code_only(chars : & char, kinds : & Kind) -> String

SecurityBoundary

Taint-shape scanner.

Item
pub enum SecurityBoundary

Sink

Taint-shape scanner.

Item
pub enum Sink

Source

Taint-shape scanner.

Item
pub enum Source

Status

Taint-shape scanner.

Item
pub enum Status

Transformation

Taint-shape scanner.

Item
pub enum Transformation

pattern (other)

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
pub const CANONICAL_BOUNDARIES: & & str
pub const CANONICAL_SINKS: & & str

AnalysisLevel

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
pub enum AnalysisLevel

Instance

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
pub struct Instance

Pattern

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
pub struct Pattern

PatternRegistry

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
fn lint_unknown_vocabulary(registry : & PatternRegistry) -> Vec <String>
pub struct PatternRegistry
PatternRegistry :: fn load(path : & std::path::Path) -> anyhow::Result <Self>
PatternRegistry :: fn save(& self, path : & std::path::Path) -> anyhow::Result <()>

RepairRationale

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
pub struct RepairRationale

ScannerRuleStatus

The learning-loop half of tools-boundary-scan: capturing why a repair was

Item
pub enum ScannerRuleStatus

pseudonym (other)

Deterministic identifier pseudonymization, scoped per finding.

Item
fn code_mask(kinds : & crate::Kind) -> Vec <bool>

PseudoMap

Deterministic identifier pseudonymization, scoped per finding.

Item
pub struct PseudoMap
PseudoMap :: fn new(finding_id : & str) -> Self
PseudoMap :: fn load_or_new(cache_dir : & Path, finding_id : & str) -> Result <Self>
PseudoMap :: fn save(& self, cache_dir : & Path) -> Result <()>
PseudoMap :: fn assign(& mut self, real : & str, slot : Slot) -> String
PseudoMap :: fn real_of(& self, pseudonym_or_real : & str) -> String
fn pseudonymize_slice(raw : & str, code_mask : & bool, param_names : & String, fn_real_name : & str, map : & mut PseudoMap,) -> String

Slot

Deterministic identifier pseudonymization, scoped per finding.

Item
pub enum Slot

repair_log (other)

Durable, append-only log of the shard-repair lifecycle — shared by every

Item
fn default_log_path(workspace_root : & Path) -> std::path::PathBuf
fn now_unix_seconds() -> u64

Event

Durable, append-only log of the shard-repair lifecycle — shared by every

Item
pub enum Event

LogEntry

Durable, append-only log of the shard-repair lifecycle — shared by every

Item
pub struct LogEntry
fn append(log_path : & Path, entry : & LogEntry) -> Result <()>
fn read_all(log_path : & Path) -> Result <Vec <LogEntry>>

report (other)

One reporting shape shared by every scanner in this family

Item
fn finding_id(prefix : & str, file : & str, function : & str, line : usize) -> String

Envelope

One reporting shape shared by every scanner in this family

Item
pub struct Envelope

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

tools_boundary_scan

flowchart TD
  n_tools_boundary_scan["tools_boundary_scan"]
  n_tools_boundary_scan --> n_pattern["pattern"]
  n_tools_boundary_scan --> n_pseudonym["pseudonym"]
  n_tools_boundary_scan --> n_repair_log["repair_log"]
  n_tools_boundary_scan --> n_report["report"]

Public surface

`crate root`

ItemWhat it is
pub enum Source
pub enum Transformation
pub enum SecurityBoundary
pub enum Sink
pub enum StatusWhere the boundary evidence was found relative to the sink, or that it wasn't found at all.
pub struct Finding
Finding :: fn to_envelope(& self) -> report::EnvelopeThe standardized cross-tool reporting shape — see report module.
pub enum Kind
fn classify(src : & str) -> Vec <Kind>Classify every char in src as code, comment, or string content
fn code_only(chars : & char, kinds : & Kind) -> StringA code-only view (comments AND strings blanked to spaces) for brace matching and identifier search — same length as src.chars()
pub struct FnSpan
fn find_functions(chars : & char, code : & str) -> Vec <FnSpan>
fn scan_file(path : & Path, rel : & str) -> Result <Vec <Finding>>
fn scan(root : & Path) -> Result <Vec <Finding>>

`pattern`

ItemWhat it is
pub struct RepairRationaleWhat the model determined, for one finding, after producing a fix
pub enum AnalysisLevelHow much program understanding a detector needs — cheapest first
pub enum ScannerRuleStatus
pub const CANONICAL_BOUNDARIES: & & strCanonical boundary/sink values in current use, for the optional lint below — NOT a hard enum
pub const CANONICAL_SINKS: & & str
fn lint_unknown_vocabulary(registry : & PatternRegistry) -> Vec <String>Best-effort, informational only -- returns unrecognized boundary/sink strings found in the registry, never a hard failure
pub struct InstanceOne detector's manifestation of a Pattern -- boundary/sink are free strings (see CANONICAL_BOUNDARIES/CANONICAL_SINKS), deliberately NOT crate::SecurityBoundary/crate::Sink (those stay detector-internal to tools-boundary-scan; the registry must not force every future detector to share tools-boundary-scan's own enum).
pub struct PatternGate 1.5 decision (2026-08-11, Q1): GUC-name-drift and the advisory-lock check are NOT instances of PAT-001 -- different failure mechanism (activation/coordination failure, not "missing at the sink") and different evidence/remediation
pub struct PatternRegistry
PatternRegistry :: fn load(path : & std::path::Path) -> anyhow::Result <Self>
PatternRegistry :: fn save(& self, path : & std::path::Path) -> anyhow::Result <()>

`pseudonym`

ItemWhat it is
pub enum Slot
pub struct PseudoMap
PseudoMap :: fn new(finding_id : & str) -> Self
PseudoMap :: fn load_or_new(cache_dir : & Path, finding_id : & str) -> Result <Self>
PseudoMap :: fn save(& self, cache_dir : & Path) -> Result <()>
PseudoMap :: fn assign(& mut self, real : & str, slot : Slot) -> StringGet-or-assign the pseudonym for real in slot
PseudoMap :: fn real_of(& self, pseudonym_or_real : & str) -> StringResolve a pseudonym back to its real name, if known to this map.
fn pseudonymize_slice(raw : & str, code_mask : & bool, param_names : & String, fn_real_name : & str, map : & mut PseudoMap,) -> StringRename identifiers in raw (a code slice, chars, code_mask same length as raw.chars(), code_maski true where i is real code, not string/comment content) using map, seeding parameter names from param_names as Slot::Arg before the general pass.
fn code_mask(kinds : & crate::Kind) -> Vec <bool>Code-region mask for a chars, kinds slice — true where kindsi is Kind::Code (as opposed to string or comment content).

`repair_log`

ItemWhat it is
pub enum Event
pub struct LogEntry
fn default_log_path(workspace_root : & Path) -> std::path::PathBuf
fn append(log_path : & Path, entry : & LogEntry) -> Result <()>
fn now_unix_seconds() -> u64
fn read_all(log_path : & Path) -> Result <Vec <LogEntry>>

`report`

ItemWhat it is
fn finding_id(prefix : & str, file : & str, function : & str, line : usize) -> StringDeterministic, content-addressed finding id: same (file, function, line) always produces the same id, independent of scan order or which index a site happened to be at in a particular run
pub struct Envelope

No pub use re-exports: every item above is declared in this crate.

Boundary

Depends on no other workspace tier.

Shares tier tools with 84 other crates: tools-advisory-reach, tools-archive-guard, tools-artifact-scaffold, tools-ask-ai-core, tools-ask-ais, tools-ask-gemini, tools-book, tools-book-report, … (84 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)tools
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/tools/boundary-scan
Vocabulary in force (lexicon)current

Dependencies

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
anyhow^1noalways
serde^1derivenoalways
serde_json^1noalways

Development. None.

Build. None.

Depended on by. 1 workspace crate.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  n_tools_advisory_reach["tools-advisory-reach"] -->|uses| SELF
  SELF["tools-boundary-scan"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
bintools-boundary-scan`src/main.rs`
libtools_boundary_scan`src/lib.rs`

Error model

No public error type was detected: no public item declares a type named *Error, and no public signature returns one.

Operational characteristics

PropertyEvidence
async public surfacenone detected
async runtimenone detected
database accessnone detected
network I/Onone detected
unsafe codenone detected
environment variablesyes

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

VariableRead in
CARGO_MANIFEST_DIRsrc/lib.rs

1 workspace crate depends on this one: tools-advisory-reach.

Verification

KindCount
Unit tests24
Integration tests0
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
crate root1304
pattern900
pseudonym404
repair_log605
report202

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc1542
Public modules with a //! block44
pie showData
    title Public items with rustdoc
    "Documented" : 15
    "No rustdoc detected" : 27

Metrics

MetricValue
Rust source files6
Source lines1927
Code lines1442
Public API items42
Public modules4
Tests24
Examples0
Cargo features0
Direct runtime dependencies3
Workspace reverse dependencies1
pie showData
    title Public API by kind
    "constant" : 2
    "enum" : 10
    "function" : 13
    "method" : 8
    "struct" : 9
pie showData
    title Rust source composition
    "Code" : 1442
    "Blank or comment" : 485

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

Todas las tools · Manual