Skip to content

feat(l7): add JSON-RPC policy enforcement#1865

Open
krishicks wants to merge 14 commits into
mainfrom
hicks/push-nvuozlywzuwu
Open

feat(l7): add JSON-RPC policy enforcement#1865
krishicks wants to merge 14 commits into
mainfrom
hicks/push-nvuozlywzuwu

Conversation

@krishicks

@krishicks krishicks commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds JSON-RPC L7 policy enforcement for sandbox proxy traffic. The implementation supports JSON-RPC endpoint configuration, rpc_method matching, scalar object params matching, forward-proxy inspection, CONNECT tunnel inspection, and deny-if-any-denied batch handling.

JSON-RPC enforcement applies to sandbox-to-server HTTP request bodies sent to the configured endpoint. It does not yet enforce policy on server-to-client JSON-RPC messages carried on MCP SSE streams or response bodies. Tool results continue to pass because responses are relayed, not matched against rpc_method.

Related Issue

Closes #1793

Changes

  • Add JSON-RPC as an L7 endpoint protocol in policy parsing, validation, proto conversion, and relay dispatch.
  • Parse JSON-RPC HTTP request bodies into normalized call metadata for single requests and batch arrays.
  • Extend OPA policy input and Rego rules to enforce rpc_method and flattened scalar object params matchers for allow and deny rules.
  • Inspect JSON-RPC request bodies on both forward-proxy and CONNECT tunnel paths before relaying upstream.
  • Evaluate JSON-RPC batch items independently and deny the whole batch when any call is denied.
  • Redact raw JSON-RPC params from L7 logs and record endpoint, RPC methods, params SHA-256 digest, and policy version instead.
  • Document current JSON-RPC directionality limits and params matcher scope.

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated (if applicable)

Additional targeted checks:

  • cargo test -p openshell-sandbox jsonrpc
  • mise run e2e:rust -- --test forward_proxy_jsonrpc_l7

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@copy-pr-bot

copy-pr-bot Bot commented Jun 10, 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.

@github-actions

Copy link
Copy Markdown

@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch 2 times, most recently from 62da29d to 8dc2a54 Compare June 11, 2026 15:20
@krishicks krishicks marked this pull request as ready for review June 12, 2026 16:35
@krishicks krishicks requested review from a team, derekwaynecarr and mrunalp as code owners June 12, 2026 16:35
@johntmyers johntmyers added the gator:in-review Gator is reviewing or awaiting PR review feedback label Jun 13, 2026
@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Status

Validation: This maintainer-authored PR is project-valid because it implements the JSON-RPC/MCP method-level policy work discussed in #1793, with documented v1 scope around sandbox-to-server HTTP request inspection.
Head SHA: 8dc2a54f9b99d2aa297ccfd49c102ea10ce982f4

Review findings:

  • Blocking: crates/openshell-sandbox/src/l7/jsonrpc.rs flattens JSON-RPC params into dot-separated keys without rejecting literal dotted keys or collisions. A request can present arguments.scope as a top-level param while sending a different nested arguments.scope object path to the upstream server, which can bypass params selectors. Please fail closed on ambiguous/dotted param keys or preserve nested params through policy evaluation.
  • Blocking: crates/openshell-sandbox/src/proxy.rs only force-denies GraphQL parse errors in the forward-proxy path. JSON-RPC parse errors are carried in request_info.jsonrpc.error but can still be allowed by generic REST-style method/path rules such as access: full or read-write. Please include JSON-RPC parse errors in the same force-deny path.
  • Warning: forward-proxy JSON-RPC audit logs use generic FORWARD_L7 / l7 output and omit RPC methods, params digest, and policy version, while the CONNECT path has richer JSON-RPC logging.
  • Warning: json_rpc.on_parse_error and json_rpc.batch_policy appear accepted by policy YAML but are not enforced or converted into proto behavior. Please either implement them or reject/remove them from the accepted schema.

Docs: Fern docs were updated for the new policy schema and sandbox policy behavior.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: 8dc2a54f9b99d2aa297ccfd49c102ea10ce982f4

The required independent reviewer pass confirmed the two blocking findings from the previous gator review:

  • JSON-RPC params flattening can create a policy/upstream parser differential through dotted-key collisions.
  • Forward-proxy JSON-RPC parse errors are not force-denied, so invalid JSON-RPC can still be allowed by generic method/path rules.

Additional non-blocking warning from the independent review:

  • parse_jsonrpc_call accepts any object with a string method and does not require "jsonrpc": "2.0". If this endpoint is documented as JSON-RPC 2.0 enforcement, malformed objects should become parse errors and follow the same fail-closed path.

