mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
build: pin the runner's Node and PostgreSQL client packages
nodejs-22 and postgresql-18-client are installed at exact package versions, so a rebuild of the same commit runs the same Node and the same pg_dump; apk upgrade still moves the libraries under them. No updater reads an apk pin. The image scan does the job instead: Wolfi records the fixed version for each advisory, so a pinned package with a published fix turns the HIGH/CRITICAL gate red and names the version. A guard holds the pin format and keeps the client's minor on the bundled database's.
This commit is contained in:
1 parent
a11ea8444d
commit
42cae738f1
2 files changed
+69
-1
No files matched your search
+13
-1
@@ -106,7 +106,19 @@ FROM cgr.dev/chainguard/wolfi-base:latest@sha256:629d9acaceda7746cd9293365eb0d8e
|
||||
#
|
||||
# busybox, part of the base, is the shell the entrypoint runs under and
|
||||
# carries `tar`/`gzip` for the GeoLite2 extraction and `addgroup`/`adduser`.
|
||||
RUN apk add --no-cache nodejs-22 tzdata postgresql-18-client && \
|
||||
#
|
||||
# The two packages the app runs on are pinned to an exact package version,
|
||||
# so a rebuild of the same commit runs the same Node and the same pg_dump;
|
||||
# `apk upgrade` cannot move a pinned package, and moves only the libraries
|
||||
# under them. No updater reads these pins. What moves them is the image
|
||||
# scan: Wolfi records the fixed package version for every advisory, so a
|
||||
# pinned package with a published fix turns the HIGH/CRITICAL gate red and
|
||||
# names the version to pin. To bump, take the newest from
|
||||
# `apk policy nodejs-22` / `apk policy postgresql-18-client` in the pinned
|
||||
# base. `src/__tests__/runtime-package-pins.test.ts` holds the pin format,
|
||||
# and the client's minor to the bundled database's in docker-compose.yml.
|
||||
# tzdata stays unpinned on purpose: a zone rule change is a fix to take.
|
||||
RUN apk add --no-cache nodejs-22=22.23.2-r1 tzdata postgresql-18-client=18.6-r7 && \
|
||||
apk upgrade --no-cache && \
|
||||
mkdir -p /usr/local/bin
|
||||
COPY --from=builder /app/.native-abi /tmp/.native-abi
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* The runtime packages the image installs from apk are pinned, and the
|
||||
* PostgreSQL client moves with the bundled database.
|
||||
*
|
||||
* The runner installs Node and the PostgreSQL client from the Wolfi
|
||||
* repository. Unpinned, a rebuild of the same commit could ship another
|
||||
* Node or another pg_dump than the one the release was checked with. No
|
||||
* updater reads an apk pin; the image scan is what flags a pinned package
|
||||
* once Wolfi publishes a fix (the Dockerfile comment explains the bump), so
|
||||
* this file only holds the pins' shape and their agreement with the rest of
|
||||
* the repository.
|
||||
*/
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const ROOT = process.cwd();
|
||||
const DOCKERFILE = readFileSync(join(ROOT, "Dockerfile"), "utf8");
|
||||
const COMPOSE = readFileSync(join(ROOT, "docker-compose.yml"), "utf8");
|
||||
|
||||
function runner(): string {
|
||||
const start = DOCKERFILE.search(/^FROM .* AS runner$/m);
|
||||
expect(start, "the Dockerfile has a runner stage").toBeGreaterThan(0);
|
||||
return DOCKERFILE.slice(start);
|
||||
}
|
||||
|
||||
function apkAdds(): string[] {
|
||||
return [...runner().matchAll(/apk add --no-cache ([^&\n\\]+)/g)].flatMap(
|
||||
(m) => m[1]!.trim().split(/\s+/),
|
||||
);
|
||||
}
|
||||
|
||||
describe("runtime package pins", () => {
|
||||
it("pins nodejs-22 to one exact Node 22 package version", () => {
|
||||
const pins = apkAdds().filter((p) => p.startsWith("nodejs"));
|
||||
expect(pins).toHaveLength(1);
|
||||
expect(pins[0]).toMatch(/^nodejs-22=22\.\d+\.\d+-r\d+$/);
|
||||
});
|
||||
|
||||
it("pins postgresql-18-client to the bundled database's minor", () => {
|
||||
const pins = apkAdds().filter((p) => p.startsWith("postgresql"));
|
||||
expect(pins).toHaveLength(1);
|
||||
const client = /^postgresql-18-client=(18\.\d+)-r\d+$/.exec(pins[0]!);
|
||||
expect(client, `an exact pin, not ${pins[0]}`).not.toBeNull();
|
||||
const db = /^\s*image:\s*postgres:(\d+\.\d+)-alpine$/m.exec(COMPOSE);
|
||||
expect(db, "the compose file pins the database").not.toBeNull();
|
||||
// One decision: a database minor bump moves the client with it.
|
||||
expect(client![1]).toBe(db![1]);
|
||||
});
|
||||
|
||||
it("leaves no other package floating except tzdata and the build-only npm", () => {
|
||||
const unpinned = apkAdds().filter((p) => !p.includes("="));
|
||||
expect(new Set(unpinned)).toEqual(new Set(["tzdata", "npm"]));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user