#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use std::path::Path;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use clawft_types::placement::engine::{PlacementPolicy, WorkloadRequirements, WorkloadSpec};
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use clawft_types::placement::{CapabilityId, MemoryDemand, Requirement};
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use crate::workload_ctl::PlaneError;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use crate::workload_pkg::TrustAnchors;
use crate::workload_pkg::{ManifestEnvelope, ManifestError};
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use crate::workload_runtime::{CAP_PROJECT_LOGICAL, ProjectPayload, VerifiedWorkload, WorkloadSource};
use super::WorkloadKind;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use super::KindRegistry;
pub const KIND_PROJECT: &str = "project";
#[derive(Debug, Clone, Copy, Default)]
pub struct ProjectKind;
impl WorkloadKind for ProjectKind {
fn id(&self) -> &'static str {
KIND_PROJECT
}
fn health(&self) -> super::HealthSpec {
super::HealthSpec {
interval_ms: 5_000,
miss_limit: 2,
}
}
fn migratable(&self) -> bool {
false
}
fn validate(&self, _envelope: &ManifestEnvelope) -> Result<(), ManifestError> {
Err(ManifestError::Invalid(
"project workloads have no signed package; the user daemon supervisor starts them".into(),
))
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
fn load(
&self,
_package_dir: &Path,
_anchors: &TrustAnchors,
_kinds: &KindRegistry,
) -> Result<VerifiedWorkload, PlaneError> {
Err(PlaneError::Package(
"project workloads are authorised by a project certificate, not a package; \
use `project.start` on the user daemon"
.into(),
))
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
fn spec(&self, workload: &VerifiedWorkload) -> Result<WorkloadSpec, String> {
let capability = match &workload.source {
WorkloadSource::Project(p) if p.adapter == "wasmtime-project-v1" => "runtime.project.wasmtime",
WorkloadSource::Project(p) if p.adapter == "logical" => CAP_PROJECT_LOGICAL,
_ => return Err("unsupported project adapter".into()),
};
let id = CapabilityId::new(capability).map_err(|e| e.to_string())?;
let spec = WorkloadSpec {
kind: workload.kind.clone(),
name: workload.id.clone(),
requirements: WorkloadRequirements {
common: vec![Requirement::exact(id)],
variants: Vec::new(),
memory: MemoryDemand::default(),
},
policy: PlacementPolicy::default(),
};
spec.validate().map_err(|e| e.to_string())?;
Ok(spec)
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
fn adapters(&self) -> &'static [&'static str] {
&["logical", "wasmtime-project-v1"]
}
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix, feature = "native"))]
pub struct ProjectFacts<'a> {
pub cert: Option<&'a clawft_types::project::ProjectCert>,
pub user_pubkey: &'a [u8; 32],
pub revocations: &'a crate::project_identity::RevocationView,
pub manifest_id: &'a str,
pub root: &'a Path,
pub policy_hash: &'a str,
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix, feature = "native"))]
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ProjectPrepareError {
#[error("certificate: {0}")]
Cert(String),
#[error("identity: {0}")]
Identity(String),
#[error("certificate is for project {cert}, manifest is {manifest}")]
WrongProject {
cert: String,
manifest: String,
},
#[error("project root {0} is not a directory")]
RootGone(String),
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix, feature = "native"))]
pub fn prepare_project(f: &ProjectFacts<'_>) -> Result<VerifiedWorkload, ProjectPrepareError> {
let (project_id, key_id, serial, user_key_id) = match f.cert {
Some(cert) => {
crate::project_identity::verify_cert(cert, f.user_pubkey)
.map_err(|e| ProjectPrepareError::Cert(e.to_string()))?;
f.revocations
.check_cert(cert)
.map_err(|e| ProjectPrepareError::Identity(e.to_string()))?;
if cert.project_id != f.manifest_id {
return Err(ProjectPrepareError::WrongProject {
cert: cert.project_id.clone(),
manifest: f.manifest_id.to_owned(),
});
}
(
cert.project_id.clone(),
cert.project_key_id.clone(),
cert.serial,
cert.user_key_id.clone(),
)
}
None => (
f.manifest_id.to_owned(),
"unregistered".to_owned(),
0,
clawft_types::project::cert::key_id(f.user_pubkey),
),
};
if !f.root.is_dir() {
return Err(ProjectPrepareError::RootGone(f.root.display().to_string()));
}
Ok(VerifiedWorkload {
kind: KIND_PROJECT.into(),
id: project_id.clone(),
version: format!("cert-{serial}"),
source: WorkloadSource::Project(ProjectPayload {
adapter: "logical".into(),
project_id,
key_id,
cert_serial: serial,
user_key_id,
policy_hash: f.policy_hash.to_owned(),
root: f.root.to_path_buf(),
}),
})
}
pub fn project_healthy(expected_id: &str, handshake_project_id: Option<&str>, shared_all_down: bool) -> bool {
handshake_project_id == Some(expected_id) && !shared_all_down
}