The earlier warnings also still apply: forward-proxy JSON-RPC audit logs are less detailed than CONNECT logs, and json_rpc.on_parse_error / json_rpc.batch_policy are accepted in YAML but not preserved or enforced in runtime policy semantics.

Next state: gator:in-review

@johntmyers johntmyers added the test:e2e Requires end-to-end coverage label Jun 15, 2026
@github-actions

Copy link
Copy Markdown

Label test:e2e applied for 8dc2a54. Open the existing run and click Re-run all jobs to execute with the label set. The run will execute the standard E2E suite after building the required gateway and supervisor images once. The matching required CI gate status on this PR will flip green automatically once the run finishes.

@ddurst-nvidia

ddurst-nvidia commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

I would recommend adding an Action to add a test the functionality from and to modelcontextprotocol/conformance and through OpenShell.

There is an action, but I don't think it's setup by default in a useful way for testing through OpenShell.

There everything-{client,server} stand ins that can be used to validate. If something isn't supported, we can just mark it as unsupported, but it reduces surprises for people using it.

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Maintainer Update

I re-evaluated latest head 8dc2a54f9b99d2aa297ccfd49c102ea10ce982f4 after @ddurst-nvidia's 2026-06-15 comment recommending OpenShell-through-MCP conformance coverage.

Disposition: not resolved yet. There has not been a new commit or author response after the existing gator review feedback, and the maintainer testing recommendation is additional review feedback to address or have explicitly waived by a maintainer before this can advance.

Remaining items:

  • Blocking: JSON-RPC params matching still needs to fail closed on ambiguous dotted keys/collisions or preserve nested params through policy evaluation.
  • Blocking: JSON-RPC parse errors in the forward-proxy path still need the same fail-closed handling as GraphQL parse errors.
  • Review feedback: please address @ddurst-nvidia's recommendation for MCP conformance coverage through OpenShell, or get a maintainer decision that this does not need to block this PR.
  • Non-blocking warnings remain around forward-proxy JSON-RPC audit log detail, accepted-but-unenforced json_rpc.on_parse_error / json_rpc.batch_policy, and JSON-RPC 2.0 validation strictness.

Checks: required branch, Helm, DCO, docs preview, and standard Rust/Python checks are currently passing. OpenShell / E2E is still pending because the labeled E2E run needs execution.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After CI Update

I re-evaluated latest head 8dc2a54f9b99d2aa297ccfd49c102ea10ce982f4 after the labeled E2E run completed.

Disposition: not resolved. The PR still has unresolved review feedback, and the required OpenShell / E2E gate is now failing.

Remaining items:

  • Blocking: JSON-RPC params matching still needs to fail closed on ambiguous dotted keys/collisions or preserve nested params through policy evaluation.
  • Blocking: JSON-RPC parse errors in the forward-proxy path still need the same fail-closed handling as GraphQL parse errors.
  • Review feedback: please address @ddurst-nvidia's recommendation for MCP conformance coverage through OpenShell, or get a maintainer decision that this does not need to block this PR.
  • CI: OpenShell / E2E failed in run https://github.com/NVIDIA/OpenShell/actions/runs/27429202249. The failed jobs are e2e / E2E (rust-podman), e2e / E2E (rust-docker), e2e / E2E (rust-podman-rootless), e2e / E2E (python), and kubernetes-e2e / Kubernetes E2E (Rust smoke). The failed-log download was not available to this gator run, so a maintainer or author should inspect the failed Run tests steps in the Actions UI before deciding whether this is PR-caused or infrastructure-related.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After CI Log Review

I re-evaluated latest head 8dc2a54f9b99d2aa297ccfd49c102ea10ce982f4 after inspecting the failed OpenShell / E2E logs for run https://github.com/NVIDIA/OpenShell/actions/runs/27429202249.

Disposition: not resolved. The PR still has unresolved review feedback, and the failed E2E logs now show an actionable policy regression.

Remaining items:

  • Blocking: JSON-RPC params matching still needs to fail closed on ambiguous dotted keys/collisions or preserve nested params through policy evaluation.
  • Blocking: JSON-RPC parse errors in the forward-proxy path still need the same fail-closed handling as GraphQL parse errors.
  • Review feedback: please address @ddurst-nvidia's recommendation for MCP conformance coverage through OpenShell, or get a maintainer decision that this does not need to block this PR.
  • CI: OpenShell / E2E is failing. The logs show existing non-JSON-RPC L7 paths hitting an OPA evaluation error in crates/openshell-sandbox/data/sandbox-policy.rego: object.get(jsonrpc, "method", null) expects an object. This appears to make the new JSON-RPC matcher unsafe when request.jsonrpc is null/missing, causing GraphQL/HTTP L7 E2E regressions such as failed GraphQL forward/CONNECT tests, Python sandbox policy L7 tests returning status 0, and a Kubernetes smoke L7 bypass test returning 403 instead of 200.

Next state: gator:in-review

@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch 2 times, most recently from e9786e2 to 3516a0b Compare June 15, 2026 19:03
@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Author Update

I re-evaluated latest head 3516a0be911c2717d5789fde4ed6a70ea1a6a9c0 after the new commits addressing the prior JSON-RPC review feedback and adding MCP conformance coverage.

Disposition: partially resolved.

Resolved items:

  • JSON-RPC params matching now fails closed on literal dotted keys / flattened selector ambiguity.
  • Forward-proxy JSON-RPC parse errors now force-deny before generic L7 policy evaluation.
  • Unsupported json_rpc.on_parse_error / json_rpc.batch_policy YAML fields are now rejected instead of silently accepted.
  • MCP conformance coverage has been added, and the direct conformance runner command is wired in the expected client-mode shape.

Remaining items:

  • Blocking: crates/openshell-sandbox/data/sandbox-policy.rego still calls object.get on request.jsonrpc without first proving it is an object. The Rust L7 evaluator serializes non-JSON-RPC requests as "jsonrpc": null, so object.get(request, "jsonrpc", {}) can still return null and then object.get(jsonrpc, "method", null) can hit the same OPA type error seen in the prior E2E logs. Please guard with is_object(jsonrpc) and add a regression test for the actual "jsonrpc": null input shape.
  • Warning: .github/workflows/mcp-conformance.yml still checks out modelcontextprotocol/conformance by mutable tag v0.1.11 and runs npm ci / npm run build in a privileged Docker-socket job with job-level secrets. Please pin the upstream checkout to an immutable commit SHA for that release. Also consider narrowing/removing job-level credentials from the third-party build step.

Checks: current branch and E2E checks are queued or pending for this head, with test:e2e still applied.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Blocked

Gator is blocked because GitHub reports this PR is not mergeable against main (mergeable_state: dirty) at head 3516a0be911c2717d5789fde4ed6a70ea1a6a9c0.

Next action: @krishicks, please rebase or merge main and resolve the conflicts so review and CI monitoring can continue. The earlier JSON-RPC review feedback and the current CI status still need follow-up after the merge conflict is resolved.

@johntmyers johntmyers added gator:blocked Gator is blocked by process or repository gates and removed gator:in-review Gator is reviewing or awaiting PR review feedback labels Jun 15, 2026
@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch from 3516a0b to 6d61408 Compare June 15, 2026 19:25
Comment thread .github/workflows/mcp-conformance.yml Outdated
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
repository: modelcontextprotocol/conformance
ref: v0.1.11

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My last note on this got disappeared from history.

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Author and Reviewer Updates

I re-evaluated latest head 6d614085a82404c0491de0af757e77f234d6631c after the new author commit and @ddurst-nvidia's 2026-06-15 review comment about MCP conformance coverage.

Disposition: still blocked. GitHub still reports this PR is not mergeable against main (mergeable_state: dirty), so review and CI monitoring cannot advance until the merge conflict is resolved.

Remaining items:

  • Blocker: @krishicks, please rebase or merge main and resolve the conflicts.
  • Review feedback: @ddurst-nvidia noted that the workflow still uses the older MCP conformance v0.1.11 release while v0.1.16 is available. Please address that or get a maintainer decision that the older release is intentional.
  • Earlier review feedback should be re-checked after the conflict is resolved and the final diff is stable.

Checks: required branch, Helm, DCO, Rust, Python, and license/header checks are passing for this head. OpenShell / E2E is currently pending with test:e2e applied, including the new MCP conformance job.

Next state: gator:blocked

@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch from 6d61408 to 9af3648 Compare June 15, 2026 20:31
@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Author Update

I re-evaluated latest head 9af36485ca1b8d81799338db56df340075b3b75b after @krishicks force-pushed new commits on 2026-06-15.

Disposition: still blocked. GitHub still reports this PR is not mergeable against main (mergeable_state: dirty), so review and CI monitoring cannot advance until the merge conflict is resolved.

Remaining items:

  • Blocker: @krishicks, please rebase or merge main and resolve the conflicts.
  • Review feedback to re-check after the conflict is resolved: the JSON-RPC Rego matcher still appears to call object.get on request.jsonrpc without proving it is an object, so the prior "jsonrpc": null regression concern may still apply.
  • Maintainer review feedback: the workflow now uses modelcontextprotocol/conformance v0.1.16, but the checkout is still by mutable tag rather than an immutable commit SHA.

Checks: branch, DCO, Rust, Python, license/header, and Helm checks are currently passing or skipped for this head. OpenShell / E2E is still in progress with test:e2e applied, but gator remains blocked on mergeability first.

Next state: gator:blocked

@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch from 9af3648 to 7101a37 Compare June 15, 2026 21:26

##### JSON-RPC Deny Rule (`protocol: json-rpc`)

JSON-RPC deny rules use the same field names as JSON-RPC allow rules, but they appear directly under each `deny_rules` entry instead of under an `allow` wrapper. Deny rules take precedence over allow rules. In a batch request, one denied call denies the full batch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sibling rules and deny_rules feels like an awkward pairing, especially since each rules is scoped by an allow. I'm guessing that the intent is to not complicate the deny > allow precedence as seen in a list, but I feel like that may be better managed as:

rules:
  deny:
    - rpc.method: tools/call
      params:
        name: delete_resource
    - rpc.method: something/else
  allow:
    - rpc.method: tools/call
      params:
        name: init
    - ...

Stating that "deny rules are applied first," is probably less complicated, than splitting at rules & deny_rules.

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Reviewer Update

I re-evaluated latest head 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295 after @ddurst-nvidia's 2026-06-15 review comment on the JSON-RPC policy schema shape.

Disposition: not resolved. There has not been a new commit after the latest gator review pass, and the new schema feedback needs an author response or a maintainer decision before this can advance.

Remaining items:

  • Blocking: crates/openshell-supervisor-network/data/sandbox-policy.rego still needs to guard request.jsonrpc and params with object checks before calling object.get(...), plus a regression test for a JSON-RPC endpoint/rule with request.jsonrpc: null.
  • CI: OpenShell / E2E is failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback: please respond to @ddurst-nvidia's concern that the current sibling rules / deny_rules schema is awkward compared with a grouped allow/deny rule shape, or get a maintainer decision that the current schema should remain.
  • Warning: .github/workflows/mcp-conformance.yml still checks out upstream conformance by mutable tag v0.1.16 in a privileged Docker-socket job with token-bearing environment; please pin the upstream checkout to the full commit SHA for that release and narrow credential exposure where practical.
  • Warning: JSON-RPC params matcher validation should mirror REST query matcher validation for allow and deny rules so invalid matcher objects are rejected predictably.

Next state: gator:in-review

Comment thread proto/sandbox.proto
// GraphQL root field globs. Deny rules match when any selected root field
// matches any configured glob.
repeated string fields = 7;
// JSON-RPC method name (JSON-RPC): exact name or glob, e.g. "tools/call".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

From the perspective of JSON-RPC 2.0, * is a valid method name, any string, not starting with rpc. is available for use.

From the perspective of MCP, there is (currently) an enumerated list of methods per version of the spec.

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Reviewer Update

I re-evaluated latest head 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295 after @ddurst-nvidia's 2026-06-15 review comment on JSON-RPC rpc_method semantics in proto/sandbox.proto.

Disposition: not resolved. There has not been a new commit after the latest gator review pass, and existing review feedback plus failing E2E still block advancement.

Remaining items:

  • Blocking: crates/openshell-supervisor-network/data/sandbox-policy.rego still needs to guard request.jsonrpc and params with object checks before calling object.get(...), plus a regression test for a JSON-RPC endpoint/rule with request.jsonrpc: null.
  • CI: OpenShell / E2E is failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback: please respond to @ddurst-nvidia's concern that the current sibling rules / deny_rules schema is awkward compared with a grouped allow/deny rule shape, or get a maintainer decision that the current schema should remain.
  • Review feedback: please account for @ddurst-nvidia's note that JSON-RPC allows any non-rpc. string method name, while MCP has versioned method sets, so the rpc_method docs/comments should avoid implying * has special JSON-RPC meaning beyond OpenShell policy matching.
  • Warning: .github/workflows/mcp-conformance.yml still checks out upstream conformance by mutable tag v0.1.16 in a privileged Docker-socket job with token-bearing environment; please pin the upstream checkout to the full commit SHA for that release and narrow credential exposure where practical.
  • Warning: JSON-RPC params matcher validation should mirror REST query matcher validation for allow and deny rules so invalid matcher objects are rejected predictably.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295

The required independent reviewer pass re-checked the current head. This PR remains blocked in gator:in-review.

Blocking items:

  • crates/openshell-supervisor-network/data/sandbox-policy.rego still needs to guard request.jsonrpc and JSON-RPC params with object/string checks before calling object.get(...), plus a regression test for a JSON-RPC endpoint/rule evaluated with runtime-shaped "jsonrpc": null. This likely explains the current OpenShell / E2E failures.
  • crates/openshell-supervisor-network/src/l7/relay.rs route-selected L7 handling only parses GraphQL request bodies. If multiple L7 endpoints share a host:port and the selected endpoint is protocol: json-rpc, request_info.jsonrpc remains empty, so JSON-RPC rules do not evaluate the body correctly. Please add JSON-RPC body inspection, parse-error force-deny, and batch evaluation semantics to the route-selected path as well.
  • OpenShell / E2E is still failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback still needs disposition: @ddurst-nvidia's schema-shape comment on sibling rules / deny_rules, and the rpc_method wording concern that * is OpenShell glob matching rather than JSON-RPC method syntax.

Non-blocking warnings:

  • JSON-RPC params matcher validation should reuse the REST query matcher validation shape for allow and deny rules.
  • The MCP conformance checkout should be pinned to an immutable commit SHA, and token-bearing environment should be scoped away from the third-party build step where practical.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295

The required independent reviewer pass re-checked the current head. This PR remains in gator:in-review, but one prior blocker is now corrected: the current code does include JSON-RPC request body inspection, parse-error fail-closed handling, and batch evaluation semantics in the JSON-RPC L7 paths, so that route-selected L7 parsing concern is no longer blocking on code read.

Blocking items:

  • crates/openshell-supervisor-network/data/sandbox-policy.rego should still harden jsonrpc_rule_matches and params matching with is_object / is_string guards before calling object.get(...). Runtime-shaped inputs can carry "jsonrpc": null when metadata is absent, and this should cleanly non-match/default-deny rather than risk an OPA evaluation type error.
  • .github/workflows/mcp-conformance.yml still checks out modelcontextprotocol/conformance by mutable tag v0.1.16 and executes third-party Node code in a privileged Docker-socket job with token-bearing environment at job scope. Please pin the upstream checkout to a full commit SHA, set persist-credentials: false, and scope GitHub/GHCR token environment only to the steps that need it.
  • OpenShell / E2E is still failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback still needs disposition: @ddurst-nvidia's schema-shape comment on sibling rules / deny_rules, and the rpc_method wording concern that * is OpenShell glob matching rather than JSON-RPC method syntax.

Non-blocking warning:

  • JSON-RPC params matcher validation should reuse the REST query matcher validation shape for allow and deny rules so invalid matcher objects are rejected predictably.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295

The required independent reviewer pass re-checked the current head. This PR remains in gator:in-review.

Blocking items:

  • crates/openshell-supervisor-network/src/l7/relay.rs route-selected L7 handling still only inspects GraphQL request bodies. When multiple L7 endpoints share a host:port and the selected path is protocol: json-rpc, the route-selected path builds L7RequestInfo with jsonrpc: None, so JSON-RPC rules are not evaluated against the request body. Please add JSON-RPC body inspection, parse-error force-deny, batch evaluation/log semantics, and a regression test for the route-selected JSON-RPC path.
  • crates/openshell-supervisor-network/data/sandbox-policy.rego should harden jsonrpc_rule_matches and params matching with is_object / is_string guards before calling object.get(...). Runtime-shaped inputs can carry "jsonrpc": null when metadata is absent, and this should cleanly non-match/default-deny rather than risk an OPA evaluation type error.
  • JSON-RPC rpc_method and params policy fields need validation for both allow and deny rules. Please require a non-empty rpc_method for JSON-RPC rules, reject rpc_method / params on other protocols, and reuse the REST query matcher validator for params so invalid matcher objects do not silently fail open.
  • .github/workflows/mcp-conformance.yml still checks out upstream conformance by mutable tag v0.1.16 and executes third-party Node code in a privileged Docker-socket job with token-bearing environment at job scope. Please pin the upstream checkout to a full commit SHA, set persist-credentials: false, and scope registry/GitHub token environment only to the steps that need it.
  • OpenShell / E2E is still failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback still needs disposition: @ddurst-nvidia's schema-shape comment on sibling rules / deny_rules, and the rpc_method wording concern that * is OpenShell glob matching rather than JSON-RPC method syntax.

Non-blocking warnings:

  • The raw YAML OPA loader appears to recognize only internal json_rpc_max_body_bytes, while public docs and policy serialization use nested json_rpc.max_body_bytes. If that loader remains production-facing, please normalize the documented nested shape before L7 config parsing.
  • JSON-RPC method names are untrusted request body fields and are written directly into audit log text; consider escaping or control-character sanitization before joining method names.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295

The required independent reviewer pass re-checked the current head.

Disposition: partially resolved. One previously listed blocker is no longer blocking on code read: the current route-selected JSON-RPC path does include request body inspection, parse-error fail-closed handling, batch evaluation semantics, and denied batch logging.

