From ef6b7aa6a1ef304b5984a43f46563771e1f04ae7 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 13 Jan 2026 20:09:45 -0800 Subject: [PATCH 1/5] Allow asserting multiple `--key`s in `filepack verify` --- src/error.rs | 5 +++ src/subcommand/verify.rs | 19 ++++++++-- tests/verify.rs | 78 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index 1a1adcc8..9b40ef5c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -34,6 +34,11 @@ pub enum Error { path: DisplayPath, source: serde_yaml::Error, }, + #[snafu(display("key provided multiple times: `{key}`"))] + DuplicateKey { + backtrace: Option, + key: PublicKey, + }, #[snafu(display("{count} mismatched file{}", if *count == 1 { "" } else { "s" }))] EntryMismatch { backtrace: Option, diff --git a/src/subcommand/verify.rs b/src/subcommand/verify.rs index 86f989f9..e10dff08 100644 --- a/src/subcommand/verify.rs +++ b/src/subcommand/verify.rs @@ -6,8 +6,12 @@ pub(crate) struct Verify { fingerprint: Option, #[arg(help = "Ignore missing files", long)] ignore_missing: bool, - #[arg(help = "Verify that manifest has been signed by ", long)] - key: Option, + #[arg( + help = "Verify that manifest has been signed by ", + long = "key", + value_name = "KEY" + )] + keys: Vec, #[arg( help = "Read manifest from , defaults to `/filepack.json`", long @@ -202,7 +206,16 @@ mismatched file: `{path}` verified.signatures += 1; } - if let Some(key) = self.key { + let mut keys = BTreeSet::new(); + + for key in &self.keys { + ensure! { + keys.insert(key.clone()), + error::DuplicateKey { key: key.clone() }, + } + } + + for key in self.keys { ensure! { manifest.signatures.contains_key(&key), error::SignatureMissing { key }, diff --git a/tests/verify.rs b/tests/verify.rs index 0d0bd398..0fa69abc 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -232,6 +232,84 @@ fn missing_signature_error() { .failure(); } +#[test] +fn multiple_keys_all_present() { + let test = Test::new() + .data_dir("alice") + .args(["keygen"]) + .success() + .data_dir("bob") + .args(["keygen"]) + .success() + .touch("foo/bar") + .args(["create", "foo"]) + .success() + .data_dir("alice") + .args(["sign", "foo/filepack.json"]) + .success() + .data_dir("bob") + .args(["sign", "foo/filepack.json"]) + .success(); + + let alice_key = test.read("alice/keys/master.public"); + let bob_key = test.read("bob/keys/master.public"); + + test + .args(["verify", "foo", "--key", &alice_key, "--key", &bob_key]) + .stderr("successfully verified 1 file totaling 0 bytes with 2 signatures\n") + .success(); +} + +#[test] +fn multiple_keys_duplicate_error() { + Test::new() + .args(["create"]) + .success() + .args([ + "verify", + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + ]) + .stderr( + "error: key provided multiple times: \ + `7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b`\n", + ) + .failure(); +} + +#[test] +fn multiple_keys_one_missing() { + let test = Test::new() + .data_dir("alice") + .args(["keygen"]) + .success() + .touch("foo/bar") + .args(["create", "foo"]) + .success() + .data_dir("alice") + .args(["sign", "foo/filepack.json"]) + .success(); + + let alice_key = test.read("alice/keys/master.public"); + + test + .args([ + "verify", + "foo", + "--key", + &alice_key, + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + ]) + .stderr( + "error: no signature found for key \ + 7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b\n", + ) + .failure(); +} + #[test] fn multiple_mismatches() { Test::new() From b78064d47c1b582bb8b22aaa386eb59d3aff8c4d Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 13 Jan 2026 20:21:08 -0800 Subject: [PATCH 2/5] Enhance --- tests/verify.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/verify.rs b/tests/verify.rs index 0fa69abc..58280d17 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -233,7 +233,7 @@ fn missing_signature_error() { } #[test] -fn multiple_keys_all_present() { +fn multiple_keys() { let test = Test::new() .data_dir("alice") .args(["keygen"]) @@ -245,10 +245,10 @@ fn multiple_keys_all_present() { .args(["create", "foo"]) .success() .data_dir("alice") - .args(["sign", "foo/filepack.json"]) + .args(["sign", "foo"]) .success() .data_dir("bob") - .args(["sign", "foo/filepack.json"]) + .args(["sign", "foo"]) .success(); let alice_key = test.read("alice/keys/master.public"); From ab853a762ed85c917432b182448c384c49149651 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 13 Jan 2026 20:21:44 -0800 Subject: [PATCH 3/5] Reform --- tests/verify.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/verify.rs b/tests/verify.rs index 58280d17..84b864ef 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -251,11 +251,11 @@ fn multiple_keys() { .args(["sign", "foo"]) .success(); - let alice_key = test.read("alice/keys/master.public"); - let bob_key = test.read("bob/keys/master.public"); + let alice = test.read("alice/keys/master.public"); + let bob = test.read("bob/keys/master.public"); test - .args(["verify", "foo", "--key", &alice_key, "--key", &bob_key]) + .args(["verify", "foo", "--key", &alice, "--key", &bob]) .stderr("successfully verified 1 file totaling 0 bytes with 2 signatures\n") .success(); } From 7431d8c13e54d836c9125513e34fb43d4b1e195a Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 13 Jan 2026 20:22:28 -0800 Subject: [PATCH 4/5] Amend --- tests/verify.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/verify.rs b/tests/verify.rs index 84b864ef..6a8a4dab 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -261,7 +261,7 @@ fn multiple_keys() { } #[test] -fn multiple_keys_duplicate_error() { +fn duplicate_key() { Test::new() .args(["create"]) .success() @@ -292,14 +292,14 @@ fn multiple_keys_one_missing() { .args(["sign", "foo/filepack.json"]) .success(); - let alice_key = test.read("alice/keys/master.public"); + let alice = test.read("alice/keys/master.public"); test .args([ "verify", "foo", "--key", - &alice_key, + &alice, "--key", "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", ]) From 656949b59a60b7dfe6d993551c9502a4e602c4c9 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 13 Jan 2026 20:23:25 -0800 Subject: [PATCH 5/5] Modify --- tests/verify.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/verify.rs b/tests/verify.rs index 6a8a4dab..d9873ed5 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -1,5 +1,24 @@ use super::*; +#[test] +fn duplicate_key() { + Test::new() + .args(["create"]) + .success() + .args([ + "verify", + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + ]) + .stderr( + "error: key provided multiple times: \ + `7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b`\n", + ) + .failure(); +} + #[test] fn extra_fields_are_not_allowed() { Test::new() @@ -260,25 +279,6 @@ fn multiple_keys() { .success(); } -#[test] -fn duplicate_key() { - Test::new() - .args(["create"]) - .success() - .args([ - "verify", - "--key", - "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", - "--key", - "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", - ]) - .stderr( - "error: key provided multiple times: \ - `7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b`\n", - ) - .failure(); -} - #[test] fn multiple_keys_one_missing() { let test = Test::new()