Artifact 80daea3138284d6f1d282f05e9b3695aa9b0efafaeafa32826b43a2cc2a86cce:
- File
internal/harness/caps_test.go
— part of check-in
[31437ec328]
at
2026-08-22 16:11:52
on branch fossil-caps
— caps phases 2-3: ops declare fossil capabilities; router and web gate on them
RFC 0004 §4 table encoded on all ~45 ops; RouterWithCaps refines each Auth floor with EffectiveCaps; web gates and TrustedAuthor read caps with role fallback. Harness proves o/3/a separation end to end. (user: dmestas, size: 2454) [annotate] [blame] [check-ins using]
package harness import ( "io" "net/http" "path/filepath" "strings" "testing" "craftdesign.group/quarry/internal/api" "craftdesign.group/quarry/internal/oltp" "craftdesign.group/quarry/internal/ops" ) // TestCapsGateTheAPI is RFC 0004 §4 enforced end to end: each account // holds exactly one fossil capability letter and may reach exactly the // surfaces that letter opens. The Auth floor lets every authenticated // caller through; the capability check is what decides. func TestCapsGateTheAPI(t *testing.T) { stores := map[string]string{"alpha": buildStore(t, "capseed")} dataDir := t.TempDir() srv := ingestAndServeAuth(t, stores, dataDir, func(repo, user, pass string, need ops.Auth) api.Decision { if user == "" { return api.Denied } return api.Allowed }) // The harness opened this same file; a second handle sees its rows. odb, err := oltp.Open(filepath.Join(dataDir, "oltp.db")) if err != nil { t.Fatal(err) } defer odb.Close() must := func(err error) { t.Helper() if err != nil { t.Fatal(err) } } must(odb.AddAccount("reader", "pw12345678", false)) must(odb.SetCaps("reader", "alpha", "o")) // Read must(odb.AddAccount("forumer", "pw12345678", false)) must(odb.SetCaps("forumer", "alpha", "3")) // WrForum call := func(user, method, path, body string) int { var r io.Reader if body != "" { r = strings.NewReader(body) } req, _ := http.NewRequest(method, srv.URL+path, r) req.SetBasicAuth(user, "pw12345678") if body != "" { req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } resp, err := srv.Client().Do(req) if err != nil { t.Fatal(err) } resp.Body.Close() return resp.StatusCode } // o reads. if got := call("reader", "GET", "/api/v1/r/alpha/timeline", ""); got != http.StatusOK { t.Fatalf("o cannot read the timeline: %d", got) } // o is refused the forum write surface; 3 is not. if got := call("reader", "POST", "/api/v1/r/alpha/forum", "title=x&body=y"); got != http.StatusForbidden { t.Fatalf("o opened the forum write surface: %d", got) } if got := call("forumer", "POST", "/api/v1/r/alpha/forum", "title=from+the+forum+cap&body=hello"); got != http.StatusOK { t.Fatalf("3 cannot write the forum: %d", got) } // 3 does not carry repository administration (a). if got := call("forumer", "POST", "/api/v1/repos", "name=nope&create=1"); got == http.StatusOK { t.Fatal("3 reached repository creation") } }