Commit Graph
7 Commits
Author SHA1 Message Date
IvanHunters 3776c447b9 test(e2e): poll users-Job DESIRED_USERS_JSON for target email, not just Job existence
CI E2E showed the users-Job assertion returning `DESIRED_USERS_JSON:
[]` — but the CR body had `users: [{email: e2e-admin@example.com,
role: Admin}]`. Root cause: `hook-delete-policy: before-hook-creation`
keeps the previous hook Job around across helm upgrades, so `until
kubectl get job` matches a stale Job from the previous customconfig-
mode test where users may have been unset (the secretRef swap CR had
no `users:` field, so the schema default `[]` propagated to the
prior Job's DESIRED_USERS_JSON). The System test then grabbed that
stale Job before the helm upgrade for the new CR completed and swapped
in the fresh Job.

Fix: poll on the target env value itself — the new Job with the
correct users list is the first Job whose DESIRED_USERS_JSON string
contains `e2e-admin@example.com`. 600s window matches the inner HR's
15m timeout with room for a slow reconcile.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-07-15 15:31:45 +03:00
IvanHunters 7f9e1a8bf6 test(e2e): poll the reconciled Grafana CR field instead of racing on CR existence
CI run 28794778739 caught two race conditions in the render-side
Monitoring OIDC bats:

- `Grafana CR carries auth.generic_oauth pointing at the cozy realm`
  (monitoring-oidc-system.bats:86) failed with `enabled=` empty after
  a 0-second wait. The prior `until kubectl get grafana grafana`
  only proved the CR EXISTS — it did not prove grafana-operator had
  reconciled the mode=System values onto it. When the CR from the
  previous `Monitoring CR accepts spec.oidc.mode=System` test was
  already there but the operator hadn't yet flipped `.spec.config.auth
  .generic_oauth.enabled` to "true", the jsonpath returned empty and
  `[ "" = "true" ]` short-circuited the whole test.
- `secretRef variant mounts operator Secret under /etc/grafana/oidc`
  (monitoring-oidc-customconfig.bats:119) timed out at 180s waiting
  for the volumeMount swap from inline → ini. On a warm sandbox the
  full inner-HR upgrade + grafana-operator reconcile cycle can
  legitimately take >3m — the timeout was too tight.

Fix: replace `until kubectl get grafana` with `until [ "$(kubectl
... jsonpath=<target-field>)" = <expected> ]` on every subsequent
assertion, and bump the secretRef-swap window to 600s (well inside
the inner HR's 15m timeout). Same pattern used for the "no
role_attribute_path" and "operator payload verbatim" assertions so
the whole suite is race-free.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-07-15 15:31:45 +03:00
IvanHunters 123616a1d0 test(e2e): swap KeycloakRealmGroup assertions for the users-Job in bats
Aligns the render-side e2e bats with the users-map contract:

- Feed a `spec.oidc.users:` entry to each mode's Monitoring CR so
  the reconcile Job has real input to act on.
- Assert the users-Job appears in the release namespace with the
  desired `DESIRED_USERS_JSON` env and the expected `OIDC_MODE`.
- Assert the Grafana CR renders with `skip_org_role_sync = "true"`
  and `oauth_allow_insecure_email_lookup = "true"` and NO
  `role_attribute_path`.
- Flip the three KeycloakRealmGroup existence assertions to
  negative checks: chart-owned realm groups must NOT be present
  in either System or CustomConfig mode.

Does not add a full OIDC login flow through Keycloak — that stays
deferred to a follow-up integration suite, same posture as the
tenant kube-apiserver's kubernetes-oidc-system.bats.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-07-15 15:31:45 +03:00
Ivan Okhotnikov 5f7ed89799 fix(e2e): work around EDP schema-default strip + kubectl delete/apply race
Two follow-up bats fixes uncovered by the first live e2e pass on the
singleton-aligned monitoring OIDC tests:

1. monitoring-oidc-system, test 4 (KeycloakClient assertion). The EDP
   Keycloak operator's KeycloakClient CRD strips `spec.public: false`
   on write because false is the schema default. The chart emits
   `public: false` explicitly (confidentiality guard), but neither
   managedFields nor the resulting spec ever carries the field, so
   the assertion `[ "${public}" = "false" ]` grepped an empty string
   and tripped. Assert `spec.clientAuthenticatorType == "client-secret"`
   instead — the operator persists it, and it is the direct signal
   for "confidential client" (which is what the `public: false`
   assertion was testing for).

2. monitoring-oidc-customconfig, test 4 (secretRef variant). The
   original flow was delete-then-recreate the Monitoring CR to swap
   inline `customConfig.config` for `customConfig.secretRef.name`.
   `kubectl apply` immediately after delete raced the API server's
   grace-period cache: apply's GET-then-decide phase saw the CR
   during grace, chose the patch path, and the patch hit NotFound
   once the delete propagated. Drop the delete entirely — cozystack-
   operator reconciles the CR mode change on the same object and
   Flux re-renders the chart with the new values.

   Add an explicit wait for the target state (Grafana CR's
   `oidc-custom-ini` volumeMount present AND `spec.config.auth.generic_oauth`
   absent) before the assertions, since the CR update triggers an
   asynchronous chart re-render and the immediate get would still
   see the inline auth.generic_oauth block from @test 1.

Signed-off-by: Ivan Okhotnikov <xorokhotnikov@gmail.com>
2026-07-15 15:31:45 +03:00
Ivan Okhotnikov cb04caecee fix(e2e): align monitoring OIDC bats with chart singleton naming
The extra/monitoring chart enforces `.Release.Name == "monitoring"`
in templates/check-release-name.yaml (the tenant Monitoring is a
per-namespace singleton). Naming the Monitoring CR anything else
makes the operator materialise an outer HelmRelease with that name
and the chart hard-fails at render with

  execution error at (monitoring/templates/check-release-name.yaml:2:4):
    The name of the release MUST BE monitoring

Rename the CR to `monitoring` in both files. Rework every derived
name to match the actual reality of the chart pipeline instead of
the invented `monitoring-<TEST_NAME>` prefix the tests polled for:

  * outer HR  = ${CR_NAME}                        = monitoring
  * inner HR  = ${CR_NAME}-system                 = monitoring-system
    (rendered by extra/monitoring/templates/helmrelease.yaml as
     `metadata.name: {{ .Release.Name }}-system`)
  * clientId  = ${namespace}-${inner Release.Name}
              = tenant-test-monitoring-system
  * scope     = ${clientId}-audience
  * groups    = ${clientId}-{admin,editor,viewer}
  * client-secret Secret = ${inner Release.Name}-oidc-client
                         = monitoring-system-oidc-client

The BYO Secret name in the customconfig test is chart-independent
(the tenant provides it via customConfig.secretRef.name), so it is
kept short and no longer tied to CR_NAME.

The wait sequence in the first @test of each file is also split
into two probes: outer HR appears first (from the operator), then
inner HR (from the extra/monitoring chart's helmrelease.yaml), then
the Grafana CR. Under the previous incorrect single-probe wait
(`hr monitoring-${TEST_NAME}`) the timeout tripped after 60s
because that HR never existed under any name.

Signed-off-by: Ivan Okhotnikov <xorokhotnikov@gmail.com>
2026-07-15 15:31:45 +03:00
Ivan Okhotnikov 9ff05b2f32 test(e2e): port monitoring OIDC bats to cozytest lifecycle conventions
Mirrors the same port applied to kubernetes-oidc-*.bats in the tenant
kube-apiserver OIDC series: cozytest.sh (the e2e runner) is not real
bats, so setup()/teardown() are never invoked and any state they
established (TEST_NAME) is unset by the time an @test body runs,
tripping cozytest.sh's `set -eu` at the first "${TEST_NAME}"
expansion with `TEST_NAME: parameter not set`.

Lift TEST_NAME to file scope as a stable constant, register cleanup
via cozy_cleanup() so cozytest.sh runs it at suite exit and on the
first failing test, and call cleanup_mon() inline at the top of the
first @test for per-run isolation. Fixes the two E2E failures on
this PR: `Monitoring CR accepts spec.oidc.mode=CustomConfig with
inline config` and `Monitoring CR accepts spec.oidc.mode=System`.

Signed-off-by: Ivan Okhotnikov <xorokhotnikov@gmail.com>
2026-07-15 15:31:45 +03:00
Ivan Okhotnikov fe2c606f79 test(e2e): add Phase-1 OIDC render-side bats for Monitoring
Two bats files mirroring the shape of the tenant kube-apiserver PR's
kubernetes-oidc-{system,customconfig}.bats:

- monitoring-oidc-system.bats — asserts the Monitoring CR admits the
  new spec.oidc.mode: System field; the chart renders the Grafana CR
  with an auth.generic_oauth section pointing at the cozy realm; a
  32-char client-secret Secret is persisted; the KeycloakClient (with
  public: false), KeycloakClientScope (audience mapper), and three
  KeycloakRealmGroups (-admin, -editor, -viewer) land in cozy; and
  the Grafana Deployment injects GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
  from the Secret.

- monitoring-oidc-customconfig.bats — asserts the CR admits inline
  CustomConfig; the operator's payload lands on spec.config verbatim
  with no cozy realm in the auth_url; NO KeycloakClient / Scope /
  Groups are created in cozy; and the secretRef variant mounts the
  operator Secret under /etc/grafana/oidc without emitting
  auth.generic_oauth under spec.config.

Neither drives a real browser login through Keycloak — that is
deferred to the follow-up integration suite, same posture as the
tenant kube-apiserver's Phase-1 tests.

Signed-off-by: Ivan Okhotnikov <ivan.okhotnikov@aenix.io>
2026-07-15 15:31:44 +03:00