Files
capsule/pkg/template/rules_test.go
T
77d1810bb9 feat: add metadata enforcement (#1990)
* fix(controller): decode old object for delete requests

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* fix: preserve ca-bundles injected from external providers

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

* feat: add metadata enforcement

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

* feat: add metadata enforcement

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

* fix: add resourcepoolclaim validation

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

* fix: add resourcepoolclaim validation

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

* fix: add resourcepoolclaim validation

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

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: add resourcepoolclaim validation

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

---------

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-02 13:42:08 +02:00

328 lines
8.2 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package template
import (
"strings"
"testing"
corev1 "k8s.io/api/core/v1"
"github.com/projectcapsule/capsule/pkg/api/rules"
"github.com/projectcapsule/capsule/pkg/api/runtime"
)
func TestRenderNamespaceRuleBodies(t *testing.T) {
t.Parallel()
tests := []struct {
name string
context map[string]any
key MissingKeyOption
bodies []*rules.NamespaceRuleBodyNamespace
assertFn func(t *testing.T, got []*rules.NamespaceRuleBodyNamespace)
wantErr string
}{
{
name: "empty input returns nil",
key: MissingKeyOption("error"),
assertFn: func(t *testing.T, got []*rules.NamespaceRuleBodyNamespace) {
t.Helper()
if got != nil {
t.Fatalf("RenderNamespaceRuleBodies() = %#v, want nil", got)
}
},
},
{
name: "renders tenant and namespace values in registry exact match",
context: map[string]any{
"tenant": map[string]any{
"metadata": map[string]any{
"name": "solar",
},
},
"namespace": map[string]any{
"metadata": map[string]any{
"name": "solar-prod",
},
},
},
key: MissingKeyOption("error"),
bodies: []*rules.NamespaceRuleBodyNamespace{
{
Enforce: &rules.NamespaceRuleEnforceBody{
Action: rules.ActionTypeAllow,
Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
Registries: []rules.OCIRegistry{
{
ExpressionMatch: runtime.ExpressionMatch{
Exact: []string{
"{{ .tenant.metadata.name }}/{{ .namespace.metadata.name }}/app:1",
},
},
},
},
},
},
},
},
assertFn: func(t *testing.T, got []*rules.NamespaceRuleBodyNamespace) {
t.Helper()
if len(got) != 1 {
t.Fatalf("len(got) = %d, want 1", len(got))
}
body := got[0]
if body == nil || body.Enforce == nil {
t.Fatalf("got[0].Enforce = nil, want rendered enforce body")
}
if body.Enforce.Action != rules.ActionTypeAllow {
t.Fatalf("Action = %q, want %q", body.Enforce.Action, rules.ActionTypeAllow)
}
registries := body.Enforce.Workloads.Registries
if len(registries) != 1 {
t.Fatalf("len(Registries) = %d, want 1", len(registries))
}
exact := registries[0].Exact
if len(exact) != 1 || exact[0] != "solar/solar-prod/app:1" {
t.Fatalf("Exact = %#v, want [solar/solar-prod/app:1]", exact)
}
},
},
{
name: "renders namespace labels using index",
context: map[string]any{
"namespace": map[string]any{
"metadata": map[string]any{
"labels": map[string]any{
"registry-prefix": "harbor/team-a",
},
},
},
},
key: MissingKeyOption("error"),
bodies: []*rules.NamespaceRuleBodyNamespace{
{
Enforce: &rules.NamespaceRuleEnforceBody{
Action: rules.ActionTypeAllow,
Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
Registries: []rules.OCIRegistry{
{
ExpressionMatch: runtime.ExpressionMatch{
Exact: []string{
`{{ index .namespace.metadata.labels "registry-prefix" }}/app:1`,
},
},
},
},
},
},
},
},
assertFn: func(t *testing.T, got []*rules.NamespaceRuleBodyNamespace) {
t.Helper()
exact := got[0].Enforce.Workloads.Registries[0].Exact
if len(exact) != 1 || exact[0] != "harbor/team-a/app:1" {
t.Fatalf("Exact = %#v, want [harbor/team-a/app:1]", exact)
}
},
},
{
name: "renders multiple bodies while preserving order",
context: map[string]any{
"tenant": map[string]any{
"metadata": map[string]any{
"name": "solar",
},
},
},
key: MissingKeyOption("error"),
bodies: []*rules.NamespaceRuleBodyNamespace{
{
Enforce: &rules.NamespaceRuleEnforceBody{
Action: rules.ActionTypeAllow,
Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
Registries: []rules.OCIRegistry{
{
ExpressionMatch: runtime.ExpressionMatch{
ExpressionRegex: runtime.ExpressionRegex{
Expression: "{{ .tenant.metadata.name }}/allow/.*",
},
},
},
},
},
},
},
{
Enforce: &rules.NamespaceRuleEnforceBody{
Action: rules.ActionTypeDeny,
Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
QoSClasses: []corev1.PodQOSClass{
corev1.PodQOSBestEffort,
},
Registries: []rules.OCIRegistry{
{
ExpressionMatch: runtime.ExpressionMatch{
ExpressionRegex: runtime.ExpressionRegex{
Expression: "{{ .tenant.metadata.name }}/deny/.*",
},
},
},
},
},
},
},
},
assertFn: func(t *testing.T, got []*rules.NamespaceRuleBodyNamespace) {
t.Helper()
if len(got) != 2 {
t.Fatalf("len(got) = %d, want 2", len(got))
}
if got[0].Enforce.Action != rules.ActionTypeAllow {
t.Fatalf("got[0].Action = %q, want allow", got[0].Enforce.Action)
}
if got[1].Enforce.Action != rules.ActionTypeDeny {
t.Fatalf("got[1].Action = %q, want deny", got[1].Enforce.Action)
}
first := got[0].Enforce.Workloads.Registries[0].Expression
if first != "solar/allow/.*" {
t.Fatalf("first expression = %q, want solar/allow/.*", first)
}
second := got[1].Enforce.Workloads.Registries[0].Expression
if second != "solar/deny/.*" {
t.Fatalf("second expression = %q, want solar/deny/.*", second)
}
qos := got[1].Enforce.Workloads.QoSClasses
if len(qos) != 1 || qos[0] != corev1.PodQOSBestEffort {
t.Fatalf("QoSClasses = %#v, want [%q]", qos, corev1.PodQOSBestEffort)
}
},
},
{
name: "missing key is wrapped with render namespace rule bodies template",
context: map[string]any{
"namespace": map[string]any{
"metadata": map[string]any{
"labels": map[string]any{},
},
},
},
key: MissingKeyOption("error"),
bodies: []*rules.NamespaceRuleBodyNamespace{
{
Enforce: &rules.NamespaceRuleEnforceBody{
Action: rules.ActionTypeAllow,
Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
Registries: []rules.OCIRegistry{
{
ExpressionMatch: runtime.ExpressionMatch{
Exact: []string{
"{{ .namespace.metadata.labels.registry }}/app:1",
},
},
},
},
},
},
},
},
wantErr: "render namespace rule bodies template",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := RenderNamespaceRuleBodies(tt.context, tt.key, tt.bodies)
if tt.wantErr != "" {
if err == nil {
t.Fatalf("RenderNamespaceRuleBodies() error = nil, want containing %q", tt.wantErr)
}
if !strings.Contains(err.Error(), tt.wantErr) {
t.Fatalf("RenderNamespaceRuleBodies() error = %q, want containing %q", err.Error(), tt.wantErr)
}
return
}
if err != nil {
t.Fatalf("RenderNamespaceRuleBodies() unexpected error: %v", err)
}
if tt.assertFn != nil {
tt.assertFn(t, got)
}
})
}
}
func TestRenderNamespaceRuleBodies_DoesNotMutateInput(t *testing.T) {
t.Parallel()
bodies := []*rules.NamespaceRuleBodyNamespace{
{
Enforce: &rules.NamespaceRuleEnforceBody{
Action: rules.ActionTypeAllow,
Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
Registries: []rules.OCIRegistry{
{
ExpressionMatch: runtime.ExpressionMatch{
Exact: []string{
"{{ .tenant.metadata.name }}/app:1",
},
},
},
},
},
},
},
}
got, err := RenderNamespaceRuleBodies(
map[string]any{
"tenant": map[string]any{
"metadata": map[string]any{
"name": "solar",
},
},
},
MissingKeyOption("error"),
bodies,
)
if err != nil {
t.Fatalf("RenderNamespaceRuleBodies() unexpected error: %v", err)
}
if len(got) != 1 {
t.Fatalf("len(got) = %d, want 1", len(got))
}
originalExact := bodies[0].Enforce.Workloads.Registries[0].Exact[0]
if originalExact != "{{ .tenant.metadata.name }}/app:1" {
t.Fatalf("input body was mutated: exact = %q", originalExact)
}
renderedExact := got[0].Enforce.Workloads.Registries[0].Exact[0]
if renderedExact != "solar/app:1" {
t.Fatalf("rendered exact = %q, want solar/app:1", renderedExact)
}
}