Local Development¶
Build sceau from source and iterate against a swtpm simulator — no hardware TPM, no cluster. For installing a release on a real host, use the Guides instead.
Prerequisites¶
- Rust toolchain (1.88+).
- TPM2 TSS development libraries and
protoc(libtss2-dev protobuf-compileron Debian/Ubuntu). docker(forbuild-linux-*/docker-image).swtpmfor local TPM simulation.- Node.js (
npx) for the CALM toolchain; Poetry for the docs.
The Makefile is the source of truth¶
make help lists every target. The ones you will use daily:
| Target | What it does |
|---|---|
make build / make build-debug |
Release / debug binary via cargo. |
make test |
cargo test --all-features. |
make lint |
cargo fmt --check + clippy -D warnings. |
make audit / make deny |
cargo audit and cargo deny check (licenses, advisories, sources). |
make sbom |
CycloneDX SBOM (sceau.cdx.json). |
make calm-validate |
Validate the CALM architecture against the meta-schema (hard CI gate). |
make calm-diagrams |
Re-render the Mermaid diagrams into docs/src/architecture/. |
make build-linux-amd64 / make build-linux-arm64 |
Linux binary + staged TSS libraries under binaries/<arch>/ (runs in a rust:1-bookworm container). |
make docker-image |
Distroless image from the prebuilt binary — see Internal Registry. |
make docs / make docs-serve |
Build the docs site, or serve it with live reload at http://127.0.0.1:8000. |
The swtpm dev loop¶
# Terminal 1 — the simulator
mkdir -p /tmp/swtpm-state
swtpm socket --tpm2 \
--tpmstate dir=/tmp/swtpm-state \
--server port=2321 \
--ctrl type=tcp,port=2322 \
--flags not-need-init
# Terminal 2 — sceau against it
cargo run -- \
--socket /tmp/sceau.sock \
--tcti "swtpm:host=127.0.0.1,port=2321"
Then drive the KMS API with grpcurl as shown in the
Quickstart. The same loop
works against a remote simulator or real TPM by changing the TCTI string —
take the value from the environment rather than hard-coding a host:
SCEAU_TCTI="swtpm:host=bar.foo.io,port=2321" \
cargo run -- --socket /tmp/sceau.sock --tcti "$SCEAU_TCTI"
Logging
RUST_LOG controls verbosity (tracing-subscriber env filter):
RUST_LOG=debug cargo run -- .... The startup line always reports the
derived key_id.
Tests¶
- Tests live in separate
*_tests.rsfiles next to the code (see.claude/rules/testing.md). make testruns the full suite; TPM-dependent tests use whatever TCTI the environment provides.- End-to-end tests driving a real apiserver against a swtpm-backed sceau are on the roadmap.
Fuzzing¶
The untrusted-input parsers (envelope codec, KMS protobuf decoders) are
fuzzed with cargo-fuzz (ADR-0003); ClusterFuzzLite builds and runs the
fuzzers on every Rust-affecting PR. To run a target locally (needs nightly,
cargo install cargo-fuzz, and a Linux toolchain with libtss2-dev):
cargo fuzz run envelope_decode # KMS ciphertext envelope parser
cargo fuzz run kms_proto_decode # prost-generated request decoders
The ADD workflow for a change¶
- ADR — write
docs/adr/NNNN-title.md(Status / Context / Decision / Consequences). One decision per ADR. -
CALM — update
docs/architecture/calm/architecture.json, then: -
TDD — failing test first, then the minimum implementation, then refactor. After any
.rschange:make lint && make test. - Docs — changelog entry in
.claude/CHANGELOG.md(the**Author:**line is mandatory), README if the CLI or deployment shape changed, and these pages when behaviour or flags change. Every YAML/flag example must match the real code (src/main.rs,proto/kms/v2/api.proto) — never guess.
Building the docs¶
make docs # regenerate CALM diagrams + strict mkdocs build into docs/site/
make docs-serve # live-reload at http://127.0.0.1:8000
The site configuration is docs/mkdocs.yml; sources are docs/src/. The
system.md / flows.md architecture pages are generated — edit the CALM
model, not the rendered files.