From 2031b5a72254de99a907523ef06da2bcf62edfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 2 Oct 2026 21:03:43 +0200 Subject: [PATCH 1/3] 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. --- pnpm-workspace.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d1e045b06..a1304d0c1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -110,3 +110,13 @@ minimumReleaseAgeExclude: - "@next/bundle-analyzer@16.2.12" - lucide-react@1.27.0 - undici@8.10.0 + +auditConfig: + ignoreGhsas: + # node-forge <=1.4.0, RSA PKCS#1 v1.5 signature verification. It arrives + # only through @parse/node-apn, which uses it for certificate-based APNs + # credentials (p12 / PEM certificate). HealthLog authenticates to APNs + # with a token (.p8 key, APNS_KEY_ID / APNS_TEAM_ID), so that code path + # never runs. No patched release is published yet (latest is 1.4.0); + # remove this entry and raise the floor once 1.4.1 is out. + - GHSA-86w9-cpqp-85rv From 0cb193f812e4d80cd0d0fd02270b1bc161141c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 2 Oct 2026 21:06:37 +0200 Subject: [PATCH 2/3] chore(deps): carry the node-forge advisory in the Trivy ignore list too Same advisory, same reasoning as the pnpm audit entry: the affected signature verification sits in node-apn's certificate credential path, which token-authenticated APNs never reaches, and no fix is published. --- .trivyignore | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.trivyignore b/.trivyignore index 829fa1515..ccf17286e 100644 --- a/.trivyignore +++ b/.trivyignore @@ -21,3 +21,13 @@ CVE-2026-33671 # never reachable at runtime. Re-check when the Node base image ships an npm # build whose bundled sigstore is >= 4.1.1, then drop this entry. CVE-2026-48815 + +# CVE-2026-85393 (node-forge RSA PKCS#1 v1.5 signature forgery, HIGH; GitHub +# advisory GHSA-86w9-cpqp-85rv) — node-forge <= 1.4.0 arrives only through +# @parse/node-apn, which uses it in its certificate-based credential path +# (credentials/certificate/*: p12 / PEM certificate). HealthLog authenticates +# to APNs with a token (.p8 key via APNS_KEY_ID / APNS_TEAM_ID), so that code +# never runs. No fixed release is published (latest is 1.4.0). Remove this +# entry, the matching `auditConfig.ignoreGhsas` entry in pnpm-workspace.yaml, +# and raise the floor once node-forge 1.4.1 is out. +CVE-2026-85393 From 2979b5c4ef72cb10d3bf8b4d5a772e6b6183c7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 2 Oct 2026 21:33:31 +0200 Subject: [PATCH 3/3] test(e2e): measure the lab review rows once the dialog has stopped widening The review stage widens the sheet and the row grid re-flows from the container width; on a slow runner the 560 px case measured a half-laid-out row and failed on the first attempt. The spec now waits until the surface keeps its width across two frames before it measures. --- e2e/dialog-horizontal-overflow.spec.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/e2e/dialog-horizontal-overflow.spec.ts b/e2e/dialog-horizontal-overflow.spec.ts index 6f9ebbe21..3dbbbde62 100644 --- a/e2e/dialog-horizontal-overflow.spec.ts +++ b/e2e/dialog-horizontal-overflow.spec.ts @@ -428,6 +428,28 @@ test.describe("lab-scan review dialog uses the width it is given", () => { await expect(rows).toHaveCount(REVIEW_ROWS.length); const label = `scan review @${vp.label}`; + // The sheet widens from the picking stage to the review stage and the + // row grid re-flows from the container width it is given. Measuring in + // the middle of that sees a half-laid-out row, so wait until the + // surface has kept the same width across two frames. + await expect + .poll( + async () => { + const before = (await surface.boundingBox())!.width; + await page.evaluate( + () => + new Promise((resolve) => + requestAnimationFrame(() => + requestAnimationFrame(() => resolve()), + ), + ), + ); + const after = (await surface.boundingBox())!.width; + return Math.abs(after - before); + }, + { message: `${label}: dialog width settles` }, + ) + .toBeLessThan(0.5); await expectNoSidewaysScroll(page, label); await expectControlsInsideBox(page, label);