// Copyright 2020-2026 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package e2e

import (
	"context"
	"fmt"
	"strings"
	"time"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8stypes "k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/kubernetes"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/client"

	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
	"github.com/projectcapsule/capsule/pkg/api/meta"
	"github.com/projectcapsule/capsule/pkg/api/rbac"
	"github.com/projectcapsule/capsule/pkg/api/rules"
	"github.com/projectcapsule/capsule/pkg/api/runtime"
	"github.com/projectcapsule/capsule/pkg/runtime/events"
)

var _ = Describe("enforcing generic metadata namespace rules", Ordered, Label("tenant", "rules", "enforce", "metadata", "generic"), func() {
	const ownerName = "e2e-rules-metadata"

	var (
		tnt         *capsulev1beta2.Tenant
		tenantRules []*rules.NamespaceRuleBodyTenant
	)

	metadataByExpression := func(expression string) runtime.ExpressionMatch {
		return runtime.ExpressionMatch{
			ExpressionRegex: runtime.ExpressionRegex{
				Expression: expression,
			},
		}
	}

	metadataByNegatedExpression := func(expression string) runtime.ExpressionMatch {
		return runtime.ExpressionMatch{
			ExpressionRegex: runtime.ExpressionRegex{
				Expression: expression,
				Negate:     true,
			},
		}
	}

	metadataByExact := func(exact ...string) runtime.ExpressionMatch {
		return runtime.ExpressionMatch{
			Exact: exact,
		}
	}

	metadataByMatch := func(exact []string, expression string) runtime.ExpressionMatch {
		return runtime.ExpressionMatch{
			ExpressionRegex: runtime.ExpressionRegex{
				Expression: expression,
			},
			Exact: exact,
		}
	}

	metadataValueRule := func(required bool, values ...runtime.ExpressionMatch) rules.MetadataValueRule {
		return rules.MetadataValueRule{
			Required: required,
			Values:   values,
		}
	}

	metadataRule := func(
		action rules.ActionType,
		apiVersion string,
		kinds []string,
		labels map[string]rules.MetadataValueRule,
		annotations map[string]rules.MetadataValueRule,
	) *rules.NamespaceRuleBodyTenant {
		return &rules.NamespaceRuleBodyTenant{
			NamespaceRuleBodyNamespace: &rules.NamespaceRuleBodyNamespace{
				Enforce: &rules.NamespaceRuleEnforceBody{
					Action: action,
					Metadata: []rules.MetadataRule{
						{
							VersionKinds: runtime.VersionKinds{
								APIGroups: []string{apiVersion},
								Kinds:     kinds,
							},
							Labels:      labels,
							Annotations: annotations,
						},
					},
				},
			},
		}
	}

	selectedRule := func(
		selector map[string]string,
		rule *rules.NamespaceRuleBodyTenant,
	) *rules.NamespaceRuleBodyTenant {
		rule.NamespaceSelector = &metav1.LabelSelector{
			MatchLabels: selector,
		}

		return rule
	}

	baseTenantRules := func() []*rules.NamespaceRuleBodyTenant {
		return []*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"",
				[]string{
					"ConfigMap",
					"Service",
				},
				map[string]rules.MetadataValueRule{
					"example.corp/tenant": metadataValueRule(
						true,
						metadataByExact("prod", "test"),
					),
				},
				map[string]rules.MetadataValueRule{
					"example.corp/cost-center": metadataValueRule(
						false,
						metadataByExpression("^INV-[0-9]{4}$"),
						metadataByExact("prod", "test"),
					),
				},
			),
			metadataRule(
				rules.ActionTypeAudit,
				"*",
				[]string{
					"ConfigMap",
					"Service",
				},
				map[string]rules.MetadataValueRule{
					"example.corp/audit": metadataValueRule(
						false,
						metadataByExpression("^audit-.*"),
					),
				},
				nil,
			),
			selectedRule(
				map[string]string{
					"environment": "prod",
				},
				metadataRule(
					rules.ActionTypeAllow,
					"*",
					[]string{
						"ConfigMap",
					},
					nil,
					map[string]rules.MetadataValueRule{
						"example.corp/approval": metadataValueRule(
							true,
							metadataByExact("approved"),
						),
					},
				),
			),
		}
	}

	newTenant := func() *capsulev1beta2.Tenant {
		return &capsulev1beta2.Tenant{
			ObjectMeta: metav1.ObjectMeta{
				Name: "e2e-rule-metadata",
				Labels: map[string]string{
					"env": "e2e",
				},
			},
			Spec: capsulev1beta2.TenantSpec{
				Owners: rbac.OwnerListSpec{
					{
						CoreOwnerSpec: rbac.CoreOwnerSpec{
							UserSpec: rbac.UserSpec{
								Name: ownerName,
								Kind: "User",
							},
						},
					},
				},
				Rules: tenantRules,
			},
		}
	}

	type expectedMetadataPolicy struct {
		required    bool
		expressions []string
		exact       [][]string
		negated     []bool
	}

	type expectedMetadataStatusRule struct {
		action      rules.ActionType
		apiGroups   []string
		kinds       []string
		labels      map[string]expectedMetadataPolicy
		annotations map[string]expectedMetadataPolicy
	}

	expectMetadataPolicy := func(g Gomega, got rules.MetadataValueRule, expected expectedMetadataPolicy) {
		g.Expect(got.Required).To(Equal(expected.required))

		wantValues := len(expected.expressions)
		if len(expected.exact) > wantValues {
			wantValues = len(expected.exact)
		}
		if len(expected.negated) > wantValues {
			wantValues = len(expected.negated)
		}

		g.Expect(got.Values).To(HaveLen(wantValues))

		for i := 0; i < wantValues; i++ {
			value := got.Values[i]

			if len(expected.expressions) > i {
				g.Expect(value.Expression).To(Equal(expected.expressions[i]))
			} else {
				g.Expect(value.Expression).To(BeEmpty())
			}

			if len(expected.exact) > i {
				g.Expect(value.Exact).To(Equal(expected.exact[i]))
			} else {
				g.Expect(value.Exact).To(BeEmpty())
			}

			if len(expected.negated) > i {
				g.Expect(value.Negate).To(Equal(expected.negated[i]))
			} else {
				g.Expect(value.Negate).To(BeFalse())
			}
		}
	}

	expectNamespaceStatusRules := func(nsName string, want []expectedMetadataStatusRule) {
		Eventually(func(g Gomega) {
			nsStatus := &capsulev1beta2.RuleStatus{}

			g.Expect(k8sClient.Get(
				context.Background(),
				client.ObjectKey{
					Name:      meta.NameForManagedRuleStatus(),
					Namespace: nsName,
				},
				nsStatus,
			)).To(Succeed())

			g.Expect(nsStatus.Status.Rules).To(HaveLen(len(want)))

			for i, expected := range want {
				got := nsStatus.Status.Rules[i]

				g.Expect(got).NotTo(BeNil())
				g.Expect(got.Enforce).NotTo(BeNil())
				g.Expect(got.Enforce.Action).To(Equal(expected.action))
				g.Expect(got.Enforce.Metadata).To(HaveLen(1))

				metadata := got.Enforce.Metadata[0]

				if len(expected.apiGroups) == 0 {
					g.Expect(metadata.APIGroups).To(BeEmpty())
				} else {
					g.Expect(metadata.APIGroups).To(Equal(expected.apiGroups))
				}

				g.Expect(metadata.Kinds).To(Equal(expected.kinds))

				g.Expect(metadata.Labels).To(HaveLen(len(expected.labels)))
				for key, policy := range expected.labels {
					gotPolicy, ok := metadata.Labels[key]
					g.Expect(ok).To(BeTrue(), "expected label policy %q", key)
					expectMetadataPolicy(g, gotPolicy, policy)
				}

				g.Expect(metadata.Annotations).To(HaveLen(len(expected.annotations)))
				for key, policy := range expected.annotations {
					gotPolicy, ok := metadata.Annotations[key]
					g.Expect(ok).To(BeTrue(), "expected annotation policy %q", key)
					expectMetadataPolicy(g, gotPolicy, policy)
				}
			}
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	baseStatusRules := func() []expectedMetadataStatusRule {
		return []expectedMetadataStatusRule{
			{
				action: rules.ActionTypeAllow,
				apiGroups: []string{
					"v1",
				},
				kinds: []string{
					"ConfigMap",
					"Service",
				},
				labels: map[string]expectedMetadataPolicy{
					"example.corp/tenant": {
						required: true,
						exact: [][]string{
							{
								"prod",
								"test",
							},
						},
					},
				},
				annotations: map[string]expectedMetadataPolicy{
					"example.corp/cost-center": {
						required: false,
						expressions: []string{
							"^INV-[0-9]{4}$",
							"",
						},
						exact: [][]string{
							nil,
							{
								"prod",
								"test",
							},
						},
					},
				},
			},
			{
				action: rules.ActionTypeAudit,
				apiGroups: []string{
					"*",
				},
				kinds: []string{
					"ConfigMap",
					"Service",
				},
				labels: map[string]expectedMetadataPolicy{
					"example.corp/audit": {
						expressions: []string{
							"^audit-.*",
						},
					},
				},
			},
		}
	}

	updateTenantRules := func(next []*rules.NamespaceRuleBodyTenant) {
		UpdateTenantEventually(tnt, func(current *capsulev1beta2.Tenant) {
			current.Spec.Rules = next
		})

		tnt.Spec.Rules = next
	}

	waitForProjectedMetadata := func(nsName, key string, wantDefault, wantManaged *string) {
		Eventually(func(g Gomega) {
			status := &capsulev1beta2.RuleStatus{}
			g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{
				Name:      meta.NameForManagedRuleStatus(),
				Namespace: nsName,
			}, status)).To(Succeed())

			for _, body := range status.Status.Rules {
				if body == nil || body.Enforce == nil {
					continue
				}
				for _, metadata := range body.Enforce.Metadata {
					if policy, ok := metadata.Labels[key]; ok {
						g.Expect(policy.Default).To(Equal(wantDefault))
						g.Expect(policy.Managed).To(Equal(wantManaged))
						return
					}
					if policy, ok := metadata.Annotations[key]; ok {
						g.Expect(policy.Default).To(Equal(wantDefault))
						g.Expect(policy.Managed).To(Equal(wantManaged))
						return
					}
				}
			}

			g.Expect(false).To(BeTrue(), "metadata policy %q was not projected", key)
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	createNamespace := func(labels map[string]string) *corev1.Namespace {
		if labels == nil {
			labels = map[string]string{}
		}

		labels[meta.TenantLabel] = tnt.GetName()

		ns := NewNamespace("", labels)

		NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
		NamespaceIsPartOfTenant(tnt, ns).Should(Succeed())

		return ns
	}

	createNamespaceAndExpectDenied := func(labels map[string]string, substrings ...string) {
		if labels == nil {
			labels = map[string]string{}
		}
		labels[meta.TenantLabel] = tnt.GetName()
		base := NewNamespace("", labels)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		Eventually(func() error {
			candidate := base.DeepCopy()
			candidate.Name = fmt.Sprintf("%s-%d", base.Name, time.Now().UnixNano()%1e6)
			_, err := cs.CoreV1().Namespaces().Create(context.Background(), candidate, metav1.CreateOptions{})
			if err == nil {
				_ = cs.CoreV1().Namespaces().Delete(context.Background(), candidate.Name, metav1.DeleteOptions{})
				return fmt.Errorf("expected namespace create to be denied, but it succeeded")
			}

			msg := err.Error()
			for _, substring := range substrings {
				if !strings.Contains(msg, substring) {
					return fmt.Errorf("expected error to contain %q, got: %s", substring, msg)
				}
			}

			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	configMap := func(name string, labels map[string]string, annotations map[string]string) *corev1.ConfigMap {
		return &corev1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Name:        name,
				Labels:      labels,
				Annotations: annotations,
			},
			Data: map[string]string{
				"key": "value",
			},
		}
	}

	service := func(name string, labels map[string]string, annotations map[string]string) *corev1.Service {
		return &corev1.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:        name,
				Labels:      labels,
				Annotations: annotations,
			},
			Spec: corev1.ServiceSpec{
				Type: corev1.ServiceTypeClusterIP,
				Ports: []corev1.ServicePort{
					{
						Name: "http",
						Port: 8080,
					},
				},
			},
		}
	}

	deployment := func(name string, labels map[string]string, annotations map[string]string) *appsv1.Deployment {
		return &appsv1.Deployment{
			ObjectMeta: metav1.ObjectMeta{
				Name:        name,
				Labels:      labels,
				Annotations: annotations,
			},
			Spec: appsv1.DeploymentSpec{
				Replicas: ptr.To[int32](1),
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{
						"app": name,
					},
				},
				Template: corev1.PodTemplateSpec{
					ObjectMeta: metav1.ObjectMeta{
						Labels: map[string]string{
							"app": name,
						},
					},
					Spec: corev1.PodSpec{
						Containers: []corev1.Container{
							{
								Name:  "nginx",
								Image: "nginx:1.25",
							},
						},
					},
				},
			},
		}
	}

	createConfigMapAndExpectAllowed := func(cs kubernetes.Interface, nsName string, cm *corev1.ConfigMap) {
		EventuallyCreation(func() error {
			_, err := cs.CoreV1().ConfigMaps(nsName).Create(context.Background(), cm, metav1.CreateOptions{})

			return err
		}).Should(Succeed())
	}

	createConfigMapAndExpectDenied := func(cs kubernetes.Interface, nsName string, cm *corev1.ConfigMap, substrings ...string) {
		base := cm.DeepCopy()
		baseName := base.Name
		if baseName == "" {
			baseName = "cm"
		}

		Eventually(func() error {
			candidate := base.DeepCopy()
			candidate.Name = fmt.Sprintf("%s-%d", baseName, time.Now().UnixNano()%1e6)

			_, err := cs.CoreV1().ConfigMaps(nsName).Create(context.Background(), candidate, metav1.CreateOptions{})
			if err == nil {
				_ = cs.CoreV1().ConfigMaps(nsName).Delete(context.Background(), candidate.Name, metav1.DeleteOptions{})

				return fmt.Errorf("expected configmap create to be denied, but it succeeded")
			}

			if apierrors.IsAlreadyExists(err) {
				return fmt.Errorf("unexpected AlreadyExists: %v", err)
			}

			msg := err.Error()
			for _, substring := range substrings {
				if !strings.Contains(msg, substring) {
					return fmt.Errorf("expected error to contain %q, got: %s", substring, msg)
				}
			}

			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	updateConfigMapAndExpectDenied := func(
		cs kubernetes.Interface,
		nsName string,
		cmName string,
		mutate func(*corev1.ConfigMap),
		substrings ...string,
	) {
		Eventually(func() error {
			cm, err := cs.CoreV1().ConfigMaps(nsName).Get(context.Background(), cmName, metav1.GetOptions{})
			if err != nil {
				return err
			}

			mutate(cm)

			_, err = cs.CoreV1().ConfigMaps(nsName).Update(context.Background(), cm, metav1.UpdateOptions{})
			if err == nil {
				return fmt.Errorf("expected configmap update to be denied, but it succeeded")
			}

			msg := err.Error()
			for _, substring := range substrings {
				if !strings.Contains(msg, substring) {
					return fmt.Errorf("expected error to contain %q, got: %s", substring, msg)
				}
			}

			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	createServiceAndExpectAllowed := func(cs kubernetes.Interface, nsName string, svc *corev1.Service) {
		EventuallyCreation(func() error {
			_, err := cs.CoreV1().Services(nsName).Create(context.Background(), svc, metav1.CreateOptions{})

			return err
		}).Should(Succeed())
	}

	createServiceAndExpectDenied := func(cs kubernetes.Interface, nsName string, svc *corev1.Service, substrings ...string) {
		base := svc.DeepCopy()
		baseName := base.Name
		if baseName == "" {
			baseName = "svc"
		}

		Eventually(func() error {
			candidate := base.DeepCopy()
			candidate.Name = fmt.Sprintf("%s-%d", baseName, time.Now().UnixNano()%1e6)

			_, err := cs.CoreV1().Services(nsName).Create(context.Background(), candidate, metav1.CreateOptions{})
			if err == nil {
				_ = cs.CoreV1().Services(nsName).Delete(context.Background(), candidate.Name, metav1.DeleteOptions{})

				return fmt.Errorf("expected service create to be denied, but it succeeded")
			}

			if apierrors.IsAlreadyExists(err) {
				return fmt.Errorf("unexpected AlreadyExists: %v", err)
			}

			msg := err.Error()
			for _, substring := range substrings {
				if !strings.Contains(msg, substring) {
					return fmt.Errorf("expected error to contain %q, got: %s", substring, msg)
				}
			}

			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	createDeploymentAndExpectAllowed := func(nsName string, deploy *appsv1.Deployment) {
		owner := impersonationClient(
			tnt.Spec.Owners[0].UserSpec.Name,
			withDefaultGroups(nil),
		)

		deploy.Namespace = nsName

		EventuallyCreation(func() error {
			return owner.Create(context.Background(), deploy, &client.CreateOptions{})
		}).Should(Succeed())

		EventuallyDeletion(deploy)
	}

	createDeploymentAndExpectDenied := func(nsName string, deploy *appsv1.Deployment, substrings ...string) {
		base := deploy.DeepCopy()
		baseName := base.Name
		if baseName == "" {
			baseName = "deployment"
		}

		owner := impersonationClient(
			tnt.Spec.Owners[0].UserSpec.Name,
			withDefaultGroups(nil),
		)

		Eventually(func() error {
			candidate := base.DeepCopy()
			candidate.Name = fmt.Sprintf("%s-%d", baseName, time.Now().UnixNano()%1e6)
			candidate.Namespace = nsName
			candidate.Spec.Selector.MatchLabels["app"] = candidate.Name
			candidate.Spec.Template.Labels["app"] = candidate.Name

			err := owner.Create(context.Background(), candidate, &client.CreateOptions{})
			if err == nil {
				_ = owner.Delete(context.Background(), candidate)

				return fmt.Errorf("expected deployment create to be denied, but it succeeded")
			}

			msg := err.Error()
			for _, substring := range substrings {
				if !strings.Contains(msg, substring) {
					return fmt.Errorf("expected error to contain %q, got: %s", substring, msg)
				}
			}

			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	expectAuditEvent := func(
		cs kubernetes.Interface,
		namespace string,
		kind string,
		objectName string,
		substrings ...string,
	) {
		Eventually(func() error {
			evt, err := cs.CoreV1().Events(namespace).List(context.Background(), metav1.ListOptions{})
			if err != nil {
				return err
			}

			for _, e := range evt.Items {
				if e.Reason != events.ReasonNamespaceRuleAudit {
					continue
				}

				if e.InvolvedObject.Kind != kind {
					continue
				}

				eventObjectName := e.InvolvedObject.Name
				if eventObjectName != objectName && !strings.HasPrefix(eventObjectName, objectName+"-") {
					continue
				}

				message := e.Message

				matched := true
				for _, substring := range substrings {
					if !strings.Contains(message, substring) {
						matched = false

						break
					}
				}

				if matched {
					return nil
				}
			}

			return fmt.Errorf(
				"expected audit event for %s %q containing %q",
				kind,
				objectName,
				substrings,
			)
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	}

	BeforeEach(func() {
		tenantRules = baseTenantRules()
	})

	JustBeforeEach(func() {
		tnt = newTenant()

		EventuallyCreation(func() error {
			tnt.ResourceVersion = ""

			return k8sClient.Create(context.TODO(), tnt)
		}).Should(Succeed())

		TenantReady(tnt, metav1.ConditionTrue, defaultTimeoutInterval)
	})

	JustAfterEach(func() {
		EventuallyDeletion(tnt)
	})

	It("stores matching tenant metadata rules as independent status rule blocks", func() {
		ns := createNamespace(nil)

		expectNamespaceStatusRules(ns.GetName(), baseStatusRules())
	})

	It("stores namespace-selector matched metadata rules as additional independent status rule blocks", func() {
		ns := createNamespace(map[string]string{
			"environment": "prod",
		})

		want := baseStatusRules()
		want = append(want, expectedMetadataStatusRule{
			action: rules.ActionTypeAllow,
			apiGroups: []string{
				"*",
			},
			kinds: []string{
				"ConfigMap",
			},
			annotations: map[string]expectedMetadataPolicy{
				"example.corp/approval": {
					required: true,
					exact: [][]string{
						{
							"approved",
						},
					},
				},
			},
		})

		expectNamespaceStatusRules(ns.GetName(), want)
	})

	It("denies creation when a required label is missing", func() {
		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("required-label-missing", nil, nil),
			"metadata",
			"example.corp/tenant",
			"required",
		)
	})

	It("allows creation when a required label is present and exact value matches", func() {
		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"required-label-allowed",
				map[string]string{
					"example.corp/tenant": "prod",
				},
				nil,
			),
		)
	})

	It("denies creation when a required label is present but value is not allowed", func() {
		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"required-label-invalid",
				map[string]string{
					"example.corp/tenant": "stage",
				},
				nil,
			),
			"metadata",
			"example.corp/tenant",
			"stage",
			"not allowed",
		)
	})

	It("allows missing optional annotations but denies present non-matching annotation values", func() {
		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"optional-annotation-missing",
				map[string]string{
					"example.corp/tenant": "prod",
				},
				nil,
			),
		)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"optional-annotation-invalid",
				map[string]string{
					"example.corp/tenant": "prod",
				},
				map[string]string{
					"example.corp/cost-center": "BAD-1234",
				},
			),
			"metadata",
			"example.corp/cost-center",
			"BAD-1234",
			"not allowed",
		)
	})

	It("allows optional annotation values matching regex, exact, or combined matchers", func() {
		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"annotation-regex-allowed",
				map[string]string{
					"example.corp/tenant": "prod",
				},
				map[string]string{
					"example.corp/cost-center": "INV-1234",
				},
			),
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"annotation-exact-allowed",
				map[string]string{
					"example.corp/tenant": "prod",
				},
				map[string]string{
					"example.corp/cost-center": "test",
				},
			),
		)
	})

	It("matches label and annotation key expressions through the regex cache", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"v1",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					`example\.corp/label-.*`: metadataValueRule(false, metadataByExact("allowed")),
				},
				map[string]rules.MetadataValueRule{
					"example.corp/*": metadataValueRule(false, metadataByExpression("^INV-[0-9]{4}$")),
				},
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(cs, ns.Name, configMap(
			"key-regex-allowed",
			map[string]string{"example.corp/label-team": "allowed"},
			map[string]string{"example.corp/cost-center": "INV-1234"},
		))

		createConfigMapAndExpectDenied(cs, ns.Name, configMap(
			"key-regex-label-denied",
			map[string]string{"example.corp/label-team": "blocked"},
			nil,
		), "metadata", "example.corp/label-team", "blocked", "not allowed")

		createConfigMapAndExpectDenied(cs, ns.Name, configMap(
			"key-regex-annotation-denied",
			nil,
			map[string]string{"example.corp/cost-center": "BAD-1234"},
		), "metadata", "example.corp/cost-center", "BAD-1234", "not allowed")
	})

	It("requires Namespace to be explicitly included in kinds", func() {
		policy := map[string]rules.MetadataValueRule{
			"example.corp/namespace-policy": metadataValueRule(true, metadataByExact("allowed")),
		}

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(rules.ActionTypeAllow, "*", []string{"*"}, policy, nil),
		})
		createNamespace(nil)

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(rules.ActionTypeAllow, "*", []string{"*", "Namespace"}, policy, nil),
		})
		createNamespaceAndExpectDenied(
			nil,
			"metadata",
			"example.corp/namespace-policy",
			"required",
		)
		createNamespace(map[string]string{"example.corp/namespace-policy": "allowed"})
	})

	It("applies one metadata rule to multiple core kinds", func() {
		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("multi-kind-configmap-denied", nil, nil),
			"metadata",
			"example.corp/tenant",
			"required",
		)

		createServiceAndExpectDenied(
			cs,
			ns.Name,
			service("multi-kind-service-denied", nil, nil),
			"metadata",
			"example.corp/tenant",
			"required",
		)

		createServiceAndExpectAllowed(
			cs,
			ns.Name,
			service(
				"multi-kind-service-allowed",
				map[string]string{
					"example.corp/tenant": "prod",
				},
				nil,
			),
		)
	})

	It("treats empty apiVersion as core v1 and does not match grouped resources", Label("skip-on-openshift"), func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"",
				[]string{
					"*",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("core-v1-configmap-denied", nil, nil),
			"metadata",
			"env",
			"required",
		)

		deploy := deployment("apps-deployment-not-matched", nil, nil)
		deploy.Namespace = ns.Name

		createDeploymentAndExpectAllowed(ns.Name, deploy)
	})

	It("matches grouped apiVersion and selected kinds", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"apps/v1",
				[]string{
					"Deployment",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)

		createDeploymentAndExpectDenied(
			ns.Name,
			deployment("apps-deployment-missing-env", nil, nil),
			"metadata",
			"env",
			"required",
		)

		deploy := deployment(
			"apps-deployment-env-allowed",
			map[string]string{
				"env": "prod",
			},
			nil,
		)
		deploy.Namespace = ns.Name

		createDeploymentAndExpectAllowed(ns.Name, deploy)
	})

	It("denies a later matching deny rule after an earlier allow rule matched", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod", "test"),
					),
				},
				nil,
			),
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						false,
						metadataByExact("test"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"later-deny-prod-allowed",
				map[string]string{
					"env": "prod",
				},
				nil,
			),
		)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"later-deny-test-denied",
				map[string]string{
					"env": "test",
				},
				nil,
			),
			"metadata",
			"env",
			"test",
			"denied",
		)
	})

	It("allows a later matching allow rule after an earlier deny rule did not match", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						false,
						metadataByExact("blocked"),
					),
				},
				nil,
			),
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"later-allow-prod-allowed",
				map[string]string{
					"env": "prod",
				},
				nil,
			),
		)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"later-allow-blocked-denied",
				map[string]string{
					"env": "blocked",
				},
				nil,
			),
			"metadata",
			"env",
			"blocked",
			"denied",
		)
	})

	It("supports negated metadata matchers", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"team": metadataValueRule(
						false,
						metadataByNegatedExpression("^trusted-.*"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"negated-denied",
				map[string]string{
					"team": "untrusted",
				},
				nil,
			),
			"metadata",
			"team",
			"untrusted",
			"denied",
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"negated-allowed",
				map[string]string{
					"team": "trusted-platform",
				},
				nil,
			),
		)
	})

	It("audits matching metadata but does not deny when a separate allow rule matches", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAudit,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"example.corp/audit": metadataValueRule(
						false,
						metadataByExpression("^audit-.*"),
					),
				},
				nil,
			),
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		cm := configMap(
			"metadata-audit-allowed",
			map[string]string{
				"env":                "prod",
				"example.corp/audit": "audit-this",
			},
			nil,
		)

		createConfigMapAndExpectAllowed(cs, ns.Name, cm)

		expectAuditEvent(
			clusterAdminClient(),
			ns.Name,
			"ConfigMap",
			cm.Name,
			"metadata",
			"example.corp/audit",
			"audit-this",
		)
	})

	It("applies namespace-selector matched required annotation only to selected namespaces", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			selectedRule(
				map[string]string{
					"environment": "prod",
				},
				metadataRule(
					rules.ActionTypeAllow,
					"*",
					[]string{
						"ConfigMap",
					},
					nil,
					map[string]rules.MetadataValueRule{
						"example.corp/approval": metadataValueRule(
							true,
							metadataByExact("approved"),
						),
					},
				),
			),
		})

		devNS := createNamespace(map[string]string{
			"environment": "dev",
		})
		prodNS := createNamespace(map[string]string{
			"environment": "prod",
		})
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			devNS.Name,
			configMap("selected-rule-dev-allowed", nil, nil),
		)

		createConfigMapAndExpectDenied(
			cs,
			prodNS.Name,
			configMap("selected-rule-prod-denied", nil, nil),
			"metadata",
			"example.corp/approval",
			"required",
		)

		createConfigMapAndExpectAllowed(
			cs,
			prodNS.Name,
			configMap(
				"selected-rule-prod-allowed",
				nil,
				map[string]string{
					"example.corp/approval": "approved",
				},
			),
		)
	})

	It("denies an update when a metadata value becomes invalid", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod", "test"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		cm := configMap(
			"metadata-update-denied",
			map[string]string{
				"env": "prod",
			},
			nil,
		)

		createConfigMapAndExpectAllowed(cs, ns.Name, cm)

		updateConfigMapAndExpectDenied(
			cs,
			ns.Name,
			cm.Name,
			func(cm *corev1.ConfigMap) {
				cm.Labels["env"] = "stage"
			},
			"metadata",
			"env",
			"stage",
			"not allowed",
		)
	})

	It("supports required metadata without value constraints", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"presence-only": metadataValueRule(true),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("presence-only-missing", nil, nil),
			"metadata",
			"presence-only",
			"required",
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"presence-only-present",
				map[string]string{
					"presence-only": "any-value",
				},
				nil,
			),
		)
	})

	It("does not enforce rules for Capsule managed metadata keys", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					meta.TenantLabel: metadataValueRule(
						true,
						metadataByExact("some-other-tenant"),
					),
				},
				map[string]rules.MetadataValueRule{
					meta.ReconcileAnnotation: metadataValueRule(
						true,
						metadataByExact("must-not-matter"),
					),
				},
			),
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					meta.ManagedByCapsuleLabel: metadataValueRule(
						false,
						metadataByExact("blocked"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"managed-metadata-ignored",
				map[string]string{
					meta.ManagedByCapsuleLabel: "blocked",
				},
				nil,
			),
		)
	})

	It("skips generic metadata validation for controller-managed objects", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"controller-managed-skipped",
				map[string]string{
					meta.NewManagedByCapsuleLabel: meta.ValueController,
					"env":                         "prod",
				},
				nil,
			),
		)
	})

	It("enforces non-skipped objects even when a similar managed-by value does not match the skip rule", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"managed-by-other-not-skipped",
				map[string]string{
					meta.ManagedByCapsuleLabel: "human",
				},
				nil,
			),
			"metadata",
			"env",
			"required",
		)
	})

	It("supports combined exact and regex value matchers for metadata labels", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{
					"ConfigMap",
				},
				map[string]rules.MetadataValueRule{
					"release": metadataValueRule(
						true,
						metadataByMatch(
							[]string{
								"stable",
							},
							"^release-[0-9]+$",
						),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"combined-exact-allowed",
				map[string]string{
					"release": "stable",
				},
				nil,
			),
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"combined-regex-allowed",
				map[string]string{
					"release": "release-42",
				},
				nil,
			),
		)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"combined-denied",
				map[string]string{
					"release": "canary",
				},
				nil,
			),
			"metadata",
			"release",
			"canary",
			"not allowed",
		)
	})

	It("treats optional allow metadata as non-required but still validates it when present", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"optional-env": metadataValueRule(
						false,
						metadataByExact("prod", "test"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap("optional-label-missing-allowed", nil, nil),
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"optional-label-valid-allowed",
				map[string]string{
					"optional-env": "prod",
				},
				nil,
			),
		)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"optional-label-invalid-denied",
				map[string]string{
					"optional-env": "stage",
				},
				nil,
			),
			"metadata",
			"optional-env",
			"stage",
			"not allowed",
		)
	})

	It("does not treat required on deny rules as a presence requirement", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"blocked": metadataValueRule(
						true,
						metadataByExact("true"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap("deny-required-missing-allowed", nil, nil),
		)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"deny-required-present-denied",
				map[string]string{
					"blocked": "true",
				},
				nil,
			),
			"metadata",
			"blocked",
			"true",
			"denied",
		)
	})

	It("does not treat required on audit rules as a presence requirement", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAudit,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"audited": metadataValueRule(
						true,
						metadataByExact("true"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap("audit-required-missing-allowed", nil, nil),
		)

		cm := configMap(
			"audit-required-present-allowed",
			map[string]string{
				"audited": "true",
			},
			nil,
		)

		createConfigMapAndExpectAllowed(cs, ns.Name, cm)

		expectAuditEvent(
			clusterAdminClient(),
			ns.Name,
			"ConfigMap",
			cm.Name,
			"metadata",
			"audited",
			"true",
		)
	})

	It("enforces multiple required metadata keys independently and reports the missing key", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
					"team": metadataValueRule(
						true,
						metadataByExact("platform"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"multi-required-team-missing",
				map[string]string{
					"env": "prod",
				},
				nil,
			),
			"metadata",
			"team",
			"required",
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"multi-required-all-present",
				map[string]string{
					"env":  "prod",
					"team": "platform",
				},
				nil,
			),
		)
	})

	It("denies update when a required label is removed", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		cm := configMap(
			"required-label-remove-denied",
			map[string]string{
				"env": "prod",
			},
			nil,
		)

		createConfigMapAndExpectAllowed(cs, ns.Name, cm)

		updateConfigMapAndExpectDenied(
			cs,
			ns.Name,
			cm.Name,
			func(cm *corev1.ConfigMap) {
				delete(cm.Labels, "env")
			},
			"metadata",
			"env",
			"required",
		)
	})

	It("skips empty metadata values during value evaluation", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"empty-ok": metadataValueRule(
						true,
						metadataByExact(""),
					),
					"empty-not-ok": metadataValueRule(
						false,
						metadataByExact("prod"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"empty-label-exact-allowed",
				map[string]string{
					"empty-ok": "",
				},
				nil,
			),
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"empty-label-invalid-skipped",
				map[string]string{
					"empty-ok":     "",
					"empty-not-ok": "",
				},
				nil,
			),
		)
	})

	It("matches apiVersion wildcard and kind wildcard across core and grouped resources", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"*"},
				map[string]rules.MetadataValueRule{
					"global-required": metadataValueRule(
						true,
						metadataByExact("yes"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("wildcard-core-denied", nil, nil),
			"metadata",
			"global-required",
			"required",
		)

		createDeploymentAndExpectDenied(
			ns.Name,
			deployment("wildcard-grouped-denied", nil, nil),
			"metadata",
			"global-required",
			"required",
		)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"wildcard-core-allowed",
				map[string]string{
					"global-required": "yes",
				},
				nil,
			),
		)
	})

	It("matches kind wildcard only inside default core v1 apiVersion", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"",
				[]string{"*"},
				map[string]rules.MetadataValueRule{
					"core-required": metadataValueRule(
						true,
						metadataByExact("yes"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("core-wildcard-configmap-denied", nil, nil),
			"metadata",
			"core-required",
			"required",
		)

		deploy := deployment("core-wildcard-deployment-not-matched", nil, nil)
		deploy.Namespace = ns.Name

		createDeploymentAndExpectAllowed(ns.Name, deploy)
	})

	It("matches partial kind wildcard without matching unrelated kinds", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"v1",
				[]string{"*Map"},
				map[string]rules.MetadataValueRule{
					"map-required": metadataValueRule(
						true,
						metadataByExact("yes"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap("partial-kind-configmap-denied", nil, nil),
			"metadata",
			"map-required",
			"required",
		)

		createServiceAndExpectAllowed(
			cs,
			ns.Name,
			service("partial-kind-service-not-matched", nil, nil),
		)
	})

	It("does not let one optional matching key satisfy another required key", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"optional": metadataValueRule(
						false,
						metadataByExact("ok"),
					),
					"required": metadataValueRule(
						true,
						metadataByExact("ok"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"optional-does-not-satisfy-required",
				map[string]string{
					"optional": "ok",
				},
				nil,
			),
			"metadata",
			"required",
			"required",
		)
	})

	It("does not let a matching annotation satisfy a required label with the same key", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"shared-key": metadataValueRule(
						true,
						metadataByExact("label-value"),
					),
				},
				map[string]rules.MetadataValueRule{
					"shared-key": metadataValueRule(
						false,
						metadataByExact("annotation-value"),
					),
				},
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"annotation-does-not-satisfy-label",
				nil,
				map[string]string{
					"shared-key": "annotation-value",
				},
			),
			"metadata",
			"metadata.labels",
			"shared-key",
			"required",
		)
	})

	It("ignores managed annotation prefixes when collecting controlled metadata entries", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				nil,
				map[string]rules.MetadataValueRule{
					meta.ResourceQuotaAnnotationPrefix + "cpu": metadataValueRule(
						true,
						metadataByExact("must-not-matter"),
					),
					meta.ResourceUsedAnnotationPrefix + "memory": metadataValueRule(
						true,
						metadataByExact("must-not-matter"),
					),
				},
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap("managed-prefix-annotations-ignored", nil, nil),
		)
	})

	It("skips controller-managed objects even when a deny rule would otherwise match", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"blocked": metadataValueRule(
						false,
						metadataByExact("true"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"controller-managed-deny-skipped",
				map[string]string{
					meta.ManagedByCapsuleLabel: meta.ValueController,
					"blocked":                  "false",
				},
				nil,
			),
		)
	})

	It("still enforces controller skip rule case-sensitively", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"blocked": metadataValueRule(
						false,
						metadataByExact("true"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"controller-managed-case-sensitive",
				map[string]string{
					meta.ManagedByCapsuleLabel: "Controller",
					"blocked":                  "true",
				},
				nil,
			),
			"metadata",
			"blocked",
			"true",
			"denied",
		)
	})

	It("allows value after later allow overrides an earlier deny for the same key", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						false,
						metadataByExact("test"),
					),
				},
				nil,
			),
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("test"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectAllowed(
			cs,
			ns.Name,
			configMap(
				"later-allow-overrides-earlier-deny",
				map[string]string{
					"env": "test",
				},
				nil,
			),
		)
	})

	It("denies value after later deny overrides an earlier allow for the same key", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						true,
						metadataByExact("test"),
					),
				},
				nil,
			),
			metadataRule(
				rules.ActionTypeDeny,
				"*",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"env": metadataValueRule(
						false,
						metadataByExact("test"),
					),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		createConfigMapAndExpectDenied(
			cs,
			ns.Name,
			configMap(
				"later-deny-overrides-earlier-allow",
				map[string]string{
					"env": "test",
				},
				nil,
			),
			"metadata",
			"env",
			"test",
			"denied",
		)
	})

	It("applies Namespace defaults only when Namespace is explicitly targeted", func() {
		defaultValue := "baseline"
		policy := map[string]rules.MetadataValueRule{
			"example.corp/namespace-default": {
				Default: &defaultValue,
			},
		}

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(rules.ActionTypeAllow, "*", []string{"*"}, policy, nil),
		})
		withoutExplicitKind := createNamespace(nil)

		Eventually(func(g Gomega) {
			current := &corev1.Namespace{}
			g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: withoutExplicitKind.Name}, current)).To(Succeed())
			g.Expect(current.Labels).NotTo(HaveKey("example.corp/namespace-default"))
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(rules.ActionTypeAllow, "*", []string{"*", "Namespace"}, policy, nil),
		})
		waitForProjectedMetadata(withoutExplicitKind.Name, "example.corp/namespace-default", &defaultValue, nil)

		withExplicitKind := createNamespace(nil)
		Eventually(func(g Gomega) {
			current := &corev1.Namespace{}
			g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: withExplicitKind.Name}, current)).To(Succeed())
			g.Expect(current.Labels).To(HaveKeyWithValue("example.corp/namespace-default", defaultValue))
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	})

	It("applies defaults, preserves supplied values, and lets managed values win in combination", func() {
		defaultOnly := "defaulted"
		combinedDefault := "fallback"
		combinedManaged := "controlled"
		standaloneManaged := "managed-annotation"

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"v1",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"example.corp/default": {
						Default: &defaultOnly,
					},
					"example.corp/combined": {
						Default: &combinedDefault,
						Managed: &combinedManaged,
					},
				},
				map[string]rules.MetadataValueRule{
					"example.corp/managed": {
						Managed: &standaloneManaged,
					},
				},
			),
		})

		ns := createNamespace(nil)
		waitForProjectedMetadata(ns.Name, "example.corp/combined", &combinedDefault, &combinedManaged)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		created, err := cs.CoreV1().ConfigMaps(ns.Name).Create(context.Background(), configMap(
			"metadata-default-managed-combination",
			map[string]string{
				"example.corp/combined": "user-value",
			},
			map[string]string{
				"example.corp/managed": "user-value",
			},
		), metav1.CreateOptions{})
		Expect(err).NotTo(HaveOccurred())
		Expect(created.Labels).To(HaveKeyWithValue("example.corp/default", defaultOnly))
		Expect(created.Labels).To(HaveKeyWithValue("example.corp/combined", combinedManaged))
		Expect(created.Annotations).To(HaveKeyWithValue("example.corp/managed", standaloneManaged))

		preserved, err := cs.CoreV1().ConfigMaps(ns.Name).Create(context.Background(), configMap(
			"metadata-default-preserves-user-value",
			map[string]string{
				"example.corp/default": "supplied",
			},
			nil,
		), metav1.CreateOptions{})
		Expect(err).NotTo(HaveOccurred())
		Expect(preserved.Labels).To(HaveKeyWithValue("example.corp/default", "supplied"))
		Expect(preserved.Labels).To(HaveKeyWithValue("example.corp/combined", combinedManaged))
		Expect(preserved.Annotations).To(HaveKeyWithValue("example.corp/managed", standaloneManaged))
	})

	It("reconciles standalone managed metadata and removes it when the rule is removed", func() {
		managedLabel := "managed-label"
		managedAnnotation := "managed-annotation"
		managedNamespace := "managed-namespace"

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"v1",
				[]string{"ConfigMap"},
				map[string]rules.MetadataValueRule{
					"example.corp/lifecycle": {Managed: &managedLabel},
				},
				map[string]rules.MetadataValueRule{
					"example.corp/lifecycle": {Managed: &managedAnnotation},
				},
			),
			metadataRule(
				rules.ActionTypeAllow,
				"v1",
				[]string{"Namespace"},
				map[string]rules.MetadataValueRule{
					"example.corp/namespace-lifecycle": {Managed: &managedNamespace},
				},
				nil,
			),
		})

		ns := createNamespace(map[string]string{"example.corp/user-owned": "keep"})
		waitForProjectedMetadata(ns.Name, "example.corp/lifecycle", nil, &managedLabel)
		cs := ownerClient(tnt.Spec.Owners[0].UserSpec)

		cm, err := cs.CoreV1().ConfigMaps(ns.Name).Create(context.Background(), configMap(
			"managed-metadata-lifecycle",
			map[string]string{"example.corp/user-owned": "keep"},
			map[string]string{"example.corp/user-annotation": "keep"},
		), metav1.CreateOptions{})
		Expect(err).NotTo(HaveOccurred())

		Eventually(func(g Gomega) {
			current, getErr := cs.CoreV1().ConfigMaps(ns.Name).Get(context.Background(), cm.Name, metav1.GetOptions{})
			g.Expect(getErr).NotTo(HaveOccurred())
			g.Expect(current.Labels).To(HaveKeyWithValue("example.corp/lifecycle", managedLabel))
			g.Expect(current.Annotations).To(HaveKeyWithValue("example.corp/lifecycle", managedAnnotation))

			currentNamespace := &corev1.Namespace{}
			g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: ns.Name}, currentNamespace)).To(Succeed())
			g.Expect(currentNamespace.Labels).To(HaveKeyWithValue("example.corp/namespace-lifecycle", managedNamespace))
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())

		updateTenantRules(nil)

		Eventually(func(g Gomega) {
			current, getErr := cs.CoreV1().ConfigMaps(ns.Name).Get(context.Background(), cm.Name, metav1.GetOptions{})
			g.Expect(getErr).NotTo(HaveOccurred())
			g.Expect(current.Labels).NotTo(HaveKey("example.corp/lifecycle"))
			g.Expect(current.Annotations).NotTo(HaveKey("example.corp/lifecycle"))
			g.Expect(current.Labels).To(HaveKeyWithValue("example.corp/user-owned", "keep"))
			g.Expect(current.Annotations).To(HaveKeyWithValue("example.corp/user-annotation", "keep"))

			currentNamespace := &corev1.Namespace{}
			g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: ns.Name}, currentNamespace)).To(Succeed())
			g.Expect(currentNamespace.Labels).NotTo(HaveKey("example.corp/namespace-lifecycle"))
			g.Expect(currentNamespace.Labels).To(HaveKeyWithValue("example.corp/user-owned", "keep"))
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	})

	It("filters mutation and validation by audience across metadata, Service, and workload rules", func() {
		defaultValue := "owner-default"
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			{
				NamespaceRuleBodyNamespace: &rules.NamespaceRuleBodyNamespace{
					Audience: []rules.Audience{{Kind: rules.AudienceKindUser, Name: ownerName}},
					Enforce: &rules.NamespaceRuleEnforceBody{
						Action: rules.ActionTypeDeny,
						Metadata: []rules.MetadataRule{{
							VersionKinds: runtime.VersionKinds{APIGroups: []string{"v1"}, Kinds: []string{"ConfigMap"}},
							Labels: map[string]rules.MetadataValueRule{
								"example.corp/audience-default": {Default: &defaultValue},
								"example.corp/audience-blocked": metadataValueRule(false, metadataByExact("true")),
							},
						}},
					},
				},
			},
			{
				NamespaceRuleBodyNamespace: &rules.NamespaceRuleBodyNamespace{
					Audience: []rules.Audience{{Kind: rules.AudienceKindGroup, Name: ownerName}},
					Enforce: &rules.NamespaceRuleEnforceBody{
						Action: rules.ActionTypeDeny,
						Services: rules.NamespaceRuleEnforceServicesBody{
							Types: []rules.ServiceType{rules.ServiceTypeClusterIP},
						},
					},
				},
			},
			{
				NamespaceRuleBodyNamespace: &rules.NamespaceRuleBodyNamespace{
					Audience: []rules.Audience{{Kind: rules.AudienceKindCustom, Name: string(rules.CustomAudienceTenantOwner)}},
					Enforce: &rules.NamespaceRuleEnforceBody{
						Action: rules.ActionTypeDeny,
						Workloads: rules.NamespaceRuleEnforceWorkloadsBody{
							QoSClasses: []corev1.PodQOSClass{corev1.PodQOSBestEffort},
						},
					},
				},
			},
		})

		ns := createNamespace(nil)
		waitForProjectedMetadata(ns.Name, "example.corp/audience-default", &defaultValue, nil)
		owner := ownerClient(tnt.Spec.Owners[0].UserSpec)
		admin := clusterAdminClient()

		ownerCM, err := owner.CoreV1().ConfigMaps(ns.Name).Create(context.Background(), configMap(
			"audience-owner-mutated",
			nil,
			nil,
		), metav1.CreateOptions{})
		Expect(err).NotTo(HaveOccurred())
		Expect(ownerCM.Labels).To(HaveKeyWithValue("example.corp/audience-default", defaultValue))

		createConfigMapAndExpectDenied(owner, ns.Name, configMap(
			"audience-owner-denied",
			map[string]string{"example.corp/audience-blocked": "true"},
			nil,
		), "example.corp/audience-blocked", "denied")

		adminCM, err := admin.CoreV1().ConfigMaps(ns.Name).Create(context.Background(), configMap(
			"audience-admin-bypasses-metadata",
			map[string]string{"example.corp/audience-blocked": "true"},
			nil,
		), metav1.CreateOptions{})
		Expect(err).NotTo(HaveOccurred())
		Expect(adminCM.Labels).NotTo(HaveKey("example.corp/audience-default"))

		createServiceAndExpectDenied(owner, ns.Name, service("audience-owner-service-denied", nil, nil), "ClusterIP", "denied")
		createServiceAndExpectAllowed(admin, ns.Name, service("audience-admin-service-allowed", nil, nil))

		ownerPod := MakePod(ns.Name, "audience-owner-pod-denied", nil, nil, "nginx:1.25", "", "")
		Eventually(func() error {
			_, createErr := owner.CoreV1().Pods(ns.Name).Create(context.Background(), ownerPod, metav1.CreateOptions{})
			if createErr == nil {
				_ = owner.CoreV1().Pods(ns.Name).Delete(context.Background(), ownerPod.Name, metav1.DeleteOptions{})
				return fmt.Errorf("expected TenantOwner audience to deny the BestEffort Pod")
			}
			if !strings.Contains(createErr.Error(), "BestEffort") || !strings.Contains(createErr.Error(), "denied") {
				return createErr
			}
			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())

		adminPod := MakePod(ns.Name, "audience-admin-pod-allowed", nil, nil, "nginx:1.25", "", "")
		EventuallyCreation(func() error {
			_, createErr := admin.CoreV1().Pods(ns.Name).Create(context.Background(), adminPod, metav1.CreateOptions{})
			return createErr
		}).Should(Succeed())
	})

	It("rejects forbidden namespace metadata injected through the status subresource", func() {
		const policyKey = "pod-security.kubernetes.io/enforce"

		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"v1",
				[]string{"Namespace"},
				map[string]rules.MetadataValueRule{
					policyKey: metadataValueRule(true, metadataByExact("baseline", "restricted")),
				},
				nil,
			),
		})

		ns := createNamespace(map[string]string{policyKey: "baseline"})
		waitForProjectedMetadata(ns.Name, policyKey, nil, nil)

		createNamespaceStatusRBACForOwner(tnt)
		DeferCleanup(deleteNamespaceStatusRBACForOwner, tnt)

		owner := ownerClient(tnt.Spec.Owners[0].UserSpec)
		patchStatus := func(value string) error {
			patch := []byte(fmt.Sprintf(
				`[{"op":"add","path":"/metadata/labels/pod-security.kubernetes.io~1enforce","value":%q}]`,
				value,
			))
			_, err := owner.CoreV1().Namespaces().Patch(
				context.Background(),
				ns.Name,
				k8stypes.JSONPatchType,
				patch,
				metav1.PatchOptions{},
				"status",
			)

			return err
		}

		By("allowing a compliant metadata update through namespaces/status")
		Eventually(func() error {
			return patchStatus("restricted")
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())

		By("rejecting a forbidden metadata update through namespaces/status")
		Eventually(func() error {
			err := patchStatus("privileged")
			if err == nil {
				return fmt.Errorf("expected namespace status patch to be denied")
			}
			if !strings.Contains(err.Error(), policyKey) ||
				!strings.Contains(err.Error(), "privileged") ||
				!strings.Contains(err.Error(), "not allowed") {
				return err
			}

			return nil
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())

		By("preserving the last allowed metadata value")
		Eventually(func(g Gomega) {
			current := &corev1.Namespace{}
			g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: ns.Name}, current)).To(Succeed())
			g.Expect(current.Labels).To(HaveKeyWithValue(policyKey, "restricted"))
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	})

	It("ignores metadata enforcement for non-Namespace subresource updates", func() {
		updateTenantRules([]*rules.NamespaceRuleBodyTenant{
			metadataRule(
				rules.ActionTypeAllow,
				"*",
				[]string{"*"},
				map[string]rules.MetadataValueRule{
					"example.corp/subresource-required": metadataValueRule(true, metadataByExact("true")),
				},
				nil,
			),
		})

		ns := createNamespace(nil)
		owner := ownerClient(tnt.Spec.Owners[0].UserSpec)
		deploy := deployment(
			"metadata-scale-subresource",
			map[string]string{"example.corp/subresource-required": "true"},
			nil,
		)
		deploy.Namespace = ns.Name

		EventuallyCreation(func() error {
			_, err := owner.AppsV1().Deployments(ns.Name).Create(context.Background(), deploy, metav1.CreateOptions{})
			return err
		}).Should(Succeed())

		Eventually(func() error {
			scale, err := owner.AppsV1().Deployments(ns.Name).GetScale(context.Background(), deploy.Name, metav1.GetOptions{})
			if err != nil {
				return err
			}
			scale.Spec.Replicas = 2
			_, err = owner.AppsV1().Deployments(ns.Name).UpdateScale(context.Background(), deploy.Name, scale, metav1.UpdateOptions{})
			return err
		}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
	})
})
