auths_cli/commands/artifact/
mod.rs1pub mod core;
2pub mod file;
3pub mod publish;
4pub mod sign;
5pub mod verify;
6
7use clap::{Args, Subcommand};
8use std::path::PathBuf;
9use std::sync::Arc;
10
11use anyhow::Result;
12use auths_core::config::EnvironmentConfig;
13use auths_core::signing::PassphraseProvider;
14
15#[derive(Args, Debug, Clone)]
16#[command(about = "Sign and verify arbitrary artifacts (tarballs, binaries, etc.).")]
17pub struct ArtifactCommand {
18 #[command(subcommand)]
19 pub command: ArtifactSubcommand,
20}
21
22#[derive(Subcommand, Debug, Clone)]
23pub enum ArtifactSubcommand {
24 Sign {
26 #[arg(help = "Path to the artifact file to sign.")]
28 file: PathBuf,
29
30 #[arg(long = "sig-output", value_name = "PATH")]
32 sig_output: Option<PathBuf>,
33
34 #[arg(
36 long,
37 visible_alias = "ika",
38 help = "Local alias of the identity key. Omit for device-only CI signing."
39 )]
40 identity_key_alias: Option<String>,
41
42 #[arg(
44 long,
45 visible_alias = "dka",
46 help = "Local alias of the device key (used for dual-signing)."
47 )]
48 device_key_alias: String,
49
50 #[arg(long, visible_alias = "days", value_name = "N")]
52 expires_in_days: Option<i64>,
53
54 #[arg(long)]
56 note: Option<String>,
57 },
58
59 Publish {
61 #[arg(long)]
63 signature: PathBuf,
64
65 #[arg(long)]
67 package: Option<String>,
68
69 #[arg(long, default_value = "https://auths-registry.fly.dev")]
71 registry: String,
72 },
73
74 Verify {
76 #[arg(help = "Path to the artifact file to verify.")]
78 file: PathBuf,
79
80 #[arg(long, value_name = "PATH")]
82 signature: Option<PathBuf>,
83
84 #[arg(long, value_parser)]
86 identity_bundle: Option<PathBuf>,
87
88 #[arg(long)]
90 witness_receipts: Option<PathBuf>,
91
92 #[arg(long, num_args = 1..)]
94 witness_keys: Vec<String>,
95
96 #[arg(long, default_value = "1")]
98 witness_threshold: usize,
99 },
100}
101
102pub fn handle_artifact(
104 cmd: ArtifactCommand,
105 repo_opt: Option<PathBuf>,
106 passphrase_provider: Arc<dyn PassphraseProvider + Send + Sync>,
107 env_config: &EnvironmentConfig,
108) -> Result<()> {
109 match cmd.command {
110 ArtifactSubcommand::Sign {
111 file,
112 sig_output,
113 identity_key_alias,
114 device_key_alias,
115 expires_in_days,
116 note,
117 } => sign::handle_sign(
118 &file,
119 sig_output,
120 identity_key_alias.as_deref(),
121 &device_key_alias,
122 expires_in_days,
123 note,
124 repo_opt,
125 passphrase_provider,
126 env_config,
127 ),
128 ArtifactSubcommand::Publish {
129 signature,
130 package,
131 registry,
132 } => publish::handle_publish(&signature, package.as_deref(), ®istry),
133 ArtifactSubcommand::Verify {
134 file,
135 signature,
136 identity_bundle,
137 witness_receipts,
138 witness_keys,
139 witness_threshold,
140 } => {
141 let rt = tokio::runtime::Runtime::new()?;
142 rt.block_on(verify::handle_verify(
143 &file,
144 signature,
145 identity_bundle,
146 witness_receipts,
147 &witness_keys,
148 witness_threshold,
149 ))
150 }
151 }
152}
153
154impl crate::commands::executable::ExecutableCommand for ArtifactCommand {
155 fn execute(&self, ctx: &crate::config::CliConfig) -> anyhow::Result<()> {
156 handle_artifact(
157 self.clone(),
158 ctx.repo_path.clone(),
159 ctx.passphrase_provider.clone(),
160 &ctx.env_config,
161 )
162 }
163}