grith proxy test
Dry-run a tool call through all 18 filters and see the decision, the score and every contribution.
grith proxy test '<CALL>'Runs one JSON tool call through the full filter pipeline and prints what would happen. Nothing is executed and nothing is recorded. It is the fastest way to answer "would grith stop this".
Exit codes: 0 allow, 1 queue, 2 deny. That makes it usable as a policy assertion
in a script.
An allow
$ grith proxy test '{"type":"FileRead","path":"/etc/passwd"}'
Proxy Test Result
==================================================
Tool call: FileRead(/etc/passwd)
Score: 2.8
Decision: ALLOW
Reason: Score 2.8 below allow threshold
Eval time: 1.35ms
Thresholds: allow < 3, deny > 8
Filters: 18 active
Filter Breakdown:
. operation-risk 0.0
. path-match 0.0
+ sensitive-path-heuristic 2.8 [warning] read access to sensitive-looking filename
. allowlist 0.0
. argument 0.0
. capability 0.0
. secret-scan 0.0
. command 0.0
. destructive-action 0.0
. egress-policy 0.0
. dlp-gate 0.0
. canary 0.0
. reputation 0.0
. behavioural 0.0
. taint 0.0
. session-containment 0.0
. rate-limit 0.0
. egress-rate 0.0
Exit code: 0 (allow)That is the registration order of all 18 filters. + marks a filter that contributed;
. marks one that ran and scored zero.
A queue
$ grith proxy test '{"type":"ShellExec","command":"curl","args":["https://evil.example.com"]}'
Proxy Test Result
==================================================
Tool call: ShellExec(curl https://evil.example.com)
Score: 4.5
Decision: QUEUE (Medium)
Reason: Score 4.5 in escalation zone
Eval time: 3.07ms
Thresholds: allow < 3, deny > 8
Filters: 18 active
Filter Breakdown:
+ operation-risk 1.0 [notice] Shell execution: curl https://evil.example.com
. path-match 0.0
. sensitive-path-heuristic 0.0
. allowlist 0.0
. argument 0.0
. capability 0.0
. secret-scan 0.0
. command 0.0
. destructive-action 0.0
+ egress-policy 3.5 [warning] Review outbound command token: curl
. dlp-gate 0.0
. canary 0.0
. reputation 0.0
. behavioural 0.0
. taint 0.0
. session-containment 0.0
. rate-limit 0.0
. egress-rate 0.0
Exit code: 1 (queue (medium))Two filters contributed 1.0 and 3.5, the sum landed between the thresholds, and the call would be held for review. All 18 still ran.
A deny, and why it is short
$ grith proxy test '{"type":"FileRead","path":"/home/u/.ssh/id_rsa"}'
Tool call: FileRead(/home/u/.ssh/id_rsa)
Score: 9.0
Decision: DENY
Reason: Access to SSH private key; read access to key/certificate file
Eval time: 0.03ms
Thresholds: allow < 3, deny > 8
Filters: 18 active
Filter Breakdown:
. operation-risk 0.0
+ path-match 5.0 [critical] Access to SSH private key
+ sensitive-path-heuristic 4.0 [error] read access to key/certificate file
. allowlist 0.0
. argument 0.0
. capability 0.0
Exit code: 2 (deny)Six lines under an 18 active header is correct. A deny reached at the end of a phase
returns immediately - the later phases and the meta-rules
never run.
Call shapes
The type field is one of 20 variants:
FileRead · FileWrite · FileAppend · FileDelete · DirList · DirCreate ·
FileRename · FileLink · FileChmod · ShellExec · ProcessSpawn · HttpRequest ·
NetConnect · NetListen · DnsQuery · OwnershipChange · FilesystemMutation ·
CrossProcessAccess · NamespaceOp · DbusMethodCall
The command's own error hint lists only 13 of them. The four shapes that catch people out:
| Type | Required fields |
|---|---|
FileRead, DirList, FileDelete | path |
ShellExec, ProcessSpawn | command and args as an array |
HttpRequest | method and url |
FileWrite | path and content_hash |
A bad payload fails before any filter runs:
$ grith proxy test 'not json'
Error: Invalid JSON: expected ident at line 1 column 2
Expected format: {"type": "FileRead", "path": "/etc/passwd"}See also
- Composite scoring - how the numbers add up
- Filter reference - what each of the 18 looks for