Agent Diagnostic
Loaded skills: openshell-cli, create-github-issue. Explored credential placeholder resolution in the L7 proxy to verify header-level injection for a user report. While testing with curl -s from inside a sandbox, discovered that policy denials and upstream failures return empty-body HTTP responses, making them indistinguishable from each other (and from "no response" to the user).
Searched all 403/502 response sites in proxy.rs and l7/rest.rs. The L7 inspection path (l7/rest.rs:344-381, send_deny_response()) already returns a rich JSON body:
{"error":"policy_denied","policy":"...","rule":"GET /path","detail":"GET /path not permitted by policy"}
The inference denial path (proxy.rs:1285-1293) also returns a JSON body:
{"error":"connection not allowed by policy"}
But the L4 CONNECT and forward-proxy paths write bare status lines with no body at all.
Description
Actual behavior: 9 denial sites in proxy.rs return HTTP/1.1 403 Forbidden\r\n\r\n (empty body). The 502 at line 2366 returns HTTP/1.1 502 Bad Gateway\r\n\r\n (also empty). With curl -s, the user sees zero output — no way to distinguish "denied by policy" from "upstream unreachable" from "no response."
Empty-body 403 sites in proxy.rs:
- Line 466 — OPA policy denial (CONNECT)
- Line 521 — SSRF: allowed_ips check failed (CONNECT)
- Line 556 — SSRF: invalid allowed_ips in policy (CONNECT)
- Line 597 — SSRF: internal address without allowed_ips (CONNECT)
- Line 2074 — OPA policy denial (forward proxy)
- Line 2202 — L7 policy denial (forward proxy)
- Line 2257 — SSRF: allowed_ips check failed (forward proxy)
- Line 2295 — SSRF: invalid allowed_ips in policy (forward proxy)
- Line 2337 — SSRF: internal IP (forward proxy)
Empty-body 502:
- Line 2366 — upstream TCP connect failed (forward proxy)
Expected behavior: All denial and error responses should include a JSON body consistent with the L7 path, e.g.:
{"error":"policy_denied","detail":"CONNECT api.example.com:443 not permitted by policy"}
{"error":"upstream_unreachable","detail":"connection refused: api.example.com:443"}
This makes proxy errors diagnosable without -v and gives tools/SDKs a machine-readable error to surface.
Proposed Design
Add a helper (or extend the existing respond()) that writes a JSON body with Content-Type: application/json and Content-Length headers. Each site should include an error code and a detail string. Pattern after the existing send_deny_response() in l7/rest.rs.
Suggested error codes:
policy_denied — request blocked by network policy
ssrf_denied — resolved IP failed allowed_ips or internal-address check
upstream_unreachable — TCP connect to upstream failed
upstream_error — upstream returned an error or closed prematurely
Alternatives Considered
- Plain-text body (e.g.,
"not permitted by policy") — simpler but not machine-readable.
- Status code only, rely on logs — current state; insufficient for
curl -s and SDK users.
Agent Diagnostic
Loaded skills:
openshell-cli,create-github-issue. Explored credential placeholder resolution in the L7 proxy to verify header-level injection for a user report. While testing withcurl -sfrom inside a sandbox, discovered that policy denials and upstream failures return empty-body HTTP responses, making them indistinguishable from each other (and from "no response" to the user).Searched all 403/502 response sites in
proxy.rsandl7/rest.rs. The L7 inspection path (l7/rest.rs:344-381,send_deny_response()) already returns a rich JSON body:{"error":"policy_denied","policy":"...","rule":"GET /path","detail":"GET /path not permitted by policy"}The inference denial path (
proxy.rs:1285-1293) also returns a JSON body:{"error":"connection not allowed by policy"}But the L4 CONNECT and forward-proxy paths write bare status lines with no body at all.
Description
Actual behavior: 9 denial sites in
proxy.rsreturnHTTP/1.1 403 Forbidden\r\n\r\n(empty body). The 502 at line 2366 returnsHTTP/1.1 502 Bad Gateway\r\n\r\n(also empty). Withcurl -s, the user sees zero output — no way to distinguish "denied by policy" from "upstream unreachable" from "no response."Empty-body 403 sites in
proxy.rs:Empty-body 502:
Expected behavior: All denial and error responses should include a JSON body consistent with the L7 path, e.g.:
{"error":"policy_denied","detail":"CONNECT api.example.com:443 not permitted by policy"}{"error":"upstream_unreachable","detail":"connection refused: api.example.com:443"}This makes proxy errors diagnosable without
-vand gives tools/SDKs a machine-readable error to surface.Proposed Design
Add a helper (or extend the existing
respond()) that writes a JSON body withContent-Type: application/jsonandContent-Lengthheaders. Each site should include anerrorcode and adetailstring. Pattern after the existingsend_deny_response()inl7/rest.rs.Suggested error codes:
policy_denied— request blocked by network policyssrf_denied— resolved IP failed allowed_ips or internal-address checkupstream_unreachable— TCP connect to upstream failedupstream_error— upstream returned an error or closed prematurelyAlternatives Considered
"not permitted by policy") — simpler but not machine-readable.curl -sand SDK users.