Skip to content

test(e2e): add OIDC E2E test variant with real Zitadel provider#2369

Open
sago2k8 wants to merge 4 commits intomasterfrom
feat/oidc-e2e-tests-zitadel
Open

test(e2e): add OIDC E2E test variant with real Zitadel provider#2369
sago2k8 wants to merge 4 commits intomasterfrom
feat/oidc-e2e-tests-zitadel

Conversation

@sago2k8
Copy link
Copy Markdown
Contributor

@sago2k8 sago2k8 commented Apr 7, 2026

Summary

  • Add zitadel-setup.mjs: provisions a complete Zitadel v4.13.1 OIDC environment (PostgreSQL + API + Login app + nginx proxy) using testcontainers
  • Extend global-setup.mjs / global-teardown.mjs with needsZitadel flag for Zitadel container lifecycle
  • Add test-variant-console-enterprise-oidc Playwright variant with 11 tests covering:
    • Full browser OIDC login flow through real Zitadel (admin + viewer users)
    • GroupBindings GBAC enforcement (admin access, viewer access, denied access)
    • Unauthenticated user redirect

Test plan

  • npm run e2e-test:variant console-enterprise-oidc — 11/11 PASS
  • Existing console-enterprise variant unaffected (needsZitadel defaults to false)
  • CI E2E pipeline

Related

  • Enterprise backend PR: redpanda-data/console-enterprise#755
  • Builds on UX-928 Console GBAC

🤖 Generated with Claude Code

sago2k8 and others added 4 commits April 3, 2026 05:12
…e cleanup timeout

- In users.spec.ts: add waitForURL after fill so nuqs async navigate completes
  before asserting filtered counts
- In debug-bundle-page.ts: increase cleanup Promise.race timeout from 60s to 90s
  for slower CI environments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add zitadel-setup.mjs that provisions a complete Zitadel v4 OIDC
environment using testcontainers (PostgreSQL + API + Login + nginx
proxy). Handles machine key auth, project/role/user creation, action
scripts for group claims injection, and config rewriting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend shared E2E infrastructure with `needsZitadel` flag:
- global-setup: Start Zitadel containers, rewrite Console config with
  real OIDC credentials, run backend as host process for localhost access
- global-teardown: Clean up Zitadel proxy/login/API/DB containers
- Consolidate container cleanup into data-driven loop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add console-enterprise-oidc Playwright test variant that exercises the
full browser OIDC login flow through a real Zitadel v4 identity provider.

Tests cover:
- Admin OIDC login (platform-admins group) with full UI access
- Viewer OIDC login (analysts group) with read-only access
- Denied access for users with no matching group binding
- Unauthenticated user redirect to login page

Uses shared loginViaOIDC helper for the Zitadel login flow (username →
password → MFA skip → Console callback → overview redirect).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

setup('authenticate viewer via OIDC', async ({ page }) => {
await loginViaOIDC(page, 'viewer-user');
await page.context().storageState({ path: authFile });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

test('can view topic list page', async ({ page }) => {
await page.goto('/topics');
// Viewer should see the topics page heading
await expect(page.getByRole('heading', { name: /topics/i })).toBeVisible({ timeout: 15_000 });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would it take 15s to run?

Comment on lines +37 to +38
// Handle any intermediate Zitadel screens (MFA setup, consent, etc.)
await page.waitForTimeout(1_000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this why you mention optimistic queries?

Comment on lines +43 to +47
// After OIDC callback, Console should either:
// 1. Redirect to /login with an error (token_exchange_failed, etc.)
// 2. Show permission denied on any page the user tries to access
// Wait for the redirect back to Console
await page.waitForURL('**/*', { timeout: 30_000 });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use .or() to check for different scenarios/paths that could occur

Comment on lines +26 to +28
const createButton = page.getByTestId('create-topic-button');
await expect(createButton).toBeVisible({ timeout: 15_000 });
await createButton.click();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we have a lot of timeouts everywhere in the past already but the problem with having so many timeouts means we would make tests run longer even if they are already inherently broken. Ideally we should audit all our tests and try to find a better assertion whenever we have to reach out for timeouts. This is how tests can be made flaky unfortunately (not having proper assertions, what if this takes 16s?) but if we were to assert against a network request happening, a redirect, a URL search param, or some other action user could take, it would be more stable long term.

for (const [key, label] of [
['sourceBackendId', 'source backend'],
['backendId', 'backend'],
['connectId', 'Kafka Connect'],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this only kafka connect or also potentially redpanda connect

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants