Files
HealthLog/src/__tests__/database-pin-is-watched.test.ts
T
Marc-André Bombeck 6058590872 chore(deps): keep PostgreSQL majors out of the update stream
The compose ecosystem added last change did its job on the first run and
immediately proposed 16.15 to 18.6. A PostgreSQL major changes the
on-disk format, so merging that would hand self-hosters a container that
cannot read their data directory without pg_upgrade or a dump and
restore. Minor releases keep arriving as reviewable PRs; a major is a
project decision with a migration path behind it, not a weekly bump.

The guard grows a case for the ignore rule, so dropping it fails rather
than quietly re-opening the door.
2026-09-16 13:05:14 +02:00

60 lines
2.4 KiB
TypeScript

import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";
/**
* The bundled database is pinned to an exact minor, AND something watches it.
*
* Both halves matter and only together. The pin exists so a database change is
* a deliberate, reviewable one rather than whatever the registry happens to
* serve on the day an operator pulls. But PostgreSQL ships security and
* data-corruption fixes in minor releases and recommends running the current
* one, so a pin nobody moves ships a knowingly outdated database: this line
* sat on 16.14 for five weeks after 16.15 was published, because the
* `docker` ecosystem Dependabot was configured with reads the Dockerfile and
* never looks at a compose file.
*
* So: drop the pin and the deliberate-update model goes; drop the watch and
* the pin ages in silence. This test fails on either.
*/
const ROOT = resolve(__dirname, "../..");
function read(relative: string): string {
return readFileSync(resolve(ROOT, relative), "utf8");
}
describe("the bundled database pin", () => {
it("names an exact minor version, not a floating major alias", () => {
const images = [
...read("docker-compose.yml").matchAll(/^\s*image:\s*(postgres:\S+)/gm),
].map((match) => match[1]);
expect(images.length).toBe(1);
// `postgres:16-alpine` or `postgres:16` would match a moving target.
expect(images[0]).toMatch(/^postgres:\d+\.\d+-alpine$/);
});
it("lets a major version through only as a decision, never as an update PR", () => {
const dependabot = read(".github/dependabot.yml");
// The first run of the compose ecosystem proposed 16.15 -> 18.6. A
// PostgreSQL major changes the on-disk format, so it is a migration the
// project schedules, not an update an operator merges on a Tuesday.
expect(dependabot).toMatch(
/dependency-name:\s*"postgres"[\s\S]{0,200}version-update:semver-major/,
);
});
it("is watched by the compose ecosystem, which is not the Dockerfile one", () => {
const dependabot = read(".github/dependabot.yml");
const ecosystems = [
...dependabot.matchAll(/package-ecosystem:\s*"([^"]+)"/g),
].map((match) => match[1]);
expect(ecosystems).toContain("docker-compose");
// The Dockerfile watch is a separate entry and does not stand in for it.
expect(ecosystems).toContain("docker");
});
});