test(kubernetes): port the Phase-1 OIDC render-side suites to Chainsaw

Main added kubernetes-oidc-system.bats and
kubernetes-oidc-customconfig.bats after the Chainsaw migration branch
was cut; without a port the 260 lines of coverage would vanish with
the hack/e2e-apps/ deletion.

Both are light cluster e2e (apply CR -> assert rendered objects; no
Kamaji bringup, minReplicas: 0), exactly Chainsaw's declarative shape:
- System mode: KamajiControlPlane carries --authentication-config +
  the chart-owned volume/mount; the AuthenticationConfiguration Secret
  carries the cozy-realm issuer (regex, script step) + per-cluster
  audience; per-cluster KeycloakClient/KeycloakClientScope land in the
  cozy realm
- CustomConfig: the flag is still wired; the Secret carries the
  tenant-supplied issuer and NOT the cozy realm (fail-loud negation);
  no Keycloak objects and no pre-rendered OIDC kubeconfig Secret,
  expressed as error ops ordered after the positive asserts so an
  unreconciled HR cannot false-pass them

The port also sheds two latent bats bugs: cozytest defines no skip()
(the Keycloak guard would have died with exit 127 had it ever fired)
and the api-resources group probe exits 0 even when the group is
absent — the chart capability-gates Keycloak rendering and CI always
ships the operator, so the asserts are unconditional here.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This commit is contained in:
Myasnikov DaniilandClaude Fable 5 committed 2026-07-08 18:20:20 +05:00
1 parent 6c76a462a0
commit cac07db8fc
4 files changed
+322

No files matched your search

