Repository navigation
OCSF JSONL enabled and OCSF events emitted, but /var/log/openshell-ocsf.* is not created on Docker Desktop / WSL2 #3895
Description
Activity
- addedstate:triage-neededOpened without agent diagnostics and needs triageOpened without agent diagnostics and needs triage
on Sep 29, 2026 Thanks — I reran this against a fresh 0.1.1 Docker Desktop / WSL2 sandbox and narrowed it down further.
The supervisor container is:
User=65534:65534 ReadonlyRootfs=trueand Docker configures:
/var/log = rw,noexec,nosuid,size=64m,uid=65534,gid=65534,mode=0700so the configured tmpfs is intended to be writable by the supervisor UID.
I then enabled JSONL:
CONFIG:UPDATED ... key:ocsf_json_enabled old:<unset> new:true CONFIG:DETECTED ... OCSF JSONL logging toggledNo
openshell-ocsf.*.logappeared.To make sure this was not just a lack of OCSF events after enabling it, I then changed the setting from
truetofalse.The supervisor emitted:
CONFIG:UPDATED ... key:ocsf_json_enabled old:true new:false CONFIG:DETECTED ... OCSF JSONL logging toggledand there was still no JSONL file.
In v0.1.1,
log_setting_changes(...)and theCONFIG:DETECTEDOCSF emission happen beforeapply_ocsf_json_setting(...), so those events should hitOcsfJsonlLayerwhile the shared enabled flag is stilltrue.One additional observation: copying
/var/logout of the supervisor showed noopenshell*files at all.The failure may therefore be in file/appender creation or the actual write path rather than the toggle itself.
I also noticed that the relevant failures are currently hard to observe:
.build("/var/log").ok()
discards the JSONL appender construction error, and
OcsfJsonlLayerdoes:let _ = w.write_all(line.as_bytes());
which discards write errors.
Instrumenting those two paths may expose the exact Docker Desktop/tmpfs failure.
Still reproduces on v0.1.2 (you tested 0.1.1), and while confirming it I found that the other documented OCSF route is not available on that release either. Posting both in case the pair is useful.
1. Sandbox JSONL — reproduces on v0.1.2
Same topology as yours (Windows 11 / WSL2 / Docker Desktop,
compute_driver = "docker"), CLI and gateway both 0.1.2, kernel6.6.114.1-microsoft-standard-WSL2.Enabled globally before the sandbox existed, then recreated the sandbox so the setting was present from birth — in case the toggle only takes effect at supervisor startup:
$ openshell settings set --global --key ocsf_json_enabled --value true --yes ✓ Set global setting ocsf_json_enabled=true (revision 1) $ openshell settings get --global | grep ocsf ocsf_json_enabled = true ocsf_schema_version = <unset> $ openshell sandbox delete demo ✓ Sandbox demo deletion accepted; cleanup is pending $ openshell sandbox create --name demo --policy policy.yaml $ openshell sandbox list NAME CREATED PHASE demo 2026-10-04 20:03:12 Ready
Then drove real L7 traffic out of the sandbox (one request allowed, one denied by a supervisor middleware registered on the gateway), and OCSF events are definitely being produced:
$ openshell logs demo | grep -oE '[A-Z][A-Z_]+:[A-Z_]+' | sort | uniq -c | sort -rn 4 HTTP:POST 3 NET:OPEN 2 SSH:OPEN 2 CONFIG:PUBLISHED 2 CONFIG:CONFIGURED 1 SSH:LISTEN 1 NET:LISTEN 1 FINDING:CREATE
The documented file is still absent inside the workload sandbox:
$ openshell sandbox exec -n demo -- bash -c 'ls /var/log/openshell-ocsf*' ls: cannot access '/var/log/openshell-ocsf*': No such file or directory $ openshell sandbox exec -n demo -- bash -c 'ls -la /var/log/' total 264 -rw-r--r-- 1 root root 4860 Sep 5 13:01 alternatives.log drwxr-xr-x 1 root root 4096 Sep 14 04:54 apt -rw-r--r-- 1 root root 61229 Sep 5 12:55 bootstrap.log -rw-rw---- 1 root utmp 0 Sep 5 12:55 btmp -rw-r--r-- 1 root root 187630 Sep 14 04:54 dpkg.log ...
No
openshell-*file of any name, not just a missing dated segment. So on this topology the behaviour is unchanged from 0.1.1 to 0.1.2.2. The gateway-side route does not exist on v0.1.2
docs/observability/ocsf-json-export.mdxonmaindocuments a second, independent sink:Configure
[openshell.gateway.ocsf_log]ingateway.tomlto collect gateway-origin OCSF events into one JSONL file. This includes gateway-wide events such as TLS certificate reloads, even when no sandbox log stream applies.That is the natural workaround for issue 1 — and the v0.1.2 gateway rejects the config outright:
Error: × failed to parse gateway config file '/root/.config/openshell/gateway.toml': TOML parse error at line 18, column 20 18 | [openshell.gateway.ocsf_log] | ^^^^^^^^ unknown field `ocsf_log`, expected one of `name`, `bind_address`, `health_bind_address`, `metrics_bind_address`, `log_level`, `compute_driver`, `credential_drivers`, `default_credential_driver`, `credential_storage`, `ssh_session_ttl_secs`, `grpc_rate_limit_requests`, `grpc_rate_limit_window_seconds`, `policy_validation_failure_mode`, `server_sans`, `enable_loopback_service_http`, `enable_websocket_tunnel`, `guest_tls_ca`, `guest_tls_cert`, `guest_tls_key`, `disable_tls`, `tls`, `oidc`, `auth`, `interceptors`, `provider_profile_sources`, `mtls_auth`, `gateway_jwt`, `otlp`, `database_url`
It is present on the 0.1.3 line. Using the
devrelease (0.1.3-dev.82+g8983642e2), the same config parses, and the accepted-field list now ends:... `mtls_auth`, `gateway_jwt`, `otlp`, `ocsf_log`, `database_url`Its sub-fields, read the same way:
expected one of `path`, `schema_version`, `rotation`, `max_files`, `queue_capacity`, `queue_max_bytes`(Checked with a deliberately bogus key in each position; 0.1.3 still rejects unknown fields strictly, so the acceptance is a real schema change rather than relaxed parsing.)
So, concretely: on the latest stable release both documented OCSF JSONL routes are unavailable on this topology — the sandbox file is never created, and the gateway sink is not in the config schema. That may be worth a line in the docs, since the page on
maindoes not say the gateway sink requires >= 0.1.3.Questions
- Is sandbox JSONL export expected to work on the Docker driver under Docker Desktop / WSL2 in 0.1.2, or is that topology known-unsupported? Your UID/tmpfs finding on 0.1.1 suggests the supervisor should be able to write there.
- Is there a supported way to get gateway-origin OCSF JSONL on 0.1.2, or is 0.1.3 the floor for that?
Happy to run further diagnostics on this setup — it reproduces consistently.
On macOS (Docker Desktop, arm64), 0.1.2, Docker driver, the file is written — and both checks above would miss it, so it may be worth ruling out on your WSL2 setups before digging further.
- The supervisor's
/var/logis the tmpfs @BondarenkoIV found (rw,noexec,nosuid,size=64m,uid=65534,gid=65534,mode=0700) over a read-only rootfs.HostConfig.Tmpfsshows it;.Mountsdoesn't. docker cpreads the container's filesystem layers, not a tmpfs mounted over them, so copying/var/logout of the supervisor shows noopenshell*files even when they're there.openshell sandbox execlands in the workload container, not the supervisor, sols /var/logthere won't show it either.
Reading through the supervisor's own mount namespace from a privileged helper does:
PID=$(docker inspect -f '{{.State.Pid}}' <sandbox>-supervisor) docker run --rm --privileged --pid=host ubuntu:24.04 \ ls -la /proc/$PID/root/var/log/Here that listed
openshell-ocsf.<date>.log— 49 JSONL records, 42 KB, covering network (4001/4002/4007), config state (5019) and relay open/close — next toopenshell.<date>.log.I haven't tried WSL2, so I can't say it's there for you, but that one command would tell you. If it is, the gap on this driver is collection rather than emission:
- the docs say the JSONL lands "inside the sandbox", but it's in the supervisor container, on a 64 MB tmpfs nobody can exec into;
- it's lost when that container restarts;
- there's no supported way to ship it from the host — and, as @shalevyoni-ops found, the gateway
ocsf_logsink needs 0.1.3.
If it's genuinely absent, +1 to instrumenting the two silent paths @BondarenkoIV pointed out (
.build("/var/log").ok()andlet _ = w.write_all).- The supervisor's
@BondarenkoIV 0.1.3 will now have
OCSF-JSONlogs available via stderr similarly to the shorthandOCSFlogs. We have some future work coming that will optionally allow all OCSF logs to be accessible via the Gateway. We're also looking at how to incorporate something like https://github.com/NVIDIA-dev/OpenShell-exporter into the architecture.For now I would plan to tail the container logs to parse out the JSON records.
John, thank you — this is exactly the minimal interface we needed for the next validation step.
We’ll target 0.1.3 and start with the approach you suggested: tail the container stderr, preserve the raw OCSF JSON records, and map them into our execution-evidence model without treating the log itself as stronger proof than it is.
The main thing we want to test is whether we can reliably correlate a requested agent action with the observed runtime events/process/resource/result across a short multi-step execution.
We’ll avoid building around the transport, so if OCSF later moves behind the Gateway/exporter, that should just replace the collection adapter rather than change the model.
Once we’ve run that small validation, I’ll share what fields were sufficient, what correlation gaps remained, and where we still needed another evidence source.
Thanks again for closing this loop.Follow-up to my comment above (0.1.2, WSL2). Same test on a native Linux kernel with the 0.1.3 dev build: the file is still not created, by either mechanism.
Environment
- Kernel:
6.8.0-142-generic, 4 vCPU (cloud VM, OpenShell installed directly on the host; no WSL, no nested container) - CLI:
openshell 0.1.3-dev.136+ge1f3c82ca - Gateway:
openshell-gateway 0.1.3-dev.136+ge1f3c82ca(from thedevrelease .deb) - Sandbox: created fresh by this gateway, 2026-10-09 10:26:30 UTC, phase Ready
Both documented mechanisms were enabled before the sandbox existed:
$ openshell settings get --global | grep ocsf ocsf_json_enabled = true ocsf_schema_version = <unset>
# gateway.toml [openshell.gateway.ocsf_log] path = "/var/log/openshell/gateway-ocsf.jsonl"
The gateway accepts this config on 0.1.3 (on 0.1.2 it is rejected as an unknown field — see my earlier comment).
/var/log/openshellexisted before the gateway started and was mode 0777.Events are being emitted. After driving HTTP requests from inside the sandbox to a host endpoint:
$ openshell logs demo | grep -oE '[A-Z][A-Z_]+:[A-Z_]+' | sort | uniq -c | sort -rn 4 HTTP:POST 3 SSH:OPEN 3 NET:OPEN 2 CONFIG:PUBLISHED 1 SSH:LISTEN 1 NET:LISTEN 1 FINDING:CREATE 1 CONFIG:READY 1 CONFIG:LOADED 1 CONFIG:ENRICHED 1 CONFIG:ENABLED 1 CONFIG:CONFIGURED
Neither file exists:
$ openshell sandbox exec -n demo -- bash -c 'ls -la /var/log/openshell-ocsf*' ls: cannot access '/var/log/openshell-ocsf*': No such file or directory $ openshell sandbox exec -n demo -- bash -c 'ls /var/log/' alternatives.log apt bootstrap.log btmp dpkg.log faillog lastlog wtmp $ ls -la /var/log/openshell/ total 8 drwxrwxrwx 2 root root 4096 Oct 9 10:25 . drwxrwxr-x 10 root syslog 4096 Oct 9 10:25 ..
What this run establishes
- The sandbox-side file is not created on a native kernel with the 0.1.3 dev gateway and supervisor, with
ocsf_json_enabled=trueset before sandbox creation and OCSF events demonstrably emitted. So the behaviour reported in this issue is not specific to WSL2 or Docker Desktop. - The gateway-side
[openshell.gateway.ocsf_log]sink, which the docs describe as collecting gateway-origin events even when no sandbox log stream applies, also produced no file in the same run.
What it does not establish
- Cause. We have not read the OpenShell source and are not guessing at one.
- Anything about the MicroVM driver (ocsf_json_enabled silently writes nothing with the MicroVM driver (supervisor cannot open /var/log) #3855) or Windows MXC gateways; not tested.
- Whether the gateway-side sink would have written anything given a different event mix. Only the events listed above occurred in this run.
- Our sandbox policy also registered a gRPC middleware for the HTTP endpoint. We did not test without it, so we cannot say whether its presence matters.
What I ran
Reconstructed from the run above, not re-executed from a clean host — the VM has been destroyed.
- On a native Linux host with Docker: install the
devrelease (openshell-dev-amd64.debfrom the releases page), confirmopenshell --versionandopenshell-gateway --versionboth report 0.1.3-dev. - Add to
gateway.toml:[openshell.gateway.ocsf_log] path = "/var/log/openshell/gateway-ocsf.jsonl"
mkdir -p /var/log/openshell; restart the gateway. openshell settings set --global --key ocsf_json_enabled --value true --yes- Create a sandbox with a network policy that allows one HTTP endpoint on the host.
- From inside the sandbox, make a few HTTP requests to that endpoint; wait ~15 s.
- Confirm events:
openshell logs <sandbox> | grep -oE '[A-Z][A-Z_]+:[A-Z_]+' | sort | uniq -c - Check both paths:
openshell sandbox exec -n <sandbox> -- ls -la /var/log/openshell-ocsf* ls -la /var/log/openshell/
Happy to re-run with a specific build or extra logging if that helps.
- Kernel:
Correction to my comment above. The sandbox-side check I used —
openshell sandbox exec … ls /var/log/— runs in the workload container. As @em198 showed on Oct 6, the supervisor writes the OCSF file into its own container's/var/logtmpfs, which that command cannot see. My conclusion that no sandbox-side file was created on the native kernel is withdrawn. The same applies to my Oct 4 comment on 0.1.2, which used the same check.What stands is the host-side observation:
/var/log/openshell/on the gateway host was empty after the run, with[openshell.gateway.ocsf_log]configured and accepted by the 0.1.3-dev.136 gateway. That path is on the host and is unaffected by the container question. I cannot re-run @em198's/proc/<pid>/root/var/log/check — the VM has been destroyed.I also posted onto a thread that had already been closed the day before. Apologies for the noise.
User Story
On Docker Desktop / WSL2 with the Docker compute driver, I need the documented OCSF JSONL file to be available in the workload sandbox after enabling ocsf_json_enabled. OCSF events are emitted, but the file does not appear.
Problem Statement
Expected
With:
OpenShell documentation says OCSF JSON records should be written to:
Observed
The setting is applied successfully. Real OCSF events are emitted, including
CONFIG:*,NET:*, policy revision changes and SSH relay events. However,/var/log/openshell-ocsf.YYYY-MM-DD.logis never created inside the workload sandbox. Reproduced after pinning both gateway and supervisor to 0.1.1.Impact / Why This Matters
The documented JSONL file is unavailable inside the workload sandbox, despite effective configuration and live OCSF events. The gateway stream contains real events. Is JSONL export expected to work with the Docker Desktop / WSL2 Docker driver path in 0.1.1? If yes, which filesystem/container should own
/var/log/openshell-ocsf.*in this topology?Acceptance Criteria
With
ocsf_json_enabled=true, the documented/var/log/openshell-ocsf.YYYY-MM-DD.logappears in the expected filesystem for this topology and contains the emitted OCSF JSON records, or the supported behavior and file location are clarified.Reproduction Steps
openshell settings set <sandbox> --key ocsf_json_enabled --value true.CONFIG:*,NET:*, policy revision changes, SSH relay events); the gateway stream contains real events./var/log/openshell-ocsf.YYYY-MM-DD.loginside the workload sandbox. It does not appear.Additional Docker Desktop / WSL2 observation:
host.openshell.internaldid not resolve from the supervisor path. The sandbox became operational only after changing the Docker driver callback endpoint tohttp://127.0.0.1:8080with host networking. This may or may not be related to the JSONL issue.Environment
Logs