- FIND-SEC-01: GetUserContext requires session ownership (handler 403 + SQL/memory owner filter); in-memory HTTP + isolated-PG regressions - FIND-ARCH-01: archtest fails closed on untracked table writes (+noise exemption) and registers 50 existing writer tables in table_owners - FIND-SEC-02: Authorizer without pool denies by default; explicit NewInMemoryAuthorizer seam opt-in via ALLOW_IN_MEMORY at composition - FIND-SEC-03: swboot commands run argv-exec (no sh -c) with exact basename allowlist match; prefix-spoof and no-shell-eval tests - FIND-FLOW-01: confirm rejects validated_only plans; ExecuteClaimed hard-refuses validated_only steps (new error codes + HTTP mapping) - FIND-QUAL-01: intentflow.ValidateFlagConsistency fail-fast at Assemble
122 lines
3.9 KiB
Go
122 lines
3.9 KiB
Go
package authz_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"chat-agent-system/internal/authz"
|
|
)
|
|
|
|
func TestService_ListCapabilities_DisabledWithoutPool(t *testing.T) {
|
|
svc := authz.NewService(nil)
|
|
caps, err := svc.ListCapabilities(context.Background(), 1)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if caps != nil {
|
|
t.Fatalf("expected nil caps when pool disabled, got %v", caps)
|
|
}
|
|
}
|
|
|
|
func TestService_IsSystemAdmin_ByRoleID(t *testing.T) {
|
|
svc := authz.NewService(nil)
|
|
admin, err := svc.IsSystemAdmin(context.Background(), 1, "role-admin")
|
|
if err != nil || !admin {
|
|
t.Fatalf("expected admin by role_id, got (%v, %v)", admin, err)
|
|
}
|
|
}
|
|
|
|
func TestService_HasSystemPermission_AdminGrantsAllSystemKeys(t *testing.T) {
|
|
svc := authz.NewService(nil)
|
|
ctx := context.Background()
|
|
for _, perm := range authz.SystemConsolePermissions() {
|
|
ok, err := svc.HasSystemPermission(ctx, 1, "role-admin", perm)
|
|
if err != nil || !ok {
|
|
t.Fatalf("admin should have %s, got (%v, %v)", perm, ok, err)
|
|
}
|
|
}
|
|
ok, err := svc.HasSystemPermission(ctx, 1, "role-admin", authz.PermManage)
|
|
if err != nil || !ok {
|
|
t.Fatalf("admin should have perm:manage, got (%v, %v)", ok, err)
|
|
}
|
|
}
|
|
|
|
func TestService_HasSystemPermission_NonAdminFailClosed(t *testing.T) {
|
|
svc := authz.NewService(nil)
|
|
ctx := context.Background()
|
|
for _, role := range []string{"role-engineer", "role-guest", "", "role-director"} {
|
|
for _, perm := range authz.SystemConsolePermissions() {
|
|
ok, err := svc.HasSystemPermission(ctx, 2, role, perm)
|
|
if err != nil {
|
|
t.Fatalf("unexpected err for %s/%s: %v", role, perm, err)
|
|
}
|
|
if ok {
|
|
t.Fatalf("non-admin %s must not have %s", role, perm)
|
|
}
|
|
}
|
|
}
|
|
ok, err := svc.HasSystemPermission(ctx, 0, "role-admin", authz.PermSystemOverview)
|
|
if err != nil || ok {
|
|
t.Fatalf("invalid userID must fail-closed, got (%v, %v)", ok, err)
|
|
}
|
|
ok, err = svc.HasSystemPermission(ctx, 1, "role-admin", "")
|
|
if err != nil || ok {
|
|
t.Fatalf("empty perm must fail-closed, got (%v, %v)", ok, err)
|
|
}
|
|
}
|
|
|
|
func TestPermissionCatalog_IncludesSystemConsoleKeys(t *testing.T) {
|
|
keys := map[string]bool{}
|
|
for _, e := range authz.PermissionCatalog() {
|
|
keys[e.Key] = true
|
|
}
|
|
for _, perm := range authz.SystemConsolePermissions() {
|
|
if !keys[perm] {
|
|
t.Fatalf("catalog missing %s", perm)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUpsertProjectMember_RejectsDocRolesWithoutDB(t *testing.T) {
|
|
a := authz.NewAuthorizer(nil)
|
|
if err := a.UpsertProjectMember(context.Background(), 1, 2, "author"); err == nil {
|
|
t.Fatal("expected author role to be rejected")
|
|
}
|
|
if err := a.UpsertProjectMember(context.Background(), 1, 2, authz.RoleOwner); err != nil {
|
|
t.Fatalf("owner should be allowed: %v", err)
|
|
}
|
|
bad := "viewer"
|
|
if err := a.UpsertProjectMemberSpec(context.Background(), 1, 2, authz.MemberUpsert{
|
|
ProjectRole: authz.RoleMember,
|
|
DocumentDuty: &bad,
|
|
}); err == nil {
|
|
t.Fatal("document_duty=viewer must be rejected")
|
|
}
|
|
}
|
|
|
|
func TestGetProjectMember_DisabledWithoutPool(t *testing.T) {
|
|
a := authz.NewAuthorizer(nil)
|
|
rec, err := a.GetProjectMember(context.Background(), 1, 2)
|
|
if err != nil || rec != nil {
|
|
t.Fatalf("disabled authorizer must not invent a member, got (%v, %v)", rec, err)
|
|
}
|
|
}
|
|
|
|
// TestMembershipChecks_FailClosedWithoutPool FIND-SEC-02 回归:
|
|
// 无池 Authorizer 的成员/owner 判定必须 fail-closed,不得放行任意登录用户。
|
|
func TestMembershipChecks_FailClosedWithoutPool(t *testing.T) {
|
|
a := authz.NewAuthorizer(nil)
|
|
for name, fn := range map[string]func() (bool, error){
|
|
"IsProjectMember": func() (bool, error) { return a.IsProjectMember(context.Background(), 1, 2) },
|
|
"IsProjectOwner": func() (bool, error) { return a.IsProjectOwner(context.Background(), 1, 2) },
|
|
} {
|
|
ok, err := fn()
|
|
if err != nil || ok {
|
|
t.Fatalf("%s without pool must fail closed (false, nil), got (%v, %v)", name, ok, err)
|
|
}
|
|
}
|
|
if err := a.RequireProjectAccess(context.Background(), 1, 2); err == nil {
|
|
t.Fatalf("RequireProjectAccess without pool must deny, got nil error")
|
|
}
|
|
}
|