Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ verify-release-key: ## Verify exported public key contains no private material
test: verify-embedded-identity ## Run all tests
@echo "Running test suite..."
$(GOTEST) ./... -v -cover
@$(MAKE) build
@bash tests/release/ceremony_test.sh

lint: ## Run lint checks with goneat
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,19 @@ Users should be able to:

This matters because the assets being scanned by this tool are often the same class of assets used to sign its releases.

## Verify a signed release

Consume fingerprints, not secrets. Per-cut steps live in
[`docs/releases/v0.1.3.md`](docs/releases/v0.1.3.md). Committed pins and
the inserter are documented in [`keys/README.md`](keys/README.md). How
those pins enter the signed set is
[`docs/decisions/PDR-0001-committed-signing-anchors.md`](docs/decisions/PDR-0001-committed-signing-anchors.md).

Download the draft (archives, signed SUMS, exported publics, staged pin
pair). Verify SUMS signatures, then run `decernor fingerprint` on the
exported publics and compare to `expected-fingerprints.txt`. Never
hand-type hex into notes or a README.

## Build

```sh
Expand Down
22 changes: 13 additions & 9 deletions docs/decernor-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,27 @@ Decernor is a CLI tool for inspecting local signing and authentication material

## Scope

Decernor answers two questions:
Decernor answers a few questions:

- `scan`: what risky or sensitive key material is present in this path?
- `guardread`: can this one file be written to stdout without first exposing supported key-material bytes?
- `fingerprint`: what safe public identity fingerprints can be emitted for this key material?
- `readiness`: does an asset set appear to have enough protected material for a capability?

It is intentionally CLI-only. It should not become a daemon, web service, remote scanner, or key store without an explicit architecture review.

## Current Commands

| Command | Purpose |
| -------------------------------- | ------------------------------------------------------------------------- |
| `scan PATH` | Inspect a directory and report local key-material findings. |
| `readiness validate-config PATH` | Validate readiness configuration JSON. |
| `version` | Print build version, with optional extended dependency details. |
| `envinfo` | Print runtime, config, and app identity details. |
| `doctor` | Run local installation diagnostics. |
| `validate` | Validate schema/data files; retained while readiness schema work matures. |
| Command | Purpose |
| -------------------------------- | ---------------------------------------------------------------------------- |
| `scan PATH` | Inspect a directory and report local key-material findings. |
| `guardread FILE` | Copy one regular file to stdout only after guarded key-material checks pass. |
| `fingerprint PATH` | Emit public identity fingerprints (alias: `fp`). |
| `readiness validate-config PATH` | Validate readiness configuration JSON. |
| `version` | Print build version, with optional extended dependency details. |
| `envinfo` | Print runtime, config, and app identity details. |
| `doctor` | Run local installation diagnostics. |
| `validate` | Validate schema/data files; retained while readiness schema work matures. |

## Scanner Model

Expand Down
4 changes: 4 additions & 0 deletions docs/decisions/PDR-0001-committed-signing-anchors.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ decernor fingerprint "$PUB" --class public --kind minisign \
# validate: each ndjson line against fingerprint-record.v0.
```

Pin-pair install uses **process-lifetime rollback** on error or
INT/TERM/HUP (restore the prior pair, or remove a first-use dest). Two
dest files are not power-loss atomic.

Rekey = new export + same script. Do not immortalize today's hex in
docs or commit messages.

Expand Down
22 changes: 22 additions & 0 deletions docs/releases/v0.1.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,25 @@ are `DECERNOR_*` environment variables only.
`envinfo`, `doctor`.

Still private. Do not treat an undrafted GitHub release as a public launch.

## Verify a draft

Download the draft assets: archives, `SHA256SUMS` / `SHA512SUMS` and their
signatures, exported publics, and the staged pin pair
(`expected-fingerprints.txt`, `expected-fingerprints.ndjson`). Check the
signatures on the SUMS, then check the SUMS against the files.

Recompute fingerprints from the **exported publics** and compare them to
the two-line pin file. Do not hand-type hex.

```sh
decernor fingerprint decernor-release-signing-key.asc \
--class public --kind gpg --format json --path-mode none --gpg-role primary
decernor fingerprint decernor-minisign.pub \
--class public --kind minisign --format json --path-mode none
```

