Skip to content

Commit 60ddfaa

Browse files
authored
Merge pull request #729 from authorizerdev/worktree-playground-e2e
test(e2e-playground): live-playground e2e suite for OIDC/SAML/SCIM/SSO/OAuth/MFA
2 parents 6718629 + 8975af2 commit 60ddfaa

119 files changed

Lines changed: 13103 additions & 49 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ test.db
1616
.yalc
1717
yalc.lock
1818
certs/
19+
# Test-only e2e-playground fixtures are intentionally checked in (docs/superpowers/plans/2026-07-20-playground-e2e.md Global Constraints).
20+
!e2e-playground/fixtures/certs/
21+
!e2e-playground/mocks/mock-saml-idp/certs/
1922
*-shm
2023
*-wal
2124
.idea

Makefile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,27 @@ perf-k6-validate:
298298
.PHONY: perf-k6-check
299299
perf-k6-check:
300300
k6 run perf/k6/fga_check.js
301+
302+
.PHONY: e2e-playground
303+
e2e-playground: ## Run the live-playground e2e suite (OIDC/SAML/SCIM/SSO/OAuth/MFA) against an ephemeral docker-compose stack
304+
export DOCKER_DEFAULT_PLATFORM=linux/$$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/'); \
305+
docker compose -f e2e-playground/docker-compose.yml up -d --wait authorizer authorizer-sso mock-oauth mock-saml-idp mailpit sms-sink; \
306+
status=$$?; \
307+
if [ $$status -eq 0 ]; then \
308+
docker compose -f e2e-playground/docker-compose.yml run --rm playwright npx playwright test; \
309+
status=$$?; \
310+
fi; \
311+
docker compose -f e2e-playground/docker-compose.yml down -v; \
312+
exit $$status
313+
314+
.PHONY: e2e-playground-sdk
315+
e2e-playground-sdk: ## Run the SDK-driven Go suite (drives authorizer-go over the enterprise/MFA surface) against an ephemeral docker-compose stack
316+
export DOCKER_DEFAULT_PLATFORM=linux/$$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/'); \
317+
docker compose -f e2e-playground/docker-compose.yml up -d --wait --build authorizer authorizer-webauthn authorizer-mfa-enforced authorizer-mfa-magic-link mock-oauth mock-saml-idp mailpit sms-sink webhook-sink; \
318+
status=$$?; \
319+
if [ $$status -eq 0 ]; then \
320+
docker compose -f e2e-playground/docker-compose.yml run --rm --build go-sdk-tests; \
321+
status=$$?; \
322+
fi; \
323+
docker compose -f e2e-playground/docker-compose.yml down -v; \
324+
exit $$status

cmd/root.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,16 @@ func runRoot(c *cobra.Command, args []string) {
421421
}
422422
}
423423

424+
// Warn if --env=e2e is set — this relaxes SSRF protection (private/loopback-IP
425+
// rejection) for the per-org SSO broker and webhook registration/delivery, and
426+
// routes social-login OAuth and SMS sending to fixed e2e-playground mock
427+
// addresses. It exists solely for e2e-playground/docker-compose.yml and must
428+
// never be set on a real deployment; unlike production/staging, there is no
429+
// other visible symptom if it is (see internal/constants/env.go's E2EEnv doc).
430+
if rootArgs.config.Env == constants.E2EEnv {
431+
log.Warn().Msg("running with --env=e2e: SSRF protection is relaxed for the SSO broker and webhooks, and OAuth/SMS are routed to e2e-playground mock addresses. This must never be set in a real deployment.")
432+
}
433+
424434
// Initialize prometheus metrics
425435
metrics.Init()
426436

e2e-playground/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
playwright-report
3+
test-results

e2e-playground/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
playwright-report/
3+
test-results/

e2e-playground/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# e2e-playground/Dockerfile
2+
FROM mcr.microsoft.com/playwright:v1.61.1-jammy
3+
WORKDIR /e2e
4+
COPY package.json package-lock.json ./
5+
RUN npm ci
6+
COPY . .
7+
CMD ["npx", "playwright", "test"]

