mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
build: run the image on a Wolfi runner
The dependency and build stages stay on node:22-trixie-slim, where pnpm picks the glibc native packages. The runner moves to wolfi-base, pinned by its index digest: glibc, about fifty packages, and every one of them known to the image scan, Node and the PostgreSQL client included. nodejs-22, tzdata and postgresql-18-client come from apk, so the pgclient stage and its pin guard go. The builder writes its Node module ABI and glibc version out and the runner refuses to build on another ABI or an older glibc. Wolfi's npm is major 12 and runs no install scripts unless package.json allows them, so the Prisma CLI install names the three packages that have one, and the build checks that the schema engine file is there before asking the CLI about it. npm is installed for that step and removed in the same layer; the check that nothing is left asks a fresh shell, whose command cache cannot remember the deleted binary.
This commit is contained in:
1 parent
377e0d0d3a
commit
5d36afb487
9 files changed
+105
-124
No files matched your search
@@ -61,20 +61,26 @@ describe("canvas binary hoist", () => {
|
||||
expect(runner).not.toMatch(/@napi-rs\+canvas[^"'\s]*@\*/);
|
||||
});
|
||||
|
||||
it("builds every Node stage on the glibc Debian base", () => {
|
||||
const froms = DOCKERFILE.match(/^FROM \S+/gm) ?? [];
|
||||
const node = froms.filter((from) => from.startsWith("FROM node:"));
|
||||
expect(node).toHaveLength(3);
|
||||
for (const from of node) {
|
||||
expect(from).toMatch(/^FROM node:22-trixie-slim@sha256:[0-9a-f]{64}$/);
|
||||
}
|
||||
// The only other stage supplies the PostgreSQL client tools, built on
|
||||
// the same Debian release so its binaries find their libraries.
|
||||
expect(froms.filter((from) => !from.startsWith("FROM node:"))).toEqual([
|
||||
it("installs on Debian and runs on Wolfi, both glibc", () => {
|
||||
const froms = DOCKERFILE.match(/^FROM \S+ AS \S+$/gm) ?? [];
|
||||
expect(froms).toEqual([
|
||||
expect.stringMatching(
|
||||
/^FROM postgres:18\.\d+-trixie@sha256:[0-9a-f]{64}$/,
|
||||
/^FROM node:22-trixie-slim@sha256:[0-9a-f]{64} AS deps$/,
|
||||
),
|
||||
expect.stringMatching(
|
||||
/^FROM node:22-trixie-slim@sha256:[0-9a-f]{64} AS builder$/,
|
||||
),
|
||||
expect.stringMatching(
|
||||
/^FROM cgr\.dev\/chainguard\/wolfi-base:latest@sha256:[0-9a-f]{64} AS runner$/,
|
||||
),
|
||||
]);
|
||||
// The native packages pnpm picked in the builder must load in the
|
||||
// runner: same module ABI, and a glibc no older than the builder's.
|
||||
expect(stage("builder")).toContain("> /app/.native-abi");
|
||||
expect(stage("runner")).toContain(
|
||||
'[ "$RUN_ABI" = "$BUILD_ABI" ] || { echo "ERROR: runner Node module ABI',
|
||||
);
|
||||
expect(stage("runner")).toContain("is older than the builder's");
|
||||
});
|
||||
|
||||
it("fails the build when the copied binary is another version", () => {
|
||||
|
||||
@@ -40,32 +40,6 @@ describe("the bundled database pin", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("ships pg_dump of the same minor the bundled database runs", () => {
|
||||
const db = /^\s*image:\s*postgres:(\d+\.\d+)-alpine$/m.exec(
|
||||
read("docker-compose.yml"),
|
||||
);
|
||||
const client =
|
||||
/^FROM postgres:(\d+\.\d+)-trixie@sha256:[0-9a-f]{64} AS pgclient$/m.exec(
|
||||
read("Dockerfile"),
|
||||
);
|
||||
expect(db, "the compose file pins the database").not.toBeNull();
|
||||
expect(client, "the Dockerfile has a pinned pgclient stage").not.toBeNull();
|
||||
// The two pins are one decision; a Dependabot PR moves them separately.
|
||||
expect(client![1]).toBe(db![1]);
|
||||
});
|
||||
|
||||
it("keeps a major bump of the client tools out of the Dockerfile watch too", () => {
|
||||
const dependabot = read(".github/dependabot.yml");
|
||||
const docker =
|
||||
/package-ecosystem:\s*"docker"\n([\s\S]*?)(?=\n\s*- package-ecosystem:)/.exec(
|
||||
dependabot,
|
||||
);
|
||||
expect(docker, "a docker ecosystem entry").not.toBeNull();
|
||||
expect(docker![1]).toMatch(
|
||||
/dependency-name:\s*"postgres"[\s\S]{0,200}version-update:semver-major/,
|
||||
);
|
||||
});
|
||||
|
||||
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
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* restart loop (live incident: a Synology DS1520+ self-host, exit code 132
|
||||
* ~18 s after every boot once the thumbnail backfill touched Skia).
|
||||
*
|
||||
* The published image is Debian (glibc) and runs the glibc build. Under an
|
||||
* The published image runs on glibc (Wolfi) and loads the glibc build. Under an
|
||||
* emulated AVX2-less Atom core that build drew a canvas and rendered
|
||||
* a PDF page to JPEG where the musl build died, but it still carries AVX2 code
|
||||
* and not every path it can take was exercised, so the x64 gate stays closed
|
||||
@@ -26,7 +26,7 @@
|
||||
* fallback, and dies with SIGILL as soon as the module loads on an ARMv8.0
|
||||
* core such as the Raspberry Pi 4's Cortex-A72 (#1311). The glibc arm64 build
|
||||
* uses neither and runs there, which is why the published image moved off
|
||||
* Alpine. The musl branch stays for a host that runs the app on musl itself,
|
||||
* musl. The musl branch stays for a host that runs the app on musl itself,
|
||||
* from source on Alpine or from an image built on it.
|
||||
*
|
||||
* Detection reads `/proc/cpuinfo` once on Linux: x64 requires the `avx2`
|
||||
|
||||
Reference in new issue
Block a user