Skip to content

Commit e294274

Browse files
committed
test: cover customer local setup journey
1 parent fbeac26 commit e294274

13 files changed

Lines changed: 585 additions & 375 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
Exercise the customer local setup journey in the consumer e2e gate.

.github/instructions/consumer-journey.instructions.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ applyTo: "apps/cli-journey-e2e/**,.github/workflows/ci.yml"
44

55
# Consumer Journey Review Instructions
66

7-
Review consumer journey changes as a required fresh-app quality gate, not as a
8-
demo-app e2e suite.
7+
Review consumer journey changes as the required customer local setup quality
8+
gate, not as a demo-app e2e suite.
99

1010
- CI must consume the current workflow's GoReleaser image and npm package
1111
tarballs. Do not replace this with public npm packages for Zitadel packages.
12+
- The journey must exercise the customer local runtime flow through `npx`:
13+
`doctor`, `start`, then `setup --framework next --server local` with
14+
`--non-interactive --json`.
1215
- Produce package artifacts with `corepack pnpm --dir <package> pack` and keep
1316
tarball verification for required package presence plus unresolved
1417
`catalog:` or `workspace:` dependency specs.
@@ -23,6 +26,7 @@ demo-app e2e suite.
2326
- Browser tests should run serially with one worker, use `localhost` for
2427
WebAuthn, and require passkey coverage in CI. `JOURNEY_ENABLE_PASSKEY=0` is
2528
only a local debugging escape hatch.
26-
- Failure artifacts should include Playwright output/report, setup JSON,
27-
setup stderr, metadata, generated app package manifests, Verdaccio logs, Next
28-
logs, and backend logs. Do not upload generated `node_modules` or `.next`.
29+
- Failure artifacts should include Playwright output/report, doctor/start/setup
30+
JSON and stderr, local runtime metadata/logs, metadata, generated app package
31+
manifests, Verdaccio logs, and Next logs. Do not upload generated
32+
`node_modules` or `.next`.

.github/workflows/ci.yml

