Artifact c99f123086c5e966cd1e852c14d238465e86762587ea2a3d57ea1366015cd117:
- File
internal/oltp/caps_test.go
— part of check-in
[f70144e381]
at
2026-08-22 16:54:36
on branch trunk
— quarry users pull: import a remote fossil's users and caps
Fetch (admin-credentialed) then import: unknown logins are created with their fossil §6.3 credential and the project code it needs, existing accounts keep their own password, categories land as categories. An unmentioned category keeps quarry's default rather than blanking into a lockout. (user: dmestas, size: 7662) [annotate] [blame] [check-ins using] [more...]
package oltp import "testing" // The expansion rules are fossil's, kept exactly (RFC 0004 §3): every // visitor holds the nobody set; logging in adds anonymous; u inherits // the reader category, v the developer category — and v does NOT imply // u; a grants everything except s, x, y; s grants everything. func TestEffectiveCapsExpansion(t *testing.T) { db := testDB(t) // Anonymous visitor: stock nobody. eff := db.EffectiveCaps("", "r") for _, c := range []string{"g", "j", "o", "r", "z"} { if !eff.HasAny(c) { t.Fatalf("visitor lacks nobody cap %q (eff=%q)", c, eff) } } if eff.HasAny("h") || eff.HasAny("i") { t.Fatalf("visitor holds login-gated caps: %q", eff) } // A signed-in account with no explicit caps: nobody + anonymous. if err := db.AddAccount("plain", "pw12345678", false); err != nil { t.Fatal(err) } eff = db.EffectiveCaps("plain", "r") for _, c := range []string{"h", "m", "n", "c", "o"} { if !eff.HasAny(c) { t.Fatalf("signed-in lacks %q (eff=%q)", c, eff) } } if eff.HasAny("k") || eff.HasAny("i") { t.Fatalf("signed-in holds category caps unasked: %q", eff) } // u inherits the reader category (stock kptw). if err := db.SetCaps("plain", "r", "u"); err != nil { t.Fatal(err) } eff = db.EffectiveCaps("plain", "r") if !eff.HasAny("k") || !eff.HasAny("w") { t.Fatalf("u did not expand to reader caps: %q", eff) } if eff.HasAny("i") { t.Fatalf("u granted developer caps: %q", eff) } // v inherits developer (stock ei) — and NOT reader. Fossil's trap, // kept deliberately. if err := db.SetCaps("plain", "r", "v"); err != nil { t.Fatal(err) } eff = db.EffectiveCaps("plain", "r") if !eff.HasAny("i") || !eff.HasAny("e") { t.Fatalf("v did not expand to developer caps: %q", eff) } if eff.HasAny("k") || eff.HasAny("w") { t.Fatalf("v implied u — fossil's rule broken: %q", eff) } } func TestAdminAndSetupRules(t *testing.T) { db := testDB(t) if err := db.AddAccount("boss", "pw12345678", false); err != nil { t.Fatal(err) } if err := db.SetCaps("boss", "r", "a"); err != nil { t.Fatal(err) } eff := db.EffectiveCaps("boss", "r") for _, c := range []string{"i", "k", "w", "5", "e"} { if !eff.HasAny(c) { t.Fatalf("a does not grant %q", c) } } for _, c := range []string{"s", "x", "y"} { if eff.HasAny(c) { t.Fatalf("a granted excluded cap %q", c) } } // s grants everything, including the exclusions. if err := db.SetCaps("boss", "r", "s"); err != nil { t.Fatal(err) } eff = db.EffectiveCaps("boss", "r") for _, c := range []string{"a", "s", "x", "y", "i", "5"} { if !eff.HasAny(c) { t.Fatalf("s does not grant %q", c) } } // The site-admin account flag IS s, everywhere. if err := db.AddAccount("root", "pw12345678", true); err != nil { t.Fatal(err) } if !db.EffectiveCaps("root", "anything").HasAny("s") { t.Fatal("site admin lacks s") } } func TestPerRepoCategoryOverride(t *testing.T) { db := testDB(t) // A repo "taken private": nobody and anonymous blanked (fossil's // Security-Audit action). Visitors hold nothing. if err := db.SetCategoryCaps("priv", "nobody", ""); err != nil { t.Fatal(err) } if err := db.SetCategoryCaps("priv", "anonymous", ""); err != nil { t.Fatal(err) } if eff := db.EffectiveCaps("", "priv"); eff.HasAny("gjorz2h") { t.Fatalf("private repo leaks visitor caps: %q", eff) } // Another repo on the same forge keeps stock defaults. if eff := db.EffectiveCaps("", "open"); !eff.HasAny("o") { t.Fatalf("open repo lost stock nobody: %q", eff) } } func TestRoleRowsTranslateToCaps(t *testing.T) { db := testDB(t) must := func(err error) { t.Helper() if err != nil { t.Fatal(err) } } must(db.AddAccount("r1", "pw12345678", false)) must(db.AddAccount("w1", "pw12345678", false)) must(db.AddAccount("a1", "pw12345678", false)) must(db.Grant("r1", "repo", Read)) must(db.Grant("w1", "repo", Write)) must(db.Grant("a1", "repo", RepoAdmin)) must(db.MigrateRolesToCaps()) if eff := db.EffectiveCaps("r1", "repo"); !eff.HasAny("k") || eff.HasAny("i") { t.Fatalf("read→u wrong: %q", eff) } if eff := db.EffectiveCaps("w1", "repo"); !eff.HasAny("k") || !eff.HasAny("i") { t.Fatalf("write→uv wrong: %q", eff) } if eff := db.EffectiveCaps("a1", "repo"); !eff.HasAny("5") || eff.HasAny("s") { t.Fatalf("admin→a wrong: %q", eff) } // Migration is idempotent and never clobbers explicit caps. must(db.SetCaps("r1", "repo", "uv")) must(db.MigrateRolesToCaps()) if eff := db.EffectiveCaps("r1", "repo"); !eff.HasAny("i") { t.Fatalf("migration clobbered explicit caps: %q", eff) } } func TestPurgeRepoSweepsCaps(t *testing.T) { db := testDB(t) if err := db.AddAccount("u1", "pw12345678", false); err != nil { t.Fatal(err) } if err := db.SetCaps("u1", "gone", "uv"); err != nil { t.Fatal(err) } if err := db.SetCategoryCaps("gone", "nobody", ""); err != nil { t.Fatal(err) } if err := db.PurgeRepo("gone"); err != nil { t.Fatal(err) } if caps, _ := db.CapsOf("u1", "gone"); caps != "" { t.Fatalf("caps survived purge: %q", caps) } if eff := db.EffectiveCaps("", "gone"); !eff.HasAny("o") { t.Fatal("category override survived purge (stock should return)") } } // Importing a peer's users creates unknown logins with their fossil // credential, replaces caps on THIS repo, and never takes over an // account quarry already has. func TestImportUsers(t *testing.T) { db := testDB(t) // A login quarry already knows, with its own password. if err := db.AddAccount("alice", "quarrypw123", false); err != nil { t.Fatal(err) } before, _ := db.AccountByName("alice") _ = before created, updated, err := db.ImportUsers("repo", "code123", []ImportedUser{ {Login: "alice", Caps: "ei", PWHash: "peerhashalice"}, {Login: "bob", Caps: "kptw", PWHash: "peerhashbob", Info: "Bob"}, {Login: "nobody", Caps: "gjor"}, }) if err != nil { t.Fatal(err) } if created != 1 { t.Fatalf("created = %d, want 1 (bob)", created) } if updated != 2 { t.Fatalf("updated = %d, want 2 (alice, nobody)", updated) } // Caps arrived verbatim for both. if c, _ := db.CapsOf("alice", "repo"); c != "ei" { t.Fatalf("alice's caps = %q", c) } if c, _ := db.CapsOf("bob", "repo"); c != "kptw" { t.Fatalf("bob's caps = %q", c) } // The category row landed as a category, not as an account. if db.CategoryCaps("repo", "nobody") != "gjor" { t.Fatalf("nobody category = %q", db.CategoryCaps("repo", "nobody")) } if _, found := db.AccountByName("nobody"); found { t.Fatal("a category became an account") } // alice keeps HER credential: an import is not a takeover. if !VerifyPassword(mustPWHash(t, db, "alice"), "quarrypw123") { t.Fatal("import overwrote an existing account's password") } if _, _, ok := db.LegacyCredential("alice"); ok { t.Fatal("an existing account gained an imported credential") } // bob can be verified against the peer's hash until he sets one. h, code, ok := db.LegacyCredential("bob") if !ok || h != "peerhashbob" || code != "code123" { t.Fatalf("bob's legacy credential = %q/%q ok=%v", h, code, ok) } if err := db.ClearLegacyCredential("bob"); err != nil { t.Fatal(err) } if _, _, ok := db.LegacyCredential("bob"); ok { t.Fatal("legacy credential survived being cleared") } // A category the peer never mentioned keeps quarry's stock default. if db.CategoryCaps("repo", "reader") != StockReader { t.Fatal("an unmentioned category was blanked") } } func mustPWHash(t *testing.T, db *DB, name string) string { t.Helper() var h string if err := db.db.QueryRow(`SELECT pwhash FROM account WHERE name = ?`, name).Scan(&h); err != nil { t.Fatal(err) } return h }