Getting started with NaZelo Trust¶
A guided first success. You will install the stack, run one sealed command, then run a BIM-governed command that shows an ALLOW and a DENY, and finally verify the sealed chain offline.
Each step ends where nazelo-trust doctor says the next capability is READY.
Full setup detail is in INSTALL.md.
1. Install¶
pip install nazelo-trust # pulls in nazelo, pimatika, pyyaml, click
nazelo-trust doctor # → Isolate READY
For sealing you also need the litatoli binary on PATH (or point
$NAZELO_TRUST_LITATOLI_BINARY at it) and its keys:
litatoli keygen # writes ~/.config/litatoli/{signing.key,ed25519.key}
nazelo-trust doctor # → Seal READY
doctor reports the capabilities in order — isolate → seal → egress → three
bricks — and tells you exactly what each remaining one needs. For egress
enforcement and the BIM path, follow the eBPF and pimatika-cli steps in
INSTALL.md.
2. A sealed run¶
# Isolated + sealed, no network (the default policy is deny-all):
nazelo-trust run -- pytest -q
# run_id: 9f2c… · exit=0 · no egress (deny-all) · sealed → …/chain.jsonl
NaZelo isolates the command, Litatoli seals the run into a signed chain, and
egress is deny-all by default. If the command passes but the evidence cannot be
sealed, NaZelo Trust reports NOT SEALED — never a green pass.
To allow specific egress without a BIM, --allow rules are enforced by NaZelo's
own eBPF filter at the IP/port level. This turns on eBPF enforcement and requires
the eBPF tooling; NaZelo Trust refuses to run an egress-granting workload it
cannot enforce:
3. A BIM-governed run — ALLOW and DENY¶
There are two ways to run.
- Without a BIM,
--allowrules are enforced by NaZelo's eBPF filter at the IP/port level — isolation and sealing, no policy engine. - With a signed BIM, PimaTika loads and verifies it and decides each
egress semantically (target, purpose, data_class, method, payload), sealing an
EGRESS_ALLOWED/EGRESS_DENIEDwith a reason the packet layer could never give (PURPOSE_MISMATCH,TARGET_NOT_IN_USAGE_CONTRACTS, …). The allowed targets are then projected into NaZelo's eBPF filter. PimaTika decides, NaZelo enforces, Litatoli seals — onerun_id, one chain, onebim_digest.
nazelo-trust run --bim policy.signed.yaml --probe https://1.1.1.1 -- ./app
# PimaTika (bim blake3:7c39…) decided:
# ALLOW https://example.com
# DENY TARGET_NOT_IN_USAGE_CONTRACTS https://1.1.1.1
# run_id: … · exit=0 · PimaTika-decided, NaZelo-enforced · sealed → …/chain.jsonl
A committed, reproducible version of this run — with the signed BIM, the probe,
the runner, and a captured sample chain — is in
examples/conclusive/ and explained in
CONCLUSIVE-TEST.md. Run it:
sudo env \
LITATOLI_KEY_FILE=~/.config/litatoli/signing.key \
LITATOLI_ED25519_KEY_FILE=~/.config/litatoli/ed25519.key \
PATH="/path/to/litatoli/dir:$PATH" \
examples/conclusive/run.sh
Why not just nazelo run?¶
nazelo run is the engine, à la carte: it can seal to Litatoli and enforce
egress with its eBPF filter, but by default it seals nothing (a null
recorder). NaZelo Trust is the opinionated integration: sealed by default,
egress deny-all by default, and it refuses to report a run as passed when its
evidence could not be sealed.
4. Verify the chain offline¶
The same run_id is stamped onto every PimaTika egress decision, every sandbox
event, and every sealed chain entry (ADR-0005). Hand it to your dashboards, your
CI, or Litatoli directly, and one query returns everything that happened in one
run — the semantic decisions and the sandbox lifecycle, in one signed chain.
PUB=$(litatoli export-pubkey)
HEAD=$(python3 -c 'import json,sys;print(json.loads([l for l in open(sys.argv[1]) if l.strip()][-1])["blake3_signature"])' examples/conclusive/sample-chain.jsonl)
litatoli verify-chain --log-file examples/conclusive/sample-chain.jsonl --expected-pubkey "$PUB" --expected-head "$HEAD"
# → overall_ok: True · pinned-leaf · head pinned (end-truncation would fail)
Query the whole run by its run_id — a structured, signed, top-level field, not
buried in the payload:
litatoli query --log-file examples/conclusive/sample-chain.jsonl --run-id RUN-CONCLUSIVE
# the PimaTika ALLOW and DENY, the NaZelo lifecycle, and the sealed output — one chain
Machine output and the Python API¶
Bring your own correlation id (for example your CI run) and get machine output:
If you are in a Python codebase:
from nazelo_trust import TrustRun
result = TrustRun(preset="ci").run(["pytest", "-q"])
assert result.ok # command passed AND evidence sealed
print(result.run_id, result.evidence_log)
Next¶
- Operating limits — what each control proves and where it stops. Read before trusting a result.
- Disclosure policy — what leaves the machine. Read before enabling any export.
- Integration contract — what the three engines guarantee together, and what they do not.