@@ -274,6 +274,15 @@ request_denied_for_endpoint(request, endpoint) if {
274274 command_matches (request.command, deny_rule.command)
275275}
276276
277+ # --- L7 deny rule matching: JSON-RPC method + params ---
278+
279+ request_denied_for_endpoint (request, endpoint) if {
280+ some deny_rule
281+ deny_rule := endpoint.deny_rules[_]
282+ deny_rule.rpc_method
283+ jsonrpc_rule_matches (request, deny_rule)
284+ }
285+
277286# --- L7 deny rule matching: GraphQL operation ---
278287
279288request_denied_for_endpoint (request, endpoint) if {
@@ -417,6 +426,15 @@ request_allowed_for_endpoint(request, endpoint) if {
417426 command_matches (request.command, rule.allow.command)
418427}
419428
429+ # --- L7 rule matching: JSON-RPC method ---
430+
431+ request_allowed_for_endpoint (request, endpoint) if {
432+ some rule
433+ rule := endpoint.rules[_]
434+ rule.allow.rpc_method
435+ jsonrpc_rule_matches (request, rule.allow)
436+ }
437+
420438# --- L7 rule matching: GraphQL operation ---
421439
422440request_allowed_for_endpoint (request, endpoint) if {
@@ -638,6 +656,35 @@ query_value_matches(value, matcher) if {
638656 glob.match (any_patterns[i], [], value)
639657}
640658
659+ # JSON-RPC method and params matching. The sandbox flattens object params into
660+ # dot-separated keys before policy evaluation, e.g. arguments.scope.
661+ jsonrpc_rule_matches (request, rule) if {
662+ jsonrpc := object.get (request, " jsonrpc" , {})
663+ method := object.get (jsonrpc, " method" , null )
664+ method != null
665+ glob.match (rule.rpc_method, [], method)
666+ jsonrpc_params_match (jsonrpc, rule)
667+ }
668+
669+ jsonrpc_params_match (jsonrpc, rule) if {
670+ param_rules := object.get (rule, " params" , {})
671+ not jsonrpc_param_mismatch (jsonrpc, param_rules)
672+ }
673+
674+ jsonrpc_param_mismatch (jsonrpc, param_rules) if {
675+ some key
676+ matcher := param_rules[key]
677+ not jsonrpc_param_key_matches (jsonrpc, key, matcher)
678+ }
679+
680+ jsonrpc_param_key_matches (jsonrpc, key, matcher) if {
681+ params := object.get (jsonrpc, " params" , {})
682+ value := object.get (params, key, null )
683+ value != null
684+ is_string (value)
685+ query_value_matches (value, matcher)
686+ }
687+
641688# SQL command matching: "*" matches any; otherwise case-insensitive.
642689command_matches (_, " *" ) if true
643690
0 commit comments