|
| 1 | +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +//! Backend-selected interpretation of opaque boundary confirmation evidence. |
| 5 | +
|
| 6 | +use openshell_isolation_interface::contract::{BackendError, BoundaryProperties}; |
| 7 | + |
| 8 | +/// Validate measured evidence and derive the properties it actually supports. |
| 9 | +/// Implementations must reject incomplete evidence and unsupported formats. |
| 10 | +pub trait BoundaryAuditValidator: std::fmt::Debug + Send + Sync { |
| 11 | + /// # Errors |
| 12 | + /// Returns an error when evidence cannot establish the boundary guarantees. |
| 13 | + fn validate(&self, evidence: &serde_json::Value) -> Result<BoundaryProperties, BackendError>; |
| 14 | +} |
| 15 | + |
| 16 | +/// Default evidence interpreter for the Linux `OpenShell` sandbox. |
| 17 | +#[derive(Debug)] |
| 18 | +pub struct LinuxBoundaryAuditValidator; |
| 19 | + |
| 20 | +impl BoundaryAuditValidator for LinuxBoundaryAuditValidator { |
| 21 | + fn validate(&self, evidence: &serde_json::Value) -> Result<BoundaryProperties, BackendError> { |
| 22 | + let audit: crate::boundary_protocol::NativeLinuxSandboxAuditEvidence = |
| 23 | + serde_json::from_value(evidence.clone()).map_err(|error| { |
| 24 | + BackendError::Confirm(format!("decode Linux sandbox audit evidence: {error}")) |
| 25 | + })?; |
| 26 | + audit.validate()?; |
| 27 | + Ok(audit.properties()) |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +#[cfg(test)] |
| 32 | +mod tests { |
| 33 | + use super::{BoundaryAuditValidator as _, LinuxBoundaryAuditValidator}; |
| 34 | + |
| 35 | + #[test] |
| 36 | + fn default_validator_accepts_complete_linux_evidence() { |
| 37 | + let evidence = serde_json::json!({ |
| 38 | + "capabilities": {"inheritable": 0, "permitted": 0, "effective": 0, |
| 39 | + "bounding": 0, "ambient": 0}, |
| 40 | + "no_new_privileges": true, "sandbox_dumpable": false, |
| 41 | + "child_dumpable": true, "core_limit_zero": true, |
| 42 | + "native_architecture": "test", "kernel_release": "test", |
| 43 | + "seccomp": { |
| 44 | + "new_listener": true, "notification_round_trip": true, |
| 45 | + "id_validation": true, "addfd_send": true, |
| 46 | + "retained_socket_operation": true, "proc_fd_identity": true, |
| 47 | + "task_memory_read": true, "task_memory_write": true, "cancellation": true, |
| 48 | + "task_memory_writes_disabled": false |
| 49 | + }, |
| 50 | + "landlock_abi": 3, "landlock_allow_deny": true, |
| 51 | + "udp_dns_round_trip": true, "tcp_dns_round_trip": true, |
| 52 | + "tcp_allow_round_trip": true, "tcp_deny_round_trip": true |
| 53 | + }); |
| 54 | + let properties = LinuxBoundaryAuditValidator.validate(&evidence).unwrap(); |
| 55 | + let audit: crate::boundary_protocol::NativeLinuxSandboxAuditEvidence = |
| 56 | + serde_json::from_value(evidence.clone()).unwrap(); |
| 57 | + assert_eq!(properties, audit.properties()); |
| 58 | + let mut incomplete = evidence; |
| 59 | + incomplete["no_new_privileges"] = false.into(); |
| 60 | + assert!(LinuxBoundaryAuditValidator.validate(&incomplete).is_err()); |
| 61 | + } |
| 62 | + |
| 63 | + #[test] |
| 64 | + fn default_validator_rejects_unknown_platform_and_incomplete_evidence() { |
| 65 | + for platform in ["windows_mxc", "unknown", "linux"] { |
| 66 | + let evidence = serde_json::json!({"platform": platform, "evidence": {}}); |
| 67 | + assert!(LinuxBoundaryAuditValidator.validate(&evidence).is_err()); |
| 68 | + } |
| 69 | + } |
| 70 | +} |
0 commit comments