use clap::{Parser, Subcommand};
use std::path::PathBuf;
mod crypto;
mod epistemic;
mod ledger;
mod routing;
#[derive(Parser)]
#[command(name = "urn-authority")]
#[command(about = "CoReason URN Authority — OCI Trust Anchor CLI", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Resolve {
urn: String,
#[arg(long)]
ledger_path: Option<PathBuf>,
#[arg(long)]
json: bool,
},
List {
#[arg(long)]
ledger_path: Option<PathBuf>,
#[arg(long)]
json: bool,
},
Promote {
#[arg(long)]
urn: String,
#[arg(long)]
oci_uri: String,
#[arg(long)]
did: String,
#[arg(long, default_value = "urn:tenant:coreason:global:authority")]
tenant_cid: String,
#[arg(long)]
mcp_namespace: Option<String>,
#[arg(long)]
dependency: Vec<String>,
#[arg(long)]
royalty_share: Vec<String>,
#[arg(long)]
payment_splitter_address: Option<String>,
#[arg(long)]
ledger_path: Option<PathBuf>,
#[arg(long)]
skip_git: bool,
},
VerifyAttestation {
code_file: PathBuf,
#[arg(long)]
expected_hash: Option<String>,
},
ScanDlp {
#[arg(long)]
payload: Option<String>,
#[arg(long)]
payload_file: Option<PathBuf>,
},
VerifyProof {
#[arg(long)]
proof: PathBuf,
#[arg(long)]
vk: PathBuf,
#[arg(long)]
settings: PathBuf,
},
EpistemicRoot {
#[arg(long)]
project_path: PathBuf,
#[arg(long)]
manifest_version: Option<String>,
},
NatsRegister {
#[arg(long)]
urn: String,
#[arg(long, default_value = "RESTRICTED")]
clearance: String,
#[arg(long, default_value = "DRAFT")]
epistemic_status: String,
#[arg(long)]
capability_metadata: Option<String>,
#[arg(long, default_value = "")]
content_hash: String,
#[arg(long, default_value = "nats://localhost:4222")]
nats_url: String,
#[arg(long, default_value = "coreason-registry")]
bucket: String,
},
NatsResolve {
#[arg(long)]
urn: String,
#[arg(long, default_value = "nats://localhost:4222")]
nats_url: String,
#[arg(long, default_value = "coreason-registry")]
bucket: String,
},
NatsList {
#[arg(long, default_value = "nats://localhost:4222")]
nats_url: String,
#[arg(long, default_value = "coreason-registry")]
bucket: String,
#[arg(long)]
json: bool,
},
CostTrackerSchema,
CostTrackerVerify {
#[arg(long)]
budget: f64,
#[arg(long)]
records_json: String,
#[arg(long)]
new_record_json: String,
},
LedgerCheckAccess {
#[arg(long)]
ledger_path: Option<PathBuf>,
#[arg(long)]
urn: String,
#[arg(long)]
tenant_tier: String,
#[arg(long)]
tenant_license: String,
},
InitWorkspace {
#[arg(long)]
target_path: PathBuf,
#[arg(long)]
categories: String, #[arg(long)]
kyc: String, },
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Resolve {
urn,
ledger_path,
json,
} => match routing::resolve_capability(&urn, ledger_path) {
Ok(receipt) => {
if json {
println!("{}", serde_json::to_string(&receipt).unwrap());
} else {
println!("--- Verified Capability Receipt ---");
println!("URN: {}", receipt.urn);
println!("OCI: {}", receipt.oci_uri);
println!("Signer: {}", receipt.authorized_signer_did);
}
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
},
Commands::List { ledger_path, json } => match ledger::load_ledger(ledger_path) {
Ok(entries) => {
if json {
println!("{}", serde_json::to_string(&entries).unwrap());
} else {
if entries.is_empty() {
println!("No capabilities registered in the ledger.");
return;
}
println!(
"--- OCI Artifact Ledger ({} capabilities) ---",
entries.len()
);
for entry in entries {
println!(" {}", entry.urn);
println!(" OCI: {}", entry.oci_uri);
println!(" Signer: {}", entry.authorized_signer_did);
println!();
}
}
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
},
Commands::Promote {
urn,
oci_uri,
did,
tenant_cid,
mcp_namespace,
dependency,
royalty_share,
payment_splitter_address,
ledger_path,
skip_git,
} => {
if !urn.starts_with("urn:coreason:") {
eprintln!("Error: URN must follow the 'urn:coreason:' schema.");
std::process::exit(1);
}
if !did.starts_with("did:key:") {
eprintln!("Error: Signer DID must follow the 'did:key:' format.");
std::process::exit(1);
}
let mut royalty_shares = std::collections::HashMap::new();
for share_str in royalty_share {
if !share_str.contains('=') {
eprintln!("Error: Royalty share must be in format 'did:key:xyz=percentage'");
std::process::exit(1);
}
let parts: Vec<&str> = share_str.splitn(2, '=').collect();
let signer_did = parts[0];
if !signer_did.starts_with("did:key:") {
eprintln!("Error: Royalty share DID must follow the 'did:key:' format.");
std::process::exit(1);
}
let pct: u32 = match parts[1].parse() {
Ok(p) => p,
Err(_) => {
eprintln!(
"Error: Royalty share percentage must be an integer: {}",
parts[1]
);
std::process::exit(1);
}
};
royalty_shares.insert(signer_did.to_string(), pct);
}
if !royalty_shares.is_empty() {
let sum: u32 = royalty_shares.values().sum();
if sum != 100 {
eprintln!(
"Error: Royalty shares must sum to 100. Current sum: {}",
sum
);
std::process::exit(1);
}
}
match ledger::promote_capability(
&urn,
&oci_uri,
&did,
&tenant_cid,
mcp_namespace.as_deref(),
dependency,
royalty_shares,
payment_splitter_address.as_deref(),
ledger_path,
skip_git,
) {
Ok(_) => {}
Err(e) => {
eprintln!("Error promoting capability: {}", e);
std::process::exit(1);
}
}
}
Commands::VerifyAttestation {
code_file,
expected_hash,
} => match crypto::verify_code_attestation(&code_file, expected_hash.as_deref()) {
Ok(_) => {
println!("Attestation succeeded: Code fingerprint matches signature.");
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
},
Commands::ScanDlp {
payload,
payload_file,
} => {
let text = if let Some(p) = payload {
p
} else if let Some(pf) = payload_file {
match std::fs::read_to_string(&pf) {
Ok(t) => t,
Err(e) => {
eprintln!("Error reading payload file: {}", e);
std::process::exit(1);
}
}
} else {
eprintln!("Error: Either --payload or --payload-file must be provided.");
std::process::exit(1);
};
let violations = coreason_urn_authority::scan_dlp_violations(&text);
let is_clean = violations.is_empty();
let result = serde_json::json!({
"clean": is_clean,
"violations": violations,
});
println!("{}", serde_json::to_string(&result).unwrap());
}
Commands::VerifyProof {
proof,
vk,
settings,
} => match crypto::verify_ezkl_proof(&proof, &vk, &settings) {
Ok(verified) => {
if verified {
println!("zk-SNARK Verification Succeeded: Proof of Valid Inference is mathematically valid.");
} else {
eprintln!("zk-SNARK Verification Failed: Invalid Proof of Valid Inference.");
std::process::exit(1);
}
}
Err(e) => {
eprintln!("Error verifying proof: {}", e);
std::process::exit(1);
}
},
Commands::EpistemicRoot {
project_path,
manifest_version,
} => {
match epistemic::calculate_epistemic_root(&project_path, manifest_version.as_deref()) {
Ok(root_hash) => {
println!("{}", root_hash);
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Commands::NatsRegister {
urn,
clearance,
epistemic_status,
capability_metadata,
content_hash,
nats_url,
bucket,
} => {
let metadata = match capability_metadata {
Some(s) => serde_json::from_str(&s).unwrap_or(serde_json::Value::Null),
None => serde_json::Value::Object(serde_json::Map::new()),
};
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
match rt.block_on(coreason_urn_authority::nats_registry::register_capability(
&nats_url,
&bucket,
&urn,
&clearance,
&epistemic_status,
metadata,
&content_hash,
)) {
Ok(_) => {
println!("Successfully registered capability: {}", urn);
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Commands::NatsResolve {
urn,
nats_url,
bucket,
} => {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
match rt.block_on(coreason_urn_authority::nats_registry::resolve_urn(
&nats_url, &bucket, &urn,
)) {
Ok(entry) => {
println!("{}", serde_json::to_string(&entry).unwrap());
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Commands::NatsList {
nats_url,
bucket,
json,
} => {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
match rt.block_on(
coreason_urn_authority::nats_registry::list_all_capabilities(&nats_url, &bucket),
) {
Ok(caps) => {
if json {
println!("{}", serde_json::to_string(&caps).unwrap());
} else {
println!("Registered capabilities in NATS KV ({} total):", caps.len());
for (urn, entry) in caps {
println!(" {} (clearance={})", urn, entry.clearance);
}
}
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Commands::CostTrackerSchema => {
println!(
"{}",
coreason_urn_authority::cost_tracker::get_postgres_schema()
);
}
Commands::CostTrackerVerify {
budget,
records_json,
new_record_json,
} => {
let records: Vec<coreason_urn_authority::cost_tracker::ThermodynamicCostRecord> =
match serde_json::from_str(&records_json) {
Ok(r) => r,
Err(e) => {
eprintln!("Invalid records JSON: {}", e);
std::process::exit(1);
}
};
let new_record: coreason_urn_authority::cost_tracker::ThermodynamicCostRecord =
match serde_json::from_str(&new_record_json) {
Ok(r) => r,
Err(e) => {
eprintln!("Invalid new record JSON: {}", e);
std::process::exit(1);
}
};
match coreason_urn_authority::cost_tracker::verify_cost_and_update(
budget, records, new_record,
) {
Ok(updated) => {
println!("{}", serde_json::to_string(&updated).unwrap());
}
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
}
}
Commands::LedgerCheckAccess {
ledger_path,
urn,
tenant_tier,
tenant_license,
} => {
let entries = match coreason_urn_authority::ledger::load_ledger(ledger_path) {
Ok(e) => e,
Err(e) => {
eprintln!("Failed to load ledger: {}", e);
std::process::exit(1);
}
};
if coreason_urn_authority::ledger::check_ledger_access(
&entries,
&urn,
&tenant_tier,
&tenant_license,
) {
println!("true");
} else {
println!("false");
std::process::exit(1);
}
}
Commands::InitWorkspace {
target_path,
categories,
kyc,
} => {
let categories_vec: Vec<String> = categories
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect();
let ram_gb = coreason_urn_authority::init::get_ram_gb();
let has_gpu = coreason_urn_authority::init::detect_gpu();
let (canonical_kyc, tenant_cid) =
match coreason_urn_authority::init::calculate_tenant_cid(&kyc) {
Ok(res) => res,
Err(e) => {
eprintln!("Invalid KYC format: {}", e);
std::process::exit(1);
}
};
match coreason_urn_authority::init::generate_egress_rules(&target_path, &categories_vec)
{
Ok(_) => {
let out = serde_json::json!({
"ram_gb": ram_gb,
"has_gpu": has_gpu,
"canonical_kyc": canonical_kyc,
"tenant_cid": tenant_cid,
});
println!("{}", serde_json::to_string(&out).unwrap());
}
Err(e) => {
eprintln!("Failed to generate egress rules: {}", e);
std::process::exit(1);
}
}
}
}
}