Skip to content

feat(observability): correlate HTTP enforcement with traces and OCSF - #5214

Draft
afourniernv wants to merge 3 commits into
NVIDIA:mainfrom
afourniernv:codex/relay-state-01-correlation-primitives
Draft

afourniernv wants to merge 3 commits into
NVIDIA:mainfrom
afourniernv:codex/relay-state-01-correlation-primitives

Conversation

@afourniernv

@afourniernv afourniernv commented Nov 3, 2026 •

Copy link
Copy Markdown

Summary

Connect an inspected HTTP request to its OpenShell policy span, OCSF record and response receipt. This replaces the primitive-only scope of this draft with the combined HTTP core, built on merged #4789.

Related Issue

Part of #5210. Keep the broader issue open for the remaining correlation layers.

Changes

  • Accept bounded W3C context as untrusted correlation data. Share an OpenShell-generated request ID with middleware context, OCSF metadata.correlation_uid and the protected X-OpenShell-Request-ID response header.
  • Add an openshell.http.request root and policy-evaluation child. Emit one primary HTTP Activity record when response headers are accepted, with a fallback for earlier failure or cancellation.
  • Reuse feat(ocsf): correlate audit events with sampled OpenTelemetry traces #4789's native OCSF trace profile, sampled log context and legacy deny spans. Avoid duplicate deny spans on inspected HTTP paths.

No new gateway RPC, protobuf field or Relay dependency. The receipt is not authorization or proof of complete delivery; L4 and uninspected passthrough traffic do not provide it. Middleware, credentials, revisions, MCP and terminal delivery remain separate layers, not part of this diff.

Testing

  • HTTP-core mise run pre-commit, including strict workspace and standalone clippy.
  • HTTP-core network suite: 1,623 passed, two existing ignored tests, no added skips.
  • Retained context-validation, receipt-integrity, single-record and upstream classification coverage.
  • Fresh cumulative Hermes/Relay validation: 13 workflows, 1,552 spans and 433 joined OCSF records, including protected synthetic APIs, authenticated GitHub, denials, mutation, policy reload, incomplete delivery and collector rejection. Native model/tool spans and receipt marks retain their original parents. This validates the cumulative prototype, not this core in isolation.
  • The cumulative stack's 1,684 network, 134 middleware, 68 OTel, 188 OCSF and 84 relay tests passed. The canonical mise run test rerun passed with four test threads. An initial unchanged VM cleanup fixture flaked; its isolated reruns and all 274 VM tests passed in the final run. Full mise run ci is not claimed.

Checklist

  • Conventional Commits.
  • DCO sign-offs preserved, including the review-history merge.
  • Crate and published correlation documentation updated.

The review-history merge preserves the old draft branch without rewriting it. Its file tree is identical to the HTTP core, directly based on merged main.

Signed-off-by: Alex Fournier <afournier@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Nov 3, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@sftimeless

Copy link
Copy Markdown

Hey, thanks for working on this.

The separation between correlation context and authorization identity is important.

I've been testing Keel as an external pre-execution authorization service through OpenShell's Supervisor Middleware, and this connects directly to an issue we encountered during our v0.1.3 qualification.

In that experiment, the adapter could associate RequestContext.request_id with a signed Keel permit, but the corresponding supervisor OCSF event did not carry that identifier. We documented the ALLOW/DENY examples in #4557.

I see this PR introduces OcsfEvent::set_correlation_uid and the OpenTelemetry correlation helpers, while leaving live HTTP enforcement and middleware integration for subsequent work.

For that next integration step, would the intended approach be to propagate the supervisor-generated RequestContext.request_id into metadata.correlation_uid on the actual middleware enforcement events, as proposed in #4557?

That would let an external authorization provider join:

  • Its signed authorization decision and permit ID
  • The middleware request ID
  • OpenShell's observed enforcement result

It would also be useful to preserve that identifier across request and response evaluation, including denials and middleware failures.

I'm not suggesting that correlation alone proves exact-request binding or downstream effects. Those remain separate guarantees.

Happy to help validate the eventual runtime integration against our existing sanitized test cases if helpful.

… record

Signed-off-by: Alex Fournier <afournier@nvidia.com>
Preserve the prior primitive-only review history while adopting the tested HTTP core built on merged NVIDIA#4789.

Signed-off-by: Alex Fournier <afournier@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Nov 6, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@afourniernv afourniernv changed the title feat(observability): add enforcement correlation primitives feat(observability): correlate HTTP enforcement with traces and OCSF Nov 6, 2026
@krishicks

Copy link
Copy Markdown
Collaborator

Written by Claude Code, reviewed by @krishicks

A question about span volume. Every inspected request gets openshell.http.request and openshell.policy.evaluate, and the queued layers add more INFO children. Supervisors use the SDK's default parentbased_always_on sampler, because OTEL_TRACES_SAMPLER doesn't reach them, and an unsampled workload traceparent can't suppress these spans. So every inspected request is exported. Inspected denials also move from supervisor.egress.deny, which #4789 bounded with per-destination and process-wide budgets, to request spans with no bound.

We see supervisor traces as a tool for latency and errors, sampled like any other service, rather than a full record of every request. OCSF already provides that record, and request rates belong in metrics. Sampling for supervisors is tracked in #5362, and supervisor metrics in #5364. In the meantime, we'd like these spans not to assume they're always exported. In particular, could you confirm that the request ID join through metadata.correlation_uid and the response header works with no sampled span? Also, when supervisor.egress.deny gives way to request spans, the request spans should stay inside whatever bound #4789 provides until sampling exists.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants