Skip to content

Commit 23c8dab

Browse files
fix(platform): document --namespace bypass and add VAP unit tests
Address review feedback from @lllamnyp on packages/core/platform/templates/ deletion-protection.yaml: The bypass instructions in both the template-author-facing comment and the user-facing CEL message did `kubectl label <kind> <name>` with no --namespace flag. Several protected objects are namespaced (cozystack-version ConfigMap, cozystack-packages Repository, tenant-root HelmRelease), so an operator who copies the documented command verbatim against their default context gets a "not found" error and concludes that the bypass mechanism is broken. Updated both call sites to show --namespace <ns> with an explicit "(omit for cluster-scoped resources)" caveat. The reviewer also flagged that the VAP contract is otherwise unasserted by unit tests. Add packages/core/platform/tests/deletion_protection_test.yaml covering: - both the VAP and the Binding carry platform.cozystack.io/no-delete=true on themselves (the self-protection contract) - failurePolicy is intentionally absent on the VAP - the deny message contains the bypass command WITH --namespace and the cluster-scoped caveat (regression catch for this fix; verified failing when --namespace is dropped from the template) - the Binding's objectSelector + validationActions: [Deny] still match the no-delete label Wire packages/core/platform/Makefile's test target to helm unittest so hack/helm-unit-tests.sh actually runs the new suite in CI (the existing tests/ files were orphaned without it). Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
1 parent 6026857 commit 23c8dab

3 files changed

Lines changed: 67 additions & 3 deletions

File tree

packages/core/platform/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ reconcile: apply
1414
diff:
1515
cozyhr diff --namespace $(NAMESPACE) $(NAME)
1616

17+
test:
18+
helm unittest .
19+
1720
image: image-migrations
1821

1922
image-migrations:

packages/core/platform/templates/deletion-protection.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
gate below keeps the template renderable on clusters that pre-date 1.30
88
(the install simply skips the guardrail there).
99

10-
Bypass: remove the label, then delete.
11-
kubectl label <kind> <name> platform.cozystack.io/no-delete-
10+
Bypass: remove the label, then delete. Pass --namespace for namespaced
11+
resources (omit it for cluster-scoped objects like CRDs and Namespaces).
12+
kubectl label <kind> <name> --namespace <ns> platform.cozystack.io/no-delete-
1213

1314
failurePolicy is intentionally omitted: the validation expression is the
1415
literal `false`, so CEL evaluation cannot fail and the default (Fail) is
@@ -35,7 +36,8 @@ spec:
3536
message: >-
3637
Deletion blocked: object carries platform.cozystack.io/no-delete=true.
3738
To bypass, first remove the label:
38-
kubectl label <kind> <name> platform.cozystack.io/no-delete-
39+
kubectl label <kind> <name> --namespace <ns> platform.cozystack.io/no-delete-
40+
(omit --namespace for cluster-scoped resources)
3941
---
4042
apiVersion: admissionregistration.k8s.io/v1
4143
kind: ValidatingAdmissionPolicyBinding
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
suite: deletion-protection VAP message and self-label coverage
2+
templates:
3+
- templates/deletion-protection.yaml
4+
release:
5+
name: cozystack
6+
namespace: cozy-system
7+
capabilities:
8+
apiVersions:
9+
- admissionregistration.k8s.io/v1/ValidatingAdmissionPolicy
10+
tests:
11+
- it: ValidatingAdmissionPolicy carries the deletion-protection label on itself
12+
documentSelector:
13+
path: kind
14+
value: ValidatingAdmissionPolicy
15+
asserts:
16+
- equal:
17+
path: metadata.labels["platform.cozystack.io/no-delete"]
18+
value: "true"
19+
20+
- it: ValidatingAdmissionPolicyBinding carries the deletion-protection label on itself
21+
documentSelector:
22+
path: kind
23+
value: ValidatingAdmissionPolicyBinding
24+
asserts:
25+
- equal:
26+
path: metadata.labels["platform.cozystack.io/no-delete"]
27+
value: "true"
28+
29+
- it: failurePolicy is intentionally unset on the VAP
30+
documentSelector:
31+
path: kind
32+
value: ValidatingAdmissionPolicy
33+
asserts:
34+
- notExists:
35+
path: spec.failurePolicy
36+
37+
- it: the deny message documents the bypass with the --namespace flag
38+
documentSelector:
39+
path: kind
40+
value: ValidatingAdmissionPolicy
41+
asserts:
42+
- matchRegex:
43+
path: spec.validations[0].message
44+
pattern: 'kubectl label <kind> <name> --namespace <ns> platform\.cozystack\.io/no-delete-'
45+
- matchRegex:
46+
path: spec.validations[0].message
47+
pattern: 'omit --namespace for cluster-scoped resources'
48+
49+
- it: binding selects on the no-delete label and denies on match
50+
documentSelector:
51+
path: kind
52+
value: ValidatingAdmissionPolicyBinding
53+
asserts:
54+
- equal:
55+
path: spec.matchResources.objectSelector.matchLabels["platform.cozystack.io/no-delete"]
56+
value: "true"
57+
- equal:
58+
path: spec.validationActions[0]
59+
value: Deny

0 commit comments

Comments
 (0)