mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
fix: harden pnpm supply chain and runtime image (#572)
This commit is contained in:
1 parent
e38179e854
commit
085aa3f5c5
15 files changed
+109
-82
No files matched your search
+7
-1
@@ -4,11 +4,17 @@ One-shot operator and build scripts. These are not part of the running applicati
|
||||
|
||||
## How to run them
|
||||
|
||||
From a source checkout:
|
||||
|
||||
```bash
|
||||
pnpm dlx tsx scripts/<file>.ts
|
||||
```
|
||||
|
||||
Use `pnpm dlx tsx`, not bare `pnpm tsx`. The production standalone image strips `tsx`, so the bare invocation fails inside the container. `scripts/` is excluded from the project typecheck.
|
||||
The production image intentionally removes npm, pnpm, and Corepack. Only
|
||||
container-safe scripts named by an operator runbook use its pinned
|
||||
`healthlog-tsx` launcher; scripts that import the full application dependency
|
||||
graph must run from a source checkout. `scripts/` is excluded from the project
|
||||
typecheck.
|
||||
|
||||
## What lives here
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { parse } from "yaml";
|
||||
|
||||
import integrationConfig from "../../vitest.integration.config.mts";
|
||||
import unitConfig from "../../vitest.config.mts";
|
||||
|
||||
function repositoryRoot(): string {
|
||||
const testPath = expect.getState().testPath;
|
||||
@@ -75,6 +76,12 @@ describe("Playwright CI determinism", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("local worktree isolation", () => {
|
||||
it("keeps nested worktree suites out of the root unit run", () => {
|
||||
expect(unitConfig.test?.exclude ?? []).toContain(".worktrees/**");
|
||||
});
|
||||
});
|
||||
|
||||
describe("integration environment isolation", () => {
|
||||
it("registers a worker setup bridge and authoritative test secrets", () => {
|
||||
const test = integrationConfig.test;
|
||||
@@ -114,11 +121,11 @@ describe("container dependency installation", () => {
|
||||
|
||||
describe("production dependency advisory floors", () => {
|
||||
it("pins vulnerable transitive ranges to compatible patched versions", () => {
|
||||
const packageJson = JSON.parse(readRepoFile("package.json")) as {
|
||||
pnpm?: { overrides?: Record<string, string> };
|
||||
const workspace = parse(readRepoFile("pnpm-workspace.yaml")) as {
|
||||
overrides?: Record<string, string>;
|
||||
};
|
||||
|
||||
expect(packageJson.pnpm?.overrides).toMatchObject({
|
||||
expect(workspace.overrides).toMatchObject({
|
||||
"dompurify@<=3.4.10": "^3.4.11",
|
||||
"postcss@<8.5.10": "^8.5.10",
|
||||
"@hono/node-server@<1.19.13": "^1.19.13",
|
||||
|
||||
@@ -232,16 +232,28 @@ describe("release container inputs", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses the packageManager pnpm version instead of a moving tag", () => {
|
||||
it("pins pnpm for builds and removes package managers from runtime", () => {
|
||||
const dockerfile = readRepoFile("Dockerfile");
|
||||
const packageJson = JSON.parse(readRepoFile("package.json")) as {
|
||||
packageManager: string;
|
||||
};
|
||||
expect(packageJson.packageManager).toBe("pnpm@10.31.0");
|
||||
expect(packageJson.packageManager).toBe("pnpm@11.15.1");
|
||||
expect(dockerfile).not.toContain("pnpm@latest");
|
||||
expect(
|
||||
dockerfile.match(/corepack prepare pnpm@10\.31\.0 --activate/g),
|
||||
).toHaveLength(3);
|
||||
dockerfile.match(/corepack prepare pnpm@11\.15\.1 --activate/g),
|
||||
).toHaveLength(2);
|
||||
expect(dockerfile).toContain(
|
||||
"rm -rf /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/corepack /root/.cache/node/corepack",
|
||||
);
|
||||
expect(dockerfile).toContain("tsx@4.23.1");
|
||||
expect(dockerfile).toContain(
|
||||
"ln -sfn /opt/prisma-cli/node_modules/.bin/tsx /usr/local/bin/healthlog-tsx",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps linked worktrees out of the Docker build context", () => {
|
||||
const dockerignore = readRepoFile(".dockerignore");
|
||||
expect(dockerignore.split(/\r?\n/)).toContain(".worktrees");
|
||||
});
|
||||
|
||||
it("bundles Prisma's adapter and verifies only runtime externals", () => {
|
||||
|
||||
@@ -64,32 +64,25 @@
|
||||
*
|
||||
* SELF-CONTAINED by design (v1.16.0)
|
||||
* ----------------------------------
|
||||
* The production standalone image ships neither the project
|
||||
* `node_modules` tree nor the `@/` path alias, so the previous
|
||||
* `dotenv/config` + `@/lib/db` import chain died with "Cannot find
|
||||
* module" inside the container. This script therefore depends on
|
||||
* exactly ONE package — `pg` — and reads `DATABASE_URL` straight from
|
||||
* the environment (no dotenv). Inside the production image `pg` resolves
|
||||
* via `NODE_PATH=/opt/pg-boss/node_modules` (Dockerfile installs
|
||||
* `pg@8.x` there); in a repo checkout it resolves from the project
|
||||
* `node_modules`. The `pnpm dlx` invocation below supplies `tsx` (the
|
||||
* standalone image strips it) and pins `pg` for any environment where
|
||||
* neither resolution path exists.
|
||||
* The production standalone image does not expose the project package
|
||||
* manager. It provides a pinned `healthlog-tsx` maintenance launcher, while
|
||||
* `pg` resolves from the standalone runtime tree. In a repo checkout, run the
|
||||
* same script through `pnpm dlx --package pg --package tsx tsx ...`.
|
||||
*
|
||||
* Usage
|
||||
* -----
|
||||
* Usage inside the production container
|
||||
* -------------------------------------
|
||||
* # dry-run (DATABASE_URL must point at the target database)
|
||||
* pnpm dlx --package pg --package tsx tsx scripts/repair-intake-anomalies.ts
|
||||
* healthlog-tsx scripts/repair-intake-anomalies.ts
|
||||
*
|
||||
* # scoped dry-run
|
||||
* pnpm dlx --package pg --package tsx tsx scripts/repair-intake-anomalies.ts --user <id>
|
||||
* healthlog-tsx scripts/repair-intake-anomalies.ts --user <id>
|
||||
*
|
||||
* # apply
|
||||
* pnpm dlx --package pg --package tsx tsx scripts/repair-intake-anomalies.ts --fix
|
||||
* pnpm dlx --package pg --package tsx tsx scripts/repair-intake-anomalies.ts --fix --tombstone-implausible
|
||||
* healthlog-tsx scripts/repair-intake-anomalies.ts --fix
|
||||
* healthlog-tsx scripts/repair-intake-anomalies.ts --fix --tombstone-implausible
|
||||
*
|
||||
* # create the proposed schedule revisions + startsOn fixes (defect 5)
|
||||
* pnpm dlx --package pg --package tsx tsx scripts/repair-intake-anomalies.ts --backfill-eras
|
||||
* healthlog-tsx scripts/repair-intake-anomalies.ts --backfill-eras
|
||||
*/
|
||||
import { Client, types } from "pg";
|
||||
|
||||
@@ -425,7 +418,7 @@ async function main(): Promise<void> {
|
||||
if (!process.env.DATABASE_URL) {
|
||||
console.error(
|
||||
`${TAG} DATABASE_URL must be set (no dotenv — export it or prefix ` +
|
||||
`the command: DATABASE_URL='postgresql://…' pnpm dlx …)`,
|
||||
`the command: DATABASE_URL='postgresql://…' healthlog-tsx …)`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
* BACKUP_S3_SECRET_KEY=... \
|
||||
* BACKUP_S3_REGION=auto \
|
||||
* BACKUP_ENCRYPTION_KEY=<hex64> \
|
||||
* pnpm tsx scripts/restore-backup.ts 2026-05-08/user-clx123.json.enc /tmp/restored.json
|
||||
* pnpm dlx tsx scripts/restore-backup.ts 2026-05-08/user-clx123.json.enc /tmp/restored.json
|
||||
*/
|
||||
import "dotenv/config";
|
||||
import { writeFileSync } from "node:fs";
|
||||
import {
|
||||
loadOffhostConfig,
|
||||
@@ -82,7 +81,7 @@ async function main() {
|
||||
?.slice("--user-id=".length);
|
||||
if (!key) {
|
||||
console.error(
|
||||
"Usage: pnpm tsx scripts/restore-backup.ts <s3-key> [output-file] [--user-id=<id>]",
|
||||
"Usage: pnpm dlx tsx scripts/restore-backup.ts <s3-key> [output-file] [--user-id=<id>]",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
/**
|
||||
* Test script for notification delivery and reminder check.
|
||||
*
|
||||
* Usage (inside Docker container):
|
||||
* npx tsx scripts/test-notifications.ts
|
||||
*
|
||||
* Or from host:
|
||||
* docker compose exec app npx tsx scripts/test-notifications.ts
|
||||
* Usage (from a source checkout with the target environment exported):
|
||||
* pnpm dlx tsx scripts/test-notifications.ts
|
||||
*
|
||||
* What it does:
|
||||
* 1. Lists all configured notification channels
|
||||
|
||||
Reference in new issue
Block a user