diff --git a/internal/server/role_authorization_test.go b/internal/server/role_authorization_test.go index de097f3..5f8079e 100644 --- a/internal/server/role_authorization_test.go +++ b/internal/server/role_authorization_test.go @@ -274,6 +274,43 @@ func TestProjectAccessIgnoresSystemGrantWithoutRole(t *testing.T) { } } +func TestProjectCreateFailsClosedWithoutRoleProvider(t *testing.T) { + srv, st := newAuthTestServer(t) + h := srv.Handler() + superAdmin := bootSuperAdmin(t, h, st) + if err := st.CreateAccount("engineer", "Engineer", "", false); err != nil { + t.Fatal(err) + } + key, err := st.CreateAPIKey("engineer", "engineer-test") + if err != nil { + t.Fatal(err) + } + + if rec := bearerRequest(h, "POST", "/api/projects", `{"name":"无职位项目"}`, key); rec.Code != http.StatusForbidden || + !strings.Contains(rec.Body.String(), "not-granted") { + t.Fatalf("project created without role: %d %s", rec.Code, rec.Body.String()) + } + if allowed, _, reason := systemDecisionFixture(t, bearerRequest(h, "GET", "/api/authz/explain?action=project.create", "", key)); allowed || reason != "not-granted" { + t.Fatalf("missing role project.create allowed=%v reason=%s", allowed, reason) + } + + createAssignedRoleFixture(t, h, st, superAdmin, "engineer", "工程师", true) + if rec := bearerRequest(h, "POST", "/api/projects", `{"name":"职位授权项目"}`, key); rec.Code != http.StatusOK { + t.Fatalf("role project create: %d %s", rec.Code, rec.Body.String()) + } + + if _, err := st.DB().Exec(`DROP TABLE role_permissions`); err != nil { + t.Fatal(err) + } + if rec := bearerRequest(h, "POST", "/api/projects", `{"name":"职位不可用项目"}`, key); rec.Code != http.StatusForbidden || + !strings.Contains(rec.Body.String(), "authority-unavailable") { + t.Fatalf("project created with unavailable role provider: %d %s", rec.Code, rec.Body.String()) + } + if allowed, source, reason := systemDecisionFixture(t, bearerRequest(h, "GET", "/api/authz/explain?action=project.create", "", key)); allowed || source != "" || reason != "authority-unavailable" { + t.Fatalf("unavailable role project.create allowed=%v source=%s reason=%s", allowed, source, reason) + } +} + func TestLegacyRoleRowsDoNotAuthorizeSystemActionsOrAccess(t *testing.T) { srv, st := newAuthTestServer(t) h := srv.Handler()