33 Commits
Author SHA1 Message Date
Marc-André Bombeck 41f90bac3f chore(deps): move @hono/node-server to 2.x and lift systeminformation
The serveStatic double decode has no fix on the 1.x line, and the MCP
SDK accepts 2.x. The app uses the web-standard transport and never loads
it. systeminformation sits under the shadcn CLI at dev time.
2026-11-04 16:56:20 +01:00
Marc-André Bombeck 369c063701 chore(deps): raise node-forge to 1.4.2 and drop its audit exception
Five high advisories against node-forge <= 1.4.0 (signature, certificate
chain and TLS record handling) joined the one the exception covered. The
copy arrives only through @parse/node-apn; 1.4.2 is what node-apn 8.1.1
pins, and with the floor raised the exception has nothing left to cover.
2026-10-31 09:37:33 +01:00
Marc-André Bombeck 30c96ff591 chore(deps): drop pdf-parse and the second pdfjs-dist it carried
Nothing imports pdf-parse any more, so its pdfjs-dist 5.4.296 and the
older @napi-rs/canvas that came with it leave the lockfile. The override
that kept that transitive copy past a renderer advisory has nothing left
to move and goes too. The standalone tracing stops naming pdf-parse; its
pdfjs-dist glob now matches the one copy the app pins. The Dockerfile and
canvas guard comments describe the second copy as history.

Refs #1277
2026-10-24 19:32:20 +02:00
Marc-André Bombeck 087d0011fc fix(deps): raise the floors for body-parser, fast-uri and undici 7
body-parser 2.3.0 (CVE-2026-111181, high) and fast-uri 3.1.8
(CVE-2026-110180, CVE-2026-110306) arrive under the MCP SDK on a
production path. undici 7.30.0 (CVE-2026-109869, CVE-2026-109841,
CVE-2026-109924) is the development-only copy under shadcn; the app's
own undici 8 is already past the fix. Each bound moves the flagged copy
and nothing else.
2026-10-24 18:11:21 +02:00
Marc-André Bombeck 06d55afc46 fix(deps): raise the ip-address floor to 10.7.4
10.7.3 and earlier take exponential time on a crafted Address6 zone
identifier. The copy under the MCP SDK's rate limiter reaches runtime, and
the one under the registry client resolves to the same version now.
2026-10-23 16:33:05 +02:00
Marc-André Bombeck 8a9bcffaa2 build(deps): raise the dompurify floor to 3.4.17
GHSA-cg2g-xh64-v4q7 (critical, a SAFE_FOR_TEMPLATES bypass) and GHSA-mrv2-3pqr-j5jr (high, an IN_PLACE hook that removes a parent) cover dompurify up to 3.4.16, which jspdf and jspdf-autotable pull in. jspdf 4.2.1 is the newest release and still allows that range, so the existing override moves its floor. The doctor-report PDF renders as before (unit and integration suites).
2026-10-22 21:16:31 +02:00
Marc-André Bombeck 73362dc0ae chore(deps): take the weekly production and development updates
Production: the AWS SDK S3 client and lib-storage 3.1152.0, Prisma
(client, adapter-pg, CLI) 7.10.1, TanStack Query 5.104.3 and Virtual
3.14.21, dotenv 18.0.8, jspdf-autotable 5.0.9, lucide-react 1.59.0,
nodemailer 10.1.2, pg-boss 12.38.0, React and React DOM 19.3.1 (still
exact) and undici 8.12.

React 19.3.1 and undici 8.12.2 are security releases. Prisma 7.10.1
stops a nested interactive transaction from leaking its id into a
later top-level one.

pg-boss moves its schema from 45 to 46; the worker applies the
migration on start and the index builds continue in the background.
Its list and delete helpers now page and batch, which touches only the
queue retirement at boot, and that is idempotent. The retention test
pins the installed version, so it moves to 12.38.0 after re-checking
every source line it asserts.

