Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 90 additions & 2 deletions crates/openshell-cli/src/commands/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct ComputeDriverInfoView {
struct ComputeDriverCapabilitiesView {
driver_name: String,
driver_version: String,
workload_compatibility: Option<openshell_core::proto::WorkloadCompatibility>,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -417,6 +418,7 @@ pub async fn gateway_info(
capabilities: ComputeDriverCapabilitiesView {
driver_name: capabilities.driver_name,
driver_version: capabilities.driver_version,
workload_compatibility: capabilities.workload_compatibility,
},
}
})
Expand Down Expand Up @@ -514,7 +516,47 @@ fn print_compute_driver_info(drivers: &[ComputeDriverInfoView]) {
"Driver version:".dimmed(),
driver.capabilities.driver_version
);
for line in
workload_compatibility_lines(driver.capabilities.workload_compatibility.as_ref())
{
println!(" {line}");
}
}
}

fn workload_compatibility_lines(
workload: Option<&openshell_core::proto::WorkloadCompatibility>,
) -> Vec<String> {
let reported = |value: &str| {
if value.is_empty() {
"unreported".to_string()
} else {
value.to_string()
}
};
let Some(workload) = workload else {
return vec![
"Workload platform: unreported".into(),
"Execution restrictions: unreported".into(),
];
};
let mut lines = vec![format!(
"Workload platform: {} / {}",
reported(&workload.operating_system),
reported(&workload.architecture)
)];
if workload.execution_restrictions.is_empty() {
lines.push("Execution restrictions: unreported".into());
} else {
lines.push("Execution restrictions (reported):".into());
lines.extend(
workload
.execution_restrictions
.iter()
.map(|restriction| format!(" {restriction}")),
);
}
lines
}