e2e-playground/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Live-Playground E2E Suite
2+
3+
A real, live-server end-to-end test suite for Authorizer. Every spec drives a real `authorizer` binary (built from this repo's source) plus a real browser (Playwright) — no unit-level mocking of Authorizer itself. Third-party services (Google/GitHub/Discord/etc. OAuth, SMS delivery, an external SAML IdP) are stood in for by small local mock servers under `mocks/`, wired in via `authorizer`'s own test-only mechanism (`--env=e2e`) — every behavior it enables is a documented no-op unless that exact env value is set, so none of this affects production behavior.
4+
5+
## Coverage
6+
7+
- OIDC provider (signup/login/PKCE/token issuance) and OIDC SSO relying-party (home-realm discovery)
8+
- SAML SP and SAML IdP
9+
- SCIM (CRUD, filter operators, webhooks — including real webhook delivery with HMAC verification)
10+
- 10 social OAuth providers (Google, GitHub, Facebook, LinkedIn, Apple, Discord, Twitter, Microsoft, Twitch, Roblox)
11+
- WebAuthn/passkeys (via Playwright's CDP-backed virtual authenticator)
12+
- TOTP, SMS-OTP, WebOTP auto-fill, magic-link
13+
- MFA enforcement routing matrix
14+
- OTP brute-force lockout
15+
- Dashboard verified-domains UI
16+
17+
## Prerequisites
18+
19+
- Docker + Docker Compose (everything else — Node, Playwright browsers, the `authorizer` binary — is built into containers; nothing needs to be installed on the host).
20+
21+
## Run the full suite
22+
23+
From the repository root:
24+
25+
```bash
26+
make e2e-playground
27+
```
28+
29+
This builds and starts the full docker-compose stack (six `authorizer` instances configured for different scenarios, the mock OAuth/SAML/SMS/webhook servers, Mailpit for email), runs the entire Playwright suite in a containerized runner, and **always** tears the stack down afterward (`docker compose down -v`) — including on failure or if the stack fails to start.
30+
31+
Equivalent to, run manually:
32+
33+
```bash
34+
docker compose -f e2e-playground/docker-compose.yml up -d --wait authorizer authorizer-sso mock-oauth mock-saml-idp mailpit sms-sink
35+
docker compose -f e2e-playground/docker-compose.yml run --rm playwright npx playwright test
36+
docker compose -f e2e-playground/docker-compose.yml down -v
37+
```
38+
39+
(The `playwright` service's own `depends_on` brings up the remaining instances — `authorizer-webauthn`, `authorizer-magic-link`, `authorizer-mfa-enforced`, `authorizer-mfa-magic-link`, `webhook-sink` — automatically; they don't need to be named in the `up` step.)
40+
41+
## Run a subset
42+
43+
Any Playwright CLI filter works. From `e2e-playground/`, after starting the stack:
44+
45+
```bash
46+
# One spec file
47+
docker compose run --rm --build playwright npx playwright test totp.spec.ts
48+
49+
# By name pattern
50+
docker compose run --rm --build playwright npx playwright test -g "SCIM"
51+
52+
# A whole directory
53+
docker compose run --rm --build playwright npx playwright test social/
54+
```
55+
56+
**`--build` is required whenever a spec file (or anything else under `e2e-playground/`) has changed** — the `playwright` service's Dockerfile bakes test files into the image at build time rather than mounting them live; without `--build` you'll run stale tests, or Playwright will report "No tests found" if a new file was added since the image was last built.
57+
58+
Don't forget to tear down afterward: `docker compose -f e2e-playground/docker-compose.yml down -v`.
59+
60+
## Verify results after a run
61+
62+
Playwright's HTML report is written to `e2e-playground/playwright-report/` on the host (mounted, survives container teardown). To view it:
63+
64+
```bash
65+
npx playwright show-report e2e-playground/playwright-report
66+
```
67+
68+
or open `e2e-playground/playwright-report/index.html` directly in a browser. It shows every test's pass/fail status, timing, and — for failures — a full trace (screenshots, network log, action-by-action replay).
69+
70+
Raw output (traces, videos on retry, etc.) is under `e2e-playground/test-results/`, also host-mounted.
71+
72+
A clean run's terminal output ends with a summary line, e.g.:
73+
74+
```
75+
XX passed (NNs)
76+
```
77+
78+
Any skip is intentional and self-documenting — read the `test.skip(...)` call's message in the relevant spec file for the reason. As of this writing there are no skips tied to real product gaps.
79+
80+
## Notes
81+
82+
- Every spec seeds its own state (org, users, connections) — specs are independently runnable and safe to run in parallel or in any order.
83+
- `authorizer-sso` runs a second, separately-configured instance (port 8081) specifically because `--enable-org-discovery=true` is a global login-UX toggle that would otherwise change behavior for every other spec sharing the default instance.
84+
- Test-only secrets (SAML certs, JWT signing keys) live under `fixtures/certs/`, are checked in, and sign nothing real — the same pattern `make dev`'s embedded dev RSA keys already use.

0 commit comments

Comments
 (0)