Development: @axe-core/playwright 4.14.0, Playwright 1.64.1, Vitest and
its coverage provider 5.0.5, shadcn 4.22.0. The Stryker runner patch
still applies; it touches the runner's own name join, and 5.0.5 changes
nothing in how Vitest builds a test's full name. axe-core 4.14 turns on
label-content-name-mismatch for the WCAG 2.1 A tag the a11y specs run.

The S3 client is held on the same release as lib-storage rather than
the newest one its range allows, so the two share one SDK core.

Vite gets a floor at 8.1.6 for GHSA-587h-7wmj-h5pm and four sibling
advisories against its dev server and bundled launch-editor. It arrives
only under Vitest and never reaches the image.

The image's separate Prisma CLI install moves with the app tree to
7.10.1, and its dotenv to 18.0.8, which it had trailed by a patch.
2026-10-22 06:53:04 +02:00
Marc-André Bombeck f5d4dd2ec6 test: mutation testing on the core libraries with per-module floors
Stryker runs against encryption at rest, medication compliance, the rollups,
source ranking, unit conversion and backup validation, with the unit tests
that live next to them (vitest.mutation.config.mts). It is too slow for a
pull request and runs nightly and on demand (.github/workflows/mutation.yml).
scripts/mutation-floors.mjs reads the JSON report and fails when a module
scores below its floor in stryker.floors.json, so one well-tested module
cannot hide a weak one. The floors sit two points below the first measured
scores: crypto 46.9 %, compliance 66.8 %, rollups 41.7 %, source ranking
57.0 %, units 87.4 %, backup validation 25.5 %.