@@ -0,0 +1,117 @@
# Chainsaw port of hack/e2e-apps/kubernetes-oidc-customconfig.bats.
#
# Phase-1 OIDC CustomConfig selector e2e — render-side only. Pairs with the
# kubernetes-oidc-system suite; see its header for why no Kamaji bringup and
# no HR Ready wait (minReplicas: 0, HR asserted to exist only).
#
# What is exercised on a live cluster: spec.oidc.mode: CustomConfig is
# admitted; the HelmRelease renders; the tenant-supplied
# AuthenticationConfiguration is wired onto the KamajiControlPlane; and —
# crucially — NO Keycloak objects are created in the cozy realm when the
# tenant brings their own issuer, and the placeholder OIDC kubeconfig Secret
# is NOT pre-rendered (System mode pre-renders it; CustomConfig distributes
# out-of-band).
#
# The absence checks run AFTER the positive authn-config Secret assert
# establishes the chart has finished rendering — otherwise a not-yet-
# reconciled HR would false-pass them, a hazard the sequential bats never had.
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: kubernetes-oidc-customconfig
spec:
catch:
- events: {}
- describe:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
name: kubernetes-oidc-byo
- describe:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: KamajiControlPlane
name: kubernetes-oidc-byo
steps:
- name: create-kubernetes-oidc-byo
try:
- apply:
file: kubernetes-oidc-byo.yaml
- assert:
timeout: 1m
resource:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: kubernetes-oidc-byo
- assert:
timeout: 3m
resource:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: KamajiControlPlane
metadata:
name: kubernetes-oidc-byo
- name: kamajicontrolplane-still-carries-authentication-config
try:
- assert:
resource:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: KamajiControlPlane
metadata:
name: kubernetes-oidc-byo
spec:
apiServer:
(contains(extraArgs, '--authentication-config=/etc/kubernetes/authentication-config/config.yaml')): true
- name: authn-config-secret-carries-tenant-issuer
try:
- assert:
timeout: 1m
resource:
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-oidc-byo-oidc-authn-config
- script:
content: |
set -eu
body=$(kubectl -n "$NAMESPACE" get secret kubernetes-oidc-byo-oidc-authn-config \
-o jsonpath='{.data.config\.yaml}' | base64 -d)
echo "$body" | grep -qF "url: https://idp.byo.example.test"
echo "$body" | grep -qF "cozystack-byo-oidc-byo"
# Fail-loud negation (a bare `! ... | grep` is vacuous under set -e):
# the cozy-realm issuer must NOT appear in a BYO config.
if echo "$body" | grep -qE 'url: https://keycloak\.[^/]+/realms/cozy'; then
echo "FAIL: BYO AuthenticationConfiguration must not carry the cozy realm issuer" >&2
exit 1
fi
check:
($error == null): true
# Absence proofs — ordered after the positive asserts above (chart has
# rendered), so `error` op polling to its timeout is a real negative, not a
# not-yet-reconciled false pass.
- name: no-keycloak-objects-and-no-prerendered-kubeconfig
try:
- error:
timeout: 30s
resource:
apiVersion: v1.edp.epam.com/v1
kind: KeycloakClient
metadata:
name: tenant-test-kubernetes-oidc-byo
- error:
timeout: 30s
resource:
apiVersion: v1.edp.epam.com/v1
kind: KeycloakClientScope
metadata:
name: tenant-test-kubernetes-oidc-byo-audience
# System mode pre-renders <release>-oidc-kubeconfig as a placeholder;
# CustomConfig must not.
- error:
timeout: 30s
resource:
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-oidc-byo-oidc-kubeconfig
@@ -0,0 +1,48 @@
apiVersion: apps.cozystack.io/v1alpha1
kind: Kubernetes
metadata:
name: oidc-byo
spec:
addons:
ingressNginx:
enabled: false
hosts: []
valuesOverride: {}
controlPlane:
apiServer:
resources: {}
resourcesPreset: small
replicas: 1
nodeGroups:
md0:
diskSize: 20Gi
gpus: []
instanceType: u1.micro
maxReplicas: 1
minReplicas: 0
resources: {}
roles:
- worker
storageClass: replicated
version: v1.35
oidc:
mode: CustomConfig
customConfig:
config: |
apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthenticationConfiguration
jwt:
- issuer:
url: https://idp.byo.example.test
audiences:
- cozystack-byo-oidc-byo
claimMappings:
username:
claim: preferred_username
prefix: ""
groups:
claim: groups
prefix: ""
users:
- email: byo-admin@example.test
role: admin
@@ -0,0 +1,123 @@
# Chainsaw port of hack/e2e-apps/kubernetes-oidc-system.bats.
#
# Phase-1 OIDC System-mode e2e — render-side only. Pairs with the
# kubernetes-oidc-customconfig suite (BYO issuer path).
#
# Does NOT spin up a full Kamaji control plane: that path is covered by the
# kubernetes-latest/previous suites and would add another ~25 min bringup for
# a feature whose end-to-end OIDC browser flow is explicitly out of scope
# (see docs/oidc-tenant.md -> Phase 1). minReplicas: 0 means no worker VMs;
# the suite runs in minutes. Accordingly the HR is only asserted to EXIST
# (cozystack-api materialised it), never Ready.
#
# What is exercised on a live cluster: the new spec.oidc.* fields are
# admitted by the aggregated API; the HelmRelease renders the OIDC templates;
# and the resulting KamajiControlPlane / AuthenticationConfiguration Secret /
# KeycloakClient / KeycloakClientScope carry the expected per-cluster shape.
# The Keycloak asserts are unconditional: the chart capability-gates their
# rendering on v1.edp.epam.com/v1 (oidc-keycloak.yaml), and the CI platform
# always ships the operator — the bats' api-resources guard was dead code
# there (and its `skip` did not exist under cozytest anyway).
#
# The Kubernetes CR is applied declaratively, so Chainsaw auto-cleanup
# deletes it at test end — the bats' hand-rolled cleanup_kr/cozy_cleanup
# hooks have no equivalent here by construction.
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: kubernetes-oidc-system
spec:
catch:
- events: {}
- describe:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
name: kubernetes-oidc-system
- describe:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: KamajiControlPlane
name: kubernetes-oidc-system
steps:
- name: create-kubernetes-oidc-system
try:
- apply:
file: kubernetes-oidc-system.yaml
# cozystack-api materialises the HelmRelease…
- assert:
timeout: 1m
resource:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: kubernetes-oidc-system
# …and the chart renders the KamajiControlPlane (no Ready wait — that
# would require the Kamaji bringup this suite deliberately avoids).
- assert:
timeout: 3m
resource:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: KamajiControlPlane
metadata:
name: kubernetes-oidc-system
- name: kamajicontrolplane-oidc-wiring
try:
- assert:
resource:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha1
kind: KamajiControlPlane
metadata:
name: kubernetes-oidc-system
spec:
apiServer:
# --authentication-config is appended to extraArgs; the
# chart-owned mount lands on extraVolumeMounts.
(contains(extraArgs, '--authentication-config=/etc/kubernetes/authentication-config/config.yaml')): true
(extraVolumeMounts[?name == 'authentication-config']):
- name: authentication-config
deployment:
# The chart-owned volume lands on extraVolumes.
(extraVolumes[?name == 'authentication-config']):
- name: authentication-config
- name: authn-config-secret
try:
- assert:
timeout: 1m
resource:
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-oidc-system-oidc-authn-config
# The issuer check is a regex (any keycloak.<host>), so it stays a script;
# the per-cluster audience literal rides along.
- script:
content: |
set -eu
body=$(kubectl -n "$NAMESPACE" get secret kubernetes-oidc-system-oidc-authn-config \
-o jsonpath='{.data.config\.yaml}' | base64 -d)
echo "$body" | grep -qE 'url: https://keycloak\.[^/]+/realms/cozy'
echo "$body" | grep -qF -- "- tenant-test-kubernetes-oidc-system"
check:
($error == null): true
- name: keycloak-objects-in-cozy-realm
try:
- assert:
timeout: 1m
resource:
apiVersion: v1.edp.epam.com/v1
kind: KeycloakClient
metadata:
name: tenant-test-kubernetes-oidc-system
spec:
public: true
- assert:
timeout: 1m
resource:
apiVersion: v1.edp.epam.com/v1
kind: KeycloakClientScope
metadata:
name: tenant-test-kubernetes-oidc-system-audience
spec:
(protocolMappers[0].protocolMapper): oidc-audience-mapper
@@ -0,0 +1,34 @@
apiVersion: apps.cozystack.io/v1alpha1
kind: Kubernetes
metadata:
name: oidc-system
spec:
addons:
ingressNginx:
enabled: false
hosts: []
valuesOverride: {}
controlPlane:
apiServer:
resources: {}
resourcesPreset: small
replicas: 1
nodeGroups:
md0:
diskSize: 20Gi
gpus: []
instanceType: u1.micro
maxReplicas: 1
minReplicas: 0
resources: {}
roles:
- worker
storageClass: replicated
version: v1.35
oidc:
mode: System
users:
- email: e2e-admin@example.test
role: admin
- email: e2e-viewer@example.test
role: view