;; lib/host/tests/middleware.sx — auth (bearer -> principal), ACL gate, and error ;; trapping, composed via host/pipeline. ACL facts: alice may "post" on "feed". (define host-mw-pass 0) (define host-mw-fail 0) (define host-mw-fails (list)) (define host-mw-test (fn (name actual expected) (if (= actual expected) (set! host-mw-pass (+ host-mw-pass 1)) (begin (set! host-mw-fail (+ host-mw-fail 1)) (append! host-mw-fails {:name name :actual actual :expected expected}))))) ;; ── fixtures ─────────────────────────────────────────────────────── (acl/load! (list (acl-grant "alice" "post" "feed"))) (define host-mw-resolve (fn (tok) (if (= tok "good") "alice" nil))) (define host-mw-handler (fn (req) (host/ok-status 201 (host/principal req)))) ;; protected: needs auth + post/feed permission (define host-mw-protected (host/pipeline (list (host/require-auth host-mw-resolve) (host/require-permission "post" (fn (req) "feed"))) host-mw-handler)) ;; protected with an action alice is NOT granted (define host-mw-protected-del (host/pipeline (list (host/require-auth host-mw-resolve) (host/require-permission "delete" (fn (req) "feed"))) host-mw-handler)) (define host-mw-req (fn (auth) (dream-request "POST" "/feed" (if auth {:authorization auth} {}) ""))) ;; ── auth ─────────────────────────────────────────────────────────── (host-mw-test "no token -> 401" (dream-status (host-mw-protected (host-mw-req nil))) 401) (host-mw-test "401 has www-authenticate" (dream-resp-header (host-mw-protected (host-mw-req nil)) "www-authenticate") "Bearer") (host-mw-test "bad token -> 401" (dream-status (host-mw-protected (host-mw-req "Bearer wrong"))) 401) ;; ── authz ────────────────────────────────────────────────────────── (host-mw-test "authed + permitted -> 201" (dream-status (host-mw-protected (host-mw-req "Bearer good"))) 201) (host-mw-test "principal threaded to handler" (contains? (dream-resp-body (host-mw-protected (host-mw-req "Bearer good"))) "\"data\":\"alice\"") true) (host-mw-test "authed but not permitted -> 403" (dream-status (host-mw-protected-del (host-mw-req "Bearer good"))) 403) (host-mw-test "403 envelope" (contains? (dream-resp-body (host-mw-protected-del (host-mw-req "Bearer good"))) "\"error\":\"forbidden\"") true) ;; ── error trapping ───────────────────────────────────────────────── (define host-mw-boom (fn (req) (error "kaboom"))) (host-mw-test "wrap-errors -> 500" (dream-status ((host/wrap-errors host-mw-boom) (host-mw-req nil))) 500) (host-mw-test "500 envelope" (contains? (dream-resp-body ((host/wrap-errors host-mw-boom) (host-mw-req nil))) "\"ok\":false") true) (define host-mw-tests-run! (fn () {:total (+ host-mw-pass host-mw-fail) :passed host-mw-pass :failed host-mw-fail :fails host-mw-fails}))