Files
SkyMoney/tests-results-for-OWASP/post-deployment-verification-checklist.md
Ricearoni1245 fe96bf85da
Some checks failed
Deploy / deploy (push) Successful in 57s
Security Tests / security-non-db (push) Successful in 18s
Security Tests / security-db (push) Failing after 20s
added db guard changes to prevent deletion
2026-03-10 21:19:24 -05:00

4.5 KiB

Post-Deployment Verification Checklist

Use this after every deploy (staging and production).

Preconditions

  1. Deployment completed successfully.
  2. Migrations completed successfully.
  3. Correct environment flags:
  • AUTH_DISABLED=false
  • ALLOW_INSECURE_AUTH_FOR_DEV=false
  1. Test DB preflight (for DB-backed suites):
  • TEST_DATABASE_URL points to a reachable PostgreSQL instance.
  • TEST_DATABASE_URL database name is not skymoney and is clearly test-only (for example skymoney_test).
  • bash ./scripts/validate-test-db-target.sh passes before DB-backed suites run.
  • Example quick check:
echo "$TEST_DATABASE_URL"

Expected:

  • single valid URL value
  • host/port match the intended test database (for local runs usually 127.0.0.1:5432)
  1. Compose/DB safety preflight:
  • COMPOSE_PROJECT_NAME=skymoney is set for deploy runtime.
  • docker-compose.yml volume pgdata is pinned to skymoney_pgdata.
  • scripts/validate-prod-db-target.sh passes for current .env.
  • scripts/guard-prod-volume.sh passes (or explicit one-time rebuild override is documented).
  • deploy runbook acknowledges forbidden destructive commands in prod:
    • prisma migrate reset
    • prisma migrate dev
    • prisma db push --accept-data-loss
    • docker compose down -v / docker-compose down -v

Database recoverability and safety checks

0) Capture current container and volume bindings

docker ps --format '{{.Names}}'
docker inspect <postgres-container> --format '{{json .Mounts}}'
docker volume ls | grep -E 'pgdata|skymoney|postgres'
PROD_DB_VOLUME_NAME=skymoney_pgdata ALLOW_EMPTY_PROD_VOLUME=0 DOCKER_CMD="sudo docker" bash ./scripts/guard-prod-volume.sh

Expected:

  • production Postgres uses skymoney_pgdata.
  • no unexpected new empty volume silently substituted.

0.1) Validate latest backup artifact exists and verifies

ls -lt /opt/skymoney/backups | head
LATEST_DUMP="$(ls -1t /opt/skymoney/backups/*.dump | head -n 1)"
sha256sum -c "${LATEST_DUMP}.sha256"

Expected:

  • latest dump and checksum exist.
  • checksum verification returns OK.

0.2) Restore drill into isolated test DB (same VPS)

RESTORE_DB="skymoney_restore_test_$(date +%Y%m%d%H%M)" \
BACKUP_FILE="$LATEST_DUMP" \
RESTORE_DATABASE_URL="postgres://<user>:<pass>@127.0.0.1:5432/${RESTORE_DB}" \
DATABASE_URL="postgres://<admin-user>:<admin-pass>@127.0.0.1:5432/skymoney" \
./scripts/restore.sh

Expected:

  • restore completes without manual edits.
  • key tables readable in restored DB.

A01 smoke checks

Replace ${API_BASE} with your deployed API base URL.

1) Protected route requires auth

curl -i "${API_BASE}/dashboard"

Expected:

  • HTTP 401
  • response body includes UNAUTHENTICATED

2) Spoofed identity header is ignored

curl -i -H "x-user-id: spoofed-user-id" "${API_BASE}/dashboard"

Expected:

  • HTTP 401

3) Admin rollover is not publicly callable

curl -i -X POST "${API_BASE}/admin/rollover" \
  -H "Content-Type: application/json" \
  -d '{"dryRun":true}'

Expected:

  • HTTP 401 or 403 (must not be publicly callable)

A09 smoke checks

4) Security events are emitted for failed auth attempts

Trigger a failed login attempt:

curl -i -X POST "${API_BASE}/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"nonexistent@example.com","password":"WrongPass123!"}'

Expected:

  • HTTP 401
  • API logs include a structured securityEvent for auth.login with outcome=failure
  • log entry includes requestId

A10 smoke checks

5) Production origin configuration is public and non-local

Verify production env/config:

  • APP_ORIGIN uses public HTTPS host (not localhost/private IP ranges)

Expected:

  • API boots successfully with production env validation.

Automated regression checks

Run in CI against a prod-like environment:

cd api
npm test -- tests/auth.routes.test.ts tests/access-control.account-delete.test.ts tests/access-control.admin-rollover.test.ts
SECURITY_DB_TESTS=0 npx vitest run -c vitest.security.config.ts
SECURITY_DB_TESTS=1 npx vitest run -c vitest.security.config.ts

Expected:

  • all tests pass

Note:

  • A06/A07 runtime suites require PostgreSQL availability.
  • SECURITY_DB_TESTS=0 runs non-DB security controls only.
  • SECURITY_DB_TESTS=1 includes DB-backed A06/A07/forgot-password suites.

Sign-off

  1. Record outputs in evidence-log-template.md.
  2. Review open residual risks in residual-risk-backlog.md.
  3. Record backup + restore drill evidence.
  4. Mark release security check as pass/fail.