Files
capsule/pkg/utils/hashes_test.go
T
Oliver BählerandGitHub 9ee5468f47 feat: add rolebindings to rules api (#2032)
* feat: add rolebindings to rules api

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add rolebindings to rules api

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add rolebindings to rules api

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add rolebindings to rules api

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add rolebindings to rules api

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: implement review

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

---------

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
2026-07-15 10:35:36 +02:00

194 lines
4.9 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package utils_test
import (
"testing"
rbacv1 "k8s.io/api/rbac/v1"
"github.com/projectcapsule/capsule/pkg/api/rbac"
"github.com/projectcapsule/capsule/pkg/utils"
)
func TestRoleBindingHashFunc_Deterministic(t *testing.T) {
b := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{
{Kind: "User", Name: "alice"},
{Kind: "Group", Name: "devops"},
},
}
h1 := utils.RoleBindingHashFunc(b)
h2 := utils.RoleBindingHashFunc(b)
if h1 != h2 {
t.Fatalf("expected deterministic hash, got %q and %q", h1, h2)
}
if h1 == "" {
t.Fatalf("expected non-empty hash")
}
}
func TestRoleBindingHashFunc_ChangesWhenClusterRoleChanges(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "view",
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes when ClusterRoleName changes, got %q", h1)
}
}
func TestRoleBindingHashFunc_ChangesWhenSubjectKindChanges(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{Kind: "Group", Name: "alice"}},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes when subject Kind changes, got %q", h1)
}
}
func TestRoleBindingHashFunc_ChangesWhenSubjectNameChanges(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{Kind: "User", Name: "bob"}},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes when subject Name changes, got %q", h1)
}
}
func TestRoleBindingHashFunc_ChangesWhenSubjectNamespaceChanges(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{
Kind: rbacv1.ServiceAccountKind,
Namespace: "team-a",
Name: "deployer",
}},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{
Kind: rbacv1.ServiceAccountKind,
Namespace: "team-b",
Name: "deployer",
}},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes when subject Namespace changes, got %q", h1)
}
}
func TestRoleBindingHashFunc_ChangesWhenSubjectAPIGroupChanges(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{
APIGroup: rbacv1.GroupName,
Kind: rbacv1.UserKind,
Name: "alice",
}},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{{
APIGroup: "example.com",
Kind: rbacv1.UserKind,
Name: "alice",
}},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes when subject APIGroup changes, got %q", h1)
}
}
func TestRoleBindingHashFunc_UsesUnambiguousFieldBoundaries(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "ab",
Subjects: []rbacv1.Subject{{Kind: "c", Name: "d"}},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "a",
Subjects: []rbacv1.Subject{{Kind: "bc", Name: "d"}},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes for differently bounded fields, got %q", h1)
}
}
func TestRoleBindingHashFunc_EmptyInputsStillProduceHash(t *testing.T) {
b := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "",
Subjects: nil,
}
h := utils.RoleBindingHashFunc(b)
if h == "" {
t.Fatalf("expected non-empty hash even for empty input")
}
}
func TestRoleBindingHashFunc_SubjectOrderMatters(t *testing.T) {
b1 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{
{Kind: "User", Name: "alice"},
{Kind: "Group", Name: "devops"},
},
}
b2 := rbac.AdditionalRoleBindingsSpec{
ClusterRoleName: "admin",
Subjects: []rbacv1.Subject{
{Kind: "Group", Name: "devops"},
{Kind: "User", Name: "alice"},
},
}
h1 := utils.RoleBindingHashFunc(b1)
h2 := utils.RoleBindingHashFunc(b2)
if h1 == h2 {
t.Fatalf("expected different hashes when subject order changes, got %q", h1)
}
}