ive harnessed the harness
Something went wrong. Try again.
19 kB · 560 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561//! Execution target descriptors: configured identity vs verified identity.//!//! A target descriptor names a configured machine/account and a CHECKED//! workspace, never just a friendly hostname. The SSH alias stays//! configuration; the identity is what a connect boundary actually returned//! and verified. A friendly hostname that resolves to a different account or//! platform than configured is a typed mismatch, never a fallback: there is//! no home-directory or local substitution anywhere in this module.//!//! Ownership: m1-protocol (klbr-m7x). Live callers: m1-backend's backend//! trait (session placement), m1-relay's launcher, m1-bootstrap's//! readiness/bundle identity, and the protocol envelope binding below.use anyhow::{ensure, Result};use serde::{Deserialize, Serialize};use std::fmt;use std::str::FromStr;
/// A config-level target name, e.g. "linux-build". This is the selector the/// operator writes, NOT a verified machine identity.#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]#[serde(try_from = "String", into = "String")]pub struct TargetId(String);impl TargetId { pub fn parse(value: impl Into<String>) -> Result<Self> { let value = value.into(); ensure!( !value.is_empty() && value.len() <= 128 && value .bytes() .all(|b| b.is_ascii_alphanumeric() || b"_.-".contains(&b)), "invalid target id" ); Ok(Self(value)) } #[must_use] pub fn as_str(&self) -> &str { &self.0 }}impl TryFrom<String> for TargetId { type Error = String; fn try_from(value: String) -> std::result::Result<Self, Self::Error> { Self::parse(value).map_err(|e| e.to_string()) }}impl From<TargetId> for String { fn from(id: TargetId) -> Self { id.0 }}impl fmt::Display for TargetId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) }}
/// Auxiliary namespace identity. M2 opens additional kernels; the identity/// exists now so every envelope binds namespaces uniformly.#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]#[serde(try_from = "String", into = "String")]pub struct NamespaceId(String);impl NamespaceId { pub fn parse(value: impl Into<String>) -> Result<Self> { let value = value.into(); ensure!( !value.is_empty() && value.len() <= 128 && value .bytes() .all(|b| b.is_ascii_alphanumeric() || b"_.-".contains(&b)), "invalid namespace id" ); Ok(Self(value)) } #[must_use] pub fn as_str(&self) -> &str { &self.0 }}impl TryFrom<String> for NamespaceId { type Error = String; fn try_from(value: String) -> std::result::Result<Self, Self::Error> { Self::parse(value).map_err(|e| e.to_string()) }}impl From<NamespaceId> for String { fn from(id: NamespaceId) -> Self { id.0 }}impl fmt::Display for NamespaceId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) }}
/// Namespace generation: a NEW generation is produced on every placement/// change or transport loss. Reattachment (M2) is a distinct explicit/// contract and never reuses a generation.#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]#[serde(try_from = "String", into = "String")]pub struct NamespaceGeneration(String);impl NamespaceGeneration { #[must_use] pub fn fresh() -> Self { Self(uuid::Uuid::new_v4().to_string()) } pub fn parse(value: impl Into<String>) -> Result<Self> { let value = value.into(); ensure!( !value.is_empty() && value.len() <= 128 && value .bytes() .all(|b| b.is_ascii_alphanumeric() || b"_.-".contains(&b)), "invalid namespace generation" ); Ok(Self(value)) } #[must_use] pub fn as_str(&self) -> &str { &self.0 }}impl TryFrom<String> for NamespaceGeneration { type Error = String; fn try_from(value: String) -> std::result::Result<Self, Self::Error> { Self::parse(value).map_err(|e| e.to_string()) }}impl From<NamespaceGeneration> for String { fn from(id: NamespaceGeneration) -> Self { id.0 }}impl fmt::Display for NamespaceGeneration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) }}
/// Opaque content identity of a provisioned environment (interpreter/ABI,/// skill source revision, dependency lock, bootstrap recipe). Bootstrap (M1/// bootstrap workstream) produces it; this vocabulary carries it verbatim/// and compares it for equality only.#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]#[serde(try_from = "String", into = "String")]pub struct EnvironmentFingerprint(String);impl EnvironmentFingerprint { pub fn parse(value: impl Into<String>) -> Result<Self> { let value = value.into(); ensure!( !value.is_empty() && value.len() <= 128 && value .bytes() .all(|b| b.is_ascii_alphanumeric() || b"_.-".contains(&b)), "invalid environment fingerprint" ); Ok(Self(value)) } #[must_use] pub fn as_str(&self) -> &str { &self.0 }}impl TryFrom<String> for EnvironmentFingerprint { type Error = String; fn try_from(value: String) -> std::result::Result<Self, Self::Error> { Self::parse(value).map_err(|e| e.to_string()) }}impl From<EnvironmentFingerprint> for String { fn from(id: EnvironmentFingerprint) -> Self { id.0 }}impl fmt::Display for EnvironmentFingerprint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) }}
/// Where a session's workbench runs. Local execution needs no descriptor;/// remote execution is always a full configured descriptor.#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]#[serde(tag = "placement", rename_all = "snake_case", deny_unknown_fields)]pub enum KernelTarget { Local, Remote(RemoteTarget),}
impl FromStr for TargetId { type Err = anyhow::Error; fn from_str(value: &str) -> std::result::Result<Self, Self::Err> { Self::parse(value.to_owned()) }}
impl FromStr for NamespaceId { type Err = anyhow::Error; fn from_str(value: &str) -> std::result::Result<Self, Self::Err> { Self::parse(value.to_owned()) }}
impl FromStr for NamespaceGeneration { type Err = anyhow::Error; fn from_str(value: &str) -> std::result::Result<Self, Self::Err> { Self::parse(value.to_owned()) }}
impl FromStr for EnvironmentFingerprint { type Err = anyhow::Error; fn from_str(value: &str) -> std::result::Result<Self, Self::Err> { Self::parse(value.to_owned()) }}/// A durable placement descriptor for a session's workbench, persisted by/// the host (store.rs, m1-backend writes it) and re-checked at read time./// A restarted daemon refuses remote work without a backend instead of/// silently falling back to local: Some(descriptor) means the placement is/// STILL the contract.#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]#[serde(deny_unknown_fields)]pub struct SessionPlacement { pub kernel_target: KernelTarget, pub namespace_id: NamespaceId, pub namespace_generation: NamespaceGeneration,}
impl SessionPlacement { /// Set-time validation: the serialized shape must be the typed /// descriptor, and a remote placement must carry an explicitly /// configured workspace. A missing workspace is a typed refusal, never /// a home fallback; machine identity is verified separately by /// RemoteTarget::verify_identity once a connect boundary resolves. pub fn from_json(value: &serde_json::Value) -> Result<Self> { let placement: Self = serde_json::from_value(value.clone()) .map_err(|e| anyhow::anyhow!("invalid session placement descriptor: {e}"))?; if let KernelTarget::Remote(target) = &placement.kernel_target { ensure!( !target.workspace.path.trim().is_empty(), TargetMismatch::WorkspaceUnusable { target: target.id.clone(), workspace: target.workspace.path.clone(), } ); } Ok(placement) }
#[must_use] pub fn to_json(&self) -> serde_json::Value { serde_json::to_value(self).unwrap_or(serde_json::Value::Null) }}
/// An explicitly configured workspace for a remote target. A missing or/// unusable configured workspace is a typed failure at the selection/// boundary; it never falls back to a home directory.#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]#[serde(deny_unknown_fields)]pub struct RemoteWorkspace { pub path: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub revision: Option<String>,}
/// Configured remote target descriptor. Everything here is DECLARED/// configuration; nothing here was verified by a connection.#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]#[serde(deny_unknown_fields)]pub struct RemoteTarget { pub id: TargetId, /// SSH alias or host as configured. Configuration, not identity. pub ssh_alias: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub account: Option<String>, pub workspace: RemoteWorkspace, /// Explicitly configured interpreter override. A configured interpreter /// must still pass the same capability/protocol checks as a default one. #[serde(default, skip_serializing_if = "Option::is_none")] pub interpreter: Option<String>, /// Platform the descriptor requires, when the configuration declares /// one (e.g. a linux-build target). None accepts any platform. #[serde(default, skip_serializing_if = "Option::is_none")] pub required_platform: Option<String>,}
/// The identity a connect/launch boundary actually verified, once per/// launch. The agent sees exactly this. Values are non-optional: an/// identity with unchecked values cannot be constructed.#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]#[serde(deny_unknown_fields)]pub struct TargetIdentity { /// Canonical account as the machine reports it, e.g. "mayer". pub account: String, /// Canonical machine identity as returned (uname nodename), not the /// configured alias. pub machine: String, /// Platform as returned, e.g. "Darwin", "Linux", "NixOS". pub platform: String, pub arch: String, /// Absolute interpreter path as resolved on the target. pub interpreter_path: String, /// Interpreter version string as reported. pub interpreter_version: String, /// Working directory the boundary actually chdir'd into and verified. pub cwd: String, /// Verified environment fingerprint, when the deployment records one. #[serde(default, skip_serializing_if = "Option::is_none")] pub environment_fingerprint: Option<EnvironmentFingerprint>, /// Highest capability/protocol revision the target serves. pub capability_revision: u16,}
impl TargetIdentity { /// Fallible constructor: an identity cannot be constructed from /// unchecked values. #[allow(clippy::too_many_arguments)] pub fn new( account: impl Into<String>, machine: impl Into<String>, platform: impl Into<String>, arch: impl Into<String>, interpreter_path: impl Into<String>, interpreter_version: impl Into<String>, cwd: impl Into<String>, environment_fingerprint: Option<EnvironmentFingerprint>, capability_revision: u16, ) -> Result<Self> { let identity = Self { account: account.into(), machine: machine.into(), platform: platform.into(), arch: arch.into(), interpreter_path: interpreter_path.into(), interpreter_version: interpreter_version.into(), cwd: cwd.into(), environment_fingerprint, capability_revision, }; ensure!( !identity.account.trim().is_empty(), "target identity account is empty" ); ensure!( !identity.machine.trim().is_empty(), "target identity machine is empty" ); ensure!( !identity.platform.trim().is_empty(), "target identity platform is empty" ); ensure!( !identity.arch.trim().is_empty(), "target identity arch is empty" ); ensure!( !identity.interpreter_path.trim().is_empty(), "target identity interpreter path is empty" ); ensure!( !identity.interpreter_version.trim().is_empty(), "target identity interpreter version is empty" ); ensure!( !identity.cwd.trim().is_empty(), "target identity cwd is empty" ); Ok(identity) }}
/// One typed mismatch kind per check that can fail when a resolved identity/// contradicts the configured target. No fallback variant exists: a/// mismatch is fatal at the selection boundary.#[derive(Clone, Debug, PartialEq, Eq)]pub enum TargetMismatch { AccountMismatch { target: TargetId, configured: String, resolved: String, }, PlatformMismatch { target: TargetId, configured: String, resolved: String, }, WorkspaceUnusable { target: TargetId, workspace: String, },}
impl fmt::Display for TargetMismatch { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::AccountMismatch { target, configured, resolved, } => write!( f, "target {target}: account mismatch: configured {configured:?}, resolved {resolved:?}" ), Self::PlatformMismatch { target, configured, resolved, } => write!( f, "target {target}: platform mismatch: configured {configured:?}, resolved {resolved:?}" ), Self::WorkspaceUnusable { target, workspace } => write!( f, "target {target}: workspace {workspace:?} does not exist or is unusable on the target" ), } }}
impl std::error::Error for TargetMismatch {}
/// A target whose configured and verified identities agree, plus the/// identity that was actually checked.#[derive(Clone, Debug, PartialEq, Eq)]pub struct ResolvedTarget { pub target: RemoteTarget, pub identity: TargetIdentity,}
impl RemoteTarget { /// Which platform identity this descriptor requires, if it declares one /// (e.g. a linux-build target may require Linux). None means any. #[must_use] pub fn required_platform(&self) -> Option<String> { self.required_platform.clone() }
/// Check a resolved identity against this descriptor. This is the /// "no wrong-machine, no wrong-account" contract: mismatch is typed, /// fatal, and reported - never silently retried elsewhere. pub fn verify_identity(&self, resolved: &TargetIdentity) -> Result<ResolvedTarget> { if let Some(expected_account) = &self.account { ensure!( resolved.account == *expected_account, TargetMismatch::AccountMismatch { target: self.id.clone(), configured: expected_account.clone(), resolved: resolved.account.clone(), } ); } if let Some(expected_platform) = &self.required_platform { ensure!( resolved.platform == *expected_platform, TargetMismatch::PlatformMismatch { target: self.id.clone(), configured: expected_platform.clone(), resolved: resolved.platform.clone(), } ); } ensure!( resolved.cwd == self.workspace.path, TargetMismatch::WorkspaceUnusable { target: self.id.clone(), workspace: self.workspace.path.clone(), } ); Ok(ResolvedTarget { target: self.clone(), identity: resolved.clone(), }) }}
#[cfg(test)]mod tests { use super::*;
fn identity(account: &str, platform: &str, cwd: &str) -> TargetIdentity { TargetIdentity::new( account, "chernobog.internal", platform, "arm64", "/usr/bin/python3", "3.11.9", cwd, None, 1, ) .expect("identity") }
fn remote_target() -> RemoteTarget { serde_json::from_value(serde_json::json!({ "id": "linux-build", "ssh_alias": "linux-build", "account": "mayer", "workspace": {"path": "/srv/work/tangled"}, "required_platform": "Linux" })) .expect("target") }
#[test] fn target_id_rejects_bad_names() { assert!(TargetId::parse("").is_err()); assert!(TargetId::parse("a b").is_err()); assert!(TargetId::parse("linux-build").is_ok()); }
#[test] fn mismatching_account_is_a_typed_failure_not_a_fallback() { let target = remote_target(); let resolved = identity("root", "Linux", "/srv/work/tangled"); let err = target.verify_identity(&resolved).expect_err("mismatch"); assert!(matches!( err.downcast_ref::<TargetMismatch>(), Some(TargetMismatch::AccountMismatch { .. }) )); }
#[test] fn mismatching_platform_is_a_typed_failure_not_a_fallback() { let target = remote_target(); let resolved = identity("mayer", "Darwin", "/srv/work/tangled"); let err = target.verify_identity(&resolved).expect_err("mismatch"); assert!(matches!( err.downcast_ref::<TargetMismatch>(), Some(TargetMismatch::PlatformMismatch { .. }) )); }
#[test] fn wrong_directory_is_never_a_home_fallback() { let target = remote_target(); let resolved = identity("mayer", "Linux", "/home/mayer"); let err = target.verify_identity(&resolved).expect_err("mismatch"); assert!(matches!( err.downcast_ref::<TargetMismatch>(), Some(TargetMismatch::WorkspaceUnusable { .. }) )); }
#[test] fn verified_identity_binds() { let target = remote_target(); let resolved = identity("mayer", "Linux", "/srv/work/tangled"); let bound = target.verify_identity(&resolved).expect("bound"); assert_eq!(bound.target.id.as_str(), "linux-build"); assert_eq!(bound.identity.account, "mayer"); }}