Operator inspection and evidence
The host commands below collect observations through the existing console or gateway and package them for offline review. They explain differences; they grant no authority and do not repair target state. Missing optional facilities remain missing or unknown. They never become a health, execution, hardware, or release verdict.
Commands
Credentials use the existing host-tool environment resolution. Non-public
gateway reads need request authentication and a scoped delegated read ticket;
set COH_REST_AUTH_TOKEN and COH_REST_TICKET from the deployment’s secret
store before using the examples. When a gateway owns the target console, use
its REST URL rather than opening a second console.
For example, with that gateway already running:
coh inspect --rest-url http://127.0.0.1:8080 --json
coh evidence pack --rest-url http://127.0.0.1:8080 --out out/incident
coh inspect --input out/incident --json
coh diff --left out/before --right out/incident
coh diff --left out/incident --right http://127.0.0.1:8080
coh attest --input out/incident --json
coh evidence timeline --input out/incident --scenario incident
inspect accepts existing connection options or --input DIR for offline
inspection. It lists lifecycle, root, session, pressure, attestation, scheduling,
and lease roots and reads bounded children, boot, spool status, and policy rules.
The output orders source paths and records observed, missing, error, or
unknown, sanitized content, and stable reasons. Inventory contradictions,
unreadable captured files, malformed bounded inputs, and impossible known field
values produce a nonzero exit. Optional absence alone does not. JSON and text
carry the same observations, without a healthy/unhealthy label.
The bounded /proc listing establishes which optional roots are advertised;
an absent root is recorded as missing without issuing an invalid file read.
A failed listing or a failed read of an advertised node remains an error.
/proc/lease/by-id is a directory, including when it contains no active leases.
diff --left SOURCE --right SOURCE accepts directories (optionally pack:),
tcp://host:port, or HTTP(S) gateway URLs. It emits ordered exact field changes
as JSON; missing values remain absent and object keys use JSON-pointer escaping.
Collector metadata remains labeled as host metadata, separate from observed
target files. Differences themselves exit zero; invalid sources exit nonzero.
bundle is an alias for evidence pack with identical arguments and layout.
Optional --manifest FILE, --resolved-manifest FILE, --serial-log FILE, and
--trace FILE add sanitized host attachments. Manifest TOML is retained as JSON;
its original SHA-256 and retained-byte SHA-256 are separate. Trace attachments
must be validated version-2 canonical captures. artifact_refs.json records
byte counts, source classes, hashes, and proof=none. The pack adds an
attestation.json result, a sorted checksums.json, and pack.sha256; the CLI
prints the final pack digest. This digest detects byte changes when compared
with a trusted copy; it is not a signature. Captured inventory files and
attachments are never inferred from arbitrary neighboring files.
Directory listings are inventory-addressed leaves at
namespace/<source-path>/.listing, so parent and child directories can both
be retained. Readers continue to accept older inventory-selected listing paths.
Inputs reuse compiler-owned diagnostic limits: currently 1 MiB per aggregate inspection and attachment input, with 682 inventory entries derived from the directory and path limits. Each file must be regular and bounded; traversal, control characters, symlink components, duplicate namespace paths, and excessive depth are rejected. Output files use unique same-directory temporary files and atomic replacement. A failed filesystem operation can leave a subset of a multi-file export; consumers must validate its inventory. Legacy pack-v1 and timeline-v1 inputs remain readable, with absent inventories classified unknown.
Canonical traces
The cohsh-core version-2 trace container retains redacted shell output and
read observations in the same
bounded frame/ACK container. It is consumed by cohsh, coh trace,
coh-status::captured_namespace, and SwarmUI’s trace replay backend.
cohsh --transport rest --rest-url http://127.0.0.1:8080 --role queen \
--record-trace out/session.trace \
--trace-target-id expected-target --trace-session-id expected-boot
coh trace --input out/session.trace
cohsh --replay-trace out/session.trace
Use an appropriate read-only script for incident collection. Recording does
not change the script’s behavior or block its writes. TCP uses the same recorder
and existing --transport tcp --tcp-host HOST --tcp-port PORT options. Live
capture works without the in-process feature; version-1 fixture execution
retains that feature requirement. Replay opens no target transport. It exposes
only retained reads; unavailable reads fail and every write is rejected.
SwarmUI reads those observations through its normal console parsers without
network access. It cannot reconstruct observations that were never captured.
The header binds backend, caller-supplied target/session label hashes, optional
--trace-manifest-sha256 and --trace-image-sha256, capture time, completion,
and generated policy/redaction digest. Zero identity hashes mean unknown.
These are expected identities supplied by the collector, not device-attested
identities. Classify actual QEMU, Pi, and host-projection captures using external
exact-target provenance; transport choice alone never proves target class.
Version-1 traces and checked-in samples are offline fixtures only.
Generated schema 1.19 adds client_policies.trace.max_duration_ms (default
60000). Byte, frame, ACK, and duration limits stop recording without altering
the underlying session. Completion values are 0 complete, 1 partial/error,
2 byte/frame limit, and 3 duration limit; incomplete CLI recordings/replays
exit nonzero. A partial line is not committed. The digest covers metadata and
all retained bytes. Replay rejects malformed counts, tamper, wrong policy,
oversize input, and records that do not satisfy the shared redaction rules.
Authentication exchanges and raw write payloads are omitted. Secret-bearing JSON fields (including nested JSON strings) are redacted and tickets are hashed; unstructured payloads without a supported field contract are withheld. Known connection credentials are also removed before persistence. ACK/ERR/END order is exact after redaction. Host fixture and loopback transport tests do not satisfy fresh QEMU or Pi acceptance.
Case summaries
evidence timeline --scenario generic|incident|change|maintenance|rollout|federation
adds case.json and case.md alongside the existing timeline files. Scenario
changes the review framing only. Records correlate by the full request,
idempotency, source-hive, and target-hive tuple; incomplete identities remain
separate instead of guessing a join.
Each chain covers request, decision, state/lease/lifecycle, host result,
receipt/dead-letter, and federation relay stages. A stage is observed,
missing, error, unknown, or ambiguous. Source links include the original
namespace path, timeline event index, sequence, and SHA-256 of that canonical
event. Conflicting terminal records remain ambiguous. Outcomes are limited to
recorded-terminal, refused, deadlettered, incomplete, and ambiguous.
An observed host result does not establish execution, and a missing linked
decision is not synthesized from a later status. For an independently
verified native outcome, use the enrolled causal evidence
chain.
Python CohesixClient.evidence_case(pack_dir) and
CohesixClient.attestation_result(pack_dir) read these canonical records
offline. The shared operator fixture binds Rust output and Python source-link
validation. Unknown additive fields are sanitized, absent optional records
raise CohesixError, and malformed required structure is rejected. Python retains
traces as opaque bounded hash references and never parses or replays them.
Signed attestation
coh attest --trust-policy <file> uses the shared TPM2 quote and certificate
verifier. Live mode submits one fresh authenticated ephemeral challenge only
when the target advertises an issuer. --record <file> retains its public
request and signed response; coh evidence pack --attestation-record <file>
adds it to the canonical pack. coh attest --input <pack> --trust-policy <file>
verifies it offline with an explicit historical-signature scope.
Results include PASS/FAIL/UNAVAILABLE, source and evidence class, proof scope, and verified evidence/policy/nonce digests. A PASS for an offline fixture does not establish hardware identity or fresh target state. The selected Pi profile reports measurement-only under the owner’s stock-Pi exemption; selected images without a device provider advertise unavailable and receive no challenge. The signed device contract defines exact bounds, algorithms, nonce and PCR binding, enrollment, revocation and remaining device-runtime work.