From 9505981031d5ea1115fba9e531adf2002d87927e Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Thu, 28 May 2026 09:23:11 -0400 Subject: [PATCH] feat(sandbox): add OPENSHELL_OCSF_JSONL opt-in for standalone mode The JSONL audit layer is gated by an AtomicBool that the policy poll loop swaps when the gateway-side `ocsf_json_enabled` setting changes. The poll loop only spawns when an `OPENSHELL_ENDPOINT` is configured, so a supervisor running standalone has no way to flip the flag and `/var/log/openshell-ocsf.YYYY-MM-DD.log` stays empty. Seed the initial value from `OPENSHELL_OCSF_JSONL` (matching the boolean-env pattern already used by `OPENSHELL_NO_BROWSER`). The default is unchanged: an unset variable still starts the flag at false. Signed-off-by: Davanum Srinivas --- crates/openshell-core/src/sandbox_env.rs | 3 +++ crates/openshell-sandbox/src/main.rs | 5 ++++- docs/observability/ocsf-json-export.mdx | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/openshell-core/src/sandbox_env.rs b/crates/openshell-core/src/sandbox_env.rs index b367e450c..7d27ae864 100644 --- a/crates/openshell-core/src/sandbox_env.rs +++ b/crates/openshell-core/src/sandbox_env.rs @@ -53,3 +53,6 @@ pub const SANDBOX_TOKEN_FILE: &str = "OPENSHELL_SANDBOX_TOKEN_FILE"; /// writes and rotates this file; the supervisor exchanges its contents /// for a gateway JWT at startup and on refresh. pub const K8S_SA_TOKEN_FILE: &str = "OPENSHELL_K8S_SA_TOKEN_FILE"; + +/// Opt-in switch for the OCSF JSONL tracing layer in standalone mode. +pub const OCSF_JSONL_ENABLED: &str = "OPENSHELL_OCSF_JSONL"; diff --git a/crates/openshell-sandbox/src/main.rs b/crates/openshell-sandbox/src/main.rs index 3c9e21578..7b1c6418f 100644 --- a/crates/openshell-sandbox/src/main.rs +++ b/crates/openshell-sandbox/src/main.rs @@ -221,7 +221,10 @@ fn main() -> Result<()> { // Shared flag: the sandbox poll loop toggles this when the // `ocsf_json_enabled` setting changes. The JSONL layer checks it // on each event and short-circuits when false. - let ocsf_enabled = Arc::new(AtomicBool::new(false)); + let ocsf_enabled = Arc::new(AtomicBool::new( + std::env::var(openshell_core::sandbox_env::OCSF_JSONL_ENABLED) + .is_ok_and(|v| v == "1" || v.eq_ignore_ascii_case("true")), + )); // Keep guards alive for the entire process. When a guard is dropped the // non-blocking writer flushes remaining logs. diff --git a/docs/observability/ocsf-json-export.mdx b/docs/observability/ocsf-json-export.mdx index 5c326d665..36e1fdd55 100644 --- a/docs/observability/ocsf-json-export.mdx +++ b/docs/observability/ocsf-json-export.mdx @@ -33,6 +33,10 @@ To disable: openshell settings set --global --key ocsf_json_enabled --value false ``` +### Standalone mode + +When the supervisor runs without a gateway endpoint, the policy poll loop that toggles `ocsf_json_enabled` never starts. Set `OPENSHELL_OCSF_JSONL=1` in the supervisor's environment at startup to enable JSON export in this mode. + ## Output Location When enabled, OCSF JSON records are written to `/var/log/openshell-ocsf.YYYY-MM-DD.log` inside the sandbox. The file rotates daily and retains the 3 most recent files, matching the main log file rotation.