You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Expansion happens in `expand_access_presets()` before the Rego engine loads the data. The `rules` and `access` fields are mutually exclusive (validated at startup).
1049
1050
@@ -1055,14 +1056,17 @@ Expansion happens in `expand_access_presets()` before the Rego engine loads the
1055
1056
1056
1057
-`rules` and `access` both specified on same endpoint
1057
1058
-`protocol` specified without `rules` or `access`
1059
+
- unknown `protocol`
1058
1060
-`protocol: sql` with `enforcement: enforce` (SQL parsing not available in v1)
1059
1061
- Empty `rules` array (would deny all traffic)
1062
+
- invalid GraphQL operation types, persisted-query mode, body limit, or rule shape
1060
1063
1061
1064
**Warnings** (logged):
1062
1065
1063
1066
-`tls: terminate` or `tls: passthrough` on any endpoint (deprecated — TLS termination is now automatic; use `tls: skip` to disable)
1064
1067
-`tls: skip` with L7 rules on port 443 (L7 inspection cannot work on encrypted traffic)
1065
1068
- Unknown HTTP method in rules
1069
+
- GraphQL-specific fields on non-GraphQL endpoints
1066
1070
1067
1071
### TLS termination (auto-detect)
1068
1072
@@ -1237,13 +1241,21 @@ Implements `L7Provider` for HTTP/1.1:
1237
1241
1238
1242
-**`looks_like_http()`**: Protocol detection via first-byte peek -- checks for standard HTTP method prefixes (GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS, CONNECT, TRACE).
GraphQL inspection reuses the HTTP parser, then buffers the request body up to `graphql_max_body_bytes` for classification. It supports `GET` and `POST` GraphQL-over-HTTP envelopes, JSON batches, named operations, root fragment expansion, Apollo persisted-query hashes, and saved-query IDs (`id`, `documentId`, `queryId`). The classifier emits `GraphqlRequestInfo` with operation type, optional operation name, root fields, and persisted-query identifiers.
1249
+
1250
+
Hash-only or saved-query-only requests cannot be parsed into operation fields. They are denied unless the endpoint sets `persisted_queries: allow_registered` and provides a trusted `graphql_persisted_queries` entry for the hash or ID. Batch requests are fail-closed: any malformed, denied, or unregistered operation denies the whole HTTP request.
1251
+
1240
1252
### Per-request L7 evaluation
1241
1253
1242
1254
`relay_with_inspection()` in `crates/openshell-sandbox/src/l7/relay.rs` is the main relay loop:
1243
1255
1244
1256
1. Parse one HTTP request from client via the provider. Parser and path-canonicalization failures close the connection and emit a denied OCSF network event with the rejection reason in `status_detail`.
1245
1257
2. Resolve credential placeholders in the request target via `rewrite_target_for_eval()`. OPA receives the redacted path (`[CREDENTIAL]` markers); the resolved path goes only to upstream. If resolution fails, return HTTP 500 and close the connection.
1246
-
3. Build L7 input JSON with `request.method`, the **redacted**`request.path`, `request.query_params`, plus the CONNECT-level context (host, port, binary, ancestors, cmdline)
1258
+
3. Build L7 input JSON with `request.method`, the **redacted**`request.path`, `request.query_params`, optional `request.graphql`, plus the CONNECT-level context (host, port, binary, ancestors, cmdline)
1247
1259
4. Evaluate `data.openshell.sandbox.allow_request` and `data.openshell.sandbox.request_deny_reason`
1248
1260
5. Log the L7 decision (tagged `L7_REQUEST`) using the redacted target — real credential values never appear in logs
1249
1261
6. If allowed (or audit mode): relay request to upstream via `relay_http_request_with_resolver()` (which rewrites all remaining credential placeholders in headers, query parameters, path segments, and Basic auth tokens) and relay the response back to client, then loop
0 commit comments