feat(19-05): global-setup local_credentials seed + login.spec.ts + CI harness env
- global-setup.ts: TRUNCATE local_credentials + seed devuser/devpass (PHC scrypt inline) - Create login.spec.ts: real-login-form e2e (gate redirect, wrong-password error, correct login) - ci.yml: add LOCAL_SESSION_SECRET dev value + local_credentials seed step in harness job - Fix all test mocks: add devSessionCookieMiddleware no-op to vi.mock(devBypass.js) blocks in admin/setup/push/lists/localAuth/authMode/requireAdmin tests (Rule 1 - Bug: missing export) - Full API suite: 446/446 tests pass; pnpm typecheck: exit 0
This commit is contained in:
@@ -285,6 +285,49 @@ jobs:
|
||||
# CI=true makes Playwright start Vite :5173 itself (reuseExistingServer=false), use
|
||||
# retries:2/workers:1, and apply reporter:'github' — which --reporter=list,html overrides
|
||||
# because Gitea does not render github annotations (Pitfall 5 / D-06). Both projects run.
|
||||
# Phase 19 (AUTH-LOCAL-16, D-14/D-15): seed local_credentials for dev user (id=1).
|
||||
# devSessionCookieMiddleware issues a local-session cookie on each /api/* request
|
||||
# when DEV_AUTH_BYPASS=true and LOCAL_SESSION_SECRET is set, so the PWA login gate
|
||||
# skips /login and existing specs still reach the authed app unchanged.
|
||||
# global-setup.ts also seeds this row via hashPasswordInline — this step is a
|
||||
# belt-and-suspenders seed for the initial CI DB state before Playwright runs.
|
||||
# The dev password 'devpass' is NOT a secret — it only exists in the ephemeral CI DB.
|
||||
- name: Seed local_credentials for dev user (id=1)
|
||||
env:
|
||||
DB_HOST: mariadb
|
||||
DB_PORT: 3306
|
||||
DB_USER: familysync
|
||||
DB_PASSWORD: testpass
|
||||
DB_NAME: familysync
|
||||
run: |
|
||||
node --input-type=commonjs - <<'EOF'
|
||||
const mysql = require('mysql2/promise');
|
||||
const crypto = require('crypto');
|
||||
// Inline PHC scrypt hash (matches apps/api/src/auth/localCredentials.ts)
|
||||
function hashPassword(password) {
|
||||
const salt = crypto.randomBytes(16);
|
||||
const hash = crypto.scryptSync(password, salt, 32, { N: 16384, r: 8, p: 1 });
|
||||
return ['scrypt', 16384, 8, 1, salt.toString('base64url'), hash.toString('base64url')].join('$');
|
||||
}
|
||||
(async () => {
|
||||
const conn = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: Number(process.env.DB_PORT ?? 3306),
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
});
|
||||
const passwordHash = hashPassword('devpass');
|
||||
await conn.execute(
|
||||
"INSERT INTO local_credentials (user_id, username, password_hash) VALUES (1, 'devuser', ?) ON DUPLICATE KEY UPDATE password_hash = VALUES(password_hash)",
|
||||
[passwordHash],
|
||||
);
|
||||
console.log('seeded local_credentials for dev user id=1');
|
||||
await conn.end();
|
||||
})();
|
||||
EOF
|
||||
working-directory: apps/pwa
|
||||
|
||||
- name: Run harness (start API + Playwright iphone + pixel + desktop)
|
||||
env:
|
||||
CI: 'true'
|
||||
@@ -298,6 +341,12 @@ jobs:
|
||||
NODE_OPTIONS: '--dns-result-order=ipv4first'
|
||||
DEV_AUTH_BYPASS: 'true'
|
||||
NODE_ENV: development
|
||||
# Phase 19 (AUTH-LOCAL-16, D-14/D-15): LOCAL_SESSION_SECRET required for
|
||||
# devSessionCookieMiddleware to issue real local-session cookies under bypass.
|
||||
# This is a fixed dev-only value — NEVER a production secret.
|
||||
# Must be >=32 chars (assertLocalSessionSecretSet boot guard skips in bypass mode,
|
||||
# but the cookie signing requires a non-empty secret to function).
|
||||
LOCAL_SESSION_SECRET: 'dev-secret-change-me-0000000000000000'
|
||||
DB_HOST: mariadb
|
||||
DB_PORT: 3306
|
||||
DB_USER: familysync
|
||||
|
||||
Reference in New Issue
Block a user