160 lines
4.3 KiB
Markdown
160 lines
4.3 KiB
Markdown
# 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`
|
|
4. Test DB preflight (for DB-backed suites):
|
|
- `TEST_DATABASE_URL` points to a reachable PostgreSQL instance.
|
|
- Example quick check:
|
|
```bash
|
|
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`)
|
|
5. 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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)
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
curl -i "${API_BASE}/dashboard"
|
|
```
|
|
|
|
Expected:
|
|
- HTTP `401`
|
|
- response body includes `UNAUTHENTICATED`
|
|
|
|
### 2) Spoofed identity header is ignored
|
|
|
|
```bash
|
|
curl -i -H "x-user-id: spoofed-user-id" "${API_BASE}/dashboard"
|
|
```
|
|
|
|
Expected:
|
|
- HTTP `401`
|
|
|
|
### 3) Admin rollover is not publicly callable
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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.
|