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
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ include_dir = "0.7"

# Glob matching
glob = "0.3"
globset = "0.4"

# Utilities
futures = "0.3"
Expand Down
5 changes: 5 additions & 0 deletions crates/openshell-core/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub struct FilesystemPolicy {
/// Read-write directory allow list.
pub read_write: Vec<PathBuf>,

/// Path globs for observed workload open attempts.
pub audit_paths: Vec<String>,

/// Automatically include the workdir as read-write.
pub include_workdir: bool,
}
Expand All @@ -37,6 +40,7 @@ impl Default for FilesystemPolicy {
Self {
read_only: Vec::new(),
read_write: Vec::new(),
audit_paths: Vec::new(),
include_workdir: true,
}
}
Expand Down Expand Up @@ -150,6 +154,7 @@ impl From<ProtoFilesystemPolicy> for FilesystemPolicy {
.into_iter()
.map(|p| PathBuf::from(normalize_path(&p)))
.collect(),
audit_paths: proto.audit_paths,
include_workdir: proto.include_workdir,
}
}
Expand Down
16 changes: 16 additions & 0 deletions crates/openshell-core/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ impl RegisteredSetting {
/// still applies when this flag is on.
pub const AGENT_POLICY_PROPOSALS_ENABLED_KEY: &str = "agent_policy_proposals_enabled";

/// Opt in to launch and exit events for processes started by the Linux
/// sandbox boundary. The value is captured when the sandbox starts.
pub const PROCESS_ACTIVITY_ENABLED_KEY: &str = "process_activity_enabled";

/// Approval mode for agent-authored policy proposals.
///
/// `"manual"` (the default when unset): every proposal lands in the draft
Expand Down Expand Up @@ -115,6 +119,11 @@ pub const REGISTERED_SETTINGS: &[RegisteredSetting] = &[
kind: SettingValueKind::Bool,
allowed_string_values: None,
},
RegisteredSetting {
key: PROCESS_ACTIVITY_ENABLED_KEY,
kind: SettingValueKind::Bool,
allowed_string_values: None,
},
// Deprecated and ignored: OpenShell emits OCSF 1.8.0 only. Still
// registered so existing values load; the supervisor reports a set value.
RegisteredSetting {
Expand Down Expand Up @@ -187,6 +196,13 @@ mod tests {
assert!(setting_for_key("providers_v2_enabled").is_none());
}

#[test]
fn process_activity_is_an_opt_in_boolean_setting() {
let setting = setting_for_key("process_activity_enabled")
.expect("process activity setting should be registered");
assert_eq!(setting.kind, SettingValueKind::Bool);
}

// ---- RegisteredSetting::validate_string_value ----

#[test]
Expand Down
1 change: 1 addition & 0 deletions crates/openshell-driver-mxc/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,7 @@ mod lifecycle_tests {
include_workdir: false,
read_only: Vec::new(),
read_write: read_write.iter().map(ToString::to_string).collect(),
audit_paths: Vec::new(),
}),
..Default::default()
}
Expand Down
7 changes: 4 additions & 3 deletions crates/openshell-driver-mxc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ mod driver;
mod grpc;
#[cfg(target_os = "windows")]
mod mxc;
#[cfg(target_os = "windows")]
#[cfg(any(target_os = "windows", test))]
mod policy;
// Embedded mapper logic (source of truth; was the `openshell-policy-mapper`
// crate). Windows-only — MXC and the policy mapper are not built for Linux/WSL.
#[cfg(target_os = "windows")]
// crate). Production code is Windows-only; tests run the pure mapper on Linux.
#[cfg(any(target_os = "windows", test))]
#[cfg_attr(not(target_os = "windows"), allow(unused_imports))]
mod policy_map;
// Real-time ETW → OCSF audit consumer (Plane A). Consumes the OS Sandboxing
// provider MXC drives and emits OCSF through the gateway's tracing sink.
Expand Down
21 changes: 21 additions & 0 deletions crates/openshell-driver-mxc/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ mod tests {
include_workdir: false,
read_only: ro.iter().map(ToString::to_string).collect(),
read_write: rw.iter().map(ToString::to_string).collect(),
audit_paths: Vec::new(),
}),
..Default::default()
}
Expand Down Expand Up @@ -234,6 +235,26 @@ mod tests {
assert!(matches!(err, MapError::Internal(_)));
}

#[test]
fn embedded_rejects_file_audit_on_both_mxc_paths() {
let mapper = EmbeddedPolicyMapper;
let mut policy = fs_policy(&["C:/work/demo"], &[]);
policy.filesystem.as_mut().unwrap().audit_paths = vec!["/sandbox/private/**".to_string()];
for egress in [None, Some("127.0.0.1:18080".parse().unwrap())] {
let ctx = MapCtx {
sandbox_id: "sb-audit".into(),
egress,
};
let error = mapper.map(Some(&policy), &ctx).unwrap_err();
let MapError::Unsupported(loss) = error else {
panic!("expected unsupported audit policy");
};
assert_eq!(loss.len(), 1);
assert_eq!(loss[0].rule_kind, "filesystem_policy.audit_paths");
assert!(!loss[0].detail.contains("/sandbox/private"));
}
}

#[test]
fn embedded_rejects_network_policy_on_isolation_session() {
use openshell_core::proto::{NetworkEndpoint, NetworkPolicyRule};
Expand Down
10 changes: 10 additions & 0 deletions crates/openshell-driver-mxc/src/policy_map/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,16 @@ fn map_filesystem(

match &policy.filesystem {
Some(fs) => {
if !fs.audit_paths.is_empty() {
add_loss(
items,
"filesystem_policy.audit_paths",
"error",
"MXC cannot observe watched file opens.",
"watched file opens",
"The sandbox would emit no file activity events for this policy.",
);
}
readwrite.clone_from(&fs.read_write);
readonly.clone_from(&fs.read_only);
if fs.include_workdir {
Expand Down
1 change: 1 addition & 0 deletions crates/openshell-driver-mxc/tests/policy_mapper_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,7 @@ fn handled_fields_inventory() {
include_workdir: false,
read_only: vec!["/usr".into()],
read_write: vec!["/work".into()],
audit_paths: Vec::new(),
}),
landlock: Some(LandlockPolicy {
compatibility: "best_effort".into(),
Expand Down
2 changes: 2 additions & 0 deletions crates/openshell-driver-mxc/tests/wxc_exec_real.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ fn dryrun_accepts_split_policy_output() {
include_workdir: false,
read_only: Vec::new(),
read_write: vec![temp_path.clone()],
audit_paths: Vec::new(),
}),
..Default::default()
};
Expand Down Expand Up @@ -724,6 +725,7 @@ async fn pc_https_egress_reads_injected_ca_bundle() {
include_workdir: false,
read_only: Vec::new(),
read_write: vec![output_dir_string],
audit_paths: Vec::new(),
}),
network_policies: std::collections::HashMap::from([(
"https_example".to_string(),
Expand Down
2 changes: 2 additions & 0 deletions crates/openshell-isolation-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub struct AgentSpec {
/// Whether the supervisor serves the OTLP relay for this sandbox. The
/// boundary points workload SDKs at the relay only while it is active.
pub otlp_relay_active: bool,
/// Whether the boundary emits lifecycle events for processes it starts.
pub process_activity_enabled: bool,
}

pub mod contract;
Loading
Loading