teqo/tests/helpers/assertTestDatabase.ts
Francisco Solla 659f25f076
Some checks failed
CI (PR) / checks (pull_request) Failing after 1m38s
PR Ready + auto-merge / ready-automerge (pull_request) Failing after 2m5s
fix(OPS62): services por nome na rede do job — Forgejo 9 não expande expressões em ports
Achado ao vivo (run 730): a expressão ${{ 5433 + (github.run_id % 100) }} no
ports do service não é avaliada pelo Forgejo 9 — o literal ia ao runner e o
job falhava em 1s. E portas fixas colidiriam entre runs concorrentes (o job
único segura os services pelo run inteiro). Correção: services sem publish
host, alcançados por nome na rede do job (postgres-int/postgres-build:5432)
— solução canônica do Actions, mata a colisão de raiz. Guards fail-closed
(LOCAL_HOSTS + assertTestDatabase) admitem os nomes dos services (hosts
internos do runner; hosts remotos continuam rejeitados); pins novos em
localHosts.unit.spec.ts e ciSkipInvariants (sem ports:, URLs por nome).
2026-08-18 19:43:53 -03:00

62 lines
2.4 KiB
TypeScript

/**
* Fail-closed guard for the automated test suite.
*
* The tests delete and recreate records (see seedUser.ts), so they must NEVER
* run against the production database. Rather than trying to detect prod (an
* allowlist we could forget to update), we require a LOCAL database whose name
* is `teqo_test` or `teqo_<worktree>_test` (per-worktree isolation generated
* by `pnpm worktree next`). A remote database is rejected even if its name
* looks test-like.
*/
/** `teqo_test`, `teqo_wt15_test`, … — the _test suffix is the hard contract. */
const TEST_DATABASE_NAME = /^teqo(_[a-z0-9]+)?_test$/
// Self-hosted Forgejo runner: services are reached by NAME on the job network
// (postgres-int / postgres-build, OPS62 X1) or, on the legacy per-port
// publish, through the bridge gateway IP (RFC1918). Same source as the CLI
// guard so both guards admit exactly the same hosts (OPS50/OPS62).
import { defaultGatewayHost } from '../../scripts/lib/cli.mjs'
export function assertTestDatabase(databaseUrl: string | undefined): void {
if (!databaseUrl) {
throw new Error(
'DATABASE_URL is not set. Tests require a dedicated local test database configured in ' +
'.env.test (e.g. postgresql://teqo:teqo@localhost:5432/teqo_test).',
)
}
let parsedUrl: URL
try {
parsedUrl = new URL(databaseUrl)
} catch {
throw new Error('DATABASE_URL is not a valid PostgreSQL connection string.')
}
const databaseName = decodeURIComponent(parsedUrl.pathname.replace(/^\//, ''))
const localHosts = new Set([
'localhost',
'127.0.0.1',
'::1',
'[::1]',
'postgres-int',
'postgres-build',
])
const gateway = defaultGatewayHost()
if (gateway) localHosts.add(gateway)
if (
parsedUrl.protocol !== 'postgresql:' ||
!TEST_DATABASE_NAME.test(databaseName) ||
!localHosts.has(parsedUrl.hostname)
) {
throw new Error(
`Refusing to run tests using protocol "${parsedUrl.protocol || '(unknown)'}" against database ` +
`"${databaseName || '(unknown)'}" on host ` +
`"${parsedUrl.hostname || '(unknown)'}". Tests require a local database named ` +
'`teqo_test` or `teqo_<worktree>_test` (per-worktree isolation from `pnpm worktree next`) ' +
'over postgresql: on localhost, 127.0.0.1, or ::1. ' +
'Configure DATABASE_URL in .env.test (e.g. postgresql://teqo:teqo@localhost:5432/teqo_test).',
)
}
}