Skip to content

fix(ocsf): HTTP activity shorthand log drops port from URL #808

@johntmyers

Description

@johntmyers

Agent Diagnostic

Loaded skills: openshell-cli, create-github-issue. Discovered while investigating #807 — sandbox logs showed http://172.20.0.1/test for a request that was actually sent to http://172.20.0.1:9876/test. The missing port made it harder to diagnose the 502 (wrong host IP) since the log looked like it was hitting port 80.

Searched all OCSF shorthand formatting code and HTTP activity event emission sites. The port is correctly stored in the OCSF event struct and serialized to JSONL, but the shorthand human-readable formatter drops it.

Description

Actual behavior: Url::to_display_string() in crates/openshell-ocsf/src/objects/http.rs:62-67 formats the URL as {scheme}://{hostname}{path}, ignoring self.port:

pub fn to_display_string(&self) -> String {
    let scheme = self.scheme.as_deref().unwrap_or("https");
    let hostname = self.hostname.as_deref().unwrap_or("unknown");
    let path = self.path.as_deref().unwrap_or("/");
    format!("{scheme}://{hostname}{path}")
}

The shorthand formatter at crates/openshell-ocsf/src/format/shorthand.rs:130-135 calls this method, producing log lines like:

HTTP:GET [INFO] ALLOWED curl(96) -> GET http://host.docker.internal/test [policy:allow_host_docker_internal_9876]

The policy name shows 9876 but the URL does not.

Expected behavior: Non-default ports should appear in the shorthand URL:

HTTP:GET [INFO] ALLOWED curl(96) -> GET http://host.docker.internal:9876/test [policy:allow_host_docker_internal_9876]

Not affected: The OCSF JSONL output correctly includes the port in http_request.url.port. The NetworkActivity shorthand (shorthand.rs:80-93) also correctly renders ports via dst_endpoint.port. Only HttpActivity shorthand is affected.

Proposed Design

Update Url::to_display_string() to include the port when present and non-default for the scheme:

pub fn to_display_string(&self) -> String {
    let scheme = self.scheme.as_deref().unwrap_or("https");
    let hostname = self.hostname.as_deref().unwrap_or("unknown");
    let path = self.path.as_deref().unwrap_or("/");
    let port_suffix = match self.port {
        Some(443) if scheme == "https" => String::new(),
        Some(80) if scheme == "http" => String::new(),
        Some(p) => format!(":{p}"),
        None => String::new(),
    };
    format!("{scheme}://{hostname}{port_suffix}{path}")
}

Update the existing test at http.rs:97-99 and the shorthand test at shorthand.rs:422-448 to cover non-default ports.

Affected Sites

All emit the port correctly — only the display method is wrong:

File Lines Description
crates/openshell-ocsf/src/objects/http.rs 62-67 to_display_string() — bug location
crates/openshell-ocsf/src/format/shorthand.rs 130-135 Shorthand formatter — consumer
crates/openshell-sandbox/src/proxy.rs 2050-2052, 2171, 2231, 2269, 2311, 2351, 2379 Forward proxy emitters — all pass port correctly
crates/openshell-sandbox/src/l7/relay.rs 237 L7 relay emitter — passes port correctly

Related: #807

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:sandboxSandbox runtime and isolation work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions