Skip to main content

atlas_cli/cli/
commands.rs

1use clap::Subcommand;
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, clap::ValueEnum)]
5pub enum HashAlgorithmChoice {
6    Sha256,
7    Sha384,
8    Sha512,
9}
10
11impl HashAlgorithmChoice {
12    pub fn to_cose_algorithm(&self) -> atlas_c2pa_lib::cose::HashAlgorithm {
13        match self {
14            HashAlgorithmChoice::Sha256 => atlas_c2pa_lib::cose::HashAlgorithm::Sha256,
15            HashAlgorithmChoice::Sha384 => atlas_c2pa_lib::cose::HashAlgorithm::Sha384,
16            HashAlgorithmChoice::Sha512 => atlas_c2pa_lib::cose::HashAlgorithm::Sha512,
17        }
18    }
19}
20
21#[derive(Debug, Subcommand)]
22pub enum DatasetCommands {
23    /// Create a new dataset manifest
24    Create {
25        #[arg(long = "paths", num_args = 1.., value_delimiter = ',')]
26        paths: Vec<PathBuf>,
27
28        /// Names for each ingredient (comma-separated)
29        #[arg(long = "ingredient-names", num_args = 1.., value_delimiter = ',')]
30        ingredient_names: Vec<String>,
31
32        /// Dataset name
33        #[arg(long = "name")]
34        name: String,
35
36        /// Author organization name
37        #[arg(long = "author-org")]
38        author_org: Option<String>,
39
40        /// Author name
41        #[arg(long = "author-name")]
42        author_name: Option<String>,
43
44        /// Optional description
45        #[arg(long = "description")]
46        description: Option<String>,
47
48        /// Optional linked manifest IDs
49        #[arg(long = "linked-manifests")]
50        linked_manifests: Option<Vec<String>>,
51
52        /// Path to private key file for signing (PEM format)
53        #[arg(long = "key")]
54        key: Option<PathBuf>,
55
56        /// Path to X.509 certificate file (PEM format, required for Rekor storage)
57        #[arg(long = "cert")]
58        cert: Option<PathBuf>,
59
60        /// Use Fulcio to obtain a certificate via OIDC (alternative to --cert)
61        #[arg(long = "fulcio", default_value = "false")]
62        fulcio: bool,
63
64        /// OIDC identity token for Fulcio (required when --fulcio is set)
65        #[arg(long = "oidc-token")]
66        oidc_token: Option<String>,
67
68        /// Hash algorithm to use for signing (default: sha384)
69        #[arg(long = "hash-alg", value_enum, default_value = "sha384")]
70        hash_alg: HashAlgorithmChoice,
71
72        /// Only print manifest without storing
73        #[arg(long = "print")]
74        print: bool,
75
76        /// Output encoding (json or cbor)
77        #[arg(long = "encoding", default_value = "json")]
78        encoding: String,
79
80        /// Storage backend (local or rekor)
81        #[arg(long = "storage-type", default_value = "database")]
82        storage_type: Box<String>,
83
84        /// Storage URL
85        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
86        storage_url: Box<String>,
87
88        /// Collect the underlying TDX attestation, if available
89        #[arg(long = "with-tdx", default_value = "false")]
90        with_tdx: bool,
91    },
92    /// List all dataset manifests
93    List {
94        /// Storage backend (local or rekor)
95        #[arg(long = "storage-type", default_value = "database")]
96        storage_type: Box<String>,
97
98        /// Storage URL
99        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
100        storage_url: Box<String>,
101    },
102    Verify {
103        /// Manifest ID to verify
104        #[arg(long = "id")]
105        id: String,
106        /// Storage backend (local or rekor)
107        #[arg(long = "storage-type", default_value = "database")]
108        storage_type: Box<String>,
109
110        /// Storage URL
111        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
112        storage_url: Box<String>,
113    },
114}
115
116#[derive(Debug, Subcommand)]
117pub enum ModelCommands {
118    /// Create a new signed model manifest compliant with OpenSSF Model Signing (OMS) specification
119    Create {
120        /// Paths to the model ingredient files
121        #[arg(long = "paths", num_args = 1.., value_delimiter = ',')]
122        paths: Vec<PathBuf>,
123
124        /// Names for each ingredient (comma-separated)
125        #[arg(long = "ingredient-names", num_args = 1.., value_delimiter = ',')]
126        ingredient_names: Vec<String>,
127
128        /// Model name
129        #[arg(long = "name")]
130        name: String,
131
132        /// Author organization name
133        #[arg(long = "author-org")]
134        author_org: Option<String>,
135
136        /// Author name
137        #[arg(long = "author-name")]
138        author_name: Option<String>,
139
140        /// Optional description
141        #[arg(long = "description")]
142        description: Option<String>,
143
144        /// Optional linked manifest IDs
145        #[arg(long = "linked-manifests")]
146        linked_manifests: Option<Vec<String>>,
147
148        /// Path to private key file for signing (PEM format)
149        #[arg(long = "key")]
150        key: Option<PathBuf>,
151
152        /// Path to X.509 certificate file (PEM format, required for Rekor storage)
153        #[arg(long = "cert")]
154        cert: Option<PathBuf>,
155
156        /// Use Fulcio to obtain a certificate via OIDC (alternative to --cert)
157        #[arg(long = "fulcio", default_value = "false")]
158        fulcio: bool,
159
160        /// OIDC identity token for Fulcio (required when --fulcio is set)
161        #[arg(long = "oidc-token")]
162        oidc_token: Option<String>,
163
164        /// Hash algorithm to use for signing (default: sha384)
165        #[arg(long = "hash-alg", value_enum, default_value = "sha384")]
166        hash_alg: HashAlgorithmChoice,
167
168        /// Only print manifest without storing
169        #[arg(long = "print")]
170        print: bool,
171
172        /// Encoding (json or cbor)
173        #[arg(long = "encoding", default_value = "json")]
174        encoding: String,
175
176        /// Format (standalone c2pa or oms)
177        #[arg(long = "format", default_value = "standalone")]
178        format: String,
179
180        /// Storage backend (local or rekor)
181        #[arg(long = "storage-type", default_value = "database")]
182        storage_type: Box<String>,
183
184        /// Storage URL
185        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
186        storage_url: Box<String>,
187
188        /// Collect the underlying CC attestation, if available
189        #[arg(long = "with-tdx", default_value = "false")]
190        with_tdx: bool,
191    },
192    /// List all model manifests
193    List {
194        /// Storage backend (local or rekor)
195        #[arg(long = "storage-type", default_value = "database")]
196        storage_type: Box<String>,
197
198        /// Storage URL
199        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
200        storage_url: Box<String>,
201    },
202    Verify {
203        /// Manifest ID to verify
204        #[arg(long = "id")]
205        id: String,
206        /// Storage backend (local or rekor)
207        #[arg(long = "storage-type", default_value = "database")]
208        storage_type: Box<String>,
209
210        /// Storage URL
211        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
212        storage_url: Box<String>,
213    },
214    LinkDataset {
215        /// Model manifest ID
216        #[arg(long = "model-id")]
217        model_id: String,
218
219        /// Dataset manifest ID
220        #[arg(long = "dataset-id")]
221        dataset_id: String,
222
223        /// Storage backend (local or rekor)
224        #[arg(long = "storage-type", default_value = "database")]
225        storage_type: Box<String>,
226
227        /// Storage URL
228        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
229        storage_url: Box<String>,
230    },
231}
232
233#[derive(Subcommand)]
234pub enum ManifestCommands {
235    /// Link manifests together
236    Link {
237        /// Source manifest ID
238        #[arg(short, long)]
239        source: String,
240
241        /// Target manifest ID
242        #[arg(short, long)]
243        target: String,
244
245        /// Storage backend (local or rekor)
246        #[arg(long = "storage-type", default_value = "database")]
247        storage_type: Box<String>,
248
249        /// Storage URL
250        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
251        storage_url: Box<String>,
252    },
253
254    /// Show manifest details
255    Show {
256        /// Manifest ID to show
257        #[arg(short, long)]
258        id: String,
259
260        /// Storage backend (local or rekor)
261        #[arg(long = "storage-type", default_value = "database")]
262        storage_type: Box<String>,
263
264        /// Storage URL
265        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
266        storage_url: Box<String>,
267    },
268
269    /// Validate manifest cross-references
270    Validate {
271        /// Manifest ID to validate
272        #[arg(short, long)]
273        id: String,
274
275        /// Storage backend (local or rekor)
276        #[arg(long = "storage-type", default_value = "database")]
277        storage_type: Box<String>,
278
279        /// Storage URL
280        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
281        storage_url: Box<String>,
282    },
283
284    /// Verify a specific link between two manifests
285    VerifyLink {
286        /// Source manifest ID
287        #[arg(short, long)]
288        source: String,
289
290        /// Target manifest ID
291        #[arg(short, long)]
292        target: String,
293
294        /// Storage backend (local or rekor)
295        #[arg(long = "storage-type", default_value = "database")]
296        storage_type: Box<String>,
297
298        /// Storage URL
299        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
300        storage_url: Box<String>,
301    },
302    /// Export provenance graph information
303    Export {
304        /// Manifest ID to export provenance for
305        #[arg(short, long)]
306        id: String,
307
308        /// Storage backend (local or rekor)
309        #[arg(long = "storage-type", default_value = "database")]
310        storage_type: Box<String>,
311
312        /// Storage URL
313        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
314        storage_url: Box<String>,
315
316        /// Output encoding (json or yaml)
317        #[arg(long = "encoding", default_value = "json")]
318        encoding: String,
319
320        /// Output file path (defaults to stdout if not provided)
321        #[arg(short, long)]
322        output: Option<String>,
323
324        /// Max depth to traverse the provenance graph (default: 10)
325        #[arg(long = "max-depth", default_value = "10")]
326        max_depth: u32,
327    },
328}
329/// Commands for evaluation results
330#[derive(Subcommand)]
331pub enum EvaluationCommands {
332    /// Create a new evaluation result manifest
333    Create {
334        /// Path to evaluation results file
335        #[arg(long = "path")]
336        path: PathBuf,
337
338        /// Evaluation name
339        #[arg(long = "name")]
340        name: String,
341
342        /// Model ID that was evaluated
343        #[arg(long = "model-id")]
344        model_id: String,
345
346        /// Evaluation dataset ID
347        #[arg(long = "dataset-id")]
348        dataset_id: String,
349
350        /// Evaluation metrics (key=value pairs)
351        #[arg(long = "metrics", num_args = 1.., value_delimiter = ',')]
352        metrics: Vec<String>,
353
354        /// Author organization name
355        #[arg(long = "author-org")]
356        author_org: Option<String>,
357
358        /// Author name
359        #[arg(long = "author-name")]
360        author_name: Option<String>,
361
362        /// Optional description
363        #[arg(long = "description")]
364        description: Option<String>,
365
366        /// Path to private key file for signing (PEM format)
367        #[arg(long = "key")]
368        key: Option<PathBuf>,
369
370        /// Path to X.509 certificate file (PEM format, required for Rekor storage)
371        #[arg(long = "cert")]
372        cert: Option<PathBuf>,
373
374        /// Use Fulcio to obtain a certificate via OIDC (alternative to --cert)
375        #[arg(long = "fulcio", default_value = "false")]
376        fulcio: bool,
377
378        /// OIDC identity token for Fulcio (required when --fulcio is set)
379        #[arg(long = "oidc-token")]
380        oidc_token: Option<String>,
381
382        /// Hash algorithm to use for signing (default: sha384)
383        #[arg(long = "hash-alg", value_enum, default_value = "sha384")]
384        hash_alg: HashAlgorithmChoice,
385
386        /// Only print manifest without storing
387        #[arg(long = "print")]
388        print: bool,
389
390        /// Output encoding (json or cbor)
391        #[arg(long = "encoding", default_value = "json")]
392        encoding: String,
393
394        /// Storage backend (local or rekor)
395        #[arg(long = "storage-type", default_value = "database")]
396        storage_type: Box<String>,
397
398        /// Storage URL
399        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
400        storage_url: Box<String>,
401    },
402
403    /// List all evaluation results
404    List {
405        /// Storage backend (local or rekor)
406        #[arg(long = "storage-type", default_value = "database")]
407        storage_type: Box<String>,
408
409        /// Storage URL
410        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
411        storage_url: Box<String>,
412    },
413
414    /// Verify an evaluation result manifest
415    Verify {
416        /// Evaluation result manifest ID to verify
417        #[arg(long = "id")]
418        id: String,
419
420        /// Storage backend (local or rekor)
421        #[arg(long = "storage-type", default_value = "database")]
422        storage_type: Box<String>,
423
424        /// Storage URL
425        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
426        storage_url: Box<String>,
427    },
428}
429
430/// CCAttestationCommands are mostly for debugging since CC attestations
431/// will be collected directly during asset creation/modification
432#[derive(Subcommand)]
433pub enum CCAttestationCommands {
434    /// Reads the CC attestation and display it
435    Show,
436    /// Extracts the VM launch measurement value from the CC attestation
437    GetLaunchMeasurement,
438    /// Verify VM launch measurement against a launch endorsement
439    VerifyLaunch {
440        /// VM host platform (determines download command and format)
441        #[arg(long = "host-platform", default_value = "gcp-tdx")]
442        host_platform: String,
443    },
444}
445
446#[derive(Debug, Subcommand)]
447pub enum SoftwareCommands {
448    /// Create a new software component manifest
449    Create {
450        #[arg(long = "paths", num_args = 1.., value_delimiter = ',')]
451        paths: Vec<PathBuf>,
452
453        /// Names for each component (comma-separated)
454        #[arg(long = "ingredient-names", num_args = 1.., value_delimiter = ',')]
455        ingredient_names: Vec<String>,
456
457        /// Software name
458        #[arg(long = "name")]
459        name: String,
460
461        /// Software type (script, container, VM, etc.)
462        #[arg(long = "software-type")]
463        software_type: String,
464
465        /// Software version
466        #[arg(long = "version")]
467        version: Option<String>,
468
469        /// Author organization name
470        #[arg(long = "author-org")]
471        author_org: Option<String>,
472
473        /// Author name
474        #[arg(long = "author-name")]
475        author_name: Option<String>,
476
477        /// Optional description
478        #[arg(long = "description")]
479        description: Option<String>,
480
481        /// Optional linked manifest IDs
482        #[arg(long = "linked-manifests")]
483        linked_manifests: Option<Vec<String>>,
484
485        /// Path to private key file for signing (PEM format)
486        #[arg(long = "key")]
487        key: Option<PathBuf>,
488
489        /// Path to X.509 certificate file (PEM format, required for Rekor storage)
490        #[arg(long = "cert")]
491        cert: Option<PathBuf>,
492
493        /// Use Fulcio to obtain a certificate via OIDC (alternative to --cert)
494        #[arg(long = "fulcio", default_value = "false")]
495        fulcio: bool,
496
497        /// OIDC identity token for Fulcio (required when --fulcio is set)
498        #[arg(long = "oidc-token")]
499        oidc_token: Option<String>,
500
501        /// Hash algorithm to use for signing (default: sha384)
502        #[arg(long = "hash-alg", value_enum, default_value = "sha384")]
503        hash_alg: HashAlgorithmChoice,
504
505        /// Only print manifest without storing
506        #[arg(long = "print")]
507        print: bool,
508
509        /// Output encoding (json or cbor)
510        #[arg(long = "encoding", default_value = "json")]
511        encoding: String,
512
513        /// Storage backend (local or rekor)
514        #[arg(long = "storage-type", default_value = "database")]
515        storage_type: Box<String>,
516
517        /// Storage URL
518        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
519        storage_url: Box<String>,
520
521        /// Collect the underlying CC attestation, if available
522        #[arg(long = "with-tdx", default_value = "false")]
523        with_tdx: bool,
524    },
525    /// List all software component manifests
526    List {
527        /// Storage backend (local or rekor)
528        #[arg(long = "storage-type", default_value = "database")]
529        storage_type: Box<String>,
530
531        /// Storage URL
532        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
533        storage_url: Box<String>,
534    },
535    /// Verify a software component manifest
536    Verify {
537        /// Manifest ID to verify
538        #[arg(long = "id")]
539        id: String,
540        /// Storage backend (local or rekor)
541        #[arg(long = "storage-type", default_value = "database")]
542        storage_type: Box<String>,
543
544        /// Storage URL
545        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
546        storage_url: Box<String>,
547    },
548    /// Link software to a model
549    LinkModel {
550        /// Software manifest ID
551        #[arg(long = "software-id")]
552        software_id: String,
553
554        /// Model manifest ID
555        #[arg(long = "model-id")]
556        model_id: String,
557
558        /// Storage backend (local or rekor)
559        #[arg(long = "storage-type", default_value = "database")]
560        storage_type: Box<String>,
561
562        /// Storage URL
563        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
564        storage_url: Box<String>,
565    },
566    /// Link software to a dataset
567    LinkDataset {
568        /// Software manifest ID
569        #[arg(long = "software-id")]
570        software_id: String,
571
572        /// Dataset manifest ID
573        #[arg(long = "dataset-id")]
574        dataset_id: String,
575
576        /// Storage backend (local or rekor)
577        #[arg(long = "storage-type", default_value = "database")]
578        storage_type: Box<String>,
579
580        /// Storage URL
581        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
582        storage_url: Box<String>,
583    },
584}
585
586#[derive(Debug, Subcommand)]
587pub enum RekorCommands {
588    /// Verify a local manifest against a Rekor transparency log entry
589    Verify {
590        /// Rekor entry UUID
591        #[arg(long = "uuid")]
592        uuid: String,
593
594        /// Path to the local manifest JSON file
595        #[arg(long = "manifest")]
596        manifest: PathBuf,
597
598        /// Rekor server URL
599        #[arg(long = "rekor-url", default_value = "https://rekor.sigstore.dev")]
600        rekor_url: String,
601    },
602    /// Look up a Rekor entry by UUID
603    Get {
604        /// Rekor entry UUID
605        #[arg(long = "uuid")]
606        uuid: String,
607
608        /// Rekor server URL
609        #[arg(long = "rekor-url", default_value = "https://rekor.sigstore.dev")]
610        rekor_url: String,
611    },
612}
613
614#[derive(Debug, Subcommand)]
615pub enum PipelineCommands {
616    /// Generate SLSA Build Provenance v1 for the given pipeline
617    GenerateProvenance {
618        /// Paths to any pipeline inputs and other external parameters
619        #[arg(long = "inputs", num_args = 1.., value_delimiter = ',')]
620        inputs: Vec<PathBuf>,
621
622        /// Path to pipeline script or configuration
623        #[arg(long = "pipeline")]
624        pipeline: PathBuf,
625
626        /// Paths to any pipeline products
627        #[arg(long = "products", num_args = 1.., value_delimiter = ',')]
628        products: Vec<PathBuf>,
629
630        /// Path to private key file for signing (PEM format)
631        #[arg(long = "key")]
632        key: Option<PathBuf>,
633
634        /// Hash algorithm to use for signing (default: sha384)
635        #[arg(long = "hash-alg", value_enum, default_value = "sha384")]
636        hash_alg: HashAlgorithmChoice,
637
638        /// Only print SLSA Provenance without storing
639        #[arg(long = "print")]
640        print: bool,
641
642        /// Output encoding (json or cbor)
643        #[arg(long = "encoding", default_value = "json")]
644        encoding: String,
645
646        /// Storage backend (only local supported)
647        #[arg(long = "storage-type", default_value = "local-fs")]
648        storage_type: Box<String>,
649
650        /// Storage URL
651        #[arg(long = "storage-url", default_value = "http://localhost:8080")]
652        storage_url: Box<String>,
653
654        /// Collect the underlying TDX attestation, if available
655        #[arg(long = "with-tdx", default_value = "false")]
656        with_tdx: bool,
657    },
658}