Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 19s
The identity coordinator now owns an audit ledger and a membership registry alongside its token table (started with the ledger) and session registry. login/logout are audited; new ops history/enroll/member_status/member_project surface the audit and membership axes through the one `identity` door. Identity proves who and reports membership; acl still decides permission. Existing api behaviour unchanged. New tests/facade.sx. 177/177. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
98 lines
4.0 KiB
Plaintext
98 lines
4.0 KiB
Plaintext
;; identity/tests/facade.sx — the unified facade: one coordinator wiring
|
|
;; sessions+tokens, the audit ledger, and membership. Exercises the
|
|
;; cross-module integration (login/logout auditing, audit history, member
|
|
;; enrollment + projection) through the single `identity` door.
|
|
|
|
(define id-facade-test-count 0)
|
|
(define id-facade-test-pass 0)
|
|
(define id-facade-test-fails (list))
|
|
|
|
(define
|
|
id-facade-test
|
|
(fn
|
|
(name actual expected)
|
|
(set! id-facade-test-count (+ id-facade-test-count 1))
|
|
(if
|
|
(= actual expected)
|
|
(set! id-facade-test-pass (+ id-facade-test-pass 1))
|
|
(append! id-facade-test-fails {:name name :expected expected :actual actual}))))
|
|
|
|
(define idfc-ev erlang-eval-ast)
|
|
(define idfcnm (fn (v) (get v :name)))
|
|
|
|
(identity-load-all!)
|
|
|
|
;; ── login + logout are audited through the ledger ────────────────
|
|
|
|
(id-facade-test
|
|
"login then logout records login, issue, logout in order"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n {ok, Sid, _Tok} = identity:login(Svc, alice, web, read),\n identity:logout(Svc, Sid),\n case identity:history(Svc, alice) of\n [login, issue, logout] -> ordered;\n Other -> Other\n end"))
|
|
"ordered")
|
|
|
|
(id-facade-test
|
|
"revoking a token is audited"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n {ok, _Sid, Tok} = identity:login(Svc, alice, web, read),\n identity:revoke(Svc, Tok),\n case identity:history(Svc, alice) of\n [login, issue, revoke] -> ordered;\n Other -> Other\n end"))
|
|
"ordered")
|
|
|
|
(id-facade-test
|
|
"history is per-subject"
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n identity:login(Svc, alice, web, read),\n identity:login(Svc, bob, cli, read),\n identity:login(Svc, alice, mobile, read),\n length(identity:history(Svc, alice))")
|
|
4)
|
|
|
|
;; ── membership through the facade ────────────────────────────────
|
|
|
|
(id-facade-test
|
|
"enroll makes the subject an active member"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n identity:enroll(Svc, alice, supporter),\n case identity:member_status(Svc, alice) of\n {ok, St, _} -> St;\n {none} -> none\n end"))
|
|
"active")
|
|
|
|
(id-facade-test
|
|
"enroll keeps the tier"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n identity:enroll(Svc, alice, supporter),\n case identity:member_status(Svc, alice) of\n {ok, _, Tier} -> Tier\n end"))
|
|
"supporter")
|
|
|
|
(id-facade-test
|
|
"an enrolled member projects per-app"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n identity:enroll(Svc, alice, basic),\n case identity:member_project(Svc, alice, market) of\n {member, _, App} -> App;\n {Tag, _} -> Tag\n end"))
|
|
"market")
|
|
|
|
(id-facade-test
|
|
"a non-member projects as non_member"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n case identity:member_project(Svc, stranger, blog) of\n {member, _, _} -> member;\n {Tag, _} -> Tag\n end"))
|
|
"non_member")
|
|
|
|
;; ── the facade still proves identity ─────────────────────────────
|
|
|
|
(id-facade-test
|
|
"verify still returns the subject after login"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n {ok, _Sid, Tok} = identity:login(Svc, alice, web, read),\n case identity:verify(Svc, Tok) of\n {active, Subject, _, _} -> Subject;\n {inactive} -> inactive\n end"))
|
|
"alice")
|
|
|
|
;; ── identity and membership are distinct axes ────────────────────
|
|
|
|
(id-facade-test
|
|
"logging in does not enroll membership"
|
|
(idfcnm
|
|
(idfc-ev
|
|
"Svc = identity:start(),\n identity:login(Svc, alice, web, read),\n case identity:member_status(Svc, alice) of\n {ok, St, _} -> St;\n {none} -> none\n end"))
|
|
"none")
|
|
|
|
(define
|
|
id-facade-test-summary
|
|
(str "facade " id-facade-test-pass "/" id-facade-test-count))
|