use crate::open_epiphany_cultmesh_node; use anyhow::{Context, Result, anyhow, bail}; use chrono::{DateTime, Utc}; use cultcache_rs::{DatabaseEntry, SingleFileMessagePackBackingStore}; use fs2::FileExt; use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, BTreeSet}; use std::fs; use std::path::{Path, PathBuf}; use uuid::Uuid; pub const EPIPHANY_PACKAGED_RELEASE_SCHEMA_VERSION: &str = "epiphany.packaged_release.v0"; pub const EPIPHANY_PACKAGED_RELEASE_HEAD_SCHEMA_VERSION: &str = "epiphany.packaged_release_head.v0"; const RELEASE_KEY_PREFIX: &str = "epiphany-local/packaged-release/by-id/"; const RELEASE_HEAD_KEY: &str = "epiphany-local/packaged-release/current"; pub const EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE: &str = "release-witness.ccmp"; #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct EpiphanyPackagedReleaseBinary { pub role: String, pub file_name: String, pub canonical_path: String, pub sha256: String, pub byte_len: u64, } #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache( type = "epiphany.packaged_release", schema = "EpiphanyPackagedReleaseEntry" )] pub struct EpiphanyPackagedReleaseEntry { #[cultcache(key = 0)] pub schema_version: String, #[cultcache(key = 1)] pub release_id: String, #[cultcache(key = 2)] pub runtime_id: String, #[cultcache(key = 3)] pub source_commit_sha: String, #[cultcache(key = 4)] pub target_triple: String, #[cultcache(key = 5)] pub cargo_profile: String, #[cultcache(key = 6)] pub toolchain_fingerprint: String, #[cultcache(key = 7)] pub created_at_utc: String, #[cultcache(key = 8)] pub package_root: String, #[cultcache(key = 9)] pub binaries: Vec, #[cultcache(key = 10)] pub private_state_exposed: bool, } #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache( type = "epiphany.packaged_release_head", schema = "EpiphanyPackagedReleaseHead" )] pub struct EpiphanyPackagedReleaseHead { #[cultcache(key = 0)] pub schema_version: String, #[cultcache(key = 1)] pub runtime_id: String, #[cultcache(key = 2)] pub release_id: String, #[cultcache(key = 3)] pub witness_sha256: String, #[cultcache(key = 4)] pub published_at_utc: String, } pub struct PackageReleaseRequest<'a> { pub repo: &'a Path, pub destination: &'a Path, pub build_cache_root: &'a Path, pub runtime_id: &'a str, pub target_triple: &'a str, } pub fn required_packaged_release_binaries(target_triple: &str) -> Vec<(&'static str, String)> { let file_name = |name: &str| target_binary_file_name(target_triple, name); vec![ ("supervisor", file_name("epiphany-daemon-supervisor")), ("release-publisher", file_name("epiphany-release")), ( "semantic-projector", file_name("epiphany-memory-semantic-projector"), ), ( "workspace-coverage-projector", file_name("epiphany-workspace-coverage-projector"), ), ("semantic-query", file_name("epiphany-memory-semantic")), ("verse-query", file_name("epiphany-verse-query")), ("repository-body", file_name("epiphany-repository-body")), ("host-identity", file_name("epiphany-host-identity")), ("swarm", file_name("epiphany-swarm")), ("operator-command", file_name("epiphany-operator-command")), ("heartbeat", file_name("epiphany-heartbeat-store")), ( "persona-feedback-ingress", file_name("epiphany-persona-feedback-ingress"), ), ("persona-service", file_name("epiphany-persona-service")), ( "persona-mouth-identity", file_name("epiphany-persona-mouth-identity"), ), ( "persona-discord-permit", file_name("epiphany-persona-discord-permit"), ), ( "persona-discord-permit-identity", file_name("epiphany-persona-discord-permit-identity"), ), ("coordinator", file_name("epiphany-mvp-coordinator")), ("frontier-proposal", file_name("epiphany-frontier-proposal")), ("hands-action", file_name("epiphany-hands-action")), ("model-runtime", file_name("epiphany-model-runtime")), ("tool-mcp-runtime", file_name("epiphany-tool-mcp-runtime")), ] } fn target_binary_file_name(target_triple: &str, binary: &str) -> String { if target_triple .split('-') .any(|component| component == "windows") { format!("{binary}.exe") } else { binary.to_string() } } pub fn package_epiphany_release( request: PackageReleaseRequest<'_>, ) -> Result { let (source_commit_sha, source_commit_time) = clean_source_commit(request.repo)?; require_nonempty("runtime id", request.runtime_id)?; require_nonempty("target triple", request.target_triple)?; let toolchain = installed_toolchain()?; fs::create_dir_all(request.destination).with_context(|| { format!( "failed to create release destination {}", request.destination.display() ) })?; let build_root = request.build_cache_root.to_path_buf(); fs::create_dir_all(&build_root).with_context(|| { format!( "failed to create stable build cache {}", build_root.display() ) })?; let destination = canonical_path(request.destination)?; let source_guard = ReleaseSourceGuard::prepare(request.repo, &build_root, &source_commit_sha)?; let built_binaries = build_required_release_siblings( &source_guard.path, &build_root, request.target_triple, &toolchain.fingerprint, &toolchain.cargo, )?; // Construction authority is scoped to one exact source generation. The // shared release root remains root-owned while the builder creates only a // private staging sibling beneath its commit-specific directory. let commit_root = destination.join(&source_commit_sha); fs::create_dir_all(&commit_root).with_context(|| { format!( "failed to create release commit root {}", commit_root.display() ) })?; let staging = commit_root.join(format!(".staging-{}", Uuid::new_v4())); fs::create_dir(&staging) .with_context(|| format!("failed to create release staging {}", staging.display()))?; let result = (|| { let mut binaries = Vec::new(); for (role, file_name) in required_packaged_release_binaries(request.target_triple) { let source = built_binaries .binaries .get(role) .with_context(|| format!("required packaged sibling was not built: {role}"))?; if !source.is_file() { bail!("required packaged sibling is absent: {}", source.display()); } let target = staging.join(&file_name); fs::copy(&source, &target).with_context(|| { format!( "failed to copy {} to {}", source.display(), target.display() ) })?; binaries.push(binary_record(role, &file_name, &target)?); } binaries.sort_by(|left, right| left.role.cmp(&right.role)); let release_id = release_id( request.runtime_id, &source_commit_sha, request.target_triple, &toolchain.fingerprint, &binaries, ); let final_root = commit_root.join(&release_id); for binary in &mut binaries { binary.canonical_path = final_root.join(&binary.file_name).display().to_string(); } let witness = EpiphanyPackagedReleaseEntry { schema_version: EPIPHANY_PACKAGED_RELEASE_SCHEMA_VERSION.into(), release_id, runtime_id: request.runtime_id.into(), source_commit_sha, target_triple: request.target_triple.into(), cargo_profile: "release".into(), toolchain_fingerprint: toolchain.fingerprint, created_at_utc: source_commit_time, package_root: final_root.display().to_string(), binaries, private_state_exposed: false, }; validate_epiphany_packaged_release(&witness)?; write_epiphany_packaged_release_witness( &staging.join(EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE), &witness, )?; if final_root.exists() { verify_epiphany_packaged_release_files(&witness)?; fs::remove_dir_all(&staging)?; } else { fs::rename(&staging, &final_root) .context("failed to atomically publish packaged release directory")?; verify_epiphany_packaged_release_files(&witness)?; } Ok(witness) })(); if staging.exists() { let _ = fs::remove_dir_all(staging); } result } fn release_source_cache_identity(repo: &Path) -> Result { let canonical_repo = canonical_path(repo)?; let mut digest = Sha256::new(); digest.update(b"epiphany.release_source_cache.v0\0"); digest.update(canonical_repo.to_string_lossy().as_bytes()); Ok(format!("{:x}", digest.finalize())) } struct ReleaseSourceGuard { path: PathBuf, _source_lock: fs::File, } impl ReleaseSourceGuard { fn prepare(repo: &Path, build_root: &Path, commit: &str) -> Result { validate_commit(commit)?; let identity = release_source_cache_identity(repo)?; let path = build_root.join(format!("source-{identity}")); let lock_path = build_root.join(format!(".epiphany-release-source-{identity}.lock")); let source_lock = fs::OpenOptions::new() .create(true) .read(true) .write(true) .open(&lock_path) .with_context(|| { format!("failed to open release source lock {}", lock_path.display()) })?; source_lock.lock_exclusive().with_context(|| { format!( "failed to acquire release source lock {}", lock_path.display() ) })?; if path.exists() { verify_cached_worktree_owner(repo, &path)?; run_git_checked( &path, &["-c", "core.longpaths=true", "clean", "-ffdx"], "failed to pre-clean cached release worktree", )?; run_git_checked( &path, &[ "-c", "core.longpaths=true", "checkout", "--detach", "--force", commit, ], "failed to move cached release worktree to exact commit", )?; run_git_checked( &path, &["-c", "core.longpaths=true", "clean", "-ffdx"], "failed to clean cached release worktree", )?; } else { let output = std::process::Command::new("git") .args(["-c", "core.longpaths=true", "worktree", "add", "--detach"]) .arg(&path) .arg(commit) .current_dir(repo) .output()?; if !output.status.success() { bail!( "failed to create cached exact-source release worktree: {}", String::from_utf8_lossy(&output.stderr) ); } } run_git_checked( &path, &[ "-c", "core.longpaths=true", "submodule", "update", "--init", "--recursive", "--force", ], "failed to initialize exact release submodules", )?; run_git_checked( &path, &["submodule", "foreach", "--recursive", "git reset --hard"], "failed to reset exact release submodules", )?; run_git_checked( &path, &["submodule", "foreach", "--recursive", "git clean -ffdx"], "failed to clean exact release submodules", )?; let head = git_output(&path, &["rev-parse", "HEAD"])?; if head.trim() != commit { bail!("cached release worktree resolved {head:?}, expected {commit}"); } let status = git_output( &path, &["status", "--porcelain=v1", "--untracked-files=all"], )?; if !status.trim().is_empty() { bail!("cached release worktree is not clean after preparation: {status}"); } let submodule_status = git_output(&path, &["submodule", "status", "--recursive"])?; if submodule_status .lines() .any(|line| matches!(line.as_bytes().first(), Some(b'-' | b'+' | b'U'))) { bail!("cached release worktree has inexact submodules: {submodule_status}"); } Ok(Self { path, _source_lock: source_lock, }) } } fn verify_cached_worktree_owner(repo: &Path, worktree: &Path) -> Result<()> { let expected = PathBuf::from(git_output(repo, &["rev-parse", "--git-common-dir"])?.trim()); let expected = if expected.is_absolute() { canonical_path(&expected)? } else { canonical_path(&repo.join(expected))? }; let common = PathBuf::from(git_output(worktree, &["rev-parse", "--git-common-dir"])?.trim()); let common = if common.is_absolute() { canonical_path(&common)? } else { canonical_path(&worktree.join(common))? }; if common != expected { bail!( "cached release worktree {} belongs to {}, expected {}", worktree.display(), common.display(), expected.display() ); } Ok(()) } fn git_output(repo: &Path, args: &[&str]) -> Result { let output = std::process::Command::new("git") .args(["-c", "core.longpaths=true"]) .args(args) .current_dir(repo) .output()?; if !output.status.success() { bail!( "git {} failed: {}", args.join(" "), String::from_utf8_lossy(&output.stderr) ); } Ok(String::from_utf8(output.stdout)?) } fn run_git_checked(repo: &Path, args: &[&str], context: &str) -> Result<()> { git_output(repo, args).with_context(|| context.to_string())?; Ok(()) } struct BuiltReleaseSiblings { binaries: BTreeMap<&'static str, PathBuf>, _graph_lock: fs::File, } fn build_required_release_siblings( repo: &Path, target_root: &Path, target: &str, toolchain_fingerprint: &str, cargo: &std::ffi::OsStr, ) -> Result { verify_release_bundle_lock(repo, cargo)?; let manifest = repo.join("Cargo.toml"); let target_dir = release_bundle_target_dir( target_root, &fs::read(repo.join("Cargo.lock")).context("failed to read release bundle lockfile")?, target, toolchain_fingerprint, ); fs::create_dir_all(&target_dir).with_context(|| { format!( "failed to create release graph cache {}", target_dir.display() ) })?; let graph_lock_path = target_dir.join(".epiphany-release-graph.lock"); let graph_lock = fs::OpenOptions::new() .create(true) .read(true) .write(true) .open(&graph_lock_path) .with_context(|| { format!( "failed to open release graph lock {}", graph_lock_path.display() ) })?; graph_lock.lock_exclusive().with_context(|| { format!( "failed to acquire release graph lock {}", graph_lock_path.display() ) })?; let mut outputs = BTreeMap::new(); let required = required_packaged_release_binaries(target); for (role, file_name) in &required { required_release_build_target(role)?; outputs.insert( *role, target_dir.join(target).join("release").join(file_name), ); } let mut command = std::process::Command::new(cargo); command .arg("build") .arg("--release") .arg("--manifest-path") .arg(&manifest) .arg("--target-dir") .arg(&target_dir) .arg("--target") .arg(target) .arg("--locked") .arg("--bins"); let status = command .status() .context("failed to start Epiphany release bundle build")?; if !status.success() { bail!("Epiphany release bundle build failed"); } let coordinator_status = std::process::Command::new(cargo) .arg("build") .arg("--release") .arg("--manifest-path") .arg(&manifest) .arg("--target-dir") .arg(&target_dir) .arg("--target") .arg(target) .arg("--locked") .arg("--features") .arg("coordinator-runtime") .arg("--bin") .arg("epiphany-mvp-coordinator") .status() .context("failed to start feature-gated coordinator release build")?; if !coordinator_status.success() { bail!("feature-gated coordinator release build failed"); } Ok(BuiltReleaseSiblings { binaries: outputs, _graph_lock: graph_lock, }) } fn verify_release_bundle_lock(repo: &Path, cargo: &std::ffi::OsStr) -> Result<()> { let manifest = repo.join("Cargo.toml"); if !manifest.is_file() { bail!( "Epiphany release bundle manifest is absent: {}", manifest.display() ); } let output = std::process::Command::new(cargo) .arg("metadata") .arg("--locked") .arg("--no-deps") .arg("--format-version") .arg("1") .arg("--manifest-path") .arg(&manifest) .output() .context("failed to validate Epiphany release bundle lockfile")?; if !output.status.success() { bail!( "Epiphany release bundle lockfile is stale: {}", String::from_utf8_lossy(&output.stderr).trim() ); } Ok(()) } fn release_bundle_target_dir( target_root: &Path, _lockfile: &[u8], target: &str, toolchain_fingerprint: &str, ) -> PathBuf { let mut digest = Sha256::new(); digest.update(b"epiphany.release_bundle_build_cache.v1\0"); digest.update(target.as_bytes()); digest.update(b"\0"); digest.update(toolchain_fingerprint.as_bytes()); target_root.join(format!("graph-{:x}", digest.finalize())) } fn required_release_build_target(role: &str) -> Result<(&'static str, &'static str)> { match role { "supervisor" => Ok(("epiphany-core", "epiphany-daemon-supervisor")), "release-publisher" => Ok(("epiphany-core", "epiphany-release")), "semantic-projector" => Ok(("epiphany-core", "epiphany-memory-semantic-projector")), "workspace-coverage-projector" => { Ok(("epiphany-core", "epiphany-workspace-coverage-projector")) } "semantic-query" => Ok(("epiphany-core", "epiphany-memory-semantic")), "verse-query" => Ok(("epiphany-core", "epiphany-verse-query")), "repository-body" => Ok(("epiphany-core", "epiphany-repository-body")), "host-identity" => Ok(("epiphany-core", "epiphany-host-identity")), "swarm" => Ok(("epiphany-core", "epiphany-swarm")), "operator-command" => Ok(("epiphany-core", "epiphany-operator-command")), "heartbeat" => Ok(("epiphany-core", "epiphany-heartbeat-store")), "persona-feedback-ingress" => Ok(("epiphany-core", "epiphany-persona-feedback-ingress")), "persona-service" => Ok(("epiphany-openai-runtime", "epiphany-persona-service")), "persona-mouth-identity" => Ok(("epiphany-core", "epiphany-persona-mouth-identity")), "persona-discord-permit" => Ok(("epiphany-core", "epiphany-persona-discord-permit")), "persona-discord-permit-identity" => { Ok(("epiphany-core", "epiphany-persona-discord-permit-identity")) } "coordinator" => Ok((".", "epiphany-mvp-coordinator")), "frontier-proposal" => Ok(("epiphany-core", "epiphany-frontier-proposal")), "hands-action" => Ok(("epiphany-core", "epiphany-hands-action")), "model-runtime" => Ok(("epiphany-openai-runtime", "epiphany-model-runtime")), "tool-mcp-runtime" => Ok(("epiphany-tool-mcp-runtime", "epiphany-tool-mcp-runtime")), _ => bail!("unknown required release role {role}"), } } pub fn validate_epiphany_packaged_release(entry: &EpiphanyPackagedReleaseEntry) -> Result<()> { if entry.schema_version != EPIPHANY_PACKAGED_RELEASE_SCHEMA_VERSION { bail!("unsupported packaged release schema"); } require_nonempty("runtime id", &entry.runtime_id)?; validate_commit(&entry.source_commit_sha)?; require_nonempty("target triple", &entry.target_triple)?; if entry.cargo_profile != "release" { bail!("packaged release profile must be release"); } require_nonempty("toolchain fingerprint", &entry.toolchain_fingerprint)?; DateTime::parse_from_rfc3339(&entry.created_at_utc)?; if entry.private_state_exposed { bail!("packaged release may not expose private state"); } let root = Path::new(&entry.package_root); if !root.is_absolute() { bail!("packaged release root must be absolute"); } let required = required_packaged_release_binaries(&entry.target_triple); if entry.binaries.len() != required.len() { bail!("packaged release sibling set is incomplete"); } let mut roles = BTreeSet::new(); let mut names = BTreeSet::new(); for binary in &entry.binaries { if !roles.insert(binary.role.as_str()) || !names.insert(binary.file_name.as_str()) { bail!("packaged release contains duplicate role or filename"); } if !required .iter() .any(|pair| pair.0 == binary.role && pair.1 == binary.file_name) { bail!("packaged release contains an unknown or swapped sibling role"); } validate_sha256(&binary.sha256)?; if binary.byte_len == 0 { bail!("packaged release binary is empty"); } if Path::new(&binary.canonical_path) != root.join(&binary.file_name) { bail!("packaged release binary path escapes or disagrees with package root"); } } let mut identity_binaries = entry.binaries.clone(); identity_binaries.sort_by(|left, right| left.role.cmp(&right.role)); let expected = release_id( &entry.runtime_id, &entry.source_commit_sha, &entry.target_triple, &entry.toolchain_fingerprint, &identity_binaries, ); if entry.release_id != expected { bail!("packaged release id does not authenticate sibling set"); } Ok(()) } pub fn verify_epiphany_packaged_release_files(entry: &EpiphanyPackagedReleaseEntry) -> Result<()> { validate_epiphany_packaged_release(entry)?; let root = canonical_path(&entry.package_root).context("packaged release root is absent")?; if root != PathBuf::from(&entry.package_root) { bail!("packaged release root is not canonical"); } let actual_names = fs::read_dir(&root)? .map(|item| Ok(item?.file_name().to_string_lossy().into_owned())) .collect::>>()?; let mut expected_names = entry .binaries .iter() .map(|binary| binary.file_name.clone()) .collect::>(); expected_names.insert(EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE.into()); if actual_names != expected_names { bail!("packaged release directory is not the exact witnessed sibling set"); } for binary in &entry.binaries { let path = root.join(&binary.file_name); if canonical_path(&path)? != PathBuf::from(&binary.canonical_path) { bail!("packaged sibling path aliases another file"); } let metadata = fs::metadata(&path)?; if !metadata.is_file() || metadata.len() != binary.byte_len || file_sha256(&path)? != binary.sha256 { bail!( "packaged sibling bytes disagree with witness: {}", binary.role ); } } let stored = read_epiphany_packaged_release_witness(&root.join(EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE))?; if stored != *entry { bail!("packaged release witness artifact disagrees with inspected release"); } Ok(()) } pub fn write_epiphany_packaged_release_witness( path: &Path, entry: &EpiphanyPackagedReleaseEntry, ) -> Result<()> { validate_epiphany_packaged_release(entry)?; let bytes = rmp_serde::to_vec(entry).context("failed to encode packaged release witness")?; fs::write(path, bytes).with_context(|| { format!( "failed to write packaged release witness {}", path.display() ) }) } pub fn read_epiphany_packaged_release_witness(path: &Path) -> Result { let bytes = fs::read(path) .with_context(|| format!("failed to read packaged release witness {}", path.display()))?; let entry = rmp_serde::from_slice(&bytes).with_context(|| { format!( "failed to decode packaged release witness {}", path.display() ) })?; validate_epiphany_packaged_release(&entry)?; Ok(entry) } pub fn inspect_epiphany_packaged_release_witness( witness_path: &Path, destination: &Path, runtime_id: &str, source_commit: &str, ) -> Result { let entry = read_epiphany_packaged_release_witness(witness_path)?; if entry.runtime_id != runtime_id || entry.source_commit_sha != source_commit { bail!("packaged release witness disagrees with authorized runtime or source commit"); } let destination = canonical_path(destination)?; let package_root = canonical_path(&entry.package_root)?; if package_root.parent().and_then(Path::parent) != Some(destination.as_path()) { bail!("packaged release root is outside the canonical destination"); } if package_root.join(EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE) != canonical_path(witness_path)? { bail!("packaged release witness path disagrees with package root"); } verify_epiphany_packaged_release_files(&entry)?; Ok(entry) } pub fn publish_epiphany_packaged_release( store: &Path, runtime_id: &str, entry: EpiphanyPackagedReleaseEntry, ) -> Result { validate_epiphany_packaged_release(&entry)?; verify_epiphany_packaged_release_files(&entry)?; if entry.runtime_id != runtime_id { bail!("release witness runtime disagrees with target Verse"); } let node = open_epiphany_cultmesh_node(store, runtime_id.to_string())?; let identity_key = format!("{RELEASE_KEY_PREFIX}{}", entry.release_id); let existing = node.get::(&identity_key)?; if existing.as_ref().is_some_and(|current| current != &entry) { bail!("immutable packaged release identity collision"); } let head = EpiphanyPackagedReleaseHead { schema_version: EPIPHANY_PACKAGED_RELEASE_HEAD_SCHEMA_VERSION.into(), runtime_id: runtime_id.into(), release_id: entry.release_id.clone(), witness_sha256: witness_sha256(&entry)?, published_at_utc: Utc::now().to_rfc3339(), }; let prior_head = node .cache() .get_envelope::(RELEASE_HEAD_KEY)?; let mut expected = Vec::new(); if let Some(envelope) = prior_head { expected.push(envelope); } let mut replacements = Vec::new(); if existing.is_none() { replacements.push(node.cache().prepare_entry(&identity_key, &entry)?.0); } replacements.push(node.cache().prepare_entry(RELEASE_HEAD_KEY, &head)?.0); if !SingleFileMessagePackBackingStore::new(store) .compare_and_swap_batch(&expected, replacements)? { bail!("packaged release publication lost current-head compare-and-swap"); } Ok(entry) } pub fn load_epiphany_packaged_release( store: &Path, runtime_id: &str, release_id: &str, ) -> Result> { open_epiphany_cultmesh_node(store, runtime_id.to_string())? .get(&format!("{RELEASE_KEY_PREFIX}{release_id}")) } pub fn load_epiphany_packaged_release_head( store: &Path, runtime_id: &str, ) -> Result> { open_epiphany_cultmesh_node(store, runtime_id.to_string())?.get(RELEASE_HEAD_KEY) } pub fn authenticate_epiphany_packaged_release( store: &Path, runtime_id: &str, release_id: &str, expected_witness_sha256: &str, ) -> Result { validate_sha256(expected_witness_sha256)?; let entry = load_epiphany_packaged_release(store, runtime_id, release_id)? .context("packaged release witness is absent")?; validate_epiphany_packaged_release(&entry)?; verify_epiphany_packaged_release_files(&entry)?; if witness_sha256(&entry)? != expected_witness_sha256 { bail!("packaged release witness digest disagrees with pinned task authority"); } Ok(entry) } pub fn epiphany_packaged_release_witness_sha256( entry: &EpiphanyPackagedReleaseEntry, ) -> Result { witness_sha256(entry) } pub fn epiphany_packaged_release_binary_path( entry: &EpiphanyPackagedReleaseEntry, role: &str, ) -> Result { entry .binaries .iter() .find(|binary| binary.role == role) .map(|binary| PathBuf::from(&binary.canonical_path)) .with_context(|| format!("packaged release lacks required role {role}")) } fn clean_source_commit(repo: &Path) -> Result<(String, String)> { let head = git(repo, &["rev-parse", "HEAD"])?; validate_commit(&head)?; if !git(repo, &["status", "--porcelain=v1", "--untracked-files=no"])?.is_empty() { bail!("packaged release requires a clean tracked source commit"); } if git(repo, &["submodule", "status", "--recursive"])? .lines() .any(|line| line.starts_with(['-', '+', 'U'])) { bail!("packaged release requires clean initialized submodules"); } let committed_at = git(repo, &["show", "-s", "--format=%cI", "HEAD"])?; DateTime::parse_from_rfc3339(&committed_at).context("Git commit time is not RFC3339")?; Ok((head, committed_at)) } fn git(repo: &Path, args: &[&str]) -> Result { let output = std::process::Command::new("git") .args(args) .current_dir(repo) .output()?; if !output.status.success() { bail!( "git {} failed: {}", args.join(" "), String::from_utf8_lossy(&output.stderr) ); } Ok(String::from_utf8(output.stdout)?.trim().to_string()) } struct InstalledToolchain { cargo: std::ffi::OsString, fingerprint: String, } fn installed_toolchain() -> Result { let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); let cargo_version = command_version(&cargo, "cargo")?; let rustc_version = command_version(&rustc, "rustc")?; Ok(InstalledToolchain { cargo: cargo.clone(), fingerprint: format!( "cargo-command={}\ncargo-vV:\n{}\nrustc-command={}\nrustc-vV:\n{}", Path::new(&cargo).display(), cargo_version, Path::new(&rustc).display(), rustc_version ), }) } fn command_version(command: &std::ffi::OsStr, label: &str) -> Result { let output = std::process::Command::new(command).arg("-vV").output()?; if !output.status.success() { bail!( "{label} -vV failed: {}", String::from_utf8_lossy(&output.stderr) ); } Ok(String::from_utf8(output.stdout)?.trim().to_string()) } fn binary_record( role: &str, file_name: &str, path: &Path, ) -> Result { let canonical = canonical_path(path)?; let len = fs::metadata(&canonical)?.len(); if len == 0 { bail!("required packaged sibling is empty: {file_name}"); } Ok(EpiphanyPackagedReleaseBinary { role: role.into(), file_name: file_name.into(), canonical_path: canonical.display().to_string(), sha256: file_sha256(&canonical)?, byte_len: len, }) } fn release_id( runtime: &str, commit: &str, target: &str, toolchain: &str, binaries: &[EpiphanyPackagedReleaseBinary], ) -> String { let mut hash = Sha256::new(); for value in [ "epiphany.packaged-release.identity.v0", runtime, commit, target, "release", toolchain, ] { hash.update((value.len() as u64).to_be_bytes()); hash.update(value.as_bytes()); } for binary in binaries { for value in [ &binary.role, &binary.file_name, &binary.sha256, &binary.byte_len.to_string(), ] { hash.update((value.len() as u64).to_be_bytes()); hash.update(value.as_bytes()); } } format!("sha256-{:x}", hash.finalize()) } fn witness_sha256(entry: &EpiphanyPackagedReleaseEntry) -> Result { Ok(format!( "sha256-{:x}", Sha256::digest(rmp_serde::to_vec(entry)?) )) } fn file_sha256(path: &Path) -> Result { Ok(format!("sha256-{:x}", Sha256::digest(fs::read(path)?))) } fn canonical_path(path: impl AsRef) -> Result { let canonical = fs::canonicalize(path)?; #[cfg(windows)] { let text = canonical.to_string_lossy(); if let Some(rest) = text.strip_prefix(r"\\?\UNC\") { return Ok(PathBuf::from(format!(r"\\{rest}"))); } if let Some(rest) = text.strip_prefix(r"\\?\") { return Ok(PathBuf::from(rest)); } } Ok(canonical) } fn validate_sha256(value: &str) -> Result<()> { if value.len() != 71 || !value.starts_with("sha256-") || !value[7..] .bytes() .all(|b| b.is_ascii_hexdigit() && !b.is_ascii_uppercase()) { bail!("invalid SHA-256 digest"); } Ok(()) } fn validate_commit(value: &str) -> Result<()> { if value.len() != 40 || !value.bytes().all(|b| b.is_ascii_hexdigit()) { bail!("source commit must be a full 40-hex Git object id"); } Ok(()) } fn require_nonempty(label: &str, value: &str) -> Result<()> { if value.trim().is_empty() { return Err(anyhow!("{label} must not be empty")); } Ok(()) } #[cfg(test)] mod tests { use super::*; use tempfile::TempDir; #[test] fn every_required_release_role_has_a_build_target() { for (role, _) in required_packaged_release_binaries("x86_64-unknown-linux-gnu") { required_release_build_target(role).expect("required release role must resolve"); } } #[test] fn binary_suffix_follows_requested_target_not_packager_host() { let windows = required_packaged_release_binaries("x86_64-pc-windows-msvc"); assert!(windows.iter().all(|(_, name)| name.ends_with(".exe"))); let linux = required_packaged_release_binaries("x86_64-unknown-linux-gnu"); assert!(linux.iter().all(|(_, name)| !name.ends_with(".exe"))); } #[test] fn release_bundle_cache_is_owned_by_build_graph() { let root = Path::new("release-build-cache"); let first = release_bundle_target_dir(root, b"lock-v1", "target-a", "toolchain-a"); let second = release_bundle_target_dir(root, b"lock-v1", "target-a", "toolchain-a"); assert_eq!(first, second); assert!( first .file_name() .and_then(|name| name.to_str()) .is_some_and(|name| name.starts_with("graph-")) ); } #[test] fn release_bundle_cache_is_stable_across_lockfile_edits() { let root = Path::new("release-build-cache"); let baseline = release_bundle_target_dir(root, b"lock-v1", "target-a", "toolchain-a"); assert_eq!( baseline, release_bundle_target_dir(root, b"lock-v2", "target-a", "toolchain-a") ); } #[test] fn release_bundle_cache_separates_targets_and_toolchains() { let root = Path::new("release-build-cache"); let baseline = release_bundle_target_dir(root, b"lock-v1", "target-a", "toolchain-a"); assert_ne!( baseline, release_bundle_target_dir(root, b"lock-v1", "target-b", "toolchain-a") ); assert_ne!( baseline, release_bundle_target_dir(root, b"lock-v1", "target-a", "toolchain-b") ); } #[test] fn release_source_cache_is_stable_per_repository() { let root = TempDir::new().expect("temporary root"); let first = root.path().join("first"); let second = root.path().join("second"); fs::create_dir_all(&first).expect("first repository path"); fs::create_dir_all(&second).expect("second repository path"); assert_eq!( release_source_cache_identity(&first).expect("first identity"), release_source_cache_identity(&first).expect("stable first identity") ); assert_ne!( release_source_cache_identity(&first).expect("first identity"), release_source_cache_identity(&second).expect("second identity") ); } #[test] fn release_bundle_lockfile_is_frozen() { let core = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let repo = core .parent() .expect("epiphany-core has a repository parent"); let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); verify_release_bundle_lock(repo, &cargo) .unwrap_or_else(|error| panic!("release bundle lockfile is not frozen: {error:#}")); } #[test] fn resident_cognition_roles_keep_their_owning_manifests() { let packaged_roles = required_packaged_release_binaries("x86_64-unknown-linux-gnu") .into_iter() .map(|(role, _)| role) .collect::>(); for role in [ "swarm", "operator-command", "heartbeat", "coordinator", "hands-action", "model-runtime", "persona-service", "persona-mouth-identity", "persona-discord-permit", "persona-discord-permit-identity", "tool-mcp-runtime", ] { assert!(packaged_roles.contains(role), "release omits {role}"); } assert_eq!( required_release_build_target("swarm").unwrap(), ("epiphany-core", "epiphany-swarm") ); assert_eq!( required_release_build_target("operator-command").unwrap(), ("epiphany-core", "epiphany-operator-command") ); assert_eq!( required_release_build_target("heartbeat").unwrap(), ("epiphany-core", "epiphany-heartbeat-store") ); assert_eq!( required_release_build_target("coordinator").unwrap(), (".", "epiphany-mvp-coordinator") ); assert_eq!( required_release_build_target("hands-action").unwrap(), ("epiphany-core", "epiphany-hands-action") ); assert_eq!( required_release_build_target("model-runtime").unwrap(), ("epiphany-openai-runtime", "epiphany-model-runtime") ); assert_eq!( required_release_build_target("persona-service").unwrap(), ("epiphany-openai-runtime", "epiphany-persona-service") ); assert_eq!( required_release_build_target("persona-mouth-identity").unwrap(), ("epiphany-core", "epiphany-persona-mouth-identity") ); assert_eq!( required_release_build_target("persona-discord-permit").unwrap(), ("epiphany-core", "epiphany-persona-discord-permit") ); assert_eq!( required_release_build_target("persona-discord-permit-identity").unwrap(), ("epiphany-core", "epiphany-persona-discord-permit-identity") ); assert_eq!( required_release_build_target("tool-mcp-runtime").unwrap(), ("epiphany-tool-mcp-runtime", "epiphany-tool-mcp-runtime") ); } #[test] fn coordinator_policy_is_feature_gated_outside_core_binary_ownership() { let core = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let repo = core.parent().expect("epiphany-core repository parent"); let root_manifest = fs::read_to_string(repo.join("Cargo.toml")).expect("root manifest"); let core_manifest = fs::read_to_string(core.join("Cargo.toml")).expect("core manifest"); assert!(root_manifest.contains( "coordinator-runtime = [\"dep:epiphany-self-policy\"]" )); assert!(root_manifest.contains( "required-features = [\"coordinator-runtime\"]" )); assert!(core_manifest.contains("autobins = false")); assert!(!core_manifest.contains("name = \"epiphany-mvp-coordinator\"")); assert!(!core_manifest.contains("name = \"epiphany-mvp-status\"")); } fn fixture() -> (TempDir, EpiphanyPackagedReleaseEntry) { let dir = TempDir::new().unwrap(); let root = dir.path().join("release"); fs::create_dir(&root).unwrap(); let mut binaries = Vec::new(); for (index, (role, name)) in required_packaged_release_binaries("x86_64-unknown-linux-gnu") .into_iter() .enumerate() { let path = root.join(&name); fs::write(&path, format!("binary-{index}")).unwrap(); binaries.push(binary_record(role, &name, &path).unwrap()); } binaries.sort_by(|a, b| a.role.cmp(&b.role)); let id = release_id("runtime", &"a".repeat(40), "target", "rustc", &binaries); let entry = EpiphanyPackagedReleaseEntry { schema_version: EPIPHANY_PACKAGED_RELEASE_SCHEMA_VERSION.into(), release_id: id, runtime_id: "runtime".into(), source_commit_sha: "a".repeat(40), target_triple: "target".into(), cargo_profile: "release".into(), toolchain_fingerprint: "rustc".into(), created_at_utc: Utc::now().to_rfc3339(), package_root: canonical_path(root).unwrap().display().to_string(), binaries, private_state_exposed: false, }; write_epiphany_packaged_release_witness( &Path::new(&entry.package_root).join(EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE), &entry, ) .unwrap(); (dir, entry) } #[test] fn exact_fixture_verifies() { let (_d, e) = fixture(); verify_epiphany_packaged_release_files(&e).unwrap(); } #[test] fn witness_reader_refuses_tamper_and_inspector_refuses_wrong_runtime() { let (d, e) = fixture(); let witness = Path::new(&e.package_root).join(EPIPHANY_PACKAGED_RELEASE_WITNESS_FILE); assert!( inspect_epiphany_packaged_release_witness( &witness, d.path(), "alien-runtime", &e.source_commit_sha, ) .is_err() ); fs::write(&witness, b"hostile witness").unwrap(); assert!(read_epiphany_packaged_release_witness(&witness).is_err()); } #[test] fn one_byte_replacement_is_rejected() { let (_d, e) = fixture(); fs::write(&e.binaries[0].canonical_path, "hostile").unwrap(); assert!(verify_epiphany_packaged_release_files(&e).is_err()); } #[test] fn extra_sibling_is_rejected() { let (_d, e) = fixture(); fs::write(Path::new(&e.package_root).join("stowaway.exe"), "x").unwrap(); assert!(verify_epiphany_packaged_release_files(&e).is_err()); } #[test] fn swapped_role_is_rejected() { let (_d, mut e) = fixture(); let role = e.binaries[0].role.clone(); e.binaries[0].role = e.binaries[1].role.clone(); e.binaries[1].role = role; assert!(validate_epiphany_packaged_release(&e).is_err()); } #[test] fn missing_resident_cognition_binary_is_rejected() { let (_d, mut e) = fixture(); e.binaries.retain(|binary| binary.role != "model-runtime"); assert!(validate_epiphany_packaged_release(&e).is_err()); } #[test] fn substituted_resident_cognition_binary_is_rejected() { let (_d, mut e) = fixture(); let model = e .binaries .iter_mut() .find(|binary| binary.role == "model-runtime") .unwrap(); model.file_name = "epiphany-openai-runtime".into(); assert!(validate_epiphany_packaged_release(&e).is_err()); } #[test] fn counterfeit_release_id_is_rejected() { let (_d, mut e) = fixture(); e.release_id = format!("sha256-{}", "0".repeat(64)); assert!(validate_epiphany_packaged_release(&e).is_err()); } }