fix(ocsf): widen the shorthand [reason:] budget so denial endpoints stay readable (NVIDIA/NemoClaw#4760)#1799
Conversation
bacdb37 to
041c98e
Compare
| /// denial reason carries the full destination endpoint plus the rejecting | ||
| /// policy name (e.g. `endpoint host.example:443 not in policy <name>`), so the | ||
| /// budget has to be wide enough to keep the port and policy name readable in | ||
| /// `nemoclaw <sb> logs --tail`; 80 chars cut a typical reason mid-endpoint. |
There was a problem hiding this comment.
nit: remove nemoclaw ref
PR Review StatusValidation: This is a small concentrated Review findings:
Docs: No Fern docs or E2E: No Next state: |
…tay readable (NVIDIA/NemoClaw#4760) A denied egress logs an OCSF NET:OPEN DENIED line whose [reason:] field carries the full destination endpoint and the rejecting policy name, but the shorthand formatter capped the reason at 80 bytes and appended a literal "...". A typical reason is longer than that, so the shorthand denial logs showed the endpoint cut mid-string with the port and policy name lost: NET:OPEN [MED] DENIED ... [reason:endpoint host.example:44...] Raise MAX_REASON_LEN to 256 so a full endpoint plus policy name fits, and route both reason_tag and message_tag through a shared char-boundary truncation helper. The previous `&text[..MAX]` byte slice would also panic if the cut fell inside a multibyte UTF-8 character. Per review: reason_tag now also normalizes embedded newlines to spaces before truncating (matching message_tag), so endpoint- or error-derived text cannot inject CR/LF into the single-line shorthand (CWE-117); the multibyte-boundary test now slices inside a multibyte character to actually exercise the step-back. The issue was reported on the NemoClaw tracker (NVIDIA/NemoClaw#4760), but the OCSF shorthand emitter is OpenShell code, so the fix lands here. Cross-repo references do not auto-close, so no closing keyword is used. Ref: NVIDIA/NemoClaw#4760 (NVIDIA/NemoClaw#4760) Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
041c98e to
334b4df
Compare
|
Thanks @johntmyers — all three addressed.
Full |
Summary
When a sandbox blocks an outbound connection, it writes a denial log line that should explain what was blocked and why: the destination address and the policy that rejected it. That explanation was being cut off at 80 characters and replaced with a literal
..., sonemoclaw <sb> logs --tailshowed something like[reason:endpoint host.example:44...], with the port and the policy name chopped off. The operator can see that something was denied but not which endpoint to allow or which policy to adjust.This widens the reason budget from 80 to 256 characters so the full endpoint and policy name fit. It also makes the truncation cut on a character boundary instead of a raw byte position, which keeps multi-byte text intact and removes a latent crash (the old byte-position slice could panic if it landed in the middle of a multi-byte character). The same safe truncation now also covers the related
[msg:...]field.Related Issue
Fixes NemoClaw issue #4760.
The user-facing symptom surfaces via
nemoclaw <sb> logs --tail, but the OCSF shorthand emitter that truncates the reason is OpenShell code (crates/openshell-ocsf), so the fix lands in this repo.Changes
MAX_REASON_LEN80 -> 256 incrates/openshell-ocsf/src/format/shorthand.rsso a denial reason (endpoint <fqdn>:<port> not in policy <name>) stays readable instead of being cut mid-endpoint.truncate_with_ellipsis(text, max)helper that steps back to the nearest UTF-8 char boundary before slicing; used by bothreason_tagandmessage_tag(the latter carried the same latent&text[..MAX]panic on multibyte input).Testing
Ran the full gate in a container matching CI (rust 1.95.0 per
rust-toolchain.tomlplus the mise toolchain):mise run pre-commitpasses end-to-end (rust:format:check, rust:lint, rust:check, test:rust, python:format:check/lint/typecheck/proto, helm:lint, helm:docs:check, markdown:lint, license:check).test_shorthand_reason_keeps_full_endpoint_and_policy(regression for NemoClaw issue #4760: a fullendpoint <fqdn>:443 not in policy balancedreason renders end-to-end with no...),test_shorthand_reason_truncated_beyond_max_len(an over-256 reason still truncates), andtest_shorthand_reason_truncates_on_multibyte_char_boundary(multibyte input truncates without panicking).openshell-ocsfleaf crate (it changes the rendered width of one log tag); there is no cluster or gateway-runtime behavior to assert, so the crate's own#[cfg(test)]module is the appropriate coverage.Checklist