Artifact a510da6bfa14d92c52448f34f27805192bde5432622136f00d2fb19ec7110965:
- File
internal/web/protectpage_test.go
— part of check-in
[2a68c15ebf]
at
2026-08-26 23:24:05
on branch protect-5
— RFC 0007 phase 5: the matrix, driven through the forge
Every row of the RFC's table, the way a person or a client would do it: the forge's accept through the API as owner and non-owner; a clone's accept pushed through the sync gate, refused whole with the branch named, then admitted for the owner with no reply posted; a stock fossil client's merge refused; branching off trunk and pushing to an unprotected branch admitted; a forged accepted reply recorded as a claim. A branch continued past its merge stays accepted.
Compatibility and disposability as the RFC states them: a clone's artifacts are identical with the row present or absent, and the record renders identically before and after the row, and across the section-11 wipe.
The disabled control with its reason is proved in the web package, where a viewer has an identity — and proving it found the landing page asking MayLand about nobody: the viewer now travels with the read. Three rows are proved elsewhere and named in the file so the matrix reads complete. (user: dmestas, size: 3187) [annotate] [blame] [check-ins using] [more...]
package web import ( "io" "net/http" "net/http/httptest" "strings" "testing" "craftdesign.group/quarry/internal/api" "craftdesign.group/quarry/internal/index" "craftdesign.group/quarry/internal/oltp" "craftdesign.group/quarry/internal/ops" ) type stubCaps struct{ letters string } func (s stubCaps) CapsOf(string, string) CapSet { return s } func (s stubCaps) HasAny(letters string) bool { return strings.ContainsAny(letters, s.letters) } // stubPolicy protects trunk for alice; dan holds `i` and owns nothing. type stubPolicy struct{ owner string } func (p stubPolicy) MayJoin(_, user, branch string) bool { return branch != "trunk" || user == p.owner } func (p stubPolicy) Protections(string) ([]oltp.Protection, error) { return []oltp.Protection{{Branch: "trunk", Owners: []string{p.owner}}}, nil } func protectedLandingServer(t *testing.T, ix *index.Index, owner string) *httptest.Server { t.Helper() r := ops.NewRegistry() if err := api.RegisterAll(r, api.Deps{Version: "v", Repos: api.NewRepos(map[string]*api.Repo{"alpha": {Index: ix}}), Protect: stubPolicy{owner: owner}}); err != nil { t.Fatal(err) } srv := httptest.NewServer(HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "dan"}), WithCaps(stubCaps{letters: "i"})})) t.Cleanup(srv.Close) return srv } func asDan(t *testing.T, srv *httptest.Server, path string) string { t.Helper() req, _ := http.NewRequest("GET", srv.URL+path, nil) req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"}) resp, err := srv.Client().Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() b, _ := io.ReadAll(resp.Body) return string(b) } // RFC 0007 §Testing, "non-owner with i / forge accept / control // disabled". A control that would fail is not offered // (docs/landings.md); one that names why is better than none — and it // says forge policy, never a capability. func TestProtectedTargetDisablesAcceptWithTheReason(t *testing.T) { srv := protectedLandingServer(t, landingIndex(t, false), "alice") html := asDan(t, srv, "/r/alpha/landing/"+strings.Repeat("a1", 6)) if !strings.Contains(html, `disabled title="trunk is protected; owners: alice"`) { t.Fatalf("no disabled control with the reason:\n%.800s", html) } if strings.Contains(html, `formaction="/r/alpha/landing/a1a1a1a1a1a1/accept"`) { t.Error("an enabled accept was drawn for a non-owner") } if !strings.Contains(html, "is protected on this forge") { t.Error("the page does not say this is the forge's policy") } } // ...and for the owner, protection is not the reason for anything. // Whether the control is offered is mergeability's call (unknowable // without a store behind the index, and unknowable must not read as // clean); what this proves is that an owner is never shown the // non-owner's refusal. func TestOwnerIsNotRefused(t *testing.T) { srv := protectedLandingServer(t, landingIndex(t, false), "dan") html := asDan(t, srv, "/r/alpha/landing/"+strings.Repeat("a1", 6)) if strings.Contains(html, "is protected on this forge") || strings.Contains(html, `title="trunk is protected`) { t.Fatalf("the owner is shown the non-owner's reason:\n%.800s", html) } }