kra-new/internal/data/system/api_policy_test.go

166 lines
5.8 KiB
Go

package system
import (
"context"
"kra/internal/biz/system"
"strings"
"testing"
"kra/internal/conf"
)
func newPolicyTestData(t *testing.T) *Data {
t.Helper()
db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&apiPO{}, &casbinRulePO{}, &authorityPO{}, &authorityAPIPO{}); err != nil {
t.Fatal(err)
}
data := &Data{
gormDB: newReloadableDB(db, nil),
runtime: conf.NewRuntime(
&conf.Data{Database: &conf.Data_Database{Driver: "sqlite"}},
&conf.AdminBackend{System: &conf.AdminBackend_System{UseStrictAuth: true}},
),
}
t.Cleanup(func() { data.gormDB.close() })
return data
}
func apiPolicyUintPointer(value uint) *uint { return &value }
func TestSetPolicyPathsStrictRootRequiresRegisteredAPI(t *testing.T) {
data := newPolicyTestData(t)
ctx := system.NewActorContext(context.Background(), system.Actor{AuthorityID: 888})
if err := data.gormDB.WithContext(ctx).Create(&[]authorityPO{
{AuthorityID: 888, ParentID: apiPolicyUintPointer(0)},
{AuthorityID: 999, ParentID: apiPolicyUintPointer(888)},
}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&apiPO{Path: "/known", Method: "POST"}).Error; err != nil {
t.Fatal(err)
}
err := (&apiRepo{data: data}).SetPolicyPaths(ctx, 999, []*system.API{{Path: "/unknown", Method: "POST"}})
if err == nil || !strings.Contains(err.Error(), "存在api不在权限列表中") {
t.Fatalf("unregistered root assignment error = %v", err)
}
if err := (&apiRepo{data: data}).SetPolicyPaths(ctx, 999, []*system.API{{Path: "/known", Method: "POST"}}); err != nil {
t.Fatal(err)
}
}
func TestSetPolicyPathsStrictChildRejectsStalePolicy(t *testing.T) {
data := newPolicyTestData(t)
ctx := system.NewActorContext(context.Background(), system.Actor{AuthorityID: 1001})
if err := data.gormDB.WithContext(ctx).Create(&[]authorityPO{
{AuthorityID: 888, ParentID: apiPolicyUintPointer(0)},
{AuthorityID: 1001, ParentID: apiPolicyUintPointer(888)},
{AuthorityID: 1002, ParentID: apiPolicyUintPointer(1001)},
}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&apiPO{Path: "/known", Method: "POST"}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&[]casbinRulePO{
newPolicyRule(1001, "/known", "POST"),
newPolicyRule(1001, "/stale", "POST"),
}).Error; err != nil {
t.Fatal(err)
}
err := (&apiRepo{data: data}).SetPolicyPaths(ctx, 1002, []*system.API{{Path: "/stale", Method: "POST"}})
if err == nil || !strings.Contains(err.Error(), "存在api不在权限列表中") {
t.Fatalf("stale child assignment error = %v", err)
}
if err := (&apiRepo{data: data}).SetPolicyPaths(ctx, 1002, []*system.API{{Path: "/known", Method: "POST"}}); err != nil {
t.Fatal(err)
}
}
func TestSetPolicyPathsUsesCompatibleDedupeKey(t *testing.T) {
data := newPolicyTestData(t)
ctx := system.NewActorContext(context.Background(), system.Actor{AuthorityID: 888})
if err := data.gormDB.WithContext(ctx).Create(&[]authorityPO{
{AuthorityID: 888, ParentID: apiPolicyUintPointer(0)},
{AuthorityID: 999, ParentID: apiPolicyUintPointer(888)},
}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&[]apiPO{
{Path: "/a", Method: "BC"},
{Path: "/aB", Method: "C"},
}).Error; err != nil {
t.Fatal(err)
}
if err := (&apiRepo{data: data}).SetPolicyPaths(ctx, 999, []*system.API{
{Path: "/a", Method: "BC"},
{Path: "/aB", Method: "C"},
}); err != nil {
t.Fatal(err)
}
rows, err := policyRowsForAuthority(data.gormDB.WithContext(ctx), 999)
if err != nil {
t.Fatal(err)
}
if len(rows) != 1 || rows[0].V1 != "/a" || rows[0].V2 != "BC" {
t.Fatalf("deduplicated policies = %#v, want only the first concatenated-key match", rows)
}
}
func TestCheckPolicyStore(t *testing.T) {
data := newPolicyTestData(t)
repo := &apiRepo{data: data}
if err := repo.CheckPolicyStore(context.Background()); err != nil {
t.Fatalf("CheckPolicyStore returned error for migrated table: %v", err)
}
if err := data.gormDB.WithContext(context.Background()).Migrator().DropTable(&casbinRulePO{}); err != nil {
t.Fatal(err)
}
if err := repo.CheckPolicyStore(context.Background()); err == nil {
t.Fatal("CheckPolicyStore succeeded after casbin_rule was dropped")
}
}
func TestSetAPIRolesStrictOnlyChangesManagedAuthorities(t *testing.T) {
data := newPolicyTestData(t)
db := data.gormDB.WithContext(context.Background())
rootID, actorID, childID, siblingID := uint(888), uint(2001), uint(2002), uint(3001)
if err := db.Create(&[]authorityPO{
{AuthorityID: rootID, ParentID: apiPolicyUintPointer(0)},
{AuthorityID: actorID, ParentID: &rootID},
{AuthorityID: childID, ParentID: &actorID},
{AuthorityID: siblingID, ParentID: &rootID},
}).Error; err != nil {
t.Fatal(err)
}
if err := db.Create(&apiPO{Path: "/known", Method: "POST"}).Error; err != nil {
t.Fatal(err)
}
if err := db.Create(&[]casbinRulePO{
newPolicyRule(actorID, "/known", "POST"),
newPolicyRule(siblingID, "/known", "POST"),
}).Error; err != nil {
t.Fatal(err)
}
ctx := system.NewActorContext(context.Background(), system.Actor{AuthorityID: actorID})
repo := &apiRepo{data: data}
if err := repo.SetAPIRoles(ctx, "/known", "POST", []uint{siblingID}); err == nil {
t.Fatal("SetAPIRoles() accepted an out-of-scope authority")
}
if err := repo.SetAPIRoles(ctx, "/known", "POST", []uint{childID}); err != nil {
t.Fatalf("SetAPIRoles() rejected a managed authority: %v", err)
}
if exists, err := policyExists(db, siblingID, "/known", "POST"); err != nil || !exists {
t.Fatalf("out-of-scope policy exists=%v err=%v, want preserved", exists, err)
}
if exists, err := policyExists(db, childID, "/known", "POST"); err != nil || !exists {
t.Fatalf("managed policy exists=%v err=%v, want added", exists, err)
}
}