@@ -17,7 +17,7 @@ The three tiers trade cost for depth, so expensive judgment runs only on what ch
1717
1818| tier | mechanism | latency | runs on |
1919| ---| ---| ---| ---|
20- | ** L1** | deterministic regex rule engine (HCL -configurable) | µs | every event |
20+ | ** L1** | deterministic regex rule engine (ACL -configurable) | µs | every event |
2121| ** L2** | a fast LLM classifier (OpenAI-compatible endpoint) | ~ 100s ms | events L1 escalates |
2222| ** L3** | a deep [ a3s-code] ( https://github.com/AI45Lab/Code ) agent with security skills | seconds–minutes | events L2 escalates |
2323
@@ -103,8 +103,8 @@ before exiting. (No signal-handling dependency.)
103103
104104Ships a conservative built-in rule set (privesc, reverse shells, pipe-to-shell, disk overwrite,
105105credential-file access, secret/injection markers in I/O, cloud-metadata SSRF). Only the unambiguous
106- cases ` block ` ; the rest ` escalate ` to L2/L3 rather than guess. Extend or override with an HCL policy
107- (` A3S_SENTRY_POLICY=policy/rules.hcl ` ):
106+ cases ` block ` ; the rest ` escalate ` to L2/L3 rather than guess. Extend or override with an ACL policy
107+ (` A3S_SENTRY_POLICY=policy/rules.acl ` ):
108108
109109``` hcl
110110rules = [
@@ -113,22 +113,22 @@ rules = [
113113]
114114```
115115
116- First match wins; no match = allow. See [ ` policy/rules.hcl ` ] ( policy/rules.hcl ) .
116+ First match wins; no match = allow. See [ ` policy/rules.acl ` ] ( policy/rules.acl ) .
117117
118118## Dynamic policy & embedding
119119
120120** Hot-reload.** The policy file is watched — rewrite it from any program (a controller, your config
121121system, an operator) and the rules update ** live within ~ 2s, no restart** . A parse error keeps the
122122current rules, so a bad edit never disarms the engine. This is the language-agnostic way to drive
123- sentry dynamically: your logic, in any language, rewrites the HCL .
123+ sentry dynamically: your logic, in any language, rewrites the ACL .
124124
125125** Embed it.** sentry is a library — build the pipeline in-process and apply config changes at runtime:
126126
127127``` rust
128128use a3s_sentry :: {LiveRules , LlmJudge , Pipeline , Severity };
129129use std :: {sync :: Arc , time :: Duration };
130130
131- let rules = Arc :: new (LiveRules :: new (Some (" rules.hcl " . into ()))? ); // hot-reloadable
131+ let rules = Arc :: new (LiveRules :: new (Some (" rules.acl " . into ()))? ); // hot-reloadable
132132let pipeline = Pipeline :: new (rules . clone ()) // L1
133133 . with_l2 (Arc :: new (LlmJudge :: new (" http://llm:18051/v1" , " glm" , None , Duration :: from_secs (10 ))))
134134 . speculate_above (Some (Severity :: High )) // run L2 + L3 in parallel on high-risk
@@ -141,6 +141,42 @@ rules.reload()?; // force-apply config changes now (e.g. on a signal / admin A
141141Every tier is a ` Judge ` trait impl, so you can swap L1/L2/L3 for your own (a different model, an
142142in-house ruleset) and keep the escalation machinery.
143143
144+ ## SDKs (Python · TypeScript)
145+
146+ Drive sentry from your own code — author ACL policy, run the judge, submit events, stream typed
147+ decisions, read metrics — instead of wiring stdin/stdout by hand. Both are dependency-free and mirror
148+ the same model; each is contract-tested against the real binary (an SSRF event round-trips to a
149+ ` block ` , and an SDK-authored ACL rule fires through the daemon's own parser).
150+
151+ - ** Python** — [ ` sdk/python ` ] ( sdk/python ) (` pip install a3s-sentry ` ), async:
152+
153+ ``` python
154+ from a3s_sentry import Sentry, SentryConfig, Event, Policy, Rule, Verdict, Severity, Action
155+
156+ Policy([Rule(" no-netcat" , " ToolExec" , r " (?i) \b ( ncat| netcat) \b " ,
157+ Verdict.BLOCK , Severity.MEDIUM , " netcat" , Action.DENY_EXEC )]).write(" rules.acl" )
158+
159+ async with Sentry(SentryConfig(policy = " rules.acl" , egress_deny = " egress.txt" )) as s:
160+ await s.submit(Event.egress(1 , " 169.254.169.254" , 80 )) # cloud-metadata SSRF
161+ async for audit in s.decisions():
162+ print (audit.decision.verdict, audit.subject); break
163+ ```
164+
165+ - ** TypeScript** — [ ` sdk/typescript ` ] ( sdk/typescript ) (` @a3s-lab/sentry ` ), Node 18+:
166+
167+ ``` ts
168+ import { Sentry , Policy , Event } from " @a3s-lab/sentry" ;
169+
170+ new Policy ([{ name: " no-netcat" , on: " ToolExec" , match: " (?i)\\ b(ncat|netcat)\\ b" ,
171+ verdict: " block" , severity: " medium" , reason: " netcat" , action: " deny-exec" }])
172+ .write (" rules.acl" );
173+
174+ const s = new Sentry ({ policy: " rules.acl" , egressDeny: " egress.txt" });
175+ await s .start ();
176+ await s .submit (Event .egress (1 , " 169.254.169.254" , 80 ));
177+ for await (const audit of s .decisions ()) { console .log (audit .decision .verdict , audit .subject ); break ; }
178+ ```
179+
144180## Speculative parallelism
145181
146182By default the tiers run serially (L2, then L3 only if L2 escalates). Set ` A3S_SENTRY_SPECULATE=high `
@@ -176,7 +212,7 @@ SSH client… key material can be transmitted outbound after being loaded into m
176212
177213| var | effect |
178214| ---| ---|
179- | ` A3S_SENTRY_POLICY ` | extra L1 rules (HCL ); built-ins always apply; ** hot-reloaded** (~ 2s) |
215+ | ` A3S_SENTRY_POLICY ` | extra L1 rules (ACL ); built-ins always apply; ** hot-reloaded** (~ 2s) |
180216| ` A3S_SENTRY_LLM_URL ` | enable L2; OpenAI-compatible chat base URL (` …/v1 ` ) |
181217| ` A3S_SENTRY_LLM_MODEL ` / ` _KEY ` | L2 model name / bearer token |
182218| ` A3S_SENTRY_AGENT_BIN ` | enable L3; the agent command (e.g. ` scripts/l3-agent.mjs ` ) |
0 commit comments