mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-19 04:26:45 +00:00
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>
This commit is contained in:
+13
-2
@@ -4,6 +4,7 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
|
||||
@@ -12,11 +13,21 @@ import (
|
||||
|
||||
func RoleBindingHashFunc(binding rbac.AdditionalRoleBindingsSpec) string {
|
||||
h := fnv.New64a()
|
||||
writeField := func(value string) {
|
||||
var length [8]byte
|
||||
|
||||
_, _ = h.Write([]byte(binding.ClusterRoleName))
|
||||
binary.LittleEndian.PutUint64(length[:], uint64(len(value)))
|
||||
_, _ = h.Write(length[:])
|
||||
_, _ = h.Write([]byte(value))
|
||||
}
|
||||
|
||||
writeField(binding.ClusterRoleName)
|
||||
|
||||
for _, sub := range binding.Subjects {
|
||||
_, _ = h.Write([]byte(sub.Kind + sub.Name))
|
||||
writeField(sub.APIGroup)
|
||||
writeField(sub.Kind)
|
||||
writeField(sub.Namespace)
|
||||
writeField(sub.Name)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", h.Sum64())
|
||||
|
||||
@@ -86,6 +86,76 @@ func TestRoleBindingHashFunc_ChangesWhenSubjectNameChanges(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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: "",
|
||||
@@ -98,9 +168,7 @@ func TestRoleBindingHashFunc_EmptyInputsStillProduceHash(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoleBindingHashFunc_SubjectOrderMatters_CurrentBehavior(t *testing.T) {
|
||||
// This test documents the CURRENT behavior:
|
||||
// the hash is order-dependent because subjects are written in slice order.
|
||||
func TestRoleBindingHashFunc_SubjectOrderMatters(t *testing.T) {
|
||||
b1 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{
|
||||
@@ -120,6 +188,6 @@ func TestRoleBindingHashFunc_SubjectOrderMatters_CurrentBehavior(t *testing.T) {
|
||||
h2 := utils.RoleBindingHashFunc(b2)
|
||||
|
||||
if h1 == h2 {
|
||||
t.Fatalf("expected different hashes when subject order changes (current behavior), got %q", h1)
|
||||
t.Fatalf("expected different hashes when subject order changes, got %q", h1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user