From ec1597de06836736f7a21a9fc06909a3c7b4a7d3 Mon Sep 17 00:00:00 2001 From: Ilan Harel Date: Mon, 9 Nov 2026 09:21:55 +0200 Subject: [PATCH] test: add real OpenShell v0.1.7 OCSF 1.8.0 log fixtures tests/fixtures/logs/ocsf-1.8.0.jsonl holds 17 supervisor records captured from an OpenShell v0.1.7 sandbox: classes 0, 4001 (Open allowed/denied and two policy-DNS Refuse records), 4002 (L7 allow/deny), 4007 and 5019. Device, container and record identifiers are scrubbed, and real resolved IPs are replaced with 203.0.113.x. tests/fixtures/ocsf-1.8.0-app mirrors the annotated app the records came from. The new CLI test checks the JSON counts and suggestions and adds a plain human golden. Closes #70 Signed-off-by: Ilan Harel --- tests/cli.rs | 54 +++++++++++++++++++ tests/fixtures/logs/ocsf-1.8.0.jsonl | 17 ++++++ tests/fixtures/ocsf-1.8.0-app/app.py | 32 +++++++++++ .../ocsf-1.8.0-app/openshell-annotate.toml | 3 ++ tests/golden/diff_logs_ocsf_1_8_0_plain.txt | 42 +++++++++++++++ 5 files changed, 148 insertions(+) create mode 100644 tests/fixtures/logs/ocsf-1.8.0.jsonl create mode 100644 tests/fixtures/ocsf-1.8.0-app/app.py create mode 100644 tests/fixtures/ocsf-1.8.0-app/openshell-annotate.toml create mode 100644 tests/golden/diff_logs_ocsf_1_8_0_plain.txt diff --git a/tests/cli.rs b/tests/cli.rs index 0706d05..1fb56fe 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -2152,3 +2152,57 @@ fn committed_policy(example: &Path) -> String { .unwrap() .replace("@VERSION@", env!("CARGO_PKG_VERSION")) } + +/// Real OpenShell v0.1.7 supervisor records (native OCSF 1.8.0, scrubbed), checked against the app they came from. +/// The two policy-DNS "Refuse" records (activity 5) are skipped (#69), so JSON gives the same result as shorthand. +#[test] +fn diff_logs_reads_openshell_0_1_7_ocsf_1_8_0_records() { + let t = tempfile::tempdir().unwrap(); + copy_dir( + &Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/ocsf-1.8.0-app"), + t.path(), + ); + std::fs::copy( + logs_fixture("ocsf-1.8.0.jsonl"), + t.path().join("ocsf.jsonl"), + ) + .unwrap(); + let text = std::fs::read_to_string(logs_fixture("ocsf-1.8.0.jsonl")).unwrap(); + assert!(text + .lines() + .all(|l| l.contains("\"metadata\":{\"version\":\"1.8.0\""))); + + let o = run(t.path(), &["diff-logs", "ocsf.jsonl", "--json"]); + assert_eq!(o.status.code(), Some(1), "{}", err(&o)); + let v: serde_json::Value = serde_json::from_str(&out(&o)).unwrap(); + assert_eq!( + ( + v["events"].as_u64(), + v["denied"].as_u64(), + v["allowed"].as_u64() + ), + (Some(10), Some(3), Some(7)) + ); + let k = kinds(&v); + for want in [ + ("missing_egress", "example.com", "/usr/bin/curl"), + ("missing_egress", "pypi.org", "/usr/local/bin/python3.12"), + ("l7_allow", "httpbin.org", ""), + ] { + assert!( + k.iter() + .any(|(a, b, c)| (a.as_str(), b.as_str()) == (want.0, want.1) + && (want.2.is_empty() || c == want.2)), + "{want:?} not in {k:?}" + ); + } + assert!(!k.iter().any(|(a, _, _)| a == "manual"), "{k:?}"); + + let o = run_env( + t.path(), + &["diff-logs", "ocsf.jsonl", "--color", "never", "--no-icons"], + &[], + ); + assert_eq!(o.status.code(), Some(1), "{}", err(&o)); + golden("diff_logs_ocsf_1_8_0_plain.txt", &out(&o)); +} diff --git a/tests/fixtures/logs/ocsf-1.8.0.jsonl b/tests/fixtures/logs/ocsf-1.8.0.jsonl new file mode 100644 index 0000000..5914106 --- /dev/null +++ b/tests/fixtures/logs/ocsf-1.8.0.jsonl @@ -0,0 +1,17 @@ +{"class_uid":0,"class_name":"Base Event","category_uid":0,"category_name":"Uncategorized","activity_id":99,"activity_name":"Relay open","type_uid":99,"type_name":"Base Event: Relay open","time":1794000000000,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"ssh relay open (channel_id=00000000-0000-4000-8000-000000000001, target=unix:/run/openshell/ssh.sock)","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["container","host"],"uid":"00000000-0000-4000-8000-000000000001"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000001"}} +{"class_uid":4007,"class_name":"SSH Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400701,"type_name":"SSH Activity: Open","time":1794000000001,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"SSH connection accepted on supervisor Unix socket","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","container","host"],"uid":"00000000-0000-4000-8000-000000000002"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000002"},"dst_endpoint":{"name":"/run/openshell/ssh.sock","svc_name":"ssh"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed"} +{"class_uid":5019,"class_name":"Device Config State Change","category_uid":5,"category_name":"Discovery","activity_id":1,"activity_name":"Log","type_uid":501901,"type_name":"Device Config State Change: Log","time":1794000000104,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"Policy DNS mapped icanhazip.com resolved=203.0.113.10,203.0.113.11 synthetic=198.18.0.2 ports=443 mapping_id=00000000-0000-4000-8000-000000000003","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","container","host"],"uid":"00000000-0000-4000-8000-000000000003"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000003"},"unmapped":{"normalized_domain":"icanhazip.com","address_family":"Ipv4","approved_real_ip_candidates":["203.0.113.10","203.0.113.11"],"synthetic_ip":"198.18.0.2","allowed_ports":[443],"policy_generation":1,"mapping_generation":1,"mapping_id":"00000000-0000-4000-8000-000000000003"},"state_id":2,"state":"published"} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400101,"type_name":"Network Activity: Open","time":1794000000172,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"CONNECT_L7 allowed icanhazip.com:443","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000004"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000004"},"src_endpoint":{"ip":"0.0.0.0","port":0},"dst_endpoint":{"domain":"icanhazip.com","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"actor":{"process":{"name":"/usr/bin/curl","pid":0,"cmd_line":"/dev/null","parent_process":{"name":"-","pid":0}}},"firewall_rule":{"name":"icanhazip_com","type":"opa"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","is_src_dst_assignment_known":true} +{"class_uid":4002,"class_name":"HTTP Activity","category_uid":4,"category_name":"Network Activity","activity_id":99,"activity_name":"Other","type_uid":400299,"type_name":"HTTP Activity: Other","time":1794000000309,"severity_id":1,"severity":"Informational","message":"L7_REQUEST allow GET icanhazip.com:443/ reason=","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000005"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000005"},"http_request":{"http_method":"GET","url":{"scheme":"https","hostname":"icanhazip.com","path":"/","port":443}},"dst_endpoint":{"domain":"icanhazip.com","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"firewall_rule":{"name":"icanhazip_com","type":"l7"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","observation_point_id":2} +{"class_uid":0,"class_name":"Base Event","category_uid":0,"category_name":"Uncategorized","activity_id":99,"activity_name":"Relay closed","type_uid":99,"type_name":"Base Event: Relay closed","time":1794000000390,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"ssh relay closed (channel_id=00000000-0000-4000-8000-000000000006, target=unix:/run/openshell/ssh.sock)","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["container","host"],"uid":"00000000-0000-4000-8000-000000000006"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000006"}} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":5,"activity_name":"Refuse","type_uid":400105,"type_name":"Network Activity: Refuse","time":1794000000477,"severity_id":3,"severity":"Medium","status_id":2,"status":"Failure","message":"Policy DNS refused a name that is not eligible in the active policy","status_detail":"policy_dns_ineligible","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000007"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000007"},"dst_endpoint":{"domain":"example.com"},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"action_id":2,"action":"Denied","disposition_id":2,"disposition":"Blocked","is_src_dst_assignment_known":true} +{"class_uid":5019,"class_name":"Device Config State Change","category_uid":5,"category_name":"Discovery","activity_id":1,"activity_name":"Log","type_uid":501901,"type_name":"Device Config State Change: Log","time":1794000000477,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"Policy DNS staged unapproved name example.com synthetic=198.18.0.3 for TCP policy review","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","container","host"],"uid":"00000000-0000-4000-8000-000000000008"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000008"},"unmapped":{"normalized_domain":"example.com","address_family":"Ipv4","synthetic_ip":"198.18.0.3","policy_generation":1,"mapping_generation":2,"mapping_id":"00000000-0000-4000-8000-000000000008"},"state_id":2,"state":"observation"} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400101,"type_name":"Network Activity: Open","time":1794000000478,"severity_id":3,"severity":"Medium","status_id":2,"status":"Failure","message":"Transparent TCP denied before relay: endpoint example.com:443 is not allowed by any policy","status_detail":"transparent_tcp_policy_denied","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000009"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000009"},"dst_endpoint":{"domain":"example.com","ip":"198.18.0.3","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"actor":{"process":{"name":"/usr/bin/curl","pid":0,"cmd_line":"/dev/null"}},"action_id":2,"action":"Denied","disposition_id":2,"disposition":"Blocked","is_src_dst_assignment_known":true} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400101,"type_name":"Network Activity: Open","time":1794000000797,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"CONNECT_L7 allowed httpbin.org:443","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000010"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000010"},"src_endpoint":{"ip":"0.0.0.0","port":0},"dst_endpoint":{"domain":"httpbin.org","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"actor":{"process":{"name":"/usr/local/bin/python3.12","pid":0,"cmd_line":"-","parent_process":{"name":"-","pid":0}}},"firewall_rule":{"name":"httpbin_org","type":"opa"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","is_src_dst_assignment_known":true} +{"class_uid":4002,"class_name":"HTTP Activity","category_uid":4,"category_name":"Network Activity","activity_id":99,"activity_name":"Other","type_uid":400299,"type_name":"HTTP Activity: Other","time":1794000000950,"severity_id":1,"severity":"Informational","message":"L7_REQUEST allow GET httpbin.org:443/get reason=","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000011"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000011"},"http_request":{"http_method":"GET","url":{"scheme":"https","hostname":"httpbin.org","path":"/get","port":443}},"dst_endpoint":{"domain":"httpbin.org","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"firewall_rule":{"name":"httpbin_org","type":"l7"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","observation_point_id":2} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400101,"type_name":"Network Activity: Open","time":1794000001378,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"CONNECT_L7 allowed httpbin.org:443","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000012"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000012"},"src_endpoint":{"ip":"0.0.0.0","port":0},"dst_endpoint":{"domain":"httpbin.org","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"actor":{"process":{"name":"/usr/local/bin/python3.12","pid":0,"cmd_line":"-","parent_process":{"name":"-","pid":0}}},"firewall_rule":{"name":"httpbin_org","type":"opa"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","is_src_dst_assignment_known":true} +{"class_uid":4002,"class_name":"HTTP Activity","category_uid":4,"category_name":"Network Activity","activity_id":99,"activity_name":"Other","type_uid":400299,"type_name":"HTTP Activity: Other","time":1794000001533,"severity_id":3,"severity":"Medium","message":"L7_REQUEST deny POST httpbin.org:443/post reason=POST /post not permitted by policy","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000013"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000013"},"http_request":{"http_method":"POST","url":{"scheme":"https","hostname":"httpbin.org","path":"/post","port":443}},"dst_endpoint":{"domain":"httpbin.org","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"firewall_rule":{"name":"httpbin_org","type":"l7"},"action_id":2,"action":"Denied","disposition_id":2,"disposition":"Blocked","observation_point_id":2} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400101,"type_name":"Network Activity: Open","time":1794000001674,"severity_id":1,"severity":"Informational","status_id":1,"status":"Success","message":"CONNECT_L7 allowed api.github.com:443","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000014"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000014"},"src_endpoint":{"ip":"0.0.0.0","port":0},"dst_endpoint":{"domain":"api.github.com","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"actor":{"process":{"name":"/usr/local/bin/python3.12","pid":0,"cmd_line":"-","parent_process":{"name":"-","pid":0}}},"firewall_rule":{"name":"api_github_com","type":"opa"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","is_src_dst_assignment_known":true} +{"class_uid":4002,"class_name":"HTTP Activity","category_uid":4,"category_name":"Network Activity","activity_id":99,"activity_name":"Other","type_uid":400299,"type_name":"HTTP Activity: Other","time":1794000001683,"severity_id":1,"severity":"Informational","message":"L7_REQUEST allow GET api.github.com:443/zen reason=","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000015"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000015"},"http_request":{"http_method":"GET","url":{"scheme":"https","hostname":"api.github.com","path":"/zen","port":443}},"dst_endpoint":{"domain":"api.github.com","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"firewall_rule":{"name":"api_github_com","type":"l7"},"action_id":1,"action":"Allowed","disposition_id":1,"disposition":"Allowed","observation_point_id":2} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":5,"activity_name":"Refuse","type_uid":400105,"type_name":"Network Activity: Refuse","time":1794000001788,"severity_id":3,"severity":"Medium","status_id":2,"status":"Failure","message":"Policy DNS refused a name that is not eligible in the active policy","status_detail":"policy_dns_ineligible","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000016"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000016"},"dst_endpoint":{"domain":"pypi.org"},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"action_id":2,"action":"Denied","disposition_id":2,"disposition":"Blocked","is_src_dst_assignment_known":true} +{"class_uid":4001,"class_name":"Network Activity","category_uid":4,"category_name":"Network Activity","activity_id":1,"activity_name":"Open","type_uid":400101,"type_name":"Network Activity: Open","time":1794000001789,"severity_id":3,"severity":"Medium","status_id":2,"status":"Failure","message":"Transparent TCP denied before relay: endpoint pypi.org:443 is not allowed by any policy","status_detail":"transparent_tcp_policy_denied","metadata":{"version":"1.8.0","product":{"name":"OpenShell Sandbox Supervisor","vendor_name":"OpenShell","version":"0.1.7"},"profiles":["security_control","network_proxy","container","host"],"uid":"00000000-0000-4000-8000-000000000017"},"device":{"hostname":"sandbox","type_id":99,"type":"Sandbox","os":{"name":"Linux","type_id":200,"type":"Linux"}},"container":{"name":"fixture","uid":"00000000-0000-4000-8000-000000000017"},"dst_endpoint":{"domain":"pypi.org","ip":"198.18.0.6","port":443},"proxy_endpoint":{"ip":"127.0.0.1","port":3128},"actor":{"process":{"name":"/usr/local/bin/python3.12","pid":0,"cmd_line":""}},"action_id":2,"action":"Denied","disposition_id":2,"disposition":"Blocked","is_src_dst_assignment_known":true} diff --git a/tests/fixtures/ocsf-1.8.0-app/app.py b/tests/fixtures/ocsf-1.8.0-app/app.py new file mode 100644 index 0000000..2f4be8f --- /dev/null +++ b/tests/fixtures/ocsf-1.8.0-app/app.py @@ -0,0 +1,32 @@ +import subprocess +import urllib.request + + +def github_zen(): + # @openshell egress api.github.com:443 reason="allowed host" access=read-only + return urllib.request.urlopen("https://api.github.com/zen").read() + + +def httpbin_get(): + # @openshell egress httpbin.org:443 reason="L7 path rule" allow=GET:/get + return urllib.request.urlopen("https://httpbin.org/get").read() + + +def httpbin_post(): + # @openshell ignore kind=net reason="host is declared above; the L7 rule denies this request" + return urllib.request.urlopen("https://httpbin.org/post", data=b"x").read() + + +def curl_icanhazip(): + # @openshell egress icanhazip.com:443 reason="rule bound to curl only" access=read-only bin=/usr/bin/curl + return subprocess.run(["curl", "-sS", "https://icanhazip.com"], check=True) + + +def example_com(): + # Deliberately unannotated: the sandbox blocks it. + return subprocess.run(["curl", "-sS", "https://example.com"], check=True) + + +def todos(): + # @openshell egress jsonplaceholder.typicode.com:443 reason="never called in the captured run" allow=GET:/todos/1 + return urllib.request.urlopen("https://jsonplaceholder.typicode.com/todos/1").read() diff --git a/tests/fixtures/ocsf-1.8.0-app/openshell-annotate.toml b/tests/fixtures/ocsf-1.8.0-app/openshell-annotate.toml new file mode 100644 index 0000000..6cb918a --- /dev/null +++ b/tests/fixtures/ocsf-1.8.0-app/openshell-annotate.toml @@ -0,0 +1,3 @@ +# Mirrors the playground sandbox that produced tests/fixtures/logs/ocsf-1.8.0.jsonl (OpenShell v0.1.7). +[languages] +python = "/usr/local/bin/python3.12" diff --git a/tests/golden/diff_logs_ocsf_1_8_0_plain.txt b/tests/golden/diff_logs_ocsf_1_8_0_plain.txt new file mode 100644 index 0000000..a761077 --- /dev/null +++ b/tests/golden/diff_logs_ocsf_1_8_0_plain.txt @@ -0,0 +1,42 @@ +diff-logs 10 events: 3 denied, 7 allowed + +Missing directives (2) + +missing egress: example.com:443 x1 /usr/bin/curl + --> app.py:27 + | +26 | # Deliberately unannotated: the sandbox blocks it. + + | # @openshell egress example.com:443 reason="observed in sandbox log: /usr/bin/curl (confirm it is needed)" bin=/usr/bin/curl +27 | return subprocess.run(["curl", "-sS", "https://example.com"], check=True) + | + = why: no directive covers this host:port + +missing egress: pypi.org:443 x1 /usr/local/bin/python3.12 + = why: no directive covers this host:port + = where: no source line mentions this host; `--write` appends it to openshell/observed-egress.sh + = add: @openshell egress pypi.org:443 reason="observed in sandbox log: /usr/local/bin/python3.12 (confirm it is needed)" bin=/usr/local/bin/python3.12 + +L7 rules too narrow (1) + +l7 allow: httpbin.org:443 x1 + --> app.py:11 + | +10 | def httpbin_get(): + + | # @openshell egress httpbin.org:443 reason="observed L7 deny: POST /post (confirm it is needed)" allow="POST:/post" bin=/usr/local/bin/python3.12 +11 | # @openshell egress httpbin.org:443 reason="L7 path rule" allow=GET:/get + | + = why: method/path not permitted by the rules at app.py:11 + +Stale directives (1) + +stale: jsonplaceholder.typicode.com:443 /usr/local/bin/python3.12 + --> app.py:31 + | +31 | # @openshell egress jsonplaceholder.typicode.com:443 reason="never called in the captured run" allow=GET:/... + | + = note: never matched in these logs (advisory: logs are lossy, remove only after a run that exercised + this feature) + +3 suggestions (1 stale directive) +next: `openshell-annotate diff-logs ocsf.jsonl --write` inserts 3 directives (review, then regenerate the policy) +note: logs are best-effort and lossy; absence of an event is not proof. Filesystem denials are not logged by OpenShell 0.1.7 (#4270).