package handler import ( "bytes" "context" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "strings" "testing" "codeberg.org/VARASYS/ZDDC/zddc/internal/config" "codeberg.org/VARASYS/ZDDC/zddc/internal/zddc" ) // auth_invariants_test.go — behavioral lock-in for the admin/elevation/ // WORM invariants. These tests must pass against the CURRENT code before // the consolidation refactor (single bypass site in InternalDecider) so // the refactor can be validated against a green baseline. // // Each test covers one invariant called out in the security audit. The // names are deliberately verbose — when one fails, the failure message // alone tells you which property got broken. // invariantsFixture sets up a synthetic ZDDC root with: // // - admin@example.com — root super-admin // - alice@example.com — subtree admin of Project-1/working (via per-dir // .zddc admins:) — used to test subtree scope // - bob@example.com — document_controller role member (gets WORM cr // on received/ + issued/ via cascade defaults) // - eve@example.com — non-admin, project_team only (read-only across // the project per defaults) // // Plus one file each in working/, issued/, received/ so we can exercise // reads + writes across the cascade. func invariantsFixture(t *testing.T) (config.Config, string) { t.Helper() root := t.TempDir() mustWriteHelper(t, filepath.Join(root, ".zddc"), "admins:\n - admin@example.com\n"+ "roles:\n"+ " document_controller:\n members: [bob@example.com]\n"+ " project_team:\n members: [\"*@example.com\"]\n") for _, d := range []string{ "Project-1/working/eve@example.com", "Project-1/archive/Acme/received/Acme-0042", "Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test", } { if err := os.MkdirAll(filepath.Join(root, d), 0o755); err != nil { t.Fatalf("mkdir %s: %v", d, err) } } // Subtree-admin grant: alice administers Project-1/working/. mustWriteHelper(t, filepath.Join(root, "Project-1/working/.zddc"), "admins:\n - alice@example.com\n") // Files to act on. mustWriteHelper(t, filepath.Join(root, "Project-1/working/eve@example.com/draft.md"), "# eve's draft\n") mustWriteHelper(t, filepath.Join(root, "Project-1/archive/Acme/received/Acme-0042/Acme-0042_A (RFI) - Test.pdf"), "%PDF-A\n") mustWriteHelper(t, filepath.Join(root, "Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md"), "# issued draft\n") zddc.InvalidateCache(root) return config.Config{ Root: root, EmailHeader: "X-Auth-Request-Email", MaxWriteBytes: 64 * 1024, }, root } // do executes a request with the given email / elevation flag. URL-encoding // is computed from the path so spaces and parens (real ZDDC filenames) // round-trip cleanly. func doReq(cfg config.Config, method, urlPath, email string, elevated bool, body []byte, op string) *httptest.ResponseRecorder { u := &url.URL{Path: urlPath} req := httptest.NewRequest(method, u.RequestURI(), bytes.NewReader(body)) if op != "" { req.Header.Set(headerOp, op) } ctx := context.WithValue(req.Context(), EmailKey, email) ctx = context.WithValue(ctx, ElevatedKey, elevated) req = req.WithContext(ctx) rec := httptest.NewRecorder() ServeFileAPI(cfg, rec, req) return rec } // ── Invariant 1 — Un-elevated admin has no admin authority ──────────────── func TestInvariant_UnelevatedAdminCannotBypassWorm(t *testing.T) { cfg, _ := invariantsFixture(t) target := "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md" rec := doReq(cfg, http.MethodPut, target, "admin@example.com", false, []byte("# mutated\n"), "") if rec.Code != http.StatusForbidden { t.Fatalf("un-elevated admin write succeeded: status=%d body=%s", rec.Code, rec.Body.String()) } } func TestInvariant_UnelevatedAdminCannotEditZddc(t *testing.T) { // .zddc edits route through the decider as ActionAdmin. The bypass // for elevated admins fires only when Principal.Elevated is true. // Exercised at the HTTP boundary: a PUT to .zddc from an un-elevated // super-admin must return Forbidden. cfg, _ := invariantsFixture(t) target := "/Project-1/working/.zddc" rec := doReq(cfg, http.MethodPut, target, "admin@example.com", false, []byte("title: mutated\n"), "") if rec.Code != http.StatusForbidden { t.Fatalf("un-elevated admin .zddc write succeeded: status=%d body=%s", rec.Code, rec.Body.String()) } } func TestInvariant_ElevatedAdminCanEditZddc(t *testing.T) { // Positive control: a super-admin who has elevated CAN write any // .zddc. The decider's IsActiveAdmin short-circuit fires in // AllowActionFromChainP and the file API write proceeds. cfg, _ := invariantsFixture(t) target := "/Project-1/working/.zddc" rec := doReq(cfg, http.MethodPut, target, "admin@example.com", true, []byte("title: elevated edit\n"), "") if rec.Code != http.StatusOK && rec.Code != http.StatusCreated { t.Fatalf("elevated admin .zddc write blocked: status=%d body=%s", rec.Code, rec.Body.String()) } } // ── Invariant 2 — Elevated admin can do everything (positive control) ───── func TestInvariant_ElevatedAdminBypassesWorm(t *testing.T) { cfg, _ := invariantsFixture(t) target := "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md" rec := doReq(cfg, http.MethodPut, target, "admin@example.com", true, []byte("# fix-mis-filed\n"), "") if rec.Code != http.StatusOK && rec.Code != http.StatusCreated { t.Fatalf("elevated admin write blocked: status=%d body=%s", rec.Code, rec.Body.String()) } } // ── Invariant 3 — Subtree admin scope ────────────────────────────────────── func TestInvariant_ElevatedSubtreeAdminWritesInScope(t *testing.T) { cfg, _ := invariantsFixture(t) target := "/Project-1/working/eve@example.com/draft.md" rec := doReq(cfg, http.MethodPut, target, "alice@example.com", true, []byte("# alice override\n"), "") // alice is subtree admin of Project-1/working/ — should override eve's // fenced auto-own and write through. if rec.Code != http.StatusOK && rec.Code != http.StatusCreated { t.Fatalf("elevated subtree admin write in scope blocked: status=%d body=%s", rec.Code, rec.Body.String()) } } func TestInvariant_ElevatedSubtreeAdminBlockedOutsideScope(t *testing.T) { cfg, _ := invariantsFixture(t) // alice is subtree admin of /Project-1/working/, NOT of /Project-1/archive/. target := "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md" rec := doReq(cfg, http.MethodPut, target, "alice@example.com", true, []byte("# out-of-scope\n"), "") if rec.Code != http.StatusForbidden { t.Fatalf("subtree admin escaped scope: status=%d body=%s", rec.Code, rec.Body.String()) } } // ── Invariant 4 — .zddc strict-ancestor self-elevation prevention ───────── // Strict-ancestor was retired — a subtree admin owns their .zddc. // These tests pin the post-change contract: an elevated admin // granted in /