use crate::contract::budget::{
AdmittedBudgets, BudgetDimension, BudgetFailure, BudgetRequirements,
};
use crate::contract::capability::{Capability, Enforcement, EvidenceClaim, EvidenceSet};
use crate::contract::host_control::HostControl;
use crate::contract::ids::{BackendId, BoundaryPlanHash};
use crate::contract::support::BackendProfileSnapshot;
use batpak_macros::Error;
use serde::{Deserialize, Serialize};
pub const BOUNDARY_PLAN_SCHEMA_VERSION: u16 = 1;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum BoundaryRequirement {
Capability(Capability),
HostControl(HostControl),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Workload {
Process {
exe: String,
args: Vec<String>,
},
Wasm {
module_ref: String,
},
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct EvidenceRequirements {
pub require_captured_streams: bool,
pub require_exit_status: bool,
}
impl EvidenceRequirements {
#[must_use]
pub fn required_claims(&self) -> EvidenceSet {
let mut set = EvidenceSet::new();
if self.require_captured_streams {
set.insert(EvidenceClaim::CapturedStreams);
}
if self.require_exit_status {
set.insert(EvidenceClaim::TerminalOutcome);
}
set
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BoundarySpec {
pub workload: Workload,
pub capabilities: Vec<Capability>,
pub controls: Vec<HostControl>,
pub budgets: BudgetRequirements,
pub evidence: EvidenceRequirements,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AdmittedRequirement {
pub requirement: BoundaryRequirement,
pub enforcement: Enforcement,
pub mechanism: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BoundaryPlan {
pub schema_version: u16,
pub plan_id: BoundaryPlanHash,
pub backend: BackendId,
pub profile: BackendProfileSnapshot,
pub admitted: Vec<AdmittedRequirement>,
pub workload: Workload,
pub budgets: AdmittedBudgets,
pub evidence: EvidenceRequirements,
}
#[derive(Clone, Debug, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum PlanError {
#[error("backend {backend} cannot enforce required requirement {requirement:?}")]
Unsupported {
requirement: BoundaryRequirement,
backend: BackendId,
},
#[error("backend {backend} cannot run workload {workload:?}")]
WorkloadIncompatible {
backend: BackendId,
workload: Workload,
},
#[error("backend {backend} machine profile insufficient: {detail}")]
ProfileInsufficient {
backend: BackendId,
detail: String,
},
#[error("invalid budget: {detail}")]
BudgetInvalid {
detail: String,
},
#[error("backend {backend} cannot satisfy required evidence: {detail}")]
EvidenceUnsatisfiable {
backend: BackendId,
detail: String,
},
#[error("backend {backend} budget membrane refused dimension {dimension:?}: {failure:?}")]
BudgetRefused {
backend: BackendId,
dimension: BudgetDimension,
failure: BudgetFailure,
},
#[error("unknown backend {backend}")]
UnknownBackend {
backend: BackendId,
},
#[error("invalid capability policy: {detail}")]
InvalidPolicy {
detail: String,
},
#[error("admission shadow divergence (fail-closed): {detail}")]
ShadowDivergence {
detail: String,
},
}