viettranx
|
a556161d0d
|
feat(hooks/script): goja ES5.1 script handler + deny-all sandbox
Wave 1 Phase 02 — pure runtime + sandbox. Dispatcher wiring, edition gate,
and DB migration land in Phase 03.
Handler:
- internal/hooks/handlers/script.go — ScriptHandler with two-layer semaphore
(global 10 / per-tenant 3), hashicorp/golang-lru v2 program cache (cap 500),
InvalidateHook hook for Phase 03, watchdog goroutine interrupting on ctx
cancel, sanitized error text (strips \n + goja " at <frame>" inline tails)
- internal/hooks/handlers/script_sandbox.go — deny-all/allowlist hardening,
SetMaxCallStackSize(256), prototype-chain nullify running BEFORE deny pass
so Function.prototype.constructor can still be reached
- internal/hooks/handlers/script_runtime.go — LRU compile, JSON round-trip +
deep-freeze event binding, 4KiB truncating stdout capture, strict return
parser enforcing {decision, reason?, updatedInput?}
Types:
- HandlerScript HandlerType = "script"
- DecisionAsk / DecisionDefer reserved (Wave 1 treats as block + warn)
- hooks.ScriptResult + WithScriptResult / ScriptResultFrom ctx helpers for
Phase 03 dispatcher to apply builtin-source UpdatedInput
Tests (go test -race green):
- script_test.go — 12 unit cases (happy/error/timeout/ask/defer/truncate/H1)
- script_sandbox_corpus_test.go — 27 cases: escape primitives (constructor
chain, Reflect, Proxy, Symbol, Promise, __proto__ walk, eval, Function,
Date chain, JSON replacer, toJSON DoS), resource bombs (recursion, loop,
memory, ReDoS), typeof sanity (Reflect/Proxy/Symbol/Promise/GoError/
globalThis/eval/Function undefined), mutation defense (toolInput/rawInput
frozen, Go-side map unchanged)
Deps: github.com/dop251/goja, github.com/hashicorp/golang-lru/v2.
Gates: go vet clean, go test -race clean, go build ./... + sqliteonly clean.
|
2026-04-16 14:17:47 +07:00 |
|