diff --git a/.forgejo/workflows/deps-audit.yml b/.forgejo/workflows/deps-audit.yml new file mode 100644 index 0000000..68b63b5 --- /dev/null +++ b/.forgejo/workflows/deps-audit.yml @@ -0,0 +1,25 @@ +# Weekly dependency guard (QA-B0-02 durable fix): dependency rot must surface +# as a red scheduled run, not wait for the next manual audit. Fails on any +# high+ vulnerability in production deps; prints the outdated report either way. +name: deps-audit +on: + schedule: + - cron: '0 11 * * 1' # Mondays 11:00 UTC (~06:00 America/Chicago) + workflow_dispatch: + +jobs: + audit: + runs-on: docker + container: + image: node:22-bookworm + steps: + - uses: actions/checkout@v4 + + - name: Install (lockfile-exact) + run: npm ci + + - name: Audit production deps (fail on high or critical) + run: npm audit --omit=dev --audit-level=high + + - name: Outdated report (informational) + run: npm outdated || true diff --git a/docs/DEPLOY_CHECKLIST.md b/docs/DEPLOY_CHECKLIST.md new file mode 100644 index 0000000..43d829e --- /dev/null +++ b/docs/DEPLOY_CHECKLIST.md @@ -0,0 +1,45 @@ +# Production Deploy Checklist + +The environment/config items that are **not** enforced by code or CI and must be +verified on the production instance itself. Each has a boot-time warning or a +QA-plan pointer; this list is the single place they live (previously they only +existed in session notes). + +## Required environment (production) + +| Variable | Why | Symptom if missing | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | +| `TOKEN_ENCRYPTION_KEY` | At-rest secrets (SimpleFIN token, SMTP/OIDC secrets, login IP/UA) otherwise fall back to a key stored **inside the database** — anyone with DB/backup read access can decrypt. On first boot with the key set, stored `v2:` ciphertexts migrate to env-keyed `e2:`. | Boot warning: `TOKEN_ENCRYPTION_KEY is not set in production` | +| `WEBAUTHN_RP_ID` | Passkeys bind cryptographically to this hostname; the `localhost` default silently breaks all passkey sign-ins behind a real domain. Bare hostname, no scheme/port (e.g. `bills.example.com`). Changing it later invalidates registered keys. | Boot warning: `WEBAUTHN_RP_ID is not set in production` | +| `WEBAUTHN_ORIGIN` (optional) | Pin the exact expected origin for WebAuthn ceremonies when the app is served from a non-default origin. When unset, the API origin plus any request origin whose hostname equals the RP ID is accepted. | Passkey enroll/sign-in fails origin verification | + +## One-time settings (Admin panel / DB) + +- [ ] **Turn OFF `simplefin_debug_logging`** on the production instance + (Admin → bank sync config). It is a debugging aid; leaving it on logs + more sync detail than production needs. + +## Build/runtime infrastructure + +- [ ] **`cdn.sheetjs.com` egress** — the lockfile pins `xlsx` to the official + SheetJS dist tarball (the npm registry line is abandoned with unfixed + high CVEs). CI runners and Docker builds must be able to reach it for + `npm ci`. +- [ ] **Node version alignment** — `package.json` engines, the Dockerfile base + image, and the CI image must agree (all `node:22` today). Bump all three + together. +- [ ] Volumes/permissions/migrations: handled by `docker-entrypoint.sh` + (`chmod 700` data dirs, non-root `bill` user, `RUN_DB_MIGRATIONS=true`) + — covered by QA batch B16. + +## Standing dependency guard + +- `renovate.json` is in the repo — enable Renovate on the Forgejo instance for + grouped weekly update PRs. +- Until then, `.forgejo/workflows/deps-audit.yml` runs weekly: it fails on any + high+ vulnerability (`npm audit --omit=dev --audit-level=high`) and prints + `npm outdated`, so dependency rot surfaces as a red scheduled run instead of + waiting for the next manual audit. +- Deferred upgrade, tracked: **TypeScript 7** typechecks this codebase clean but + `typescript-eslint` (peer `<6.1.0`) cannot parse under it yet — revisit when + typescript-eslint ships TS 7 support. diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..a7dd780 --- /dev/null +++ b/renovate.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"], + "timezone": "America/Chicago", + "schedule": ["before 6am on monday"], + "labels": ["dependencies"], + "rangeStrategy": "bump", + "packageRules": [ + { + "description": "Group all non-major updates into one weekly PR", + "matchUpdateTypes": ["minor", "patch"], + "groupName": "non-major dependencies" + }, + { + "description": "Majors stay separate — each needs its own verification pass (see docs/QA_PLAN.md B0 dependency recon)", + "matchUpdateTypes": ["major"], + "dependencyDashboardApproval": true + }, + { + "description": "xlsx is pinned to the official SheetJS CDN tarball (npm line is abandoned with unfixed CVEs) — do not touch", + "matchPackageNames": ["xlsx"], + "enabled": false + }, + { + "description": "typescript is capped at 6.x until typescript-eslint supports TS 7 (peer <6.1.0)", + "matchPackageNames": ["typescript"], + "allowedVersions": "<7.0.0" + } + ], + "vulnerabilityAlerts": { "enabled": true }, + "osvVulnerabilityAlerts": true +}