Files
cozystack/hack/e2e-chainsaw/securitygroup/chainsaw-test.yaml
T
Myasnikov DaniilandClaude Fable 5 dd2f89d208 test(sdn): port the securitygroup and serviceexposure suites to Chainsaw
Main added securitygroup.bats (#2922 membership model) and
serviceexposure.bats (#3081 ExposureClass/ServiceExposure) after the
Chainsaw migration branch was cut.

- securitygroup: two Tests — the aggregated-API projection round-trip
  (backing CNP marker label, empty-value membership endpointSelector,
  lineage fromApp + membership fromSG peers, 1:1 rule translation, the
  view hiding storage internals, unmarked-CNP invisibility via an error
  op, delete propagation) and the controller membership-label
  stamp/clear lifecycle. Only the attachments annotation stays a jq
  script (it is a JSON string). Chainsaw auto-cleanup covers every
  fixture even on mid-test failure — the bats had no teardown hook and
  leaked its fixtures.
- serviceexposure: the externalIPs backend resolve/Ready/assignedIPs
  path with the no-MetalLB-pool negative as an error op (ordered after
  resolvedBackend so it cannot false-pass), and the finalizer-removal
  test collapsed onto the delete op itself, which waits for full
  disappearance.
- selection: kubernetes-application now also maps to the two OIDC
  render-side suites (they exercise the same app chart — a gap main's
  bats selection had too); the new dirs enter all_apps discovery
  automatically. Selector unit tests extended and green (13/13 under
  cozytest).
- README: suites list updated.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-07-08 18:24:24 +05:00

196 lines
6.5 KiB
YAML

# Chainsaw port of hack/e2e-apps/securitygroup.bats.
#
# Exercises the SecurityGroup membership model against a live cluster. Two
# things unit tests cannot prove: that the in-tree CiliumNetworkPolicy mirror
# (membership endpointSelector, app/SG peer selectors, attachments annotation)
# round-trips against the real cilium.io/v2 CRD, and that the
# securitygroup-controller actually stamps the membership label onto an
# attached application's pods.
#
# Everything both Tests create is chainsaw-applied, so auto-cleanup reclaims
# it even on mid-test failure — strictly better than the bats, which had no
# teardown hook and leaked its fixtures on failure. The one operator-created
# object (the backing CNP) is the same storage object as the tracked
# SecurityGroup, so no finally block is needed anywhere.
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: securitygroup-projection
spec:
catch:
- events: {}
- describe:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
name: sg-e2e
steps:
- name: create-securitygroup
try:
- apply:
file: securitygroup.yaml
- name: assert-backing-cnp
try:
# The backing CNP must materialise with the marker label, the group's own
# membership label as endpointSelector (the EMPTY value must round-trip
# against the real cilium.io/v2 CRD), fromApp projected to the three
# lineage labels, fromSG to the peer group's membership label (index
# order fromApp-then-fromSG is code-guaranteed by projectIngress), and
# the rule list translated 1:1 (port is a string in the CRD).
- assert:
timeout: 1m
resource:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: sg-e2e
labels:
sdn.cozystack.io/securitygroup: "true"
spec:
endpointSelector:
matchLabels:
securitygroup.sdn.cozystack.io/sg-e2e: ""
(ingress[0].fromEndpoints[0].matchLabels):
apps.cozystack.io/application.group: apps.cozystack.io
apps.cozystack.io/application.kind: Kubernetes
apps.cozystack.io/application.name: web
(ingress[0].fromEndpoints[1].matchLabels):
securitygroup.sdn.cozystack.io/sg-frontend-e2e: ""
(ingress[0].toPorts[0].ports[0].port): "5432"
(ingress[0].toPorts[0].ports[0].protocol): TCP
# The attachments annotation is a JSON *string* on the backing policy —
# parsed with jq, exactly like the bats (no reliance on JMESPath JSON
# parsing in chainsaw v0.2.15).
- script:
timeout: 1m
content: |
set -eu
att=$(kubectl -n "$NAMESPACE" get ciliumnetworkpolicy sg-e2e \
-o jsonpath='{.metadata.annotations.sdn\.cozystack\.io/attachments}')
echo "$att" | jq -e '.[0].kind == "Postgres" and .[0].name == "db"' >/dev/null
check:
($error == null): true
- name: assert-securitygroup-view
try:
# The SecurityGroup view reconstructs attachments and peers, and HIDES the
# internal marker label + storage annotation.
- assert:
timeout: 1m
resource:
apiVersion: sdn.cozystack.io/v1alpha1
kind: SecurityGroup
metadata:
name: sg-e2e
spec:
(attachments[0].kind): Postgres
(attachments[0].name): db
(ingress[0].fromApp[0].name): web
(ingress[0].fromSG[0]): sg-frontend-e2e
(metadata.labels."sdn.cozystack.io/securitygroup" == null): true
(metadata.annotations."sdn.cozystack.io/attachments" == null): true
- name: unmarked-cnp-invisible
try:
- apply:
file: plain-cnp.yaml
# The aggregated API filters by the marker label synchronously, so
# non-existence of the view is deterministic.
- error:
timeout: 30s
resource:
apiVersion: sdn.cozystack.io/v1alpha1
kind: SecurityGroup
metadata:
name: plain-cnp-e2e
- name: delete-propagates
try:
# Deleting the SecurityGroup removes its backing policy (the delete op
# waits for full disappearance of the view); the unmarked CNP survives.
- delete:
timeout: 1m
ref:
apiVersion: sdn.cozystack.io/v1alpha1
kind: SecurityGroup
name: sg-e2e
- error:
timeout: 1m
resource:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: sg-e2e
- assert:
timeout: 30s
resource:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: plain-cnp-e2e
---
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: securitygroup-membership
spec:
catch:
- events: {}
- describe:
apiVersion: v1
kind: Pod
name: sg-member-pod-e2e
- podLogs:
namespace: cozy-securitygroup-controller
selector: app=securitygroup-controller
tail: 100
steps:
- name: create-member-pod-and-securitygroup
try:
- apply:
file: member-pod.yaml
- apply:
file: securitygroup-member.yaml
- name: membership-label-stamped
try:
# The controller must stamp the membership label onto the member pod;
# the value is the empty string (reconciler sets pod.Labels[key] = "").
- assert:
timeout: 2m
resource:
apiVersion: v1
kind: Pod
metadata:
name: sg-member-pod-e2e
labels:
securitygroup.sdn.cozystack.io/sg-member-e2e: ""
- name: delete-clears-membership
try:
# Deleting the SecurityGroup while a pod is still a member must strip the
# membership label off that pod (the controller's finalizer runs before
# the backing policy is garbage-collected), leaving no orphaned label.
# This is the delete-with-members path, distinct from detach.
- delete:
timeout: 2m
ref:
apiVersion: sdn.cozystack.io/v1alpha1
kind: SecurityGroup
name: sg-member-e2e
- error:
timeout: 1m
resource:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: sg-member-e2e
- assert:
timeout: 1m
resource:
apiVersion: v1
kind: Pod
metadata:
name: sg-member-pod-e2e
(metadata.labels."securitygroup.sdn.cozystack.io/sg-member-e2e" == null): true