Full-depth rename per the approved plan; the 'claw' product vocabulary (claws, /claws routes, clawId, Claw Chat) stays — it is now the brand. - Display brand: Clawmates (manifest, titles, hero, login/rail logo 'clawmates'); default host app.clawmates.work; registry ghcr.io/clawmates - Crates tc-* -> cm-* (16 crates + all imports); binaries clawmates-server/broker/bundler; images clawmates/*; env prefix CLAWMATES_* (+ CM_TEST_DATABASE_URL / CM_LIVE_LLM); config clawmates.toml; helm chart deploy/helm/clawmates with clawmates-* resources; db names clawmates*; sockets /run/clawmates; cookie cm_session; kind cluster clawmates-test; seccomp node profile clawmates-agent-profile.json - All 9 Playwright brand assertions updated in lockstep; historical spec document left untouched as the only remaining 'TeamClaw' - Local env migrated: dev pg clawmates-dev-pg/clawmates_dev, shared test server clawmates-test-pg, kind cluster recreated with image + profile, compose images rebuilt under clawmates/* Verified end to end: 161 Rust + 68 frontend tests, 29 Playwright journeys, 4 live kind tests, helm/install/LOC/placeholder gates, and the clean-room install rehearsal serving the clawmates login page from a signed bundle of the rebuilt images. Co-Authored-By: Claude Fable 5 <[email protected]>
69 lines
2.5 KiB
Rust
69 lines
2.5 KiB
Rust
//! clawmates-bundler: assemble and verify air-gapped install bundles.
|
|
//!
|
|
//! Usage:
|
|
//! clawmates-bundler keygen <private.key> <public.key>
|
|
//! clawmates-bundler assemble <out-dir> <version> <private.key> \
|
|
//! <src=dest> [<src=dest> ...]
|
|
//! clawmates-bundler verify <bundle-dir> <public.key>
|
|
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::ExitCode;
|
|
|
|
fn main() -> ExitCode {
|
|
match run() {
|
|
Ok(message) => {
|
|
println!("{message}");
|
|
ExitCode::SUCCESS
|
|
}
|
|
Err(message) => {
|
|
eprintln!("clawmates-bundler: {message}");
|
|
ExitCode::FAILURE
|
|
}
|
|
}
|
|
}
|
|
|
|
fn run() -> Result<String, String> {
|
|
let args: Vec<String> = std::env::args().skip(1).collect();
|
|
match args.first().map(String::as_str) {
|
|
Some("keygen") if args.len() == 3 => {
|
|
clawmates_bundler::generate_keypair(Path::new(&args[1]), Path::new(&args[2]))
|
|
.map_err(|e| e.to_string())?;
|
|
Ok(format!("wrote {} and {}", args[1], args[2]))
|
|
}
|
|
Some("assemble") if args.len() >= 5 => {
|
|
let artifacts: Vec<(PathBuf, String)> = args[4..]
|
|
.iter()
|
|
.map(|pair| {
|
|
pair.split_once('=')
|
|
.map(|(src, dst)| (PathBuf::from(src), dst.to_owned()))
|
|
.ok_or_else(|| format!("expected src=dest, got {pair}"))
|
|
})
|
|
.collect::<Result<_, _>>()?;
|
|
clawmates_bundler::assemble(
|
|
Path::new(&args[1]),
|
|
&args[2],
|
|
&artifacts,
|
|
Path::new(&args[3]),
|
|
)
|
|
.map_err(|e| e.to_string())?;
|
|
Ok(format!(
|
|
"assembled {} artifacts into {}",
|
|
artifacts.len(),
|
|
args[1]
|
|
))
|
|
}
|
|
Some("pubkey") if args.len() == 3 => {
|
|
clawmates_bundler::derive_public_key(Path::new(&args[1]), Path::new(&args[2]))
|
|
.map_err(|e| e.to_string())?;
|
|
Ok(format!("wrote {}", args[2]))
|
|
}
|
|
Some("verify") if args.len() == 3 => {
|
|
let verified =
|
|
clawmates_bundler::verify(Path::new(&args[1]), Path::new(&args[2]))
|
|
.map_err(|e| e.to_string())?;
|
|
Ok(format!("bundle OK: {verified} artifacts verified offline"))
|
|
}
|
|
_ => Err("usage: keygen <priv> <pub> | pubkey <priv> <pub> | assemble <out> <version> <priv> <src=dest>... | verify <bundle> <pub>".into()),
|
|
}
|
|
}
|