-
Notifications
You must be signed in to change notification settings - Fork 65
feat(umami-postgres): keploy compat lane sample (smoke-test only) #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
f259fbd
f43faf2
f191a90
bf50e49
acfffe2
6c4f05c
93bbdae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # Thin wrapper around umami's official image at the version this | ||
| # sample tracks. Pin lives here (not in CI lane scripts) so a | ||
| # future umami release that changes the bug-triggering shape is a | ||
| # one-line retag, not a hunt across keploy/integrations and | ||
| # keploy/enterprise. | ||
| # | ||
| # Upstream: https://github.com/umami-software/umami | ||
| # Image: docker.io/umamisoftware/umami:postgresql-v2.18.1 | ||
| FROM ghcr.io/umami-software/umami:postgresql-v2.18.1 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # umami-postgres — keploy compat lane sample (work in progress) | ||
|
|
||
| Minimum reproducer scaffold for the umami / postgres-v3 compat lane. Mirrors the architectural pattern of the [doccano-django sample in `samples-python`](https://github.com/keploy/samples-python/tree/main/doccano-django): the sample owns orchestration (compose / bootstrap / traffic / noise filter / coverage), the keploy CI lanes consume it as a thin wrapper. | ||
|
|
||
| ## Status | ||
|
|
||
| **This is a SCAFFOLD.** The compose, bootstrap, and a minimal record-traffic loop work end-to-end against bare umami without keploy in the picture. The full traffic loop the existing keploy/enterprise lane drives (`run_api_flow` in `enterprise/.ci/scripts/umami-linux.sh`, ~250 lines covering websites / events / sessions / reports / share-tokens / shareability) has **not been ported** into `flow.sh::umami_record_traffic` yet. Lanes consuming this sample today should either: | ||
|
|
||
| 1. Port the missing curls into `flow.sh::umami_record_traffic` (preferred — that's the migration this scaffold is designed around). | ||
| 2. Or call into `enterprise/.ci/scripts/umami-linux.sh::run_api_flow` directly between `flow.sh bootstrap` and `flow.sh coverage` until the migration completes. | ||
|
|
||
| See the migration plan in this PR's description / linked issue for the full porting checklist. | ||
|
|
||
| ## Layout | ||
|
|
||
| ``` | ||
| umami-postgres/ | ||
| ├── Dockerfile # FROM ghcr.io/umami-software/umami:postgresql-v2.18.1 | ||
| ├── docker-compose.yml # postgres-15 + umami v2 on a fixed subnet, env-driven | ||
| ├── flow.sh # bootstrap | record-traffic | coverage | list-routes | ||
| ├── keploy.yml.template # globalNoise for createdAt/updatedAt/Date/uuid id fields | ||
| └── README.md # this file | ||
| ``` | ||
|
|
||
| ## Contract | ||
|
|
||
| The sample is keploy-independent: `docker compose up && bash flow.sh bootstrap && bash flow.sh record-traffic` runs end-to-end against bare umami. Lane scripts wrap that exact same path inside `keploy record` / `keploy test`. | ||
|
|
||
| * `bootstrap` — login as admin via `/api/auth/login`, capture the JWT-style auth token, persist it to `/tmp/umami-token-${UMAMI_PHASE}` so subsequent calls share a deterministic Authorization header. | ||
| * `record-traffic` — drive the umami v1 API. Every call is logged to `${UMAMI_FIRED_ROUTES_FILE}` (when set) so the `coverage` subcommand has a numerator without needing a keploy recording. | ||
| * `coverage` — walks the running container's `src/app/api/**/route.ts` tree as the denominator (the umami router is file-system based), compares against fired/recorded routes, emits a `(method, path)` percentage. | ||
| * `list-routes` — diagnostic; prints the route table. | ||
|
|
||
| ## Local run | ||
|
|
||
| ```sh | ||
| docker compose up -d | ||
| bash flow.sh bootstrap 240 | ||
| UMAMI_FIRED_ROUTES_FILE=/tmp/fired.log bash flow.sh record-traffic | ||
| UMAMI_FIRED_ROUTES_FILE=/tmp/fired.log bash flow.sh coverage | ||
| docker compose down -v | ||
| ``` | ||
|
|
||
| ## Consumers | ||
|
|
||
| Lanes pinning to this sample (pinned via `--branch feat/keploy-compat-lanes-rollout` until merge): | ||
|
|
||
| * `keploy/enterprise` `.woodpecker/umami-linux.yml` — being slimmed in a follow-up PR. | ||
| * `keploy/integrations` may add a `.woodpecker/umami-postgres.yml` falsifying lane in a future PR (currently no integrations-side coverage of this app). |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||||||||||
| # umami-postgres sample compose. Postgres-15 + umami v2 on a fixed | ||||||||||||||
| # subnet, every name env-driven so multiple matrix cells can run | ||||||||||||||
| # in parallel on the same docker daemon. Two-phase boot pattern | ||||||||||||||
| # matches the doccano-django sibling: SKIP_INIT=0 first time so | ||||||||||||||
| # umami's `npx umami-app db:up` runs migrations and seeds; volume | ||||||||||||||
| # is retained; SKIP_INIT=1 second time launches the app against | ||||||||||||||
|
Comment on lines
+4
to
+6
|
||||||||||||||
| # matches the doccano-django sibling: SKIP_INIT=0 first time so | |
| # umami's `npx umami-app db:up` runs migrations and seeds; volume | |
| # is retained; SKIP_INIT=1 second time launches the app against | |
| # matches the doccano-django sibling: UMAMI_SKIP_INIT=0 first time so | |
| # umami's `npx umami-app db:up` runs migrations and seeds; volume | |
| # is retained; UMAMI_SKIP_INIT=1 second time launches the app against |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,227 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # flow.sh — keploy-independent orchestration for the umami-postgres | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # sample. Modeled on samples-python/doccano-django/flow.sh. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Subcommands: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # bootstrap — log in as admin, install a deterministic auth | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # token so record/replay headers match. Runs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # once against a SKIP_INIT=0 launch; idempotent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # on the named volume. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # record-traffic — drive the API: the call sequence whose | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # responses we want recorded. Fire-and-forget; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # keploy is the assertion layer at replay. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # coverage — walk umami's route table inside the running | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # container, compare against fired routes, emit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # a (method, path) coverage percentage. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # list-routes — print the route table the coverage report | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # uses as its denominator (diagnostic). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # HANDOFF NOTE: this is a SCAFFOLD. The traffic loop in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # `umami_record_traffic` below is intentionally minimal — it hits | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # the API surface enough to prove the sample boots end-to-end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # without keploy. The full traffic loop (the one | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # enterprise/.ci/scripts/umami-linux.sh's `run_api_flow` function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # drives, ~250 lines of curls covering websites / events / | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # sessions / reports / share-tokens / shareability) needs to be | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ported here. Until then, the keploy lane consuming this sample | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # can either: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (a) call `bash flow.sh record-traffic` then `bash flow.sh | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # extra-traffic-from-lane` where the lane defines the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # extra calls inline, OR | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (b) call into `umami-linux.sh::run_api_flow` directly until | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # the migration completes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # See https://github.com/keploy/samples-typescript/issues/<TBD> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # for the migration plan. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -Eeuo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_APP_PORT="${UMAMI_APP_PORT:-3001}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_APP_CONTAINER="${UMAMI_APP_CONTAINER:-umami_app}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_DB_CONTAINER="${UMAMI_DB_CONTAINER:-umami_db}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_ADMIN_USER="${UMAMI_ADMIN_USER:-admin}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_ADMIN_PASSWORD="${UMAMI_ADMIN_PASSWORD:-umami}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_FIXED_TOKEN="${UMAMI_FIXED_TOKEN:-}" # populated by bootstrap; lane scripts may pre-seed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_PHASE="${UMAMI_PHASE:-local}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+29
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UMAMI_FIRED_ROUTES_FILE="${UMAMI_FIRED_ROUTES_FILE:-}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| base="http://127.0.0.1:${UMAMI_APP_PORT}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| h_json='Content-Type: application/json' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log_fired() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ -z "$UMAMI_FIRED_ROUTES_FILE" ] && return 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| printf '%s %s\n' "$1" "$2" >>"$UMAMI_FIRED_ROUTES_FILE" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # umami_wait_for_app — readiness gate. /api/heartbeat returns 200 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # only when the Next.js server has bound and Prisma is connected. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Stronger than wait_for_port; checks the actual app surface. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| umami_wait_for_app() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local timeout=${1:-180} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local start_ts code | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start_ts=$(date +%s) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while true; do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code=$(curl -sS -o /dev/null -w '%{http_code}' "${base}/api/heartbeat" 2>/dev/null || echo "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$code" = "200" ]; then return 0; fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ $(( $(date +%s) - start_ts )) -ge "$timeout" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "umami_wait_for_app: timed out (last code: ${code:-<empty>})" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "umami_wait_for_app: timed out (last code: ${code:-<empty>})" >&2 | |
| echo "umami_wait_for_app: timed out waiting for ${base}/api/heartbeat (last code: ${code:-<empty>}). Next steps: run 'docker compose ps' to confirm services are up, inspect app logs with 'docker logs ${UMAMI_APP_CONTAINER}', and verify UMAMI_APP_PORT=${UMAMI_APP_PORT} matches the compose port mapping." >&2 |
Copilot
AI
May 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/tmp/umami-login.json is a fixed path. If curl fails before writing the file, cat may print stale output from a previous run, which can mislead debugging. Consider using a temp file (e.g., mktemp) and cleaning it up, or truncating the file before the request so failures don’t surface old content.
| local resp code | |
| resp=$(curl -sS -o /tmp/umami-login.json -w '%{http_code}' \ | |
| -H "$h_json" -X POST "${base}/api/auth/login" \ | |
| -d "{\"username\":\"${UMAMI_ADMIN_USER}\",\"password\":\"${UMAMI_ADMIN_PASSWORD}\"}" 2>/dev/null || echo "") | |
| if [ "$resp" != "200" ]; then | |
| echo "umami_bootstrap: login failed (code ${resp:-empty})" >&2 | |
| cat /tmp/umami-login.json >&2 || true | |
| return 1 | |
| fi | |
| local token | |
| token=$(jq -r '.token' /tmp/umami-login.json 2>/dev/null) | |
| if [ -z "$token" ] || [ "$token" = "null" ]; then | |
| echo "umami_bootstrap: no token in login response" >&2 | |
| return 1 | |
| fi | |
| printf '%s' "$token" > "/tmp/umami-token-${UMAMI_PHASE}" | |
| local resp code login_resp_file | |
| login_resp_file=$(mktemp /tmp/umami-login.XXXXXX.json) | |
| resp=$(curl -sS -o "$login_resp_file" -w '%{http_code}' \ | |
| -H "$h_json" -X POST "${base}/api/auth/login" \ | |
| -d "{\"username\":\"${UMAMI_ADMIN_USER}\",\"password\":\"${UMAMI_ADMIN_PASSWORD}\"}" 2>/dev/null || echo "") | |
| if [ "$resp" != "200" ]; then | |
| echo "umami_bootstrap: login failed (code ${resp:-empty}); verify the app is reachable and the admin credentials are correct, then retry." >&2 | |
| cat "$login_resp_file" >&2 || true | |
| rm -f "$login_resp_file" | |
| return 1 | |
| fi | |
| local token | |
| token=$(jq -r '.token' "$login_resp_file" 2>/dev/null) | |
| if [ -z "$token" ] || [ "$token" = "null" ]; then | |
| echo "umami_bootstrap: no token in login response; inspect the login API response and confirm the expected token field is present, then retry." >&2 | |
| rm -f "$login_resp_file" | |
| return 1 | |
| fi | |
| printf '%s' "$token" > "/tmp/umami-token-${UMAMI_PHASE}" | |
| rm -f "$login_resp_file" |
Copilot
AI
May 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
record-traffic currently swallows request failures (curl ... || true), so the command can exit 0 even when the API is down / returning 401s. That makes the scaffold look healthy while not actually exercising the surface (and also logs routes as fired even if the request failed). Consider using curl -f (or checking status codes) and letting the script fail on the first unexpected response; only append to UMAMI_FIRED_ROUTES_FILE after a successful call.
Copilot
AI
May 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The website create call is wrapped with || echo "", which hides HTTP failures from curl -f and then proceeds with an empty response. This can silently skip the rest of the traffic and still exit 0. Prefer failing hard on a non-2xx response (or explicitly handling expected conflicts like “already exists” by checking the status code and response body).
| local website_resp website_id | |
| log_fired POST "$base/api/websites" | |
| website_resp=$(curl -fsS -H "$h_auth" -H "$h_json" -X POST "$base/api/websites" \ | |
| -d "{\"name\":\"keploy-${UMAMI_PHASE}\",\"domain\":\"sample.keploy.io\"}" 2>/dev/null || echo "") | |
| website_id=$(jq -r '.id // empty' <<<"$website_resp" 2>/dev/null || true) | |
| if [ -n "$website_id" ]; then | |
| log_fired GET "$base/api/websites/${website_id}" | |
| curl -sS -H "$h_auth" "$base/api/websites/${website_id}" >/dev/null || true | |
| log_fired GET "$base/api/websites/${website_id}/stats" | |
| curl -sS -H "$h_auth" "$base/api/websites/${website_id}/stats?startAt=0&endAt=$(date +%s%3N)" >/dev/null || true | |
| fi | |
| local website_resp website_id website_status website_resp_file | |
| log_fired POST "$base/api/websites" | |
| website_resp_file=$(mktemp) | |
| website_status=$(curl -sS -o "$website_resp_file" -w "%{http_code}" -H "$h_auth" -H "$h_json" -X POST "$base/api/websites" \ | |
| -d "{\"name\":\"keploy-${UMAMI_PHASE}\",\"domain\":\"sample.keploy.io\"}") | |
| website_resp=$(cat "$website_resp_file") | |
| rm -f "$website_resp_file" | |
| if [ "$website_status" -lt 200 ] || [ "$website_status" -ge 300 ]; then | |
| echo "umami_record_traffic: website creation returned HTTP ${website_status}; verify the Umami app is healthy and the admin token is valid, then retry \`flow.sh bootstrap\` or rerun this flow" >&2 | |
| return 1 | |
| fi | |
| website_id=$(jq -r '.id // empty' <<<"$website_resp" 2>/dev/null || true) | |
| if [ -z "$website_id" ]; then | |
| echo "umami_record_traffic: website creation succeeded but no website id was returned; inspect the /api/websites response format and retry the flow" >&2 | |
| return 1 | |
| fi | |
| log_fired GET "$base/api/websites/${website_id}" | |
| curl -sS -H "$h_auth" "$base/api/websites/${website_id}" >/dev/null || true | |
| log_fired GET "$base/api/websites/${website_id}/stats" | |
| curl -sS -H "$h_auth" "$base/api/websites/${website_id}/stats?startAt=0&endAt=$(date +%s%3N)" >/dev/null || true |
Copilot
AI
May 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This WARNING: message + return 0 causes coverage to succeed even when route discovery failed (e.g., wrong container name, docker exec failure, or path changes in the image). Since this is used in CI gating, consider treating “no routes discovered” as an error with an actionable next step (e.g., verify the container is running and UMAMI_APP_CONTAINER matches), and exit non-zero instead of emitting a warning.
| echo "WARNING: umami_list_routes produced no rows; skipping coverage report" >&2 | |
| rm -f "$routes_file" "$recorded_file"; return 0 | |
| echo "ERROR: umami_list_routes produced no rows. Verify the app container is running, confirm UMAMI_APP_CONTAINER='${UMAMI_APP_CONTAINER}' matches the actual container name, and check whether the route discovery path inside the image has changed." >&2 | |
| rm -f "$routes_file" "$recorded_file"; return 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # keploy.yml template for the umami-postgres sample. | ||
| # | ||
| # Lane scripts copy this into the run dir before invoking | ||
| # `keploy record` / `keploy test`. globalNoise covers the | ||
| # fields whose value is inherently non-deterministic across | ||
| # record/replay (timestamps the server stamps from time.now() | ||
| # or generates from random sources): | ||
| # | ||
| # header.Date | ||
| # Set by Next.js / the runtime on every response. | ||
| # body.createdAt / body.updatedAt | ||
| # Prisma auto-now fields stamped on insert/update. | ||
| # body.id (when it's a uuid response field) / body.token | ||
| # Server-generated identifiers — the test surface that | ||
| # gates correctness lives in the *response shape*, not | ||
| # these random values. | ||
| # | ||
| # Add to this list when umami introduces another auto-stamped | ||
| # field; do NOT add it to the lane scripts (that's how the | ||
| # noise lists drift between consumers). | ||
| test: | ||
| globalNoise: | ||
| global: | ||
| header.Date: [] | ||
| body.createdAt: [] | ||
| body.updatedAt: [] | ||
| body.id: [] | ||
| body.token: [] | ||
| body.shareId: [] | ||
| body.websiteId: [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Dockerfile comment says the pinned upstream image is
docker.io/umamisoftware/umami:postgresql-v2.18.1, but theFROMline usesghcr.io/umami-software/umami:postgresql-v2.18.1. Please align the comment with the actual registry to avoid confusion when updating the pin.