sx-gitea Phase 2: access — acl-backed permissions, collaborators, teams, auth-gated routes (TDD, 194/194)
lib/gitea/access.sx: repo role groups (admin>write>read) as acl facts saturated by the datalog engine; user-owner => admin; collaborators (per-repo role, upsert); org teams (one role, 'all' or scoped repo list); org-admin?; visible-repos; create-allowed?; bearer tokens in kv. Facts derived from forge state, acl db cached in the forge handle and rebuilt only when facts change. lib/gitea/web.sx: every repo route now requires read (404 hides private repos); repo create needs owner/org-admin, delete + collaborator API need admin (401 no credentials / 403 not allowed); index + /api/repos list only visible repos; PUT/DELETE collab endpoints. tests/access.sx (103) + repo suite updated for gating (91). Fixed a web.sx corruption from the known sx_find_all/sx_replace_node path mismatch by rewriting via sx_write_file; suite timeout 300->600s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
; lib/gitea/tests/repo.sx — Phase 1: forge core (owners, repo CRUD, git
|
||||
; wiring, ref/tree navigation) and the dream browse views + JSON API.
|
||||
; Mutating API calls authenticate as alice (Phase 2 gates them).
|
||||
|
||||
(define gitea-repo-pass 0)
|
||||
(define gitea-repo-fail 0)
|
||||
@@ -116,7 +117,7 @@
|
||||
(gitea/repos gt-forge)
|
||||
(list "alice/proj"))
|
||||
|
||||
(gitea/repo-create! gt-forge "acme" "proj" {:visibility "private"})
|
||||
(gitea/repo-create! gt-forge "acme" "proj" {})
|
||||
|
||||
(gitea-repo-test
|
||||
"same name under two owners"
|
||||
@@ -126,10 +127,6 @@
|
||||
"repos-for alice"
|
||||
(gitea/repos-for gt-forge "alice")
|
||||
(list "proj"))
|
||||
(gitea-repo-test
|
||||
"private visibility stored"
|
||||
(get (gitea/repo-get gt-forge "acme" "proj") :visibility)
|
||||
"private")
|
||||
(gitea-repo-test
|
||||
"repo-update! description"
|
||||
(begin
|
||||
@@ -145,6 +142,12 @@
|
||||
(gitea/repo-update! gt-forge "alice" "nope" (fn (r) r))
|
||||
nil)
|
||||
|
||||
(gitea/repo-create! gt-forge "alice" "hidden" {:visibility "private"})
|
||||
(gitea-repo-test
|
||||
"private visibility stored"
|
||||
(get (gitea/repo-get gt-forge "alice" "hidden") :visibility)
|
||||
"private")
|
||||
|
||||
; ── git store wiring ─────────────────────────────────────────────────
|
||||
|
||||
(define gt-grepo (gitea/repo-git gt-forge "alice" "proj"))
|
||||
@@ -241,12 +244,15 @@
|
||||
(define
|
||||
gt-get
|
||||
(fn (target) (gt-app (dream-request "GET" target {} ""))))
|
||||
|
||||
(gitea/token-create! gt-forge "alice" "tok-alice")
|
||||
(define gt-auth {:authorization "Bearer tok-alice"})
|
||||
(define
|
||||
gt-post
|
||||
(fn (target body) (gt-app (dream-request "POST" target {} body))))
|
||||
gt-posta
|
||||
(fn (target body) (gt-app (dream-request "POST" target gt-auth body))))
|
||||
(define
|
||||
gt-del
|
||||
(fn (target) (gt-app (dream-request "DELETE" target {} ""))))
|
||||
gt-dela
|
||||
(fn (target) (gt-app (dream-request "DELETE" target gt-auth ""))))
|
||||
|
||||
(gitea-repo-test "GET / status" (dream-status (gt-get "/")) 200)
|
||||
(gitea-repo-test
|
||||
@@ -376,16 +382,16 @@
|
||||
(dream-status (gt-get "/alice/proj/commit/zzz"))
|
||||
404)
|
||||
|
||||
; ── json api ─────────────────────────────────────────────────────────
|
||||
; ── json api (as alice) ──────────────────────────────────────────────
|
||||
|
||||
(gitea-repo-test
|
||||
"api repos json"
|
||||
"api repos json (anon: public only)"
|
||||
(dream-json-parse (dream-resp-body (gt-get "/api/repos")))
|
||||
(list "acme/proj" "alice/proj"))
|
||||
|
||||
(gitea-repo-test
|
||||
"api create 201"
|
||||
(dream-status (gt-post "/api/repos" (dream-json-encode {:name "web" :owner "alice"})))
|
||||
(dream-status (gt-posta "/api/repos" (dream-json-encode {:name "web" :owner "alice"})))
|
||||
201)
|
||||
(gitea-repo-test
|
||||
"api create persisted"
|
||||
@@ -393,19 +399,19 @@
|
||||
true)
|
||||
(gitea-repo-test
|
||||
"api create duplicate 409"
|
||||
(dream-status (gt-post "/api/repos" (dream-json-encode {:name "web" :owner "alice"})))
|
||||
(dream-status (gt-posta "/api/repos" (dream-json-encode {:name "web" :owner "alice"})))
|
||||
409)
|
||||
(gitea-repo-test
|
||||
"api create unknown owner 400"
|
||||
(dream-status (gt-post "/api/repos" (dream-json-encode {:name "web" :owner "zeb"})))
|
||||
(dream-status (gt-posta "/api/repos" (dream-json-encode {:name "web" :owner "zeb"})))
|
||||
400)
|
||||
(gitea-repo-test
|
||||
"api create bad name 400"
|
||||
(dream-status (gt-post "/api/repos" (dream-json-encode {:name "b d" :owner "alice"})))
|
||||
(dream-status (gt-posta "/api/repos" (dream-json-encode {:name "b d" :owner "alice"})))
|
||||
400)
|
||||
(gitea-repo-test
|
||||
"api delete 200"
|
||||
(dream-status (gt-del "/api/repos/alice/web"))
|
||||
(dream-status (gt-dela "/api/repos/alice/web"))
|
||||
200)
|
||||
(gitea-repo-test
|
||||
"api delete gone"
|
||||
@@ -413,7 +419,7 @@
|
||||
false)
|
||||
(gitea-repo-test
|
||||
"api delete missing 404"
|
||||
(dream-status (gt-del "/api/repos/alice/web"))
|
||||
(dream-status (gt-dela "/api/repos/alice/web"))
|
||||
404)
|
||||
|
||||
; ── delete purges the git namespace ──────────────────────────────────
|
||||
@@ -445,4 +451,4 @@
|
||||
(gitea-repo-test
|
||||
"other repos survive delete"
|
||||
(gitea/repos gt-forge)
|
||||
(list "acme/proj" "alice/proj"))
|
||||
(list "acme/proj" "alice/hidden" "alice/proj"))
|
||||
|
||||
Reference in New Issue
Block a user