@@ -41,7 +41,7 @@ use keys::{parse_public_keys, parse_signing_key, verify_keys_digest};
4141use preflight:: { load_verified_bundle, read_manifest_and_signatures} ;
4242use runtime_exec:: execute_wasm;
4343
44- const USAGE : & str = "usage:\n provenact-cli verify --bundle <bundle-dir> --keys <public-keys.json> --keys-digest <sha256:...> [--require-cosign --oci-ref <oci-ref>] [--allow-experimental]\n provenact-cli inspect --bundle <bundle-dir> [--allow-experimental]\n provenact-cli pack --bundle <bundle-dir> --wasm <skill.wasm> --manifest <manifest.json> [--allow-experimental]\n provenact-cli archive --bundle <bundle-dir> --output <skill.tar.zst>\n provenact-cli sign --bundle <bundle-dir> --signer <signer-id> --secret-key <ed25519-secret-key-file> [--allow-experimental]\n provenact-cli install --artifact <path|file://...|http(s)://...|oci://...> [--keys <public-keys.json> --keys-digest <sha256:...>] [--policy <policy.{json|yaml}>] [--require-signatures] [--allow-insecure-http] [--allow-experimental]\n provenact-cli export agentskills --agent <claude|codex|cursor> --scope <user|repo|admin>\n provenact-cli run --bundle <bundle-dir> --keys <public-keys.json> --keys-digest <sha256:...> --policy <policy.{json|yaml}> --input <input-file> --receipt <receipt.json> [--receipt-format <v0|v1-draft>] [--require-cosign --oci-ref <oci-ref>] [--allow-experimental]\n provenact-cli verify-receipt --receipt <receipt.json>\n provenact-cli verify-registry-entry --artifact <artifact-bytes-file> --sha256 <sha256:...> --md5 <32-lowercase-hex>\n provenact-cli experimental-validate-manifest-v1 --manifest <manifest.json>\n provenact-cli experimental-validate-receipt-v1 --receipt <receipt.json>" ;
44+ const USAGE : & str = "usage:\n provenact-cli verify --bundle <bundle-dir> --keys <public-keys.json> --keys-digest <sha256:...> [--require-cosign --oci-ref <oci-ref> --cosign-key <cosign.pub> --cosign-cert-identity <identity> --cosign-cert-oidc-issuer <issuer>] [--allow-experimental]\n provenact-cli inspect --bundle <bundle-dir> [--allow-experimental]\n provenact-cli pack --bundle <bundle-dir> --wasm <skill.wasm> --manifest <manifest.json> [--allow-experimental]\n provenact-cli archive --bundle <bundle-dir> --output <skill.tar.zst>\n provenact-cli sign --bundle <bundle-dir> --signer <signer-id> --secret-key <ed25519-secret-key-file> [--allow-experimental]\n provenact-cli install --artifact <path|file://...|http(s)://...|oci://...> [--keys <public-keys.json> --keys-digest <sha256:...>] [--policy <policy.{json|yaml}>] [--require-signatures] [--allow-insecure-http] [--allow-experimental]\n provenact-cli export agentskills --agent <claude|codex|cursor> --scope <user|repo|admin>\n provenact-cli run --bundle <bundle-dir> --keys <public-keys.json> --keys-digest <sha256:...> --policy <policy.{json|yaml}> --input <input-file> --receipt <receipt.json> [--receipt-format <v0|v1-draft>] [--require-cosign --oci-ref <oci-ref> --cosign-key <cosign.pub> --cosign-cert-identity <identity> --cosign-cert-oidc-issuer <issuer>] [--allow-experimental]\n provenact-cli verify-receipt --receipt <receipt.json>\n provenact-cli verify-registry-entry --artifact <artifact-bytes-file> --sha256 <sha256:...> --md5 <32-lowercase-hex>\n provenact-cli experimental-validate-manifest-v1 --manifest <manifest.json>\n provenact-cli experimental-validate-receipt-v1 --receipt <receipt.json>" ;
4545const EXPERIMENTAL_SCHEMA_VERSION : & str = "1.0.0-draft" ;
4646const BUNDLE_META_SCHEMA_VERSION : & str = "1.0.0" ;
4747const RECEIPT_TIMESTAMP_STRATEGY_LOCAL : & str = "local_untrusted_unix_seconds" ;
@@ -129,24 +129,38 @@ fn run_export(args: &[String]) -> Result<(), String> {
129129fn run_verify ( args : & [ String ] ) -> Result < ( ) , String > {
130130 let parsed = parse_flags_with_switches (
131131 args,
132- & [ "--bundle" , "--keys" , "--keys-digest" , "--oci-ref" ] ,
132+ & [
133+ "--bundle" ,
134+ "--keys" ,
135+ "--keys-digest" ,
136+ "--oci-ref" ,
137+ "--cosign-key" ,
138+ "--cosign-cert-identity" ,
139+ "--cosign-cert-oidc-issuer" ,
140+ ] ,
133141 & [ "--allow-experimental" , "--require-cosign" ] ,
134142 USAGE ,
135143 ) ?;
136144 let bundle_dir = required_path ( & parsed, "--bundle" , USAGE ) ?;
137145 let keys_path = required_path ( & parsed, "--keys" , USAGE ) ?;
138146 let keys_digest = required_string ( & parsed, "--keys-digest" , USAGE ) ?;
139147 let oci_ref = optional_string ( & parsed, "--oci-ref" ) ;
148+ let cosign_key = optional_string ( & parsed, "--cosign-key" ) ;
149+ let cosign_cert_identity = optional_string ( & parsed, "--cosign-cert-identity" ) ;
150+ let cosign_cert_oidc_issuer = optional_string ( & parsed, "--cosign-cert-oidc-issuer" ) ;
140151 let require_cosign = has_switch ( & parsed, "--require-cosign" ) ;
141152 let allow_experimental = has_switch ( & parsed, "--allow-experimental" ) ;
142- verify_bundle (
143- & bundle_dir,
144- & keys_path,
145- & keys_digest,
153+ verify_bundle ( VerifyBundleArgs {
154+ bundle_dir,
155+ keys_path,
156+ keys_digest,
146157 require_cosign,
147- oci_ref. as_deref ( ) ,
158+ oci_ref,
159+ cosign_key,
160+ cosign_cert_identity,
161+ cosign_cert_oidc_issuer,
148162 allow_experimental,
149- )
163+ } )
150164}
151165
152166fn run_inspect ( args : & [ String ] ) -> Result < ( ) , String > {
@@ -260,6 +274,9 @@ fn run_execute(args: &[String]) -> Result<(), String> {
260274 "--keys" ,
261275 "--keys-digest" ,
262276 "--oci-ref" ,
277+ "--cosign-key" ,
278+ "--cosign-cert-identity" ,
279+ "--cosign-cert-oidc-issuer" ,
263280 "--policy" ,
264281 "--input" ,
265282 "--receipt" ,
@@ -272,6 +289,9 @@ fn run_execute(args: &[String]) -> Result<(), String> {
272289 let keys_path = required_path ( & parsed, "--keys" , USAGE ) ?;
273290 let keys_digest = required_string ( & parsed, "--keys-digest" , USAGE ) ?;
274291 let oci_ref = optional_string ( & parsed, "--oci-ref" ) ;
292+ let cosign_key = optional_string ( & parsed, "--cosign-key" ) ;
293+ let cosign_cert_identity = optional_string ( & parsed, "--cosign-cert-identity" ) ;
294+ let cosign_cert_oidc_issuer = optional_string ( & parsed, "--cosign-cert-oidc-issuer" ) ;
275295 let require_cosign = has_switch ( & parsed, "--require-cosign" ) ;
276296 let policy_path = required_path ( & parsed, "--policy" , USAGE ) ?;
277297 let input_path = required_path ( & parsed, "--input" , USAGE ) ?;
@@ -285,6 +305,9 @@ fn run_execute(args: &[String]) -> Result<(), String> {
285305 keys_digest,
286306 require_cosign,
287307 oci_ref,
308+ cosign_key,
309+ cosign_cert_identity,
310+ cosign_cert_oidc_issuer,
288311 policy_path,
289312 input_path,
290313 receipt_path,
@@ -319,31 +342,71 @@ fn run_validate_receipt_v1_cmd(args: &[String]) -> Result<(), String> {
319342 validate_receipt_v1_file ( & receipt_path)
320343}
321344
322- fn verify_bundle (
323- bundle_dir : & Path ,
324- keys_path : & Path ,
325- keys_digest : & str ,
345+ struct VerifyBundleArgs {
346+ bundle_dir : PathBuf ,
347+ keys_path : PathBuf ,
348+ keys_digest : String ,
326349 require_cosign : bool ,
327- oci_ref : Option < & str > ,
350+ oci_ref : Option < String > ,
351+ cosign_key : Option < String > ,
352+ cosign_cert_identity : Option < String > ,
353+ cosign_cert_oidc_issuer : Option < String > ,
328354 allow_experimental : bool ,
329- ) -> Result < ( ) , String > {
355+ }
356+
357+ fn verify_bundle ( args : VerifyBundleArgs ) -> Result < ( ) , String > {
358+ let VerifyBundleArgs {
359+ bundle_dir,
360+ keys_path,
361+ keys_digest,
362+ require_cosign,
363+ oci_ref,
364+ cosign_key,
365+ cosign_cert_identity,
366+ cosign_cert_oidc_issuer,
367+ allow_experimental,
368+ } = args;
330369 let started = Instant :: now ( ) ;
331370 let result = ( || {
332371 let preflight_started = Instant :: now ( ) ;
333- let bundle = load_verified_bundle ( bundle_dir) ?;
372+ let bundle = load_verified_bundle ( & bundle_dir) ?;
334373 require_manifest_schema_allowed ( & bundle. manifest , allow_experimental) ?;
335374 let preflight_ms = preflight_started. elapsed ( ) . as_millis ( ) as u64 ;
336375
337376 let trust_started = Instant :: now ( ) ;
338- let keys_raw = read_file_limited ( keys_path, MAX_JSON_BYTES , "public-keys.json" ) ?;
339- verify_keys_digest ( & keys_raw, keys_digest) ?;
377+ let keys_raw = read_file_limited ( & keys_path, MAX_JSON_BYTES , "public-keys.json" ) ?;
378+ verify_keys_digest ( & keys_raw, & keys_digest) ?;
340379 let public_keys = parse_public_keys ( & keys_raw) ?;
341380 verify_signatures ( & bundle. signatures , & public_keys) . map_err ( |e| e. to_string ( ) ) ?;
342- if require_cosign || oci_ref. is_some ( ) {
343- let Some ( ref_value) = oci_ref else {
344- return Err ( "--oci-ref is required when --require-cosign is set" . to_string ( ) ) ;
381+ if require_cosign
382+ || oci_ref. is_some ( )
383+ || cosign_key. is_some ( )
384+ || cosign_cert_identity. is_some ( )
385+ || cosign_cert_oidc_issuer. is_some ( )
386+ {
387+ let Some ( ref_value) = oci_ref. as_deref ( ) else {
388+ return Err (
389+ "--oci-ref is required when cosign verification is configured" . to_string ( ) ,
390+ ) ;
391+ } ;
392+ let Some ( cosign_key_path) = cosign_key. as_deref ( ) else {
393+ return Err (
394+ "--cosign-key is required when cosign verification is configured" . to_string ( ) ,
395+ ) ;
396+ } ;
397+ let Some ( cert_identity) = cosign_cert_identity. as_deref ( ) else {
398+ return Err (
399+ "--cosign-cert-identity is required when cosign verification is configured"
400+ . to_string ( ) ,
401+ ) ;
402+ } ;
403+ let Some ( cert_oidc_issuer) = cosign_cert_oidc_issuer. as_deref ( ) else {
404+ return Err (
405+ "--cosign-cert-oidc-issuer is required when cosign verification is configured"
406+ . to_string ( ) ,
407+ ) ;
345408 } ;
346- verify_cosign_oci_ref ( ref_value) ?;
409+ verify_cosign_oci_ref ( ref_value, cosign_key_path , cert_identity , cert_oidc_issuer ) ?;
347410 }
348411 let trust_ms = trust_started. elapsed ( ) . as_millis ( ) as u64 ;
349412
@@ -571,6 +634,9 @@ struct RunBundleArgs {
571634 keys_digest : String ,
572635 require_cosign : bool ,
573636 oci_ref : Option < String > ,
637+ cosign_key : Option < String > ,
638+ cosign_cert_identity : Option < String > ,
639+ cosign_cert_oidc_issuer : Option < String > ,
574640 policy_path : PathBuf ,
575641 input_path : PathBuf ,
576642 receipt_path : PathBuf ,
@@ -585,6 +651,9 @@ fn run_bundle(args: RunBundleArgs) -> Result<(), String> {
585651 keys_digest,
586652 require_cosign,
587653 oci_ref,
654+ cosign_key,
655+ cosign_cert_identity,
656+ cosign_cert_oidc_issuer,
588657 policy_path,
589658 input_path,
590659 receipt_path,
@@ -612,11 +681,35 @@ fn run_bundle(args: RunBundleArgs) -> Result<(), String> {
612681
613682 let public_keys = parse_public_keys ( & keys_raw) ?;
614683 verify_signatures ( & bundle. signatures , & public_keys) . map_err ( |e| e. to_string ( ) ) ?;
615- if require_cosign || oci_ref. is_some ( ) {
684+ if require_cosign
685+ || oci_ref. is_some ( )
686+ || cosign_key. is_some ( )
687+ || cosign_cert_identity. is_some ( )
688+ || cosign_cert_oidc_issuer. is_some ( )
689+ {
616690 let Some ( ref_value) = oci_ref. as_deref ( ) else {
617- return Err ( "--oci-ref is required when --require-cosign is set" . to_string ( ) ) ;
691+ return Err (
692+ "--oci-ref is required when cosign verification is configured" . to_string ( ) ,
693+ ) ;
618694 } ;
619- verify_cosign_oci_ref ( ref_value) ?;
695+ let Some ( cosign_key_path) = cosign_key. as_deref ( ) else {
696+ return Err (
697+ "--cosign-key is required when cosign verification is configured" . to_string ( ) ,
698+ ) ;
699+ } ;
700+ let Some ( cert_identity) = cosign_cert_identity. as_deref ( ) else {
701+ return Err (
702+ "--cosign-cert-identity is required when cosign verification is configured"
703+ . to_string ( ) ,
704+ ) ;
705+ } ;
706+ let Some ( cert_oidc_issuer) = cosign_cert_oidc_issuer. as_deref ( ) else {
707+ return Err (
708+ "--cosign-cert-oidc-issuer is required when cosign verification is configured"
709+ . to_string ( ) ,
710+ ) ;
711+ } ;
712+ verify_cosign_oci_ref ( ref_value, cosign_key_path, cert_identity, cert_oidc_issuer) ?;
620713 }
621714
622715 let policy = parse_policy_document ( & policy_raw) . map_err ( |e| e. to_string ( ) ) ?;
@@ -1003,9 +1096,23 @@ fn emit_obs(event: &str, fields: Vec<(&str, Value)>) {
10031096 eprintln ! ( "{}" , Value :: Object ( record) ) ;
10041097}
10051098
1006- fn verify_cosign_oci_ref ( oci_ref : & str ) -> Result < ( ) , String > {
1099+ fn verify_cosign_oci_ref (
1100+ oci_ref : & str ,
1101+ cosign_key : & str ,
1102+ cert_identity : & str ,
1103+ cert_oidc_issuer : & str ,
1104+ ) -> Result < ( ) , String > {
10071105 let output = Command :: new ( "cosign" )
1008- . args ( [ "verify" , oci_ref] )
1106+ . args ( [
1107+ "verify" ,
1108+ "--key" ,
1109+ cosign_key,
1110+ "--certificate-identity" ,
1111+ cert_identity,
1112+ "--certificate-oidc-issuer" ,
1113+ cert_oidc_issuer,
1114+ oci_ref,
1115+ ] )
10091116 . output ( )
10101117 . map_err ( |e| format ! ( "cosign verify invocation failed: {e}" ) ) ?;
10111118 if !output. status . success ( ) {
0 commit comments