Skip to content

litatoli-scan

One command from a source tree to a sealed, clause-attributed evidence chain.

litatoli-scan ./src --standard iec62304 --languages c
IEC 62304  ./src
  functions scanned : 1
  findings          : 1
    required    : 1
  required   IEC62304-5.5     ./src/pump.c:1  factorial is recursive (direct or indirect).

sealed into .litatoli/evidence/chain.jsonl
head: 59b9968bfade3addcda071e43fa6264c946c1e9e8d1e1e65d01441e200708ce3

What it is for

Producing a clause-attributed chain meant assembling four installs and writing the glue yourself: run the structural scan, reshape each finding, shell out to litatoli attest once per claim, then dig the head out of the log so it could be pinned. The glue was short. Every adopter wrote it again, and the ones who did not write it got no evidence at all.

Nothing here is new capability. It is the assembly, done once.

Installing it

This does not install from public PyPI yet, and neither do its engines. Saying otherwise would send you to the wrong packages — see below.

pip install -e .                    # this package

# The two engines, neither of which is on a public index:
#   lisaba          — standards registry + structural evaluator
#     pip install -e /path/to/lisaba
#     plus the data package for your standard, e.g. lisaba-std-iec62304
#   muundo         — the typed code graph the rules are evaluated against
#     built from its repository: `maturin build --release` in python/,
#     then pip install the resulting wheel

Neither engine is on a public index yet, so both are built from their repositories. muundo was named for exactly this moment: the previous name, codemap, was already taken on PyPI and crates.io by unrelated projects, and an import-name collision makes a missing engine look like a bug in this tool.

Neither engine is declared as a dependency of this package, deliberately: a declared dependency fails at resolution, where nothing can explain itself, while a missing engine at call time produces an error that says what is absent and how to obtain it.

The litatoli binary is not a Python dependency either. It is resolved from PATH at run time — the same seam Jagora uses — because the evidence layer must not become an artefact of any one caller. Point at a specific build with --litatoli /path/to/litatoli when you have pinned one.

The [iec62304], [do178c], [iso26262], [en50128], [iec62443] and [iec61511] extras name the standard data packages, and will work the day those are reachable from an index you configure. The [ai-act] extra is installable the same way but has no code tier: a scan against ai_act refuses with StandardHasNoCodeTier rather than returning an empty result — the pack is there for the clause set, not the scanner.

Two decisions worth knowing about

A clean tree still produces evidence. The run is sealed before any finding, so a tree with nothing wrong yields a chain saying this standard, this tree, these rules, nothing found — rather than an empty file. "We found nothing" is a claim somebody will want signed; an empty log proves only that a log exists.

Findings do not fail the command by default. Producing evidence and deciding what blocks a release are different jobs, and the second one is yours — under your standard, with your risk analysis. --fail-on required opts into gating for CI. A tool that exits non-zero on every advisory finding gets removed from the pipeline, and then there is no evidence at all.

Verifying what you produced

The command prints the chain's head and the exact invocation to check it. Record the head. Verification without it cannot detect entries removed from the end of a log — the remainder stays correctly numbered and correctly signed, so there is nothing left to find. See docs/first-chain/ for a worked example including three deliberately broken chains.

litatoli verify-chain --log-file .litatoli/evidence/chain.jsonl \
    --expected-pubkey <your key> --expected-head <the head printed above>

Scope

Structural rules — recursion, cyclomatic complexity, function size, fan-out — evaluated against a real code graph and attributed to the clause each rule serves. --import-sarif absorbs a certified linter's report into the same chain.

This is not a substitute for the qualified tools your standard requires. It is the record that they ran, on which code, with what result, sealed so the record cannot quietly change afterwards.