server/cli/src/sigstore_cli.rs
//! **`holger sigstore-trust`** (lane HOL-OCI-EVIDENCE): the estate's Sigstore trust root
//! (`server_lib::sigstore_trust`).
//!
//! * `make` (the release build; `cargo xtask sigstore-trust stage` runs it): Sigstore's
//! `trusted_root.json` (held to the pinned digest unless `--unpinned`, a test's own root)
//! signed into a `holger.sigstore-trust/v1` bundle by the three identities under
//! `--signer-dir` (minted on first use, keys 0600), and the bundle trust policy that pins them.
//! * `status --config C`: what the box has installed under `<data_root>/holger-trust`.
//!
//! A refresh is carried in like any bundle: `holger bundle import`, the inbox, the import doors.
use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::{Args, Subcommand};
#[derive(Args)]
pub struct SigstoreTrustArgs {
#[command(subcommand)]
pub op: SigstoreTrustOp,
}
#[derive(Subcommand)]
pub enum SigstoreTrustOp {
/// Sign a trusted_root.json into a trust bundle (the release build).
Make {
/// Sigstore's trusted_root.json (the pinned TUF target).
#[arg(long)]
root: PathBuf,
/// The release trust identities, minted here on first use.
#[arg(long)]
signer_dir: PathBuf,
/// The trust bundle to write.
#[arg(long)]
out: PathBuf,
/// Write the bundle trust policy that pins the identities.
#[arg(long)]
policy_out: Option<PathBuf>,
/// The bundle's sequence (each refresh higher). Default: this machine's clock, seconds.
#[arg(long)]
sequence: Option<u64>,
#[arg(long, default_value_t = 730)]
valid_days: i64,
/// Take a root that is not the pinned public-good one (a test's own Sigstore).
#[arg(long)]
unpinned: bool,
},
/// What the box has installed.
Status {
#[arg(short, long)]
config: PathBuf,
},
}
pub fn run(a: SigstoreTrustArgs) -> Result<()> {
match a.op {
SigstoreTrustOp::Make {
root,
signer_dir,
out,
policy_out,
sequence,
valid_days,
unpinned,
} => {
let json = std::fs::read(&root).with_context(|| format!("read {}", root.display()))?;
if !unpinned {
server_lib::sigstore_trust::check_pinned(&json).map_err(|e| anyhow::anyhow!(e))?;
}
let sequence = sequence.unwrap_or_else(|| chrono::Utc::now().timestamp().max(1) as u64);
make(&json, &signer_dir, &out, sequence, valid_days, policy_out)
}
SigstoreTrustOp::Status { config } => {
let holger = server_lib::read_ron_config(&config)
.with_context(|| format!("load config {}", config.display()))?;
match server_lib::sigstore_trust::installed(&holger.data_root()) {
Some(i) => println!(
"SIGSTORE TRUST ROOT seq {} ({}) from {} at {}: trusted_root sha256:{} at {}",
i.sequence, i.bundle_id, i.from, i.at, i.trusted_root_sha256, i.path
),
None => println!(
"SIGSTORE TRUST ROOT none installed under {}",
server_lib::sigstore_trust::dir(&holger.data_root()).display()
),
}
Ok(())
}
}
}
#[cfg(feature = "export-push")]
fn make(
json: &[u8],
signer_dir: &std::path::Path,
out: &std::path::Path,
sequence: u64,
valid_days: i64,
policy_out: Option<PathBuf>,
) -> Result<()> {
let policy = server_lib::sigstore_trust::make(
json,
signer_dir,
out,
sequence,
valid_days,
Some(server_lib::sigstore_trust::pinned_url()),
)?;
println!(
"SIGSTORE TRUST BUNDLE {} seq {sequence} (valid {valid_days} d)",
out.display()
);
if let Some(p) = policy_out {
std::fs::write(
&p,
policy
.to_ron()
.map_err(|e| anyhow::anyhow!("the trust policy: {e}"))?,
)
.with_context(|| format!("write {}", p.display()))?;
println!(
"TRUST POLICY {} (the pinned release trust identities)",
p.display()
);
}
Ok(())
}
#[cfg(not(feature = "export-push"))]
fn make(
_: &[u8],
_: &std::path::Path,
_: &std::path::Path,
_: u64,
_: i64,
_: Option<PathBuf>,
) -> Result<()> {
anyhow::bail!("this build signs no trust root (the release build's, with `export-push`, does)")
}