@stryker-mutator/vitest-runner 10.0.0 predates Vitest 5, which names a test
"describe > test" where the runner still built "describe test". Every test
inside a describe block was filtered out of the mutant runs, so nearly every
mutant survived (5.5 % across the set). A pnpm patch builds the name the way
Vitest 5 does; the Docker dependency stage copies the patches directory,
which the frozen install needs.
2026-10-22 06:08:20 +02:00
Marc-André Bombeck a0e725556b chore(deps): raise the hono floor to 4.13.11 2026-10-20 19:45:11 +02:00
Marc-André Bombeck b50b5fcd21 chore(deps): drop four dependencies nothing imports
react-hook-form, @hookform/resolvers, next-themes and @vitejs/plugin-react
have no import anywhere in src/, scripts/, tests/, e2e/ or the build and
test configs; knip only stayed quiet because each sat on its ignore list.
Forms keep a controlled draft and validate with the shared Zod schemas,
and the theme bootstrap is hand-written. The ignore entries, the comments
that still named the form library, and the guideline text go with them.
2026-10-20 08:39:06 +02:00
Marc-André Bombeck 7903c3b74e fix(deps): raise source-map-js, postcss-selector-parser and smol-toml past their advisories 2026-10-08 23:05:29 +02:00
Marc-André Bombeck a3efedfb07 fix(deps): raise the MCP SDK to 1.32 and proxy-addr to 2.0.8 2026-10-06 23:26:40 +02:00
Marc-André Bombeck 2031b5a722 chore(deps): ignore the node-forge advisory until a fix is published
GHSA-86w9-cpqp-85rv affects RSA PKCS#1 v1.5 signature verification in
node-forge up to 1.4.0, which arrives only through @parse/node-apn for
certificate-based APNs credentials. HealthLog uses token authentication,
so that path never runs, and no patched release exists yet.
2026-10-02 21:03:43 +02:00
Marc-André Bombeck fab5cbccbf fix(deps): raise the dev-only grpc-js, brace-expansion and undici 7 floors
The dependency alerts flag development copies only: @grpc/grpc-js under the
test containers, brace-expansion on three major lines, and undici 7 next to
the app's own undici 8. None ships in the image.
2026-09-30 22:42:50 +02:00
Marc-André Bombeck 162ba62752 fix(deps): move next to 16.3.6 and raise the fast-uri, ip-address and dompurify floors
The production audit flags a critical advisory against next 16.2.0 to 16.3.5,
fixed in 16.3.6, and newer advisories against the transitive fast-uri (ajv),
ip-address (the MCP SDK's rate limiter) and dompurify (jspdf) copies. Next is
pinned to 16.3.6 rather than the newest patch so the install stays inside the
minimum release age without new exclusions.
2026-09-30 22:12:47 +02:00
Marc-André Bombeck 40b9427259 chore(deps): let the newer hono and js-yaml bounds win
pnpm-workspace.yaml carried two overrides for the same packages: an older floor (hono < 4.12.25, js-yaml >= 4.0.0 < 4.3.1) and the newer one added for the scanner findings. The older selector won the resolution, so the lockfile kept hono 4.13.3 and js-yaml 4.3.1 and four of the seventeen findings stayed open after v1.38.12. The stale bounds are gone; the lockfile now resolves hono 4.13.7 and js-yaml 4.3.2.
2026-09-09 21:38:16 +02:00
Marc-André Bombeck 47953f5b8a chore(deps): clear the seventeen scanner findings
Trivy flags twelve distinct advisories on the lockfile and the image, none
in this code: next 16.2.11 (two critical, fixed in 16.3.3), sharp 0.35.3
pulled by next (high), nodemailer 9.0.3 (one high, three medium), js-yaml
4.3.1 (high), hono 4.13.3 under the MCP SDK's node server (three medium),
and the vitest mocker and baseline-browser-mapping (medium). Dependabot
lists none of them, which is why they sat.

next moves to 16.3.4 and nodemailer to 9.1.1 as direct pins; vitest to
4.1.11. js-yaml, hono, baseline-browser-mapping and sharp are transitive
and move through pnpm overrides bounded to the vulnerable ranges, so the
copies the scanner names change and nothing else does. Typecheck, lint,
the unit suite and the production build pass locally; the release gate
runs the integration and end-to-end suites on the minor Next bump.
2026-09-09 18:38:29 +02:00
Marc-André Bombeck 118f100956 chore(deps): clear the advisory list and drop an unused 340 MB dependency
Three advisories stood open, all development-scope. Two are closed with
version floors in the workspace overrides, following the existing pattern:
@humanfs/node for GHSA-p498-v437-472g and esbuild for GHSA-g7r4-m6w7-qqqr.
Both patched lines stay inside the same minor, so nothing downstream moves.

The third, GHSA-jmr9-qjv8-65gv in extract-zip, had no patched release to
float to. It arrived through @openai/codex-security, which nothing in the
tree imports: the package was referenced only by its own declaration, a
knip ignore entry, and a release-age exclusion. Removing it closes the
advisory and takes about 340 MB of node_modules with it. The knip ignore
and the release-age exclusion go with it rather than being left to rot.

pnpm audit now reports no known vulnerabilities.
2026-09-03 05:19:31 +02:00
Marc-André Bombeck 1354e1d9b5 Raise two advisory floors that went stale overnight
Four advisories landed against the URI parser that arrives under ajv,
including the copy the connector SDK pulls, all of them host confusion
or request forgery through percent-encoded schemes, skipped IDN
canonicalisation and malformed authorities. The floor set yesterday was
one patch below the fix. A query-string parser needs 6.16.0 for an
array-limit bypass and a denial of service.

The audit reads no known vulnerabilities after the bump.
2026-09-03 02:07:38 +02:00
Marc-André Bombeck f62cd59789 chore(deps): raise the stale advisory floors and pin valibot
Three overrides had drifted behind the advisories they were written for,
and the scan found the packages at versions the pins were supposed to
exclude.

dompurify moves from <=3.4.10 to <3.4.13. GHSA-55q2-fjhq-7xh7 is fixed
in 3.4.13 and the tree carried 3.4.12. The copy is jspdf's optional HTML
renderer, an optionalDependency at ^3.3.1, so the raise stays inside the
range jspdf declares.

postcss moves from <8.5.10 to <8.5.23 for CVE-2026-69153. next declares
an exact postcss@8.4.31, so nothing but this bound moves it; the build
has run on the 8.5 line since the first bump and stays there.

valibot gets a floor it never had, <1.4.2, for CVE-2026-59952. Two
copies arrive and neither is ours to call: an optional peer of
@hookform/resolvers, which this app does not use because it validates
with zod, and prisma's local dev server. 1.4.2 is the same major, so no
consumer is moved onto a new one.

@hono/node-server moves from <1.19.13 to <1.19.15 for
GHSA-frvp-7c67-39w9. The app tree already resolved 1.19.17, so this
changes nothing here; it exists so the bound states the real floor and
so the Dockerfile mirror has something correct to match.

The floor test in ci-determinism asserted the exact key and replacement
string, which meant every legitimate raise failed it while a floor gone
stale against a newer advisory passed it unchanged. It now reduces each
key to a package name and asserts the pin is at or above the fixed
version, with a case proving the comparison can return false.
2026-09-02 15:46:55 +02:00
Marc-André Bombeck 97b1603cb9 Pin mysql2 past GHSA-3f6p-5ww8-9rcr in both installs
The dependency audit went red on the release branch: mysql2 below 3.22.0
downgrades its auth plugin to mysql_clear_password and leaks the
credential. It reaches the tree only through prisma's MySQL driver, which
this app never opens, but the gate does not distinguish reachable from
present. Pinned to ^3.22.0 in the workspace overrides and mirrored with
npm's own override for the /opt/prisma-cli install, the pair the
lockstep guard holds together. The audit reads three moderates, below
the gate.
2026-09-01 20:53:47 +02:00
Marc-André Bombeck ba3cf30035 Override flatted, js-yaml and minimatch past their advisories
- flatted 3.3.3 → 3.4.4: prototype pollution and unbounded recursion in
  parse(), fixed in 3.4.2 / 3.4.0.
- js-yaml 4.1.1 → 4.3.1: quadratic CPU on merge-key chains and !!omap
  resolution. The override is bounded to >=4.0.0 so a hypothetical 3.x
  consumer is never dragged onto a new major.
- minimatch 3.1.3 → 3.1.5: ReDoS via nested extglobs. The scanner
  suggested 10.x, but the fix is backported — only <3.1.4 is vulnerable —
  so the 3.x line stays where its consumers (eslint) expect it. The 5.x,
  9.x and 10.x copies in the tree were never affected.

The refreshed lockfile also carries brace-expansion 1.1.12 → 1.1.18
transitively, which clears that package's DoS advisories. pnpm audit
reports none of these packages afterwards.
2026-08-29 19:21:00 +02:00
Marc-André Bombeck b8859ae424 Force the patched deepmerge-ts through Prisma's config loader
A new advisory turned the dependency audit red on the trunk without a line of
our code changing: DeepmergeTS recurses without bound on deeply nested input
until the stack gives out (GHSA-ggr8-5vv4-36mx, fixed in 8.0.0). Re-running the
same job against the same main commit that passed on 16 August confirms it is
the advisory database that moved, not us.

Waiting for Prisma does not help. `@prisma/config` still asks for 7.1.5 on the
current 7.9.1, so the copy never updates on its own, and an override is the only
route to the patched version. The workflow reserves `auditConfig.ignoreCves` for
advisories with no upstream fix, which is not this one.

The reach is the config-loading and CLI path rather than anything under a
request, so the practical exposure was small. The blocked release train was not.

Verified rather than assumed: `pnpm audit --prod --audit-level=high`, the exact
command CI runs, drops from twelve findings with one high to eleven with none
and exits clean. Because this is a major bump under Prisma's own config loader,
`prisma generate` and `prisma validate` were run explicitly alongside typecheck,
lint, format, 21446 unit tests and the production build. All pass.
2026-08-20 08:58:16 +02:00
Marc-André Bombeck 5374bed5b7 Raise the nanoid override floor past the zero-size loop advisory 2026-08-13 20:57:58 +02:00
Marc-André Bombeck c2f67c96d4 fix(deps): float nanoid past an infinite-loop flaw
A fresh advisory names nanoid below 3.3.17: a custom generator can loop
forever when asked for a zero-size id. It reaches the tree only through
next and postcss, but the audit gate rightly blocks on a known HIGH with
a fix available. Bounded override in the established pattern; the audit
drops from one high to none.
2026-08-07 23:58:34 +02:00
Marc-André Bombeck 315ca5e67c fix(deps): move the PDF renderer past a script-execution flaw
pdfjs-dist 6.1.200 and a transitive 5.6.205 both sit in the affected range
of a flaw that lets a crafted PDF run JavaScript inside the renderer. The
document vault feeds it every uploaded PDF, so pin the direct dependency to
6.2.108 and add a bounded override so the transitive copy lands there too.
The override stops short of pdf-parse's 5.4.296, which predates the flaw and
drives the local text-extraction path.

The runtime image ships every pdfjs-dist copy in the store, not just the one
that gets loaded, so an unused transitive copy still counted.

Hoisting in the image picked whichever copy the filesystem listed first, and
more than one copy reaches it, so the version named in package.json was not
reliably the one the renderer resolved. Carry the resolved version forward
from the build stage, select it by name, and fail the build when it is
missing rather than leaving another copy in its place.
2026-08-07 14:35:23 +02:00
Marc-André Bombeck a08aa342b2 Pin ip-address past the leading-zero parsing advisory
Address4 decoded a leading-zero octet as decimal, so `010.0.0.1` parsed as
10.0.0.1 instead of being rejected. That is precisely the alternate-notation
class `isPublicUrl` was written to catch, and this copy arrives transitively
under the MCP SDK's rate limiter, where nothing of ours screens the value
first. The production tree resolved 10.2.0 while the dev tree already had a
fixed one, so the override names the floor rather than trusting resolution.
2026-08-04 01:30:57 +02:00
Marc-André Bombeck f41605efba Close two high advisories on the outbound path
`undici` moves to 8.10.0 and the `fast-uri` override rises to 3.1.5. Both were
published as high after the last run on the trunk, so this is new information
rather than neglect, and both matter here: undici is what backs `safeFetch`,
which is the one documented egress boundary and the place the connect-time
DNS-rebinding pin lives.

The undici advisory is a cross-user information disclosure and a parse-time
crash through degenerate private cache directives. `fast-uri` arrives four ways
through transitive dependencies and the existing override was pinned one patch
short of the fix.

The safe-fetch dispatcher suite passes against the new client, which is the
part that had to be checked rather than assumed: the pin reaches into undici's
connect hook and a client bump is exactly where that could quietly stop being
enforced.
2026-08-03 22:10:15 +02:00
Marc-André Bombeck b1e20f59dc release: prepare v1.34.1 2026-07-29 17:31:31 +02:00
Marc-André Bombeck 4be01a67f0 chore(release): fold in the coach discriminant, the dependency bumps, and the notes the audit found wrong 2026-07-26 18:57:21 +02:00
Marc-André Bombeck 62eb431d66 release: v1.32.0 — hardening and scalability (#580)
* release: prepare v1.32.0

* test: stabilize water capture re-entry
2026-07-22 04:14:15 +02:00
Marc-André Bombeck 085aa3f5c5 fix: harden pnpm supply chain and runtime image (#572) 2026-07-21 04:36:53 +02:00
Marc-André Bombeck 38309932f3 Initial release v1.0.0
HealthLog — personal health-tracking PWA with weight, blood pressure,
pulse, mood tracking, medication compliance, Withings integration,
doctor report PDF export, and Dracula-themed UI.
2026-03-10 20:14:33 +01:00