mod from_toml;
mod phase1;
use std::ffi::OsString;
use std::path::PathBuf;
use clap::{ArgGroup, Parser};
use vta_sdk::provision_client::OperatorMessages;
pub use from_toml::{SetupFile, run_setup_from_file};
pub use phase1::run_setup_phase1;
pub const DEFAULT_CONTEXT: &str = "trust-registry";
pub const TEMPLATE_NAME: &str = "trust-registry";
#[derive(Parser, Debug)]
#[command(
name = "trust-registry setup",
about = "Provision this Trust Registry at a VTA, headless, in two phases",
group(ArgGroup::new("phase").required(true).args(["setup_key_out", "from"]))
)]
struct SetupArgs {
#[arg(long, value_name = "PATH")]
setup_key_out: Option<PathBuf>,
#[arg(long, conflicts_with = "from")]
context: Option<String>,
#[arg(long, value_name = "FILE")]
from: Option<PathBuf>,
}
pub async fn run_cli(args: impl IntoIterator<Item = OsString>) -> i32 {
let args = match SetupArgs::try_parse_from(args) {
Ok(args) => args,
Err(e) => {
let _ = e.print();
return e.exit_code();
}
};
let result = match (args.setup_key_out, args.from) {
(Some(out), None) => {
let context = args.context.as_deref().unwrap_or(DEFAULT_CONTEXT);
run_setup_phase1(&out, context).await
}
(None, Some(file)) => run_setup_from_file(&file).await,
_ => unreachable!("clap enforces exactly one of --setup-key-out / --from"),
};
match result {
Ok(()) => 0,
Err(e) => {
eprintln!("Error: {e}");
1
}
}
}
pub(crate) struct TrustRegistryMessages;
impl OperatorMessages for TrustRegistryMessages {
fn integration_label(&self) -> &str {
"Trust Registry"
}
fn integration_label_lower(&self) -> &str {
"trust registry"
}
fn pnm_admin_command_hint(&self, context_id: &str, setup_did: &str) -> String {
format!(
"pnm contexts create --id {context_id} --name \"Trust Registry\" \\\n \
--admin-did {setup_did} --admin-expires 1h --admin-handoff"
)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn parse(args: &[&str]) -> Result<SetupArgs, clap::Error> {
SetupArgs::try_parse_from(args)
}
#[test]
fn exactly_one_phase_is_required() {
assert!(parse(&["setup"]).is_err());
assert!(parse(&["setup", "--setup-key-out", "k.json", "--from", "s.toml"]).is_err());
assert!(parse(&["setup", "--setup-key-out", "k.json"]).is_ok());
assert!(
parse(&["setup", "--from", "s.toml"])
.unwrap()
.from
.is_some()
);
}
#[test]
fn context_belongs_to_phase_one() {
assert!(parse(&["setup", "--from", "s.toml", "--context", "x"]).is_err());
}
#[test]
fn grant_hint_allows_the_admin_handoff() {
let hint = TrustRegistryMessages.pnm_admin_command_hint("tr", "did:key:z6MkSetup");
assert!(hint.contains("--id tr"));
assert!(hint.contains("--admin-did did:key:z6MkSetup"));
assert!(hint.contains("--admin-expires 1h --admin-handoff"));
}
}