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:
546
lib/gitea/tests/access.sx
Normal file
546
lib/gitea/tests/access.sx
Normal file
@@ -0,0 +1,546 @@
|
||||
; lib/gitea/tests/access.sx — Phase 2: visibility, collaborators, org
|
||||
; teams, acl-backed can?, tokens, and auth-gated web routes.
|
||||
|
||||
(define gitea-access-pass 0)
|
||||
(define gitea-access-fail 0)
|
||||
(define gitea-access-fails (list))
|
||||
|
||||
(define
|
||||
gitea-access-test
|
||||
(fn
|
||||
(name actual expected)
|
||||
(if
|
||||
(= actual expected)
|
||||
(set! gitea-access-pass (+ gitea-access-pass 1))
|
||||
(begin
|
||||
(set! gitea-access-fail (+ gitea-access-fail 1))
|
||||
(set!
|
||||
gitea-access-fails
|
||||
(append gitea-access-fails (list {:name name :expected (inspect expected) :actual (inspect actual)})))))))
|
||||
|
||||
(define ga-db (persist/mem-backend))
|
||||
(define ga-forge (gitea/forge ga-db))
|
||||
|
||||
(gitea/user-create! ga-forge "alice")
|
||||
(gitea/user-create! ga-forge "bob")
|
||||
(gitea/user-create! ga-forge "carol")
|
||||
(gitea/user-create! ga-forge "eve")
|
||||
(gitea/org-create! ga-forge "acme")
|
||||
|
||||
(gitea/repo-create! ga-forge "alice" "pub" {})
|
||||
(gitea/repo-create! ga-forge "alice" "sec" {:visibility "private"})
|
||||
(gitea/repo-create! ga-forge "acme" "app" {:visibility "private"})
|
||||
|
||||
; ── can? basics ──────────────────────────────────────────────────────
|
||||
|
||||
(gitea-access-test
|
||||
"public read anon"
|
||||
(gitea/can? ga-forge nil "read" "alice" "pub")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"public read any user"
|
||||
(gitea/can? ga-forge "eve" "read" "alice" "pub")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"public write anon denied"
|
||||
(gitea/can? ga-forge nil "write" "alice" "pub")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"public write stranger denied"
|
||||
(gitea/can? ga-forge "eve" "write" "alice" "pub")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"private read anon denied"
|
||||
(gitea/can? ga-forge nil "read" "alice" "sec")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"private read stranger denied"
|
||||
(gitea/can? ga-forge "eve" "read" "alice" "sec")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"owner reads private"
|
||||
(gitea/can? ga-forge "alice" "read" "alice" "sec")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"owner writes private"
|
||||
(gitea/can? ga-forge "alice" "write" "alice" "sec")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"owner admins private"
|
||||
(gitea/can? ga-forge "alice" "admin" "alice" "sec")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"owner admins public"
|
||||
(gitea/can? ga-forge "alice" "admin" "alice" "pub")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"missing repo denied"
|
||||
(gitea/can? ga-forge "alice" "read" "alice" "nope")
|
||||
false)
|
||||
|
||||
; ── collaborators ────────────────────────────────────────────────────
|
||||
|
||||
(gitea-access-test
|
||||
"collab-add! bob write"
|
||||
(get (gitea/collab-add! ga-forge "alice" "sec" "bob" "write") :role)
|
||||
"write")
|
||||
(gitea-access-test
|
||||
"collab-role"
|
||||
(gitea/collab-role ga-forge "alice" "sec" "bob")
|
||||
"write")
|
||||
(gitea-access-test
|
||||
"collabs list"
|
||||
(gitea/collabs ga-forge "alice" "sec")
|
||||
(list "bob"))
|
||||
(gitea-access-test
|
||||
"write collab reads"
|
||||
(gitea/can? ga-forge "bob" "read" "alice" "sec")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"write collab writes"
|
||||
(gitea/can? ga-forge "bob" "write" "alice" "sec")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"write collab cannot admin"
|
||||
(gitea/can? ga-forge "bob" "admin" "alice" "sec")
|
||||
false)
|
||||
|
||||
(gitea/collab-add! ga-forge "alice" "sec" "carol" "read")
|
||||
(gitea-access-test
|
||||
"read collab reads"
|
||||
(gitea/can? ga-forge "carol" "read" "alice" "sec")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"read collab cannot write"
|
||||
(gitea/can? ga-forge "carol" "write" "alice" "sec")
|
||||
false)
|
||||
|
||||
(gitea/collab-add! ga-forge "alice" "sec" "carol" "write")
|
||||
(gitea-access-test
|
||||
"collab upsert to write"
|
||||
(gitea/can? ga-forge "carol" "write" "alice" "sec")
|
||||
true)
|
||||
|
||||
(gitea-access-test
|
||||
"collab-add! missing repo"
|
||||
(get (gitea/collab-add! ga-forge "alice" "nope" "bob" "read") :error)
|
||||
"no-such-repo")
|
||||
(gitea-access-test
|
||||
"collab-add! missing user"
|
||||
(get (gitea/collab-add! ga-forge "alice" "sec" "zeb" "read") :error)
|
||||
"no-such-user")
|
||||
(gitea-access-test
|
||||
"collab-add! bad role"
|
||||
(get (gitea/collab-add! ga-forge "alice" "sec" "bob" "boss") :error)
|
||||
"invalid-role")
|
||||
|
||||
(gitea-access-test
|
||||
"collab-remove! carol"
|
||||
(gitea/collab-remove! ga-forge "alice" "sec" "carol")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"removed collab cannot write"
|
||||
(gitea/can? ga-forge "carol" "write" "alice" "sec")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"removed collab cannot read private"
|
||||
(gitea/can? ga-forge "carol" "read" "alice" "sec")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"collab-remove! again false"
|
||||
(gitea/collab-remove! ga-forge "alice" "sec" "carol")
|
||||
false)
|
||||
|
||||
; ── teams ────────────────────────────────────────────────────────────
|
||||
|
||||
(gitea-access-test
|
||||
"team-create! owners"
|
||||
(get (gitea/team-create! ga-forge "acme" "owners" "admin") :role)
|
||||
"admin")
|
||||
(gitea-access-test
|
||||
"team-create! duplicate conflicts"
|
||||
(get (gitea/team-create! ga-forge "acme" "owners" "read") :conflict)
|
||||
true)
|
||||
(gitea-access-test
|
||||
"team-create! on user rejected"
|
||||
(get (gitea/team-create! ga-forge "alice" "crew" "read") :error)
|
||||
"no-such-org")
|
||||
(gitea-access-test
|
||||
"team-create! bad role"
|
||||
(get (gitea/team-create! ga-forge "acme" "crew" "boss") :error)
|
||||
"invalid-role")
|
||||
|
||||
(gitea/team-add-member! ga-forge "acme" "owners" "alice")
|
||||
(gitea-access-test
|
||||
"team-members"
|
||||
(gitea/team-members ga-forge "acme" "owners")
|
||||
(list "alice"))
|
||||
(gitea-access-test
|
||||
"team-add-member! missing team"
|
||||
(get (gitea/team-add-member! ga-forge "acme" "ghosts" "bob") :error)
|
||||
"no-such-team")
|
||||
(gitea-access-test
|
||||
"team-add-member! missing user"
|
||||
(get (gitea/team-add-member! ga-forge "acme" "owners" "zeb") :error)
|
||||
"no-such-user")
|
||||
|
||||
(gitea-access-test
|
||||
"owners member admins org repo"
|
||||
(gitea/can? ga-forge "alice" "admin" "acme" "app")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"owners member reads org repo"
|
||||
(gitea/can? ga-forge "alice" "read" "acme" "app")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"non-member cannot read org private"
|
||||
(gitea/can? ga-forge "bob" "read" "acme" "app")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"org-admin? alice"
|
||||
(gitea/org-admin? ga-forge "acme" "alice")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"org-admin? bob"
|
||||
(gitea/org-admin? ga-forge "acme" "bob")
|
||||
false)
|
||||
|
||||
(gitea/team-create! ga-forge "acme" "devs" "write")
|
||||
(gitea/team-set-repos! ga-forge "acme" "devs" (list "app"))
|
||||
(gitea/team-add-member! ga-forge "acme" "devs" "bob")
|
||||
|
||||
(gitea-access-test
|
||||
"devs member writes covered repo"
|
||||
(gitea/can? ga-forge "bob" "write" "acme" "app")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"devs member cannot admin"
|
||||
(gitea/can? ga-forge "bob" "admin" "acme" "app")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"org-admin? devs member"
|
||||
(gitea/org-admin? ga-forge "acme" "bob")
|
||||
false)
|
||||
|
||||
(gitea/repo-create! ga-forge "acme" "site" {:visibility "private"})
|
||||
|
||||
(gitea-access-test
|
||||
"scoped team does not cover new repo"
|
||||
(gitea/can? ga-forge "bob" "read" "acme" "site")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"all-repos team covers new repo"
|
||||
(gitea/can? ga-forge "alice" "admin" "acme" "site")
|
||||
true)
|
||||
|
||||
(gitea/team-set-repos! ga-forge "acme" "devs" "all")
|
||||
(gitea-access-test
|
||||
"widened team covers site"
|
||||
(gitea/can? ga-forge "bob" "write" "acme" "site")
|
||||
true)
|
||||
(gitea/team-set-repos! ga-forge "acme" "devs" (list "app"))
|
||||
(gitea-access-test
|
||||
"re-narrowed team loses site"
|
||||
(gitea/can? ga-forge "bob" "write" "acme" "site")
|
||||
false)
|
||||
|
||||
(gitea/team-remove-member! ga-forge "acme" "devs" "bob")
|
||||
(gitea-access-test
|
||||
"removed member loses access"
|
||||
(gitea/can? ga-forge "bob" "write" "acme" "app")
|
||||
false)
|
||||
(gitea/team-add-member! ga-forge "acme" "devs" "bob")
|
||||
|
||||
(gitea-access-test
|
||||
"team-delete!"
|
||||
(gitea/team-delete! ga-forge "acme" "devs")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"deleted team gone"
|
||||
(gitea/teams ga-forge "acme")
|
||||
(list "owners"))
|
||||
(gitea-access-test
|
||||
"deleted team members purged"
|
||||
(gitea/team-members ga-forge "acme" "devs")
|
||||
(list))
|
||||
(gitea-access-test
|
||||
"deleted team access revoked"
|
||||
(gitea/can? ga-forge "bob" "write" "acme" "app")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"team-delete! missing false"
|
||||
(gitea/team-delete! ga-forge "acme" "devs")
|
||||
false)
|
||||
|
||||
; ── visibility ───────────────────────────────────────────────────────
|
||||
|
||||
(gitea-access-test
|
||||
"visible anon"
|
||||
(gitea/visible-repos ga-forge nil)
|
||||
(list "alice/pub"))
|
||||
(gitea-access-test
|
||||
"visible eve"
|
||||
(gitea/visible-repos ga-forge "eve")
|
||||
(list "alice/pub"))
|
||||
(gitea-access-test
|
||||
"visible bob (collab on sec)"
|
||||
(gitea/visible-repos ga-forge "bob")
|
||||
(list "alice/pub" "alice/sec"))
|
||||
(gitea-access-test
|
||||
"visible alice (owner + org admin)"
|
||||
(gitea/visible-repos ga-forge "alice")
|
||||
(list "acme/app" "acme/site" "alice/pub" "alice/sec"))
|
||||
|
||||
; ── create permission ────────────────────────────────────────────────
|
||||
|
||||
(gitea-access-test
|
||||
"create under self"
|
||||
(gitea/create-allowed? ga-forge "alice" "alice")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"create under other user"
|
||||
(gitea/create-allowed? ga-forge "bob" "alice")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"create anon"
|
||||
(gitea/create-allowed? ga-forge nil "alice")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"org admin creates in org"
|
||||
(gitea/create-allowed? ga-forge "alice" "acme")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"non-admin cannot create in org"
|
||||
(gitea/create-allowed? ga-forge "eve" "acme")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"create under unknown owner"
|
||||
(gitea/create-allowed? ga-forge "alice" "zeb")
|
||||
false)
|
||||
|
||||
; ── tokens ───────────────────────────────────────────────────────────
|
||||
|
||||
(gitea/token-create! ga-forge "alice" "tok-a")
|
||||
(gitea/token-create! ga-forge "bob" "tok-b")
|
||||
(gitea/token-create! ga-forge "eve" "tok-e")
|
||||
|
||||
(gitea-access-test
|
||||
"token resolves user"
|
||||
(gitea/token-user ga-forge "tok-a")
|
||||
"alice")
|
||||
(gitea-access-test "unknown token" (gitea/token-user ga-forge "tok-zzz") nil)
|
||||
(gitea-access-test
|
||||
"token for unknown user"
|
||||
(get (gitea/token-create! ga-forge "zeb" "tok-z") :error)
|
||||
"no-such-user")
|
||||
(gitea/token-create! ga-forge "carol" "tok-c")
|
||||
(gitea/token-revoke! ga-forge "tok-c")
|
||||
(gitea-access-test "revoked token" (gitea/token-user ga-forge "tok-c") nil)
|
||||
|
||||
; ── auth-gated web routes ────────────────────────────────────────────
|
||||
|
||||
; content in the private repo, to browse
|
||||
(define ga-gsec (gitea/repo-git ga-forge "alice" "sec"))
|
||||
(git/add! ga-gsec "secret.txt" "s3cret\n")
|
||||
(git/commit! ga-gsec {:message "hide" :time 1 :author "alice"})
|
||||
|
||||
(define ga-app (gitea/app ga-forge))
|
||||
(define ga-hdr (fn (tok) (if (nil? tok) {} {:authorization (str "Bearer " tok)})))
|
||||
(define
|
||||
ga-get
|
||||
(fn (target tok) (ga-app (dream-request "GET" target (ga-hdr tok) ""))))
|
||||
(define
|
||||
ga-post
|
||||
(fn
|
||||
(target tok body)
|
||||
(ga-app (dream-request "POST" target (ga-hdr tok) body))))
|
||||
(define
|
||||
ga-put
|
||||
(fn
|
||||
(target tok body)
|
||||
(ga-app (dream-request "PUT" target (ga-hdr tok) body))))
|
||||
(define
|
||||
ga-del
|
||||
(fn
|
||||
(target tok)
|
||||
(ga-app (dream-request "DELETE" target (ga-hdr tok) ""))))
|
||||
|
||||
(gitea-access-test
|
||||
"web: public repo anon"
|
||||
(dream-status (ga-get "/alice/pub" nil))
|
||||
200)
|
||||
(gitea-access-test
|
||||
"web: private repo anon hidden"
|
||||
(dream-status (ga-get "/alice/sec" nil))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: private repo stranger hidden"
|
||||
(dream-status (ga-get "/alice/sec" "tok-e"))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: private repo collab"
|
||||
(dream-status (ga-get "/alice/sec" "tok-b"))
|
||||
200)
|
||||
(gitea-access-test
|
||||
"web: private repo owner"
|
||||
(dream-status (ga-get "/alice/sec" "tok-a"))
|
||||
200)
|
||||
|
||||
(gitea-access-test
|
||||
"web: private tree anon hidden"
|
||||
(dream-status (ga-get "/alice/sec/tree/main" nil))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: private tree collab"
|
||||
(dream-status (ga-get "/alice/sec/tree/main" "tok-b"))
|
||||
200)
|
||||
(gitea-access-test
|
||||
"web: private raw stranger hidden"
|
||||
(dream-status (ga-get "/alice/sec/raw/main/secret.txt" "tok-e"))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: private raw collab exact"
|
||||
(dream-resp-body (ga-get "/alice/sec/raw/main/secret.txt" "tok-b"))
|
||||
"s3cret\n")
|
||||
(gitea-access-test
|
||||
"web: private commits owner"
|
||||
(dream-status (ga-get "/alice/sec/commits/main" "tok-a"))
|
||||
200)
|
||||
|
||||
(gitea-access-test
|
||||
"web: index anon shows public"
|
||||
(contains? (dream-resp-body (ga-get "/" nil)) "alice/pub")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"web: index anon hides private"
|
||||
(contains? (dream-resp-body (ga-get "/" nil)) "alice/sec")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"web: index owner shows private"
|
||||
(contains? (dream-resp-body (ga-get "/" "tok-a")) "alice/sec")
|
||||
true)
|
||||
|
||||
(gitea-access-test
|
||||
"web: api repos anon"
|
||||
(dream-json-parse (dream-resp-body (ga-get "/api/repos" nil)))
|
||||
(list "alice/pub"))
|
||||
(gitea-access-test
|
||||
"web: api repos owner"
|
||||
(dream-json-parse (dream-resp-body (ga-get "/api/repos" "tok-a")))
|
||||
(list "acme/app" "acme/site" "alice/pub" "alice/sec"))
|
||||
|
||||
(gitea-access-test
|
||||
"web: create anon 401"
|
||||
(dream-status (ga-post "/api/repos" nil (dream-json-encode {:name "x" :owner "alice"})))
|
||||
401)
|
||||
(gitea-access-test
|
||||
"web: create for other user 403"
|
||||
(dream-status
|
||||
(ga-post "/api/repos" "tok-b" (dream-json-encode {:name "x" :owner "alice"})))
|
||||
403)
|
||||
(gitea-access-test
|
||||
"web: create own 201"
|
||||
(dream-status
|
||||
(ga-post "/api/repos" "tok-a" (dream-json-encode {:name "x" :owner "alice"})))
|
||||
201)
|
||||
(gitea-access-test
|
||||
"web: org admin create 201"
|
||||
(dream-status
|
||||
(ga-post "/api/repos" "tok-a" (dream-json-encode {:name "tools" :owner "acme"})))
|
||||
201)
|
||||
(gitea-access-test
|
||||
"web: org non-admin create 403"
|
||||
(dream-status
|
||||
(ga-post "/api/repos" "tok-e" (dream-json-encode {:name "z" :owner "acme"})))
|
||||
403)
|
||||
(gitea-access-test
|
||||
"web: create unknown owner 400"
|
||||
(dream-status
|
||||
(ga-post "/api/repos" "tok-a" (dream-json-encode {:name "z" :owner "zeb"})))
|
||||
400)
|
||||
|
||||
(gitea-access-test
|
||||
"web: delete anon public 401"
|
||||
(dream-status (ga-del "/api/repos/alice/x" nil))
|
||||
401)
|
||||
(gitea-access-test
|
||||
"web: delete anon private hidden 404"
|
||||
(dream-status (ga-del "/api/repos/alice/sec" nil))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: delete stranger private hidden 404"
|
||||
(dream-status (ga-del "/api/repos/alice/sec" "tok-e"))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: delete non-admin 403"
|
||||
(dream-status (ga-del "/api/repos/alice/x" "tok-b"))
|
||||
403)
|
||||
(gitea-access-test
|
||||
"web: delete admin 200"
|
||||
(dream-status (ga-del "/api/repos/alice/x" "tok-a"))
|
||||
200)
|
||||
(gitea-access-test
|
||||
"web: deleted repo gone"
|
||||
(dream-status (ga-del "/api/repos/alice/x" "tok-a"))
|
||||
404)
|
||||
|
||||
(gitea-access-test
|
||||
"web: collab put anon 401"
|
||||
(dream-status (ga-put "/api/repos/alice/pub/collab/eve" nil "{}"))
|
||||
401)
|
||||
(gitea-access-test
|
||||
"web: collab put non-admin 403"
|
||||
(dream-status
|
||||
(ga-put
|
||||
"/api/repos/alice/pub/collab/eve"
|
||||
"tok-b"
|
||||
(dream-json-encode {:role "write"})))
|
||||
403)
|
||||
(gitea-access-test
|
||||
"web: collab put on hidden repo 404"
|
||||
(dream-status
|
||||
(ga-put
|
||||
"/api/repos/alice/sec/collab/eve"
|
||||
"tok-e"
|
||||
(dream-json-encode {:role "write"})))
|
||||
404)
|
||||
(gitea-access-test
|
||||
"web: collab put admin 200"
|
||||
(dream-status
|
||||
(ga-put
|
||||
"/api/repos/alice/pub/collab/eve"
|
||||
"tok-a"
|
||||
(dream-json-encode {:role "write"})))
|
||||
200)
|
||||
(gitea-access-test
|
||||
"web: collab granted write"
|
||||
(gitea/can? ga-forge "eve" "write" "alice" "pub")
|
||||
true)
|
||||
(gitea-access-test
|
||||
"web: collab put bad role 400"
|
||||
(dream-status
|
||||
(ga-put
|
||||
"/api/repos/alice/pub/collab/eve"
|
||||
"tok-a"
|
||||
(dream-json-encode {:role "boss"})))
|
||||
400)
|
||||
(gitea-access-test
|
||||
"web: collab put unknown user 400"
|
||||
(dream-status
|
||||
(ga-put
|
||||
"/api/repos/alice/pub/collab/zeb"
|
||||
"tok-a"
|
||||
(dream-json-encode {:role "read"})))
|
||||
400)
|
||||
(gitea-access-test
|
||||
"web: collab delete admin 200"
|
||||
(dream-status (ga-del "/api/repos/alice/pub/collab/eve" "tok-a"))
|
||||
200)
|
||||
(gitea-access-test
|
||||
"web: collab revoked"
|
||||
(gitea/can? ga-forge "eve" "write" "alice" "pub")
|
||||
false)
|
||||
(gitea-access-test
|
||||
"web: collab delete missing 404"
|
||||
(dream-status (ga-del "/api/repos/alice/pub/collab/eve" "tok-a"))
|
||||
404)
|
||||
@@ -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