Merge pull request '[E00-S03-T01] PostgreSQL 18.6 container' (#390) from feature/176 into main
This commit was merged in pull request #390.
This commit is contained in:
@@ -36,3 +36,20 @@ jobs:
|
|||||||
node-version: '24'
|
node-version: '24'
|
||||||
- name: Run secrets-not-embedded test suite
|
- name: Run secrets-not-embedded test suite
|
||||||
run: node --test tests/secrets-not-embedded.test.mjs
|
run: node --test tests/secrets-not-embedded.test.mjs
|
||||||
|
|
||||||
|
# E00-S03-T01: the static assertions of tests/compose-config.test.mjs (db
|
||||||
|
# image pinned to postgres:18.6-bookworm, health gate, volume persistence,
|
||||||
|
# build platforms) gate every PR (the docker-gated real-stack probes inside
|
||||||
|
# the same file run where a Docker daemon is available and skip cleanly
|
||||||
|
# otherwise).
|
||||||
|
compose-config:
|
||||||
|
name: Compose config (E00-S03-T01)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Node.js 24
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '24'
|
||||||
|
- name: Run compose-config test suite
|
||||||
|
run: node --test tests/compose-config.test.mjs
|
||||||
|
|||||||
+7
-4
@@ -1,4 +1,4 @@
|
|||||||
# EPPP Docker Compose baseline — [E00-S02-T01..T08]
|
# EPPP Docker Compose baseline — [E00-S02-T01..T08] + [E00-S03-T01]
|
||||||
#
|
#
|
||||||
# `docker compose up -d` starts both the database (PostgreSQL) and the
|
# `docker compose up -d` starts both the database (PostgreSQL) and the
|
||||||
# application (@personal-blog/server). Rollback: `docker compose down`.
|
# application (@personal-blog/server). Rollback: `docker compose down`.
|
||||||
@@ -53,9 +53,12 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
db:
|
db:
|
||||||
# PostgreSQL 18 on Debian bookworm — the documented runtime target
|
# PostgreSQL 18.6 on Debian bookworm — the documented runtime target
|
||||||
# (Technology-Stack §5.2/§5.4/§6.2, golden tuple §7; no Alpine drift).
|
# (Technology-Stack §5.2/§5.4/§6.2, golden tuple §7; no Alpine drift),
|
||||||
image: postgres:18-bookworm
|
# pinned to the exact 18.6 minor (E00-S03-T01) so the database container
|
||||||
|
# is reproducible and exposes the expected PostgreSQL version. Rollback:
|
||||||
|
# revert `image` to `postgres:18-bookworm`.
|
||||||
|
image: postgres:18.6-bookworm
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-eppp}
|
POSTGRES_DB: ${POSTGRES_DB:-eppp}
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-eppp}
|
POSTGRES_USER: ${POSTGRES_USER:-eppp}
|
||||||
|
|||||||
@@ -345,8 +345,8 @@ test('a platforms list on the db service (which has no build config) cannot sati
|
|||||||
const dbOnly = text
|
const dbOnly = text
|
||||||
.replace(/\n\s*platforms:\n(?:\s*- [^\n]+\n)+/, '\n')
|
.replace(/\n\s*platforms:\n(?:\s*- [^\n]+\n)+/, '\n')
|
||||||
.replace(
|
.replace(
|
||||||
' image: postgres:18-bookworm\n',
|
' image: postgres:18.6-bookworm\n',
|
||||||
' image: postgres:18-bookworm\n platforms:\n - linux/amd64\n - linux/arm64\n',
|
' image: postgres:18.6-bookworm\n platforms:\n - linux/amd64\n - linux/arm64\n',
|
||||||
);
|
);
|
||||||
assert.notEqual(dbOnly, text, 'the mutation must actually move the platforms list onto db');
|
assert.notEqual(dbOnly, text, 'the mutation must actually move the platforms list onto db');
|
||||||
assert.throws(() => assertBuildTargets(parseYaml(dbOnly)), /platforms/);
|
assert.throws(() => assertBuildTargets(parseYaml(dbOnly)), /platforms/);
|
||||||
|
|||||||
@@ -180,8 +180,9 @@ function assertDbService(compose) {
|
|||||||
assert.ok(db, 'compose.yaml must declare a "db" service (docker compose up -d starts the database)');
|
assert.ok(db, 'compose.yaml must declare a "db" service (docker compose up -d starts the database)');
|
||||||
assert.equal(
|
assert.equal(
|
||||||
db.image,
|
db.image,
|
||||||
'postgres:18-bookworm',
|
'postgres:18.6-bookworm',
|
||||||
'the "db" service must use the committed PostgreSQL 18 image (postgres:18-bookworm)',
|
'the "db" service must use the committed PostgreSQL 18.6 image (postgres:18.6-bookworm — E00-S03-T01 ' +
|
||||||
|
'pins the exact minor so the database container exposes the expected PostgreSQL version)',
|
||||||
);
|
);
|
||||||
const env = db.environment ?? {};
|
const env = db.environment ?? {};
|
||||||
assert.equal(env.POSTGRES_DB, '${POSTGRES_DB:-eppp}', 'db must set POSTGRES_DB (with a default)');
|
assert.equal(env.POSTGRES_DB, '${POSTGRES_DB:-eppp}', 'db must set POSTGRES_DB (with a default)');
|
||||||
@@ -640,6 +641,43 @@ test('a database fixture survives docker compose restart and recreate (named db-
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the database container exposes the expected PostgreSQL version (18.6)', { skip: !DOCKER_COMPOSE || !DOCKER_DAEMON }, () => {
|
||||||
|
// E00-S03-T01 acceptance criteria: a PostgreSQL 18.6 container is used as
|
||||||
|
// the database AND the container exposes the expected PostgreSQL version.
|
||||||
|
// The committed image tag is pinned to postgres:18.6-bookworm (asserted
|
||||||
|
// statically above); this probe starts the stack and asks the running
|
||||||
|
// server itself (`SHOW server_version`) — the issue's test plan ("start the
|
||||||
|
// container and confirm PostgreSQL 18.6") — so the version the container
|
||||||
|
// actually exposes is verified end to end, not just the declared tag.
|
||||||
|
const up = run('docker', ['compose', 'up', '-d'], { cwd: REPO_ROOT });
|
||||||
|
assert.equal(
|
||||||
|
up.status,
|
||||||
|
0,
|
||||||
|
`"docker compose up -d" must exit 0:\n${(up.stdout || '')}\n${(up.stderr || '')}`.trim(),
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
waitForDbHealthy();
|
||||||
|
const version = run(
|
||||||
|
'docker',
|
||||||
|
['compose', 'exec', '-T', 'db', 'psql', '-U', 'eppp', '-d', 'eppp', '-tA', '-c', 'SHOW server_version;'],
|
||||||
|
{ cwd: REPO_ROOT, timeout: 60_000 },
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
version.status,
|
||||||
|
0,
|
||||||
|
`"SHOW server_version" must succeed against the running db container:\n` +
|
||||||
|
`${(version.stdout || '')}\n${(version.stderr || '')}`.trim(),
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
version.stdout.trim(),
|
||||||
|
/^18\.6\b/,
|
||||||
|
`the running db container must expose PostgreSQL 18.6 (SHOW server_version got: "${version.stdout.trim()}")`,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
run('docker', ['compose', 'down'], { cwd: REPO_ROOT });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Non-vacuous probes — the assertions above really do fail on violations
|
// Non-vacuous probes — the assertions above really do fail on violations
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -648,7 +686,7 @@ test('the YAML parser reads the committed structure (non-vacuous parser probe)',
|
|||||||
const parsed = parseYaml(`
|
const parsed = parseYaml(`
|
||||||
services:
|
services:
|
||||||
db:
|
db:
|
||||||
image: postgres:18-bookworm
|
image: postgres:18.6-bookworm
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: eppp
|
POSTGRES_DB: eppp
|
||||||
ports:
|
ports:
|
||||||
@@ -665,7 +703,7 @@ services:
|
|||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
`);
|
`);
|
||||||
assert.equal(parsed.services.db.image, 'postgres:18-bookworm');
|
assert.equal(parsed.services.db.image, 'postgres:18.6-bookworm');
|
||||||
assert.equal(parsed.services.db.environment.POSTGRES_DB, 'eppp');
|
assert.equal(parsed.services.db.environment.POSTGRES_DB, 'eppp');
|
||||||
assert.deepEqual(parsed.services.db.ports, ['5432:5432']);
|
assert.deepEqual(parsed.services.db.ports, ['5432:5432']);
|
||||||
assert.match(parsed.services.db.healthcheck.test, /pg_isready/);
|
assert.match(parsed.services.db.healthcheck.test, /pg_isready/);
|
||||||
@@ -682,6 +720,18 @@ test('removing the db service makes the database criterion fail (mutation probe)
|
|||||||
assert.throws(() => assertDbService(compose), /"db" service/);
|
assert.throws(() => assertDbService(compose), /"db" service/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('reverting the db image to a floating major tag fails the PostgreSQL 18.6 criterion (mutation probe)', () => {
|
||||||
|
// E00-S03-T01 pins the exact 18.6 minor (postgres:18.6-bookworm). A
|
||||||
|
// floating major tag (postgres:18-bookworm / postgres:18) would not
|
||||||
|
// guarantee the container exposes PostgreSQL 18.6, so reverting to one must
|
||||||
|
// fail the pinned-image assertion.
|
||||||
|
const text = read(COMPOSE_PATH);
|
||||||
|
const mutated = text.replace('postgres:18.6-bookworm', 'postgres:18-bookworm');
|
||||||
|
assert.notEqual(mutated, text, 'the mutation must actually revert the pinned image tag');
|
||||||
|
const compose = parseYaml(mutated);
|
||||||
|
assert.throws(() => assertDbService(compose), /18\.6/);
|
||||||
|
});
|
||||||
|
|
||||||
test('removing the app service makes the application criterion fail (mutation probe)', () => {
|
test('removing the app service makes the application criterion fail (mutation probe)', () => {
|
||||||
const text = read(COMPOSE_PATH);
|
const text = read(COMPOSE_PATH);
|
||||||
const withoutApp = text.replace(/^ app:\n(?: .*\n?)*/m, '');
|
const withoutApp = text.replace(/^ app:\n(?: .*\n?)*/m, '');
|
||||||
|
|||||||
Reference in New Issue
Block a user