Step 10b: capability-based sandboxing

Capability primitives promoted from mcp_tree.ml to sx_primitives.ml:
- with-capabilities — push cap set, eval body, restore on exit/error
- current-capabilities — returns active capability list (nil = unrestricted)
- has-capability? — check if capability granted (true when unrestricted)
- require-capability! — raise if capability missing
- capability-restricted? — check if any restrictions active

Infrastructure: _cek_call_ref in sx_types.ml (forward ref pattern)
allows primitives to invoke the CEK evaluator without dependency cycles.

10 new tests: unrestricted defaults, scoping, nesting, restore-on-exit.
2693 total tests, 0 regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 23:51:25 +00:00
parent 6e216038ba
commit 5df21fca36
4 changed files with 125 additions and 0 deletions

View File

@@ -508,3 +508,72 @@
(do
(assert= (vector 1 2 3) (vector 1 2 3))
(assert (not (= (vector 1 2) (vector 1 3)))))))
(defsuite
"capabilities"
(deftest
"current-capabilities nil when unrestricted"
(assert= nil (current-capabilities)))
(deftest
"has-capability? true when unrestricted"
(assert (has-capability? "anything")))
(deftest
"with-capabilities sets capabilities"
(with-capabilities
(list "io-fetch" "io-query")
(fn () (assert= (list "io-fetch" "io-query") (current-capabilities)))))
(deftest
"has-capability? checks active set"
(with-capabilities
(list "io-fetch")
(fn
()
(do
(assert (has-capability? "io-fetch"))
(assert (not (has-capability? "io-query")))))))
(deftest
"require-capability! passes when granted"
(with-capabilities
(list "io-fetch")
(fn () (require-capability! "io-fetch"))))
(deftest
"require-capability! raises when missing"
(with-capabilities
(list "io-fetch")
(fn () (assert (not (has-capability? "io-query"))))))
(deftest
"capabilities restore after body"
(do
(with-capabilities (list "io-fetch") (fn () nil))
(assert= nil (current-capabilities))))
(deftest
"capabilities restore after nested call"
(do
(with-capabilities
(list "io-fetch")
(fn
()
(with-capabilities
(list "io-query")
(fn () (assert (has-capability? "io-query"))))))
(assert= nil (current-capabilities))))
(deftest
"nested capabilities narrow scope"
(with-capabilities
(list "io-fetch" "io-query")
(fn
()
(with-capabilities
(list "io-fetch")
(fn
()
(do
(assert (has-capability? "io-fetch"))
(assert (not (has-capability? "io-query")))))))))
(deftest
"capability-restricted? predicate"
(do
(assert (not (capability-restricted?)))
(with-capabilities
(list "pure")
(fn () (assert (capability-restricted?)))))))