Repository navigation
fix(ocsf): emit schema-conformant OCSF 1.8 events - #4288
zanetworker wants to merge 1 commit into
Conversation
ddf7841 to
56390e5
Compare
56390e5 to
78621e8
Compare
|
/ok to test 78621e8 |
|
Label |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
The independent review found no blocking defects in the OCSF conformance and schema downgrade changes. @zanetworker, I checked your note about top-level container: it is present in the base, remains an acknowledged design question, and the downgrade preserves its data under unmapped.
Current-head testing has started with test:e2e and test:windows. Trivy and Helm are green; Branch Checks, E2E, and both Windows lanes are pending. The E2E Label Help bot requests Re-run all jobs, but the identified run still has an active first attempt.
Action required: rerun Branch E2E Checks after the active attempt finishes. Gator has operator authorization and the narrow sandbox permission to perform that rerun in a subsequent cycle.
Blocking findings: None.
Carried findings: None.
Gator metadata
- Validation: Focused OCSF correctness fixes for linked issues #4283 and #4284; operator requested review and relevant tests.
- Docs: Fern documentation updates describe OS identity, mixed-version JSONL, downgrade preservation, gateway configuration, and the kept-native metric.
- Checks: DCO, OpenShell / Helm Lint, and OpenShell / Trivy Changes pass; Branch Checks and both Windows MSVC PR lint and test lanes are pending on the reviewed head.
- E2E: test:e2e applied; current-head mirror verified; Branch E2E Checks run 37657018590 attempt 1 is active. Bot-required rerun remains outstanding. Relevant E2E coverage includes the new Podman JSONL conformance test.
- Head SHA:
78621e8bb1fb9af4c91f9cf8dd5c3ebffc62b963 - Base SHA:
3fc93e28273fe304db634e6d5e9a52d57200389e - Merge base SHA:
834b79a8c2351370e7c6c363423f5be18d440256 - Patch ID:
33dfd9e90bc20c4d4b8493efc716d9a8d3c32edb - Gator payload:
11 - Review mode:
initial - Previous reviewed SHA: none
- Review budget exhausted: no
- Maintainer decision required: no
- Next state:
gator:blocked - Blocked reason:
test_dispatch_required
Author Follow-Up NudgeThis PR has been in @zanetworker, please make the vendored OCSF schemas available to the relocated Podman E2E test and push an update. The rootless Podman run fails in @NVIDIA/openshell-maintainers, both Windows lanes also need a gate resolution: Clippy reports Gator metadata
|
|
Fixed in @johntmyers could you take a look, and |
78621e8 to
aae1747
Compare
|
/ok to test aae1747 |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Thanks @zanetworker (Adel Zaalouk), I checked your reply about Windows paths. The comparison and regeneration now use the same helper to join native path components with forward slashes, and the new regression test checks that key. The independent follow-up found no new blockers, and I resolved GATOR-aae17474-01.
I posted /ok to test for the current head. Branch Checks, Helm, E2E, and both Windows lanes are running or queued. The earlier E2E rerun instruction applies to an older head; there is no current-head rerun request. Native Windows verification remains with the Windows lanes.
Action required: @NVIDIA/openshell-maintainers, approve the current-head Trivy Changes workflow, which is awaiting workflow approval. Gator will continue inspecting the active tests; the earlier unrelated Windows CLI Clippy failures still need a maintainer resolution if they recur.
Blocking findings: None.
Carried findings: None. The Windows schema-path finding is fixed and its thread is resolved.
Gator metadata
- Validation: Continuing the validated OCSF correctness fixes for linked issues #4283 and #4284.
- Docs: Existing Fern updates cover user-visible changes; this delta changes test path normalization only.
- Checks: DCO passes. Branch Checks run 38129872736, Helm run 38129872726, and Windows run 38129872735 are active. Trivy Changes run 38129078889 concluded action_required and has no passing current-head result.
- E2E: test:e2e remains applied; current-head Branch E2E Checks run 38129873026 is in progress. test:windows remains applied and both lanes are active.
- Head SHA:
4f8ea841df8a061170bd0623124c8e109e9174c4 - Base SHA:
eeba0e7954c0fb4d8e9e2e29d1bfa68e290eb8b3 - Merge base SHA:
834b79a8c2351370e7c6c363423f5be18d440256 - Patch ID:
3646f9d2c586ab7fe3c85fd231645d9dc6f787f2 - Gator payload:
11 - Review mode:
follow_up - Previous reviewed SHA:
aae17474233af3ddd272f43557a01a7cf0c7f677 - Review budget exhausted: no
- Maintainer decision required: no — no review convergence decision is needed.
- Next state:
gator:blocked - Blocked reason:
workflow_approval_required
|
The fix #4194 should help make the test:windows pass |
rhuss
left a comment
There was a problem hiding this comment.
cc-review summary
Reviewed at 4f8ea841d with a 6-dimension agent pass plus CodeRabbit. The PR is functionally solid: it builds, both drift tests pass, the downgrade logic is correct (stripped attributes are preserved under unmapped.downgraded_attributes, versions are labeled only when they validate, else kept native), security is clean, and all four goals are delivered with genuine deferrals. No blocking defect.
Three non-blocking recommendations below, worth considering before or shortly after merge. Minor and Low findings (SIGTERM process pid, 1.1 unmapped test coverage, ConnectionDirectionId dead variants, kept-native observability split detail, setter duplication) are omitted to keep this focused; happy to share them if useful.
Nice touches: the downgrade never fabricates data and asserts byte-identity on kept-native; per-version required-field differences are grounded in the vendored schemas; type-state builders make missing required fields a compile error; both generated files are drift-guarded.
Source: cc-review (correctness, architecture, security, production, test-quality, goal-alignment agents + CodeRabbit)
|
|
||
| let mut modified = false; | ||
| /// Events kept at the native version since start, and the latest reason. | ||
| static KEPT_NATIVE: std::sync::Mutex<(u64, Option<String>)> = std::sync::Mutex::new((0, None)); |
There was a problem hiding this comment.
Important (observability): kept-native events are reported two ways. The gateway path emits openshell_ocsf_log_kept_native_total{class_uid,target}, while the sandbox path feeds the process-global KEPT_NATIVE mutex that the supervisor drains into a warn!. An operator alerting on the metric misses sandbox kept-native events, and kept_native_tally() reflects only one caller.
Consider a single sink: both paths emitting the metric, or both routing through record_kept_native with the metric/warn emitted from one drain point.
There was a problem hiding this comment.
Addressed in 632853564: every output path now records kept-native events through the shared record_kept_native tally, so kept_native_tally() covers the gateway JSONL, supervisor JSONL, and OTLP export paths. The gateway also emits openshell_ocsf_log_kept_native_total (JSONL) and openshell_ocsf_otlp_kept_native_total (OTLP); the supervisor reports the tally as a warning from its settings poll loop, since it has no metrics exporter and logging from inside the tracing layer is not reliable. A supervisor metric would need a supervisor metrics pipeline, which is out of scope here.
4f8ea84 to
19f9086
Compare
19f9086 to
6328535
Compare
|
I do not think we should merge this. We should pick a specific schema version that is widely supported and stick to it rather than attempt lossy downgrades from a schema version no SIEM may support (e.g. 1.8) |
|
@krishicks on which schema version would you settle ? This directly impacts #2640 where to add any open traces to the event. 1.8 would be ideal as there is a typed section in the schema, otherwise its just an untyped key. |
6328535 to
ef9e9ec
Compare
|
I've narrowed this PR to native OCSF 1.8 conformance. The downgrade changes are out, so it no longer touches the 1.1/1.3 downgrade and closes only #4283. 1.8 is what OpenShell emits by default today, and this PR makes that output correct:
It's rebased on #4677 and uses that PR's #4284 stays open to pick the one version OpenShell emits (1.1 or 1.8) and to remove the downgrade. Until then the existing downgrade is unchanged. Nothing here is lost either way: if we stay on 1.8, #4284 only removes the downgrade and deprecates the setting; if we move to 1.1, that work builds on top of this one, since the builder fixes carry over and the validator and e2e show exactly which emitters need changes. To inform that decision, we still need discovery on how the main SIEMs handle 1.8 records (Security Lake, Google SecOps, Splunk, Elastic): accepted, rejected, or stored but not queryable. That happens separately, with any doc or code changes in follow-up PRs. @krishicks could you take another look? |
|
SIEM spike results for the version decision are on #4284: #4284 (comment) (details in https://gist.github.com/zanetworker/dd3bf999d1f18e6557fa5b95bf87712d). In short, none of the ten sinks tested rejects native 1.8.0, which is the output this PR makes conformant. |
|
Thanks for doing the testing. This makes me feel much better about choosing 1.8, and makes more sense why SIEMs might say they support specific versions only (because that support is regarding specific OCSF classes), and why they might not necessarily upgrade promptly. I think we should do two things: Fix 1.8 (this PR), and then remove everything not related to 1.8 (downgrade, 1.7 schemas). With that in mind, I see a bunch of 1.1/1.3 or otherwise non-1.8 stuff in this PR that could/should probably be removed:
The 🤖 also found this, which would be nice to resolve in this PR: The PR now has two overlapping validators with different rules:
Probably known and required fields should both be checked recursively. |
ef9e9ec to
a79eaab
Compare
|
Thanks @krishicks, all addressed in the updated commit:
A review pass also turned up a few things, fixed here too:
The PR now says "Refs #4283": #4283 stays open for top-level |
|
I captured supervisor JSONL from a released build (0.1.5, Homebrew, Docker Desktop on macOS arm64) and ran it through the official validator, as a before-picture for this PR. Capture: Results against
That matches the description: top-level Possible gap in the README's validation recipe. I tested the hosted schema.ocsf.io only, not a local ocsf-server build, so local behaviour may differ. Happy to rerun this on a build from this branch if that would help. |
Native events failed the official OCSF 1.8.0 validator: HTTP Activity emitted is_src_dst_assignment_known, sandbox Process Activity events had no actor, connection_info lacked direction_id, and SSH Activity events named no endpoint. Schema tests missed these because they checked only top-level, non-profile attributes. Add a connection direction enum, require an actor on Process Activity and an endpoint on SSH Activity at compile time, and name the supervisor's SSH server with svc_name and its socket path. Validate against OCSF 1.8.0 only. validate_required_fields and validate_known_fields share one recursive walker that rejects undefined attributes at every level and, for events, attributes from undeclared profiles; objects are validated as objects. Records labelled with another version fail. Vendor tactic and technique so ATT&CK-mapped findings validate, drop the unused v1.7.0 schemas, and make the embedded-schema drift test tolerate CRLF checkouts. Keep it fixed with a per-builder conformance test and a Podman e2e test that runs an L7 policy against a local server and validates the supervisor's real Network, HTTP and SSH Activity JSONL. Top-level container stays unchanged pending a decision on NVIDIA#4283. The schema downgrade is unchanged. Refs NVIDIA#4283 Signed-off-by: Adel Zaalouk <azaalouk@redhat.com>
a79eaab to
8dbc022
Compare
|
Thanks @houman44, this is a useful before-picture, and it matches what the PR targets: You're right about the recipe. The v1 endpoint misses A rerun on this branch would help, especially for HTTP and Process Activity, which your capture didn't produce. The e2e gets HTTP Activity by running an L7 policy against a local server and sending a request the policy denies; plain TCP to a denied host only produces Network Activity. |
|
/ok to test 8dbc022 |
|
A few remaining items found by the bot on re-review:
|
Summary
Native OCSF 1.8.0 events failed the official OCSF validator: HTTP Activity emitted an attribute the class doesn't define, Process Activity events had no actor,
connection_infolackeddirection_id, and SSH Activity events named no endpoint. The vendored-schema tests missed these because they checked only top-level, non-profile attributes.This makes every builder's native output pass
https://schema.ocsf.io/api/1.8.0/v2/validate(apart from top-levelcontainer, open on #4283) and adds structural checks that keep it that way, including an e2e test that validates the supervisor's real JSONL. The checks cover required and defined attributes, profiles, andat_least_oneconstraints, but not value types or enum ranges; the official validator stays the reference for those (seeschemas/ocsf/README.md).The schema downgrade is out of scope. #4284 tracks picking the one version OpenShell emits (1.1 or 1.8) and removing the downgrade; until then the existing downgrade is unchanged, so output with
ocsf_schema_versionset is still not conformant. This PR is needed either way:OCSF_VERSIONchanges.Related Issue
Refs #4283
With #4677 (
device.os.type_id), this meets #4283's acceptance items except the first: events still fail the official validator on top-levelcontainer, which this PR leaves unchanged, so the issue stays open for that.Changes
is_src_dst_assignment_known, which no OCSF version defines on that class.ProcessActivityBuilderrequires an acting process beforebuild()(type-state, like the HTTP and Network builders). Sandbox process events name theopenshell-sandboxlauncher with its real pid.connection_infocarries the requireddirection_idanddirection, defaulting to Unknown.SshActivityBuilderrequires a source or destination endpoint beforebuild(). All eight SSH events had none; they now name the supervisor's SSH server asdst_endpoint(svc_name: "ssh"and the listen socket path inname), using a newEndpoint::svc_namefield.validate_required_fieldsandvalidate_known_fieldsshare one recursive walker. Both reject undefined attributes at every level and, when validating an event, attributes from profiles the event doesn't declare.validate_required_fieldsalso checks required attributes andat_least_oneconstraints, and fails any event not labelled 1.8.0. New testevery_builder_emits_schema_conformant_eventscovers one event per builder, including Authentication and a fully populated Detection Finding with an ATT&CK mapping (tacticandtechniqueare vendored for it).ocsf_jsonl_conformance(Podman CI set) enables JSONL, generates denied TCP traffic and a plain HTTP request through the sandbox proxy, waits until Network, HTTP and SSH Activity records are all present, copies the supervisor's JSONL withpodman cp, and validates every record. It covers those production call sites rather than builders, and found the SSH endpoint gap. When records can't be copied, the failure names thepodmancommand and its error. The e2e crate takesopenshell-ocsf(withtest-support) as a dev-dependency so both suites share one validator.test-support, vendored schemas are compiled into the binary (validation/embedded.rs, drift-checked byembedded_schemas_match_vendored_files), so archived e2e runs on CI machines need no source files. The fallbackEventContextcarries a sandbox identity, so producer tests exercise the top-levelcontainerexception as a supervisor with a sandbox ID emits it. Top-levelcontaineris the single named exception in the validator, linked to bug(ocsf): native OCSF 1.8 events fail the official schema validator #4283.schemas/ocsf/README.mddocuments the embedded table, regeneration, and validation with the official OCSF server through its v2 endpoint (/api/v2/validatelocally,/api/1.8.0/v2/validatehosted), which reports constraint failures such asat_least_onethat the older/api/validatemisses. The unused v1.7.0 schemas are removed, so only 1.8.0 is vendored and embedded.embedded_schemas_match_vendored_filesnormalizes line endings, so CRLF checkouts on Windows pass, and skips when the source checkout isn't present, as in a relocated nextest archive.ocsf-json-export.mdxdescribes the per-class field changes (SSHdst_endpoint, Processactor.process,connection_info.direction_id, HTTP Activity withoutis_src_dst_assignment_known) and notes that top-levelcontaineris the one attribute OCSF 1.8.0 doesn't define.User-visible: HTTP events drop
is_src_dst_assignment_known; SSH events gaindst_endpoint;connection_infogainsdirection_id; Process Activity events gainactor.process(theopenshell-sandboxlauncher).Deferred: top-level
containeris undefined in every OCSF version but identifies the affected sandbox on gateway events (#4283). The SIGTERM-failure Process Activity event still uses theProcess::new("unknown", 0)fallback.Testing
Rebased on
mainat4b7486e73, which includes #4677 (device.os.type_id) and the gateway authentication events from #4728, #4761 and #4762.OPENSHELL_E2E_PODMAN_TEST=ocsf_jsonl_conformance mise run e2e:podman, gateway and supervisor images built from this branch):supervisor_jsonl_conforms_to_the_native_schemapasses. It runs an L7 policy against a local test server, requires Network, HTTP and SSH Activity records, and validates every supervisor JSONL record against 1.8.0. An earlier version of the test, with raw sockets only, produced no HTTP Activity at all; requiring the classes caught that. Before the SSH fix it failed with"SSH Activity" 1.8.0 "SSH connection accepted on supervisor Unix socket": Missing at_least_one field from [dst_endpoint, src_endpoint].cargo testforopenshell-ocsf(withtest-support),openshell-server,openshell-supervisor,openshell-supervisor-network,openshell-supervisor-process,openshell-sandbox,openshell-otel: all pass (openshell-ocsf202 unit tests, the other six crates 4299). The embedded-schema drift test also passes against a CRLF copy ofembedded.rs.cargo clippy --workspace --all-targets -- -D warnings,cargo fmt --all --check, and no clippy findings in the new e2e filessh::exec_input_tests::eof_preserves_queued_input_until_the_child_readshas a 5 s deadline and hit it on this machine on bothmainand this branch in one run; it passed in the final run.Checklist