Commit graph

3 commits

Author SHA1 Message Date
igneum-labs
7a412bd53e keys.md: every path that trusts K1 (app, jobs, Windows inputs, rig installer, HiveOS, wallet) with its state; the rig installer's two-key form; HiveOS README says the archive is unsigned and names the sha256 check (consequences C21)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 20:42:43 +00:00
igneum-labs
9062ed3e0c OTA: the second signing key (K2) with revocation, docs/security/keys.md section 4 steps 2 and 3
manifest.rs: OTA_PUBLIC_KEYS = [K1, K2] (K2 empty until tools/keys/keygen-k2.sh fills it; an empty slot is skipped),
verify_signature over the slice returning the key that verified, fingerprint8, the optional signed revoked_keys
list, the revoked.json record (load, save, trusted_keys) and check(): a key never revokes itself, a revoked key is
refused by name. ota.rs fetch_manifest goes through check() and writes <updates>/revoked.json; jobrun.rs verifies the
jobs file with the same trusted keys at every poll; jobs.rs, inputs.rs and ota-sign.rs take the slice; `embedded`
prints every key (K1 on lines 1 and 2 as before) and is accepted as the key argument of every verify command; the
engine logs "ota keys: trusted ...; revoked ..." at start and tools/logs.mjs --rotation shows it as the ota_keys
column with a K2 count.

Publisher side: publish-manifest.sh --revoke <fingerprint> (carried over until --no-revoke, the signer's own refused),
IGNEUM_OTA_KEY_FILE/IGNEUM_OTA_PUB_FILE in the three signing scripts, the embedded check accepts any embedded key.
tools/keys/keygen-k2.sh makes K2 straight into a new AES-256 image (private half never on disk), writes the .pub and
patches manifest.rs; tools/keys/with-k2.sh runs one publish with K2 from the image; tools/keys/test-keygen-k2.sh
proves both on a scratch folder with a throwaway key (25 checks).

Tests: manifest::tests second_key_verifies_third_key_fails_first_key_still_passes, revoked_keys_parse,
revocation_path; inputs sign_verify_and_tamper on the two-key slice; 79 igneum-app and 30 igneum-ota-sign unit tests
pass on the Mac; test-inputs-signing.sh 16, test-publish-jobs.sh 24, logs.mjs --self-test 12, no-secrets 0 hits.

Class fix: `"$SIGNER" embedded | grep -q` under pipefail failed on SIGPIPE once in three runs (grep exits at the
first match, the signer still has lines to write); the output is captured first in all four places, and
tools/ci/pipe-grep-q-check.sh (self-tested, wired into ci.yml) fails CI when the shape comes back.

K2 itself is not made here: the exact commands for the project lead are in docs/security/keys.md section 4. The wallet
(wallet-v1, app/igneum-common/src/manifest.rs, its own copy) is listed there as the follow-up.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 20:29:23 +00:00
igneum-labs
addeb660fd Key custody: inventory, encrypted backup and restore, no-secrets CI check
docs/security/keys.md: every key the project depends on (the folder, the gh
keyring, the Vercel env of three projects, the GitHub secrets) with where it
lives, what it unlocks, the blast radius lost and leaked, who rotates it and
the rotation status, written from the files and the scripts that read them.
No value, no private fingerprint. Section 4: the second OTA signing key kept
offline, the app change (a key list plus revocation in the manifest), 0.3.9
as the carrier, and the emergency path if the one key leaks today (a manifest
signed with a new key is useless to 0.3.x apps; the mitigation in order).

tools/keys/backup.sh: ~/Desktop/igneum-keys-<date>.dmg, AES-256, hdiutil's
own prompt (never argv, history or a file), the folder minus build-slots,
dlsite-dir and pytools/, plus a README; attached read-only, every file
compared by sha256, listed, detached. --dry-run lists. restore.sh: --check
compares the image against the live folder without printing values, --to
copies back with 0600/0644 and 0700. test-backup.sh: the end-to-end test on a
scratch folder with a throwaway passphrase, 8 steps, passed.

tools/ci/no-secrets-check.sh, in ci.yml: no tracked file named like a key of
~/.config/igneum, no 64-hex value assigned to a token/key/secret name outside
tests and the allowlist (the OTA public key, the published Hardhat and Anvil
accounts); a --self-test fires on a known-bad tree first. 776 files, 0 hits.

Also: ~/.config/igneum, vercel/ and txgen/ are 0700 now (were 0755).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 17:01:01 +00:00