From f3582bc046ff7be22c54ffba061b3967bbc2c216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kyle=20=F0=9F=90=86?= Date: Sun, 12 Jul 2026 12:25:07 -0400 Subject: [PATCH] Re-pin keep v0.7.5; assert fail-closed unlock stdout is byte-empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kyle 🐆 --- flake.lock | 8 ++++---- flake.nix | 2 +- tests/lib/oprf-common.nix | 22 ++++++++++------------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index b00cfeb..d81ca75 100644 --- a/flake.lock +++ b/flake.lock @@ -56,16 +56,16 @@ "keep": { "flake": false, "locked": { - "lastModified": 1783825609, - "narHash": "sha256-ucvDizoUnEAZuI8HNI3SpWqoM3Gbz+j+RccR2AWnXtY=", + "lastModified": 1783872129, + "narHash": "sha256-AX9dKGMA4zZbdpGkegblck1tAmB+C0A2llXiiM5MnSI=", "owner": "privkeyio", "repo": "keep", - "rev": "2ad42c50c75ed16d1f5f10a93387443e99d0381a", + "rev": "62dc446684d65864925e0e4e0d575f0c2e934381", "type": "github" }, "original": { "owner": "privkeyio", - "ref": "v0.7.4", + "ref": "v0.7.5", "repo": "keep", "type": "github" } diff --git a/flake.nix b/flake.nix index 41f9c0c..479f12b 100644 --- a/flake.nix +++ b/flake.nix @@ -8,7 +8,7 @@ # main-HEAD, so the appliance builds from a curated, known-good version rather than whatever main # happens to be; bump the tag to adopt a newer release deliberately. keep = { - url = "github:privkeyio/keep/v0.7.4"; + url = "github:privkeyio/keep/v0.7.5"; flake = false; }; # nostr-vpn (`nvpn`): the node-to-node encrypted mesh transport (boringtun userspace WireGuard, diff --git a/tests/lib/oprf-common.nix b/tests/lib/oprf-common.nix index c3a1aee..4d64fa2 100644 --- a/tests/lib/oprf-common.nix +++ b/tests/lib/oprf-common.nix @@ -121,19 +121,17 @@ in def fail_closed(node, out_path): # Shared fail-closed assertion for the below-threshold (no-quorum) unlock legs. The security - # property is "a failed unlock reconstructs no usable key," so the meaningful check is that stdout - # carries no key bytes -- not that it is byte-empty. keep-cli's error-exit path writes a terminal - # control escape (alt-screen-exit, `\e[?1049l`, the progress-spinner's cleanup) to stdout, so strip - # ANSI escapes first, then require what remains to be empty. (On the SUCCESS path stdout is exactly - # the 32-byte key -- verified in the 2-of-2 fixture -- so the frost-gate's key capture is - # unaffected; the stray escape is a keep-cli stdout-hygiene nit tracked as keep-node-95y.) The - # exact-32-byte guard is a second, independent backstop. - clean_path = out_path + ".clean" - node.succeed(rf"""sed 's/\x1b\[[0-9;?]*[A-Za-z]//g' {out_path} > {clean_path}""") - clean_size = node.succeed(f"stat -c %s {clean_path}").strip() - assert clean_size == "0", f"fail-closed unlock leaked {clean_size} non-escape bytes to stdout ({out_path})" + # property is "a failed unlock reconstructs no usable key." As of keep 0.7.5 (keep-node-95y) a + # fail-closed oprf-unlock exit writes NOTHING to stdout: the terminal alt-screen-exit escape + # (`\e[?1049l`) the SIGTERM/panic handler used to leak is now suppressed for non-TUI commands, so + # stdout is strictly empty -- no ANSI stripping needed, and we assert the raw bytes directly. (On + # the SUCCESS path stdout is exactly the 32-byte key -- verified in the 2-of-2 fixture -- so the + # frost-gate's key capture is unaffected.) Asserting byte-empty subsumes "no 32-byte key" and + # also catches any future stray write to the key-only stdout. raw_size = node.succeed(f"stat -c %s {out_path}").strip() - assert raw_size != "32", f"fail-closed unlock leaked a 32-byte key ({raw_size} bytes, {out_path})" + assert raw_size == "0", ( + f"fail-closed unlock wrote {raw_size} bytes to stdout; it must be empty (no key, no control bytes) ({out_path})" + ) def keep_bg(node, unit, args): # Run a long-lived `keep` (serve/announce) as a transient unit in the background.