219 lines
4.8 KiB
Go
219 lines
4.8 KiB
Go
package controllers
|
|
|
|
import (
|
|
"apiserver/store"
|
|
"apiserver/utils"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func resetRBACState() {
|
|
rbacConfig = RBACConfig{}
|
|
store.InitStores()
|
|
utils.Log = zap.NewNop()
|
|
}
|
|
|
|
func writeTestYAML(t *testing.T, content string) string {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "rbac.yaml")
|
|
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
|
t.Fatalf("write test yaml: %v", err)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func TestLoadRBACConfig_RolesPopulated(t *testing.T) {
|
|
resetRBACState()
|
|
|
|
yaml := `
|
|
permissions:
|
|
- queue:view
|
|
- job:view
|
|
roles:
|
|
basic_user:
|
|
permissions:
|
|
- action: queue:view
|
|
domain:
|
|
- type: all
|
|
- action: job:view
|
|
domain:
|
|
- type: self
|
|
operator:
|
|
permissions:
|
|
- action: host:view
|
|
domain:
|
|
- type: all
|
|
`
|
|
path := writeTestYAML(t, yaml)
|
|
if err := LoadRBACConfig(path); err != nil {
|
|
t.Fatalf("LoadRBACConfig: %v", err)
|
|
}
|
|
|
|
// Verify roles exist in store
|
|
if !store.Roles.Has("basic_user") {
|
|
t.Error("store should contain basic_user role")
|
|
}
|
|
if !store.Roles.Has("operator") {
|
|
t.Error("store should contain operator role")
|
|
}
|
|
|
|
// Verify basic_user permissions
|
|
perms := store.GetRolePermissions("basic_user")
|
|
if len(perms) != 2 {
|
|
t.Errorf("basic_user permissions count = %d, want 2", len(perms))
|
|
}
|
|
found := false
|
|
for _, p := range perms {
|
|
if p.Action == "queue:view" && p.DomainType == "all" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("basic_user should have queue:view with domain all")
|
|
}
|
|
}
|
|
|
|
func TestLoadRBACConfig_UserRoleMappings(t *testing.T) {
|
|
resetRBACState()
|
|
|
|
yaml := `
|
|
permissions:
|
|
- queue:view
|
|
roles:
|
|
basic_user:
|
|
permissions:
|
|
- action: queue:view
|
|
domain:
|
|
- type: all
|
|
users:
|
|
alice:
|
|
roles:
|
|
- name: basic_user
|
|
domain:
|
|
- type: all
|
|
bob:
|
|
roles:
|
|
- name: basic_user
|
|
domain:
|
|
- type: all
|
|
`
|
|
path := writeTestYAML(t, yaml)
|
|
if err := LoadRBACConfig(path); err != nil {
|
|
t.Fatalf("LoadRBACConfig: %v", err)
|
|
}
|
|
|
|
roles := store.GetUserRoleNames("alice")
|
|
if len(roles) != 1 || roles[0] != "basic_user" {
|
|
t.Errorf("alice roles = %v, want [basic_user]", roles)
|
|
}
|
|
|
|
roles = store.GetUserRoleNames("bob")
|
|
if len(roles) != 1 || roles[0] != "basic_user" {
|
|
t.Errorf("bob roles = %v, want [basic_user]", roles)
|
|
}
|
|
|
|
roles = store.GetUserRoleNames("unknown")
|
|
if len(roles) != 0 {
|
|
t.Errorf("unknown user roles = %v, want empty", roles)
|
|
}
|
|
}
|
|
|
|
func TestLoadRBACConfig_RoleIncludes(t *testing.T) {
|
|
resetRBACState()
|
|
|
|
yaml := `
|
|
permissions:
|
|
- queue:view
|
|
- job:view
|
|
- queue:control
|
|
roles:
|
|
basic_user:
|
|
permissions:
|
|
- action: queue:view
|
|
domain:
|
|
- type: all
|
|
- action: job:view
|
|
domain:
|
|
- type: self
|
|
queue_admin:
|
|
includes:
|
|
- basic_user
|
|
permissions:
|
|
- action: queue:control
|
|
domain:
|
|
- type: self
|
|
`
|
|
path := writeTestYAML(t, yaml)
|
|
if err := LoadRBACConfig(path); err != nil {
|
|
t.Fatalf("LoadRBACConfig: %v", err)
|
|
}
|
|
|
|
// queue_admin should have its own permissions + inherited basic_user permissions
|
|
perms := store.GetRolePermissions("queue_admin")
|
|
if len(perms) < 3 {
|
|
t.Errorf("queue_admin permissions count = %d, want >= 3 (own + inherited)", len(perms))
|
|
}
|
|
|
|
// Verify inherited queue:view is present
|
|
foundQueueView := false
|
|
foundQueueControl := false
|
|
for _, p := range perms {
|
|
if p.Action == "queue:view" {
|
|
foundQueueView = true
|
|
}
|
|
if p.Action == "queue:control" {
|
|
foundQueueControl = true
|
|
}
|
|
}
|
|
if !foundQueueView {
|
|
t.Error("queue_admin should inherit queue:view from basic_user")
|
|
}
|
|
if !foundQueueControl {
|
|
t.Error("queue_admin should have its own queue:control")
|
|
}
|
|
}
|
|
|
|
func TestLoadRBACConfig_EmptyRoles(t *testing.T) {
|
|
resetRBACState()
|
|
|
|
yaml := `
|
|
permissions:
|
|
- queue:view
|
|
roles:
|
|
empty_role: {}
|
|
`
|
|
path := writeTestYAML(t, yaml)
|
|
if err := LoadRBACConfig(path); err != nil {
|
|
t.Fatalf("LoadRBACConfig: %v", err)
|
|
}
|
|
|
|
if !store.Roles.Has("empty_role") {
|
|
t.Error("store should contain empty_role even with no permissions")
|
|
}
|
|
perms := store.GetRolePermissions("empty_role")
|
|
if len(perms) != 0 {
|
|
t.Errorf("empty_role permissions = %v, want empty", perms)
|
|
}
|
|
}
|
|
|
|
func TestLoadRBACConfig_FileNotFound(t *testing.T) {
|
|
resetRBACState()
|
|
|
|
err := LoadRBACConfig("/nonexistent/path/rbac.yaml")
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent file")
|
|
}
|
|
}
|
|
|
|
// TestNoMockRBACMaps ensures the hardcoded mock group/queue maps have been removed.
|
|
// This is a compile-time check — if the vars exist, this test won't compile.
|
|
func TestNoMockRBACMaps(t *testing.T) {
|
|
// If hostGroupMap, userGroupMap, or queueMap still exist as package-level vars,
|
|
// the build will fail with "declared and not used" or similar.
|
|
// This test documents the intent: those vars must not exist.
|
|
t.Log("mock RBAC maps removed — OK")
|
|
}
|