The GPG primary fingerprint and the minisign public-blob SHA-256 must
match the `gpg` and `minisign` lines in `expected-fingerprints.txt`.
See `keys/README.md` and
`docs/decisions/PDR-0001-committed-signing-anchors.md`.
4 changes: 4 additions & 0 deletions scripts/atomic-install-pair.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ cp "$SRC_NDJSON" "$NEW_NDJSON"
cp "$SRC_TXT" "$NEW_TXT"

rollback() {
# Single-shot: a signal runs this handler, then EXIT must not run it again.
trap - EXIT INT TERM HUP
rm -f "$NEW_NDJSON" "$NEW_TXT"
if [ "$had_ndjson" -eq 1 ]; then
mv -f "$BAK_NDJSON" "$DEST_NDJSON"
Expand All @@ -53,6 +55,8 @@ if ! mv -f "$NEW_NDJSON" "$DEST_NDJSON"; then
fi
if [ "${DECERNOR_TEST_KILL_AFTER_FIRST:-}" = 1 ]; then
kill -s TERM $$
# A handled TERM returns here; do not continue the second install.
exit 143
fi
if [ "${DECERNOR_TEST_FAIL_SECOND:-}" = 1 ]; then
echo "error: failed to install txt pin; restored previous pair" >&2
Expand Down
40 changes: 40 additions & 0 deletions tests/release/ceremony_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,28 @@ else
fi
rm -rf "$pair" "$empty"

# existing pair + TERM after first install restores prior bytes once (no second mv).
pair="$(mktemp -d)"
prior="$(mktemp -d)"
printf 'new-ndjson\n' >"$pair/expected-fingerprints.ndjson"
printf 'new-txt\n' >"$pair/expected-fingerprints.txt"
printf 'old-ndjson\n' >"$prior/expected-fingerprints.ndjson"
printf 'old-txt\n' >"$prior/expected-fingerprints.txt"
set +e
err="$(DECERNOR_TEST_KILL_AFTER_FIRST=1 "$INSTALL" "$pair" "$prior" 2>&1)"
set -e
if ! grep -qx 'old-ndjson' "$prior/expected-fingerprints.ndjson" ||
! grep -qx 'old-txt' "$prior/expected-fingerprints.txt"; then
fail "existing-pair signal did not restore prior dest files"
elif [ -e "$prior/expected-fingerprints.ndjson.new" ] || [ -e "$prior/expected-fingerprints.txt.new" ]; then
fail "existing-pair signal left .new residue"
elif printf '%s\n' "$err" | grep -Eqi 'no such file|cannot stat'; then
fail "existing-pair signal ran rollback twice ($err)"
else
pass "existing-pair signal restores prior dest once"
fi
rm -rf "$pair" "$prior"

# extra TXT token: helper must emit the two-field error (not keys/ cmp).
if [ -f "$ROOT/keys/expected-fingerprints.txt" ]; then
mut="$(mktemp -d)"
Expand Down Expand Up @@ -118,6 +140,24 @@ if [ -f "$ROOT/keys/expected-fingerprints.ndjson" ]; then
rm -rf "$mut"
fi

# schema path: committed pair must validate when a host binary exists.
DECERNOR_BIN="${DECERNOR_BIN:-}"
if [ -z "$DECERNOR_BIN" ] && [ -x "$ROOT/bin/decernor" ]; then
DECERNOR_BIN="$ROOT/bin/decernor"
fi
if [ -n "$DECERNOR_BIN" ] && [ -f "$ROOT/keys/expected-fingerprints.txt" ]; then
out="$(DECERNOR_BIN="$DECERNOR_BIN" "$VALIDATE" \
"$ROOT/keys/expected-fingerprints.txt" \
"$ROOT/keys/expected-fingerprints.ndjson" 2>&1)" && status=0 || status=$?
if [ "$status" -eq 0 ]; then
pass "validate accepts committed pin pair (schema path)"
else
fail "validate rejected committed pin pair ($out)"
fi
else
note "SKIP: schema path (no host decernor binary)"
fi

if [ "$FAIL" -ne 0 ]; then
note "$FAIL ceremony probe(s) failed"
exit 1
Expand Down
Loading