fn gateway_info_to_json(view: &GatewayInfoView) -> serde_json::Value {
Expand All @@ -532,6 +574,11 @@ fn gateway_info_to_json(view: &GatewayInfoView) -> serde_json::Value {
"capabilities": {
"driver_name": &driver.capabilities.driver_name,
"driver_version": &driver.capabilities.driver_version,
"workload_compatibility": driver.capabilities.workload_compatibility.as_ref().map(|workload| serde_json::json!({
"operating_system": &workload.operating_system,
"architecture": &workload.architecture,
"execution_restrictions": &workload.execution_restrictions,
})),
},
}))
.collect::<Vec<_>>(),
Expand Down Expand Up @@ -1590,7 +1637,7 @@ mod tests {
gateway_env_override_warning, gateway_info_to_json, gateway_remote_label,
gateway_select_with, gateway_to_json, gateway_type_label, http_health_check,
import_local_package_mtls_bundle, mtls_certs_exist_for_gateway, package_managed_tls_dirs,
plaintext_gateway_is_remote,
plaintext_gateway_is_remote, workload_compatibility_lines,
};
use crate::TEST_ENV_LOCK;
use crate::test_utils::{Environment, with_tmp_xdg, with_tmp_xdg_env};
Expand Down Expand Up @@ -1894,7 +1941,7 @@ mod tests {

#[test]
fn gateway_info_json_includes_compute_drivers_when_available() {
let view = GatewayInfoView {
let mut view = GatewayInfoView {
gateway: "openshell".to_string(),
server: "https://127.0.0.1:17670".to_string(),
auth: Some("bearer"),
Expand All @@ -1905,6 +1952,7 @@ mod tests {
capabilities: ComputeDriverCapabilitiesView {
driver_name: "podman".to_string(),
driver_version: "0.0.75".to_string(),
workload_compatibility: None,
},
}],
extensions: vec![ExtensionInfoView {
Expand Down Expand Up @@ -1933,6 +1981,46 @@ mod tests {
json["compute_drivers"][0]["capabilities"]["driver_version"],
"0.0.75"
);
assert!(json["compute_drivers"][0]["capabilities"]["workload_compatibility"].is_null());
assert_eq!(
workload_compatibility_lines(None),
[
"Workload platform: unreported",
"Execution restrictions: unreported"
]
);

let workload = openshell_core::proto::WorkloadCompatibility {
operating_system: "macos".into(),
architecture: "arm64".into(),
execution_restrictions: vec!["Setuid executables cannot run in this runtime.".into()],
};
assert_eq!(
workload_compatibility_lines(Some(&workload)),
[
"Workload platform: macos / arm64",
"Execution restrictions (reported):",
" Setuid executables cannot run in this runtime."
]
);
view.compute_drivers[0].capabilities.workload_compatibility = Some(workload);
assert_eq!(
gateway_info_to_json(&view)["compute_drivers"][0]["capabilities"]["workload_compatibility"],
serde_json::json!({
"operating_system": "macos",
"architecture": "arm64",
"execution_restrictions": ["Setuid executables cannot run in this runtime."],
})
);
assert_eq!(
workload_compatibility_lines(Some(
&openshell_core::proto::WorkloadCompatibility::default()
)),
[
"Workload platform: unreported / unreported",
"Execution restrictions: unreported"
]
);
}

#[test]
Expand Down
90 changes: 90 additions & 0 deletions crates/openshell-core/src/extension_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,49 @@ pub fn validate_gateway_metadata(
negotiate(family, extension_name, &gateway, extension.cloned()).map(drop)
}

/// Validate diagnostic facts before exposing a compute driver's startup snapshot.
/// Empty platform fields remain unreported; reported explanations are bounded text.
pub fn validate_workload_compatibility(
name: &str,
workload: Option<&crate::proto::compute::v1::WorkloadCompatibility>,
) -> Result<(), NegotiationError> {
let Some(workload) = workload else {
return Ok(());
};
for (field, value) in [
(
"workload_compatibility.operating_system",
&workload.operating_system,
),
(
"workload_compatibility.architecture",
&workload.architecture,
),
] {
if !value.is_empty() {
validate_text("compute", name, field, value, 64)?;
}
}
if workload.execution_restrictions.len() > 16 {
return Err(NegotiationError::InvalidMetadata {
family: "compute",
name: name.to_string(),
field: "workload_compatibility.execution_restrictions",
reason: "must contain at most 16 explanations".into(),
});
}
for restriction in &workload.execution_restrictions {
validate_text(
"compute",
name,
"workload_compatibility.execution_restrictions",
restriction,
512,
)?;
}
Ok(())
}

fn validate_text(
family: &'static str,
name: &str,
Expand Down Expand Up @@ -574,6 +617,53 @@ mod tests {
));
}

#[test]
fn workload_compatibility_preserves_unknown_values_and_bounds_plain_text() {
use crate::proto::compute::v1::WorkloadCompatibility;

assert!(validate_workload_compatibility("native", None).is_ok());
assert!(
validate_workload_compatibility("native", Some(&WorkloadCompatibility::default()))
.is_ok()
);
let valid = WorkloadCompatibility {
operating_system: "future-os".into(),
architecture: "future-arch".into(),
execution_restrictions: vec!["Fixed runtime restriction".into()],
};
assert!(validate_workload_compatibility("native", Some(&valid)).is_ok());
for invalid in [
WorkloadCompatibility {
operating_system: "x".repeat(65),
..valid.clone()
},
WorkloadCompatibility {
architecture: "bad\narch".into(),
..valid.clone()
},
WorkloadCompatibility {
execution_restrictions: vec!["x".repeat(513)],
..valid.clone()
},
WorkloadCompatibility {
execution_restrictions: vec!["fixed".into(); 17],
..valid.clone()
},
WorkloadCompatibility {
execution_restrictions: vec![" ".into()],
..valid.clone()
},
WorkloadCompatibility {
execution_restrictions: vec!["\u{1b}[31mPRIVATE DIAGNOSTIC".into()],
..valid
},
] {
let error = validate_workload_compatibility("native", Some(&invalid)).unwrap_err();
assert!(matches!(error, NegotiationError::InvalidMetadata { .. }));
assert!(!error.to_string().contains("PRIVATE DIAGNOSTIC"));
}
}

#[test]
fn extension_side_rejects_missing_and_incompatible_gateway_metadata() {
let (mut gateway, extension) = compatible();
Expand Down
7 changes: 7 additions & 0 deletions crates/openshell-driver-docker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,13 @@ impl DockerComputeDriver {
count_selection_supported: self.config.gpu.cdi_supported,
}),
}),
workload_compatibility: Some(
openshell_core::proto::compute::v1::WorkloadCompatibility {
operating_system: "linux".to_string(),
architecture: String::new(),
execution_restrictions: Vec::new(),
},
),
rootfs_tar_staging_dir: String::new(),
rootfs_tar_max_bytes: 0,
extension: Some(openshell_core::extension_protocol::extension_metadata(
Expand Down
7 changes: 7 additions & 0 deletions crates/openshell-driver-kubernetes/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,13 @@ impl KubernetesComputeDriver {
count_selection_supported: true,
}),
}),
workload_compatibility: Some(
openshell_core::proto::compute::v1::WorkloadCompatibility {
operating_system: "linux".to_string(),
architecture: String::new(),
execution_restrictions: Vec::new(),
},
),
rootfs_tar_staging_dir: String::new(),
rootfs_tar_max_bytes: 0,
extension: Some(openshell_core::extension_protocol::extension_metadata(
Expand Down
7 changes: 7 additions & 0 deletions crates/openshell-driver-mxc/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,13 @@ impl MxcComputeBackend {
supports_sandbox_authentication: false,
driver_reports_runtime_readiness: true,
resource_capabilities: None,
workload_compatibility: Some(
openshell_core::proto::compute::v1::WorkloadCompatibility {
operating_system: "windows".to_string(),
architecture: String::new(),
execution_restrictions: Vec::new(),
},
),
rootfs_tar_staging_dir: String::new(),
rootfs_tar_max_bytes: 0,
extension: Some(openshell_core::extension_protocol::extension_metadata(
Expand Down
7 changes: 7 additions & 0 deletions crates/openshell-driver-podman/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,13 @@ impl PodmanComputeDriver {
count_selection_supported: true,
}),
}),
workload_compatibility: Some(
openshell_core::proto::compute::v1::WorkloadCompatibility {
operating_system: "linux".to_string(),
architecture: String::new(),
execution_restrictions: Vec::new(),
},
),
rootfs_tar_staging_dir: String::new(),
rootfs_tar_max_bytes: 0,
extension: Some(openshell_core::extension_protocol::extension_metadata(
Expand Down
11 changes: 11 additions & 0 deletions crates/openshell-driver-vm/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1568,6 +1568,13 @@ impl VmDriver {
count_selection_supported: self.config.gpu_enabled,
}),
}),
workload_compatibility: Some(
openshell_core::proto::compute::v1::WorkloadCompatibility {
operating_system: "linux".to_string(),
architecture: linux_oci_arch().to_string(),
execution_restrictions: Vec::new(),
},
),
rootfs_tar_staging_dir: self
.config
.rootfs_tar_staging_dir()
Expand Down Expand Up @@ -14127,6 +14134,10 @@ while :; do sleep 0.05; done"#,
#[test]
fn capabilities_report_static_resource_support() {
let mut driver = test_driver_with_extensions(LifecycleExtensionRegistry::new());
let workload = driver.capabilities().workload_compatibility.unwrap();
assert_eq!(workload.operating_system, "linux");
assert_eq!(workload.architecture, linux_oci_arch());
assert!(workload.execution_restrictions.is_empty());
let resources = driver.capabilities().resource_capabilities.unwrap();
assert!(!resources.cpu.unwrap().limit_supported);
assert!(!resources.memory.unwrap().limit_supported);
Expand Down
Loading
Loading