Lines changed: 34 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -305,75 +305,6 @@ jobs:
305305
docker load -i goreleaser-dist/nextgen-image.tar
306306
docker image inspect -f '{{.Os}}/{{.Architecture}}' "$(cat goreleaser-dist/nextgen-image.tag)" | grep -q '^linux/amd64$'
307307
308-
- name: Smoke test CLI-style local runtime image
309-
run: |
310-
set -euo pipefail
311-
IMAGE="$(cat goreleaser-dist/nextgen-image.tag)"
312-
DATA_DIR="$RUNNER_TEMP/nextgen-dev-data"
313-
RUNTIME_DIR="$RUNNER_TEMP/nextgen-dev-runtime"
314-
HOST_UID="$(id -u)"
315-
HOST_GID="$(id -g)"
316-
PASSWD_FILE="$RUNTIME_DIR/container-passwd"
317-
GROUP_FILE="$RUNTIME_DIR/container-group"
318-
mkdir -p "$DATA_DIR" "$RUNTIME_DIR"
319-
# Mirror `zitadel start`: run the container as the host user so
320-
# bind-mounted state stays editable, and provide passwd/group entries
321-
# because embedded Postgres initdb refuses unknown numeric users.
322-
{
323-
echo "root:x:0:0:root:/root:/bin/sh"
324-
echo "nonroot:x:65532:65532:nonroot:/nonexistent:/usr/sbin/nologin"
325-
echo "zitadel-local:x:${HOST_UID}:${HOST_GID}:Zitadel local user:/tmp:/usr/sbin/nologin"
326-
} > "$PASSWD_FILE"
327-
{
328-
echo "root:x:0:"
329-
echo "nonroot:x:65532:"
330-
echo "zitadel-local:x:${HOST_GID}:"
331-
} > "$GROUP_FILE"
332-
CONTAINER="$(
333-
docker run -d \
334-
-p 127.0.0.1:18080:8080 \
335-
-v "$DATA_DIR:/var/lib/zitadel/nextgen-data" \
336-
-v "$PASSWD_FILE:/etc/passwd:ro" \
337-
-v "$GROUP_FILE:/etc/group:ro" \
338-
--user "${HOST_UID}:${HOST_GID}" \
339-
-e NEXTGEN_SERVER_ADDRESS=:8080 \
340-
-e NEXTGEN_SERVER_DATA_DIR=/var/lib/zitadel/nextgen-data \
341-
"$IMAGE"
342-
)"
343-
cleanup() {
344-
docker rm -f "$CONTAINER" >/dev/null 2>&1 || true
345-
}
346-
diagnose() {
347-
docker logs "$CONTAINER" || true
348-
}
349-
trap cleanup EXIT
350-
351-
ready=0
352-
for _ in $(seq 1 120); do
353-
if curl -fsS http://localhost:18080/healthz >/dev/null; then
354-
ready=1
355-
break
356-
fi
357-
sleep 1
358-
done
359-
if [ "$ready" -ne 1 ]; then
360-
echo "::error::timed out waiting for zero-config /healthz"
361-
diagnose
362-
exit 1
363-
fi
364-
test -f "$DATA_DIR/server-encryption-key"
365-
if ! curl -fsS -o /dev/null -w "%{http_code}\n" http://localhost:18080/ui/console/ | grep -q '^200$'; then
366-
echo "::error::zero-config /ui/console/ did not return 200"
367-
diagnose
368-
exit 1
369-
fi
370-
if ! curl -fsS -o /dev/null -w "%{http_code}\n" http://localhost:18080/ui/login/ | grep -q '^200$'; then
371-
echo "::error::zero-config /ui/login/ did not return 200"
372-
diagnose
373-
exit 1
374-
fi
375-
echo "CLI-style local runtime image smoke test passed"
376-
377308
- name: Prepare quick-start compose stack
378309
run: |
379310
mkdir -p nextgen_quickstart
@@ -400,8 +331,9 @@ jobs:
400331
- name: Start stack and verify HTTP endpoints
401332
run: |
402333
set -euo pipefail
403-
# Separate from the CLI-style smoke above: this keeps the documented
404-
# compose fallback valid for operators/manual quick-start usage.
334+
# Separate from the customer local setup journey: this keeps the
335+
# documented compose fallback valid for operators/manual quick-start
336+
# usage.
405337
COMPOSE=(docker compose -f nextgen_quickstart/docker-compose.yaml --env-file nextgen_quickstart/.env)
406338
"${COMPOSE[@]}" up -d --wait
407339
ready=0
@@ -682,32 +614,11 @@ jobs:
682614
test -f goreleaser-dist/nextgen-image.tag
683615
docker load -i goreleaser-dist/nextgen-image.tar
684616
docker image inspect -f '{{.Os}}/{{.Architecture}}' "$(cat goreleaser-dist/nextgen-image.tag)" | grep -q '^linux/amd64$'
685-
686-
- name: Start backend stack
687-
run: |
688-
mkdir -p "$RUNNER_TEMP/nextgen-journey"
689-
cp docs/operations/docker-compose.yaml "$RUNNER_TEMP/nextgen-journey/docker-compose.yaml"
690-
IMAGE="$(cat goreleaser-dist/nextgen-image.tag)"
691-
{
692-
echo "NEXTGEN_IMAGE=${IMAGE}"
693-
echo "NEXTGEN_PORT=8080"
694-
} > "$RUNNER_TEMP/nextgen-journey/.env"
695-
docker compose -f "$RUNNER_TEMP/nextgen-journey/docker-compose.yaml" --env-file "$RUNNER_TEMP/nextgen-journey/.env" up -d --wait
696-
for _ in $(seq 1 90); do
697-
if curl -fsS http://localhost:8080/healthz >/dev/null; then
698-
exit 0
699-
fi
700-
sleep 1
701-
done
702-
echo "::error::timed out waiting for backend /healthz"
703-
docker compose -f "$RUNNER_TEMP/nextgen-journey/docker-compose.yaml" --env-file "$RUNNER_TEMP/nextgen-journey/.env" logs nextgen
704-
exit 1
617+
echo "ZITADEL_LOCAL_IMAGE=$(cat goreleaser-dist/nextgen-image.tag)" >> "$GITHUB_ENV"
705618
706619
- name: Prepare fresh Next.js app
707620
id: prepare-app
708621
env:
709-
JOURNEY_BACKEND_URL: http://localhost:8080
710-
JOURNEY_CREATE_NEXT_APP_VERSION: 16.2.4
711622
JOURNEY_REGISTRY_URL: http://127.0.0.1:4873
712623
JOURNEY_WORK_DIR: ${{ runner.temp }}/zitadel-cli-journey
713624
run: node apps/cli-journey-e2e/scripts/prepare-next-app.mjs
@@ -735,17 +646,32 @@ jobs:
735646
- name: Collect diagnostics
736647
if: failure()
737648
run: |
738-
docker compose -f "$RUNNER_TEMP/nextgen-journey/docker-compose.yaml" --env-file "$RUNNER_TEMP/nextgen-journey/.env" logs > "$RUNNER_TEMP/backend-compose.log" 2>&1 || true
739649
DIAG_DIR="$RUNNER_TEMP/consumer-journey-diagnostics"
650+
APP_DIR="$RUNNER_TEMP/zitadel-cli-journey/myapp"
740651
mkdir -p "$DIAG_DIR/generated-app"
741-
cp "$RUNNER_TEMP/backend-compose.log" "$DIAG_DIR/" 2>/dev/null || true
652+
if [ -d "$APP_DIR" ]; then
653+
(
654+
cd "$APP_DIR"
655+
npm_config_registry=http://127.0.0.1:4873 \
656+
npm_config_yes=true \
657+
npm_config_audit=false \
658+
npm_config_fund=false \
659+
npx --yes @zitadel/cli@alpha logs --tail 400 --non-interactive --json \
660+
> "$DIAG_DIR/logs.json" 2> "$DIAG_DIR/logs.stderr.log"
661+
) || true
662+
fi
742663
cp "$RUNNER_TEMP/next-app.log" "$DIAG_DIR/" 2>/dev/null || true
743664
cp "$RUNNER_TEMP/verdaccio.log" "$DIAG_DIR/" 2>/dev/null || true
665+
cp "$RUNNER_TEMP/zitadel-cli-journey/doctor.json" "$DIAG_DIR/" 2>/dev/null || true
666+
cp "$RUNNER_TEMP/zitadel-cli-journey/doctor.stderr.log" "$DIAG_DIR/" 2>/dev/null || true
667+
cp "$RUNNER_TEMP/zitadel-cli-journey/start.json" "$DIAG_DIR/" 2>/dev/null || true
668+
cp "$RUNNER_TEMP/zitadel-cli-journey/start.stderr.log" "$DIAG_DIR/" 2>/dev/null || true
744669
cp "$RUNNER_TEMP/zitadel-cli-journey/setup.json" "$DIAG_DIR/" 2>/dev/null || true
745670
cp "$RUNNER_TEMP/zitadel-cli-journey/setup.stderr.log" "$DIAG_DIR/" 2>/dev/null || true
746671
cp "$RUNNER_TEMP/zitadel-cli-journey/metadata.json" "$DIAG_DIR/" 2>/dev/null || true
747-
cp "$RUNNER_TEMP/zitadel-cli-journey/myapp/package.json" "$DIAG_DIR/generated-app/" 2>/dev/null || true
748-
cp "$RUNNER_TEMP/zitadel-cli-journey/myapp/package-lock.json" "$DIAG_DIR/generated-app/" 2>/dev/null || true
672+
cp "$APP_DIR/.zitadel/local/runtime.json" "$DIAG_DIR/runtime.json" 2>/dev/null || true
673+
cp "$APP_DIR/package.json" "$DIAG_DIR/generated-app/" 2>/dev/null || true
674+
cp "$APP_DIR/package-lock.json" "$DIAG_DIR/generated-app/" 2>/dev/null || true
749675
750676
- name: Upload consumer journey diagnostics
751677
if: failure()
@@ -763,7 +689,15 @@ jobs:
763689
if: always()
764690
run: |
765691
if [ -n "${NEXT_APP_PID:-}" ]; then kill "$NEXT_APP_PID" 2>/dev/null || true; fi
766-
if [ -n "${VERDACCIO_PID:-}" ]; then kill "$VERDACCIO_PID" 2>/dev/null || true; fi
767-
if [ -f "$RUNNER_TEMP/nextgen-journey/docker-compose.yaml" ]; then
768-
docker compose -f "$RUNNER_TEMP/nextgen-journey/docker-compose.yaml" --env-file "$RUNNER_TEMP/nextgen-journey/.env" down -v
692+
APP_DIR="$RUNNER_TEMP/zitadel-cli-journey/myapp"
693+
if [ -d "$APP_DIR" ]; then
694+
(
695+
cd "$APP_DIR"
696+
npm_config_registry=http://127.0.0.1:4873 \
697+
npm_config_yes=true \
698+
npm_config_audit=false \
699+
npm_config_fund=false \
700+
npx --yes @zitadel/cli@alpha reset --force --non-interactive --json
701+
) || true
769702
fi
703+
if [ -n "${VERDACCIO_PID:-}" ]; then kill "$VERDACCIO_PID" 2>/dev/null || true; fi

AGENTS.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,13 @@ The local reproduction command for the fresh-app consumer journey gate is:
137137
corepack pnpm run journey
138138
```
139139

140-
This runner requires Docker for Verdaccio. By default it starts the backend from
141-
source with embedded Postgres, ensures the Playwright Chromium browsers are
142-
installed, builds and packs local npm packages with pnpm, creates a temporary
143-
Next.js app outside the repo, runs CLI setup through npm, starts the generated
144-
app on `localhost`, and runs Playwright with one worker. Use
145-
`-- --backend image --image <docker-tag>` to run the backend through the local
146-
compose profile for image parity.
140+
This runner requires Docker for Verdaccio and the CLI-managed local runtime. By
141+
default it builds a local runtime image, ensures the Playwright Chromium
142+
browsers are installed, builds and packs local npm packages with pnpm, creates
143+
an empty app directory outside the repo, runs `npx @zitadel/cli@alpha doctor`,
144+
`start`, and `setup --framework next --server local`, starts the generated app
145+
on `localhost`, and runs Playwright with one worker. Use
146+
`-- --image <docker-tag>` to reuse an existing local runtime image.
147147

148148
In CI the dedicated `node-e2e` job (in `.github/workflows/ci.yml`) gates merges
149149
on the checked-in demo integrations. The separate `consumer-journey-e2e` job is
@@ -170,7 +170,7 @@ upward**. When deciding where a new test belongs:
170170

171171
The consumer journey suite is the exception to the checked-in demo ownership
172172
rule: it belongs in `apps/cli-journey-e2e/` and must exercise a freshly
173-
generated app because it protects the real CLI onboarding path.
173+
generated app because it protects the customer local setup path.
174174

175175
A new test belongs at e2e level only when the boundary it covers is
176176
exclusively the framework integration (middleware, cookie origin, full

README.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,17 @@ Use `corepack pnpm --silent run cli -- ... --json` when a script needs
137137
parseable CLI stdout. Plain `pnpm run` prints its own script prelude before
138138
the command output.
139139

140-
Fresh-app consumer journey check:
140+
Customer local setup journey check:
141141

142142
```sh
143143
corepack pnpm run journey
144144
```
145145

146146
This opt-in check ensures the Playwright Chromium browsers are installed, builds
147-
the local npm packages, publishes them to a temporary Verdaccio registry, starts
148-
a source backend with embedded Postgres, scaffolds a new Next.js app outside the
149-
repo, and verifies registration/login journeys against the generated app.
147+
the local npm packages, publishes them to a temporary Verdaccio registry, runs
148+
`npx @zitadel/cli@alpha doctor`, `start`, and
149+
`setup --framework next --server local` in an empty app directory, starts the
150+
generated app, and verifies registration/login journeys.
150151

151152
## CI
152153

@@ -158,13 +159,15 @@ Pull requests and pushes to `main` run:
158159
- npm package dry-run/pack checks.
159160
- A non-publishing GoReleaser snapshot.
160161
- `consumer-journey-e2e`, which downloads the current workflow's GoReleaser
161-
snapshot image and npm package tarballs, installs them through a temporary
162-
npm registry into a fresh Next.js app, and runs the Playwright user journey.
162+
snapshot image and npm package tarballs, installs the CLI through a temporary
163+
npm registry, runs the customer local setup commands in a fresh app directory,
164+
and runs the Playwright user journey against the generated app.
163165

164166
CI uploads short-lived workflow artifacts for review: GoReleaser snapshot output
165167
and npm package tarballs. On consumer journey failures it also uploads focused
166-
diagnostics such as Playwright traces, setup JSON, package lock metadata, and
167-
service logs. These artifacts expire after 7 days and are not release artifacts.
168+
diagnostics such as Playwright traces, doctor/start/setup JSON, package lock
169+
metadata, local runtime logs, and service logs. These artifacts expire after 7
170+
days and are not release artifacts.
168171

169172
## Build & release
170173

apps/cli-journey-e2e/AGENTS.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ These instructions apply to `apps/cli-journey-e2e/**`. Defer to the root
55

66
## Purpose
77

8-
This project protects the real consumer onboarding journey. Tests must exercise
9-
a freshly generated Next.js app, not the checked-in demo apps.
8+
This project protects the customer local setup journey. Tests must exercise a
9+
fresh app directory that runs the CLI local runtime path (`doctor`, `start`,
10+
`setup --server local`) before starting the generated Next.js app. It must not
11+
test the checked-in demo apps.
1012

1113
## Maintenance Rules
1214

@@ -17,6 +19,9 @@ a freshly generated Next.js app, not the checked-in demo apps.
1719
protocols.
1820
- CI must install Zitadel packages from current workflow tarballs through the
1921
temporary Verdaccio registry, not from public npm.
22+
- CI must run `npx @zitadel/cli@alpha doctor`, `start`, and
23+
`setup --framework next --server local` from the fresh app directory with
24+
`--non-interactive --json`.
2025
- Pack and upload only the public packages:
2126
`@zitadel/cli`, `@zitadel/api`, `@zitadel/components`,
2227
`@zitadel/sdk-core`, `@zitadel/sdk-next`, `@zitadel/sdk-nuxt`,

0 commit comments

Comments
 (0)