Blocking items:

  • crates/openshell-supervisor-network/data/sandbox-policy.rego still needs to guard JSON-RPC metadata and params with is_object / is_string checks before object.get(...), plus regression coverage for runtime-shaped "jsonrpc": null input.
  • JSON-RPC rpc_method and params policy fields still need validation for allow and deny rules: require a non-empty rpc_method for JSON-RPC rules, reject rpc_method / params on non-JSON-RPC protocols, and reuse the REST query matcher validation for params.
  • .github/workflows/mcp-conformance.yml still checks out upstream conformance by mutable tag in a privileged Docker-socket job with token-bearing environment at job scope. Please pin the upstream checkout to a full commit SHA, set persist-credentials: false, and scope GitHub/GHCR token environment only to the steps that need it.
  • OpenShell / E2E is still failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback still needs disposition: @ddurst-nvidia's schema-shape comment on sibling rules / deny_rules, and the rpc_method wording concern that * is OpenShell glob matching rather than JSON-RPC method syntax.

Docs: present for the JSON-RPC policy schema and sandbox policy behavior.

Next state: gator:in-review

krishicks added 13 commits June 16, 2026 11:00
L7 HTTP relays previously treated unframed HTTP/1.1 responses without
`Connection: close` as empty bodies. That is correct for ordinary keep-alive
responses, but it drops Server-Sent Events streams because SSE responses often
use `Content-Type: text/event-stream` without `Content-Length` or
`Transfer-Encoding`.

Detect `text/event-stream` responses in the no-framing branch and relay them
until EOF or idle timeout, flushing each chunk as it arrives. This preserves
streaming behavior while keeping the existing empty-body handling for other
unframed keep-alive responses.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Add a Rust e2e test that drives MCP-style JSON-RPC requests through both the
forward proxy and CONNECT tunnel paths.

Cover method rules, params rules, batch handling, and invalid JSON denial
expectations so the JSON-RPC implementation can be built against one failing
scenario.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Add json-rpc as a policy protocol and carry JSON-RPC rule fields through policy
parsing and validation.

Wire the protocol into the L7 dispatcher with a passthrough placeholder so
later commits can add enforcement without changing endpoint recognition.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Move HTTP request body buffering and chunked-body normalization out of the
GraphQL module so other HTTP-carried L7 protocols can inspect request bodies
without depending on GraphQL internals.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Add the JSON-RPC HTTP parser and relay path, extract request methods, and pass
JSON-RPC metadata into L7 policy evaluation.

Wire rpc_method through proto and policy conversion, add Rego matching for
JSON-RPC methods, and inspect forward-proxy JSON-RPC bodies before relaying
upstream.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Carry JSON-RPC max body bytes from policy into runtime endpoint config and use
it on both CONNECT and forward JSON-RPC inspection paths instead of hardcoding
64 KiB.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Add JSON-RPC params matcher maps to proto and YAML policy conversion, including
shared matcher conversion helpers.

Flatten object params into dot-separated keys for policy input and extend Rego
allow and deny matching to filter JSON-RPC calls by params.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Parse JSON-RPC batch arrays into per-call metadata and evaluate each batch item
with the existing method and params policy rules.

Deny the whole batch when any call is denied.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Log JSON-RPC endpoint, RPC methods, params SHA-256 digest, and policy version
without recording raw params. Use <empty> when no params are present.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Document JSON-RPC endpoint configuration, rpc_method and params matchers, batch
denial behavior, current directionality limits, matcher scope, and the current
policy update CLI limitation.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Reject ambiguous JSON-RPC params before policy evaluation by refusing literal
dotted object keys and flattened selector collisions.

Force-deny JSON-RPC parse errors in the forward-proxy path so broad REST-style
access presets cannot bypass malformed JSON-RPC bodies.

Require JSON-RPC 2.0 request objects, use JSON-RPC-specific forward audit logs
with RPC methods, params digest, and policy generation, and reject unsupported
json_rpc YAML knobs instead of accepting unused fields.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Add a reusable MCP conformance workflow that runs upstream client scenarios
through an OpenShell sandbox.

Add a client image, wrapper, policy template, and expected-failures baseline
for expanding MCP conformance coverage.

Remove stale JSON-RPC e2e policy fields that are no longer accepted.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Signed-off-by: Kris Hicks <khicks@nvidia.com>
@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: 7101a37b3dd1fcfa36cb357cf3f5133b6c2fc295

The required independent reviewer pass re-checked the current head. This PR remains in gator:in-review.

Blocking items:

  • crates/openshell-supervisor-network/data/sandbox-policy.rego still needs to guard JSON-RPC metadata and params with is_object / is_string checks before object.get(...), plus regression coverage for runtime-shaped "jsonrpc": null input. The policy path should fail closed or non-match instead of risking an OPA evaluation type error.
  • .github/workflows/mcp-conformance.yml still checks out upstream conformance by mutable tag in a privileged Docker-socket job with token-bearing environment at job scope. Please pin the upstream checkout to a full commit SHA, set persist-credentials: false, and scope GitHub/GHCR token environment only to the steps that need it.
  • JSON-RPC rpc_method and params policy fields still need validation for allow and deny rules: require a non-empty rpc_method for JSON-RPC rules, reject rpc_method / params on non-JSON-RPC protocols, and reuse the REST query matcher validation for params.
  • OpenShell / E2E is still failing in run https://github.com/NVIDIA/OpenShell/actions/runs/27577493131, including MCP conformance and the core E2E jobs.
  • Review feedback still needs disposition: @ddurst-nvidia's schema-shape comment on sibling rules / deny_rules, and the rpc_method wording concern that * is OpenShell glob matching rather than JSON-RPC method syntax.

Non-blocking warning:

  • JSON-RPC method names are untrusted request body fields and are written into audit log text; please sanitize or structured-encode them before joining into single-line logs.

Next state: gator:in-review

MCP elicitation sends JSON-RPC result messages from the client back to the
server without a method field. Treat those as valid response-only POSTs once
the endpoint has already matched so method allowlists keep applying to request
calls.

Also wire the MCP conformance runner into the e2e task and keep known upstream
client gaps in the expected-failure list.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch from 7101a37 to 3730691 Compare June 16, 2026 20:28
@krishicks krishicks requested a review from maxamillion as a code owner June 16, 2026 20:28
@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Author Update

I re-evaluated latest head cda7955ea452f6a6fcbdd5e4150bd82acb7d9e27 after @krishicks pushed the latest JSON-RPC fixes and MCP conformance updates.

Disposition: partially resolved. The prior jsonrpc: null Rego concern is resolved, JSON-RPC parse-error handling and ambiguous params-key handling remain addressed, unsupported json_rpc config fields are rejected, and the MCP conformance source is now pinned to full commit b9041ea41b0188581803459dbae71bc7e02fd995.

Remaining blocking items:

  • crates/openshell-supervisor-network/src/l7/relay.rs: route-selected CONNECT/TLS tunnels still only do protocol-specific body parsing for GraphQL. When multiple L7 endpoints share a host:port, a path-selected protocol: json-rpc endpoint builds L7RequestInfo with jsonrpc: None, so JSON-RPC calls are not evaluated like the single-endpoint JSON-RPC and forward-proxy paths. Please parse JSON-RPC bodies in relay_with_route_selection before policy evaluation and add a shared-host/port regression test.
  • crates/openshell-supervisor-network/src/l7/mod.rs: JSON-RPC rule fields still need validation for allow and deny rules. Please require non-empty rpc_method on JSON-RPC rules, reject rpc_method / params on non-JSON-RPC protocols, and reuse the REST query matcher validation for JSON-RPC params.
  • .github/workflows/e2e-test.yml: the external conformance checkout is pinned by SHA, but the privileged E2E job still exposes MISE_GITHUB_TOKEN and OPENSHELL_REGISTRY_PASSWORD broadly to all steps, including the third-party npm install/build, and the external checkout lacks persist-credentials: false. Please narrow those credentials to only the steps that need them.
  • OpenShell / E2E is still pending for this head with test:e2e applied.

Resolved or non-blocking items:

  • Rego now guards JSON-RPC metadata with object checks and has coverage for REST inputs carrying "jsonrpc": null.
  • Docs are present for protocol: json-rpc, rpc_method, params, batch behavior, directionality limits, and the full-YAML-only policy update path.
  • OpenShell / Branch Checks, DCO, docs preview, Helm, Python, Rust, and build jobs that have completed are currently passing; the required E2E gate remains outstanding.

Next state: gator:in-review

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

PR Review Follow-Up

Head SHA: cda7955ea452f6a6fcbdd5e4150bd82acb7d9e27

The required independent reviewer pass re-checked the current head after the latest JSON-RPC fixes and MCP conformance updates.

Disposition: partially resolved. The earlier route-selected JSON-RPC parsing concern is resolved on code read: path-selected JSON-RPC endpoints now populate JSON-RPC request info before policy evaluation, and the added E2E covers forward proxy plus CONNECT allowed/denied params cases. The PR still remains in gator:in-review.

Blocking items:

  • crates/openshell-supervisor-network/data/sandbox-policy.rego: response-only JSON-RPC POST bodies are allowed without matching any rpc_method / params rule. Because the parser accepts any valid JSON-RPC response object with result or error plus id, sandbox code can send arbitrary JSON to a JSON-RPC endpoint by wrapping it as a response. Please default-deny client-to-server response-only JSON-RPC bodies unless this is explicitly enabled and documented, or correlate them to an outstanding server request.
  • crates/openshell-supervisor-network/src/l7/mod.rs: JSON-RPC rule validation is still incomplete. Please require non-empty rpc_method on JSON-RPC allow and deny rules, reject rpc_method / params on non-JSON-RPC protocols, and reuse the REST query matcher validation shape for JSON-RPC params.
  • .github/workflows/e2e-test.yml: the MCP conformance checkout is now pinned to full commit b9041ea41b0188581803459dbae71bc7e02fd995, but the privileged E2E job still exposes MISE_GITHUB_TOKEN and OPENSHELL_REGISTRY_PASSWORD at job scope while third-party npm ci / npm run build runs, and the external checkout does not set persist-credentials: false. Please scope credentials only to the steps that need them and disable persisted checkout credentials for the external repository.
  • OpenShell / E2E is failing for this head in run https://github.com/NVIDIA/OpenShell/actions/runs/27646052585. The failed jobs visible from REST are e2e / E2E (mcp), e2e / E2E (rust-docker), e2e / E2E (rust-podman), and Core E2E result; REST annotations only expose exit codes, so the author or a maintainer should inspect the job logs before classifying any failures as infrastructure-related.

Docs: present for the JSON-RPC policy schema and sandbox policy behavior on existing Fern pages; no navigation update appears necessary.

Next state: gator:in-review

@rpelevin

Copy link
Copy Markdown

I think the remaining JSON-RPC boundary is response-shaped traffic from the client side.

If the sandbox is enforcing client-to-server JSON-RPC request authority, a client-to-server POST that contains only a JSON-RPC result or error should not bypass rpc_method/params matching. A response frame is not a method call, but when it is emitted by sandboxed code toward the server, it is still outbound data. I would either default-deny response-only frames in that direction, or require an explicit correlation record proving that the server first issued an allowed request with the same id.

The regression shape I would pin:

  • client-to-server request with allowed rpc_method forwards;
  • client-to-server request with denied rpc_method never reaches upstream;
  • client-to-server response-only result/error is denied unless explicitly enabled or correlated to an allowed in-flight server request;
  • orphaned response/progress frames fail closed or produce a typed denial;
  • rpc_method and params are rejected on non-json-rpc endpoints;
  • json-rpc rules require a non-empty rpc_method and reuse the same matcher validation semantics as query selectors.

Separately, I would keep the conformance job credentials scoped to the steps that actually need registry or GitHub auth. The third-party checkout, install, and build path should run with persisted credentials disabled and no broad job-level secrets.

That keeps the parser useful without creating a blind spot where arbitrary outbound payloads can be wrapped as JSON-RPC responses and pass the policy path.

@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Re-check After Reviewer Update

I re-evaluated latest head cda7955ea452f6a6fcbdd5e4150bd82acb7d9e27 after @rpelevin's 2026-06-16 comment about response-shaped client-to-server JSON-RPC traffic.

Disposition: not resolved. The concern is confirmed by the current code and by the required independent reviewer pass. This PR remains in gator:in-review.

Remaining blocking items:

  • crates/openshell-supervisor-network/data/sandbox-policy.rego currently allows response-only JSON-RPC POST bodies on a matching protocol: json-rpc endpoint without matching any rpc_method / params rule. The parser marks method-less result/error objects as has_response, and the relay passes method: null plus has_response: true into OPA with no correlation to an outstanding server request. Please default-deny client-to-server response-only frames unless explicit, documented correlation/enablement is implemented, and add regression coverage for orphaned result/error bodies.
  • JSON-RPC rule validation is still incomplete. Please require non-empty rpc_method on JSON-RPC allow and deny rules, validate params with the same matcher semantics as REST query, reject method / path / query / command / GraphQL fields on protocol: json-rpc, and reject rpc_method / params / json_rpc on non-JSON-RPC endpoints. The independent review also noted that generic HTTP method/path allow rules and access presets can still authorize JSON-RPC endpoints without constraining RPC methods unless Rego and validation gate matchers by protocol.
  • .github/workflows/e2e-test.yml still exposes token-bearing environment at job scope while the MCP conformance suite checks out and runs third-party npm install/build code. Please scope GitHub/GHCR credentials only to the steps that need them, set persist-credentials: false for the external checkout, and run the third-party install/build path without broad token environment.
  • OpenShell / E2E is still failing for this head in run https://github.com/NVIDIA/OpenShell/actions/runs/27646052585.

Resolved or non-blocking items:

  • The MCP conformance source is pinned to full commit b9041ea41b0188581803459dbae71bc7e02fd995.
  • JSON-RPC params flattening rejects literal dotted keys/collisions, and batch calls are evaluated independently so one denied call blocks the full batch.
  • Docs are present for the JSON-RPC policy schema and sandbox behavior, but they should stay aligned with the final response-frame and rule-validation semantics.

Next state: gator:in-review

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

Labels

gator:in-review Gator is reviewing or awaiting PR review feedback test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support method-level governance for MCP tool calls (JSON-RPC) in sandbox policy

4 participants