From ecd1e4db2911df0ef0525e124531b71192712dcd Mon Sep 17 00:00:00 2001 From: Gandalf the Greybeard Date: Thu, 23 Apr 2026 10:58:22 +0000 Subject: [PATCH 1/3] fix: override lodash >=4.18.0 to patch code injection vulnerability GHSA-r5fr-rjxr-66jc is a code injection vulnerability in lodash below 4.18.0. The vulnerable transitive dependency comes through @kinvolk/headlamp-plugin. Co-Authored-By: Claude Opus 4.7 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 15af471..3732196 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ }, "overrides": { "tar": "^7.5.11", - "undici": "^7.24.3" + "undici": "^7.24.3", + "lodash": ">=4.18.0" } } -- 2.52.0 From 6fd9b5d8109507820649c92a45c29d73a02ed821 Mon Sep 17 00:00:00 2001 From: Gandalf the Greybeard Date: Sun, 26 Apr 2026 21:32:33 +0000 Subject: [PATCH 2/3] fix: update package-lock.json to satisfy lodash override The package.json override requires lodash >=4.18.0, but the lockfile had 4.17.23. Regenerated lockfile with npm install --include=dev. Co-Authored-By: Paperclip --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1aa33fd..74b7397 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11600,9 +11600,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true, "license": "MIT" }, -- 2.52.0 From d11ebd91052f07ac558492c110861d83da1e4cd8 Mon Sep 17 00:00:00 2001 From: Gandalf the Greybeard Date: Sun, 26 Apr 2026 21:44:54 +0000 Subject: [PATCH 3/3] fix(e2e): scope heading locators to main content area Cherry-picked from PR #50 to fix E2E test failures on lodash PR. Co-Authored-By: Paperclip --- e2e/intel-gpu.spec.ts | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/e2e/intel-gpu.spec.ts b/e2e/intel-gpu.spec.ts index 104380d..3aae3ef 100644 --- a/e2e/intel-gpu.spec.ts +++ b/e2e/intel-gpu.spec.ts @@ -19,16 +19,18 @@ test.describe('Intel GPU plugin smoke tests', () => { // Should navigate to the overview route await expect(page).toHaveURL(/\/intel-gpu$/); - await expect(page.getByRole('heading', { name: /Intel GPU — Overview/i })).toBeVisible(); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Overview' }) + ).toBeVisible(); }); test('overview page renders GPU device list or empty state', async ({ page }) => { await page.goto('/c/main/intel-gpu'); // Overview heading should be present - await expect(page.getByRole('heading', { name: /Intel GPU — Overview/i })).toBeVisible({ - timeout: 15_000, - }); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Overview' }) + ).toBeVisible({ timeout: 15_000 }); // Either a populated table/list or an empty-state indicator must be visible const hasTable = await page.locator('table').first().isVisible().catch(() => false); @@ -43,9 +45,9 @@ test.describe('Intel GPU plugin smoke tests', () => { test('device plugins page renders or shows empty state', async ({ page }) => { await page.goto('/c/main/intel-gpu/device-plugins'); - await expect(page.getByRole('heading', { name: /Intel GPU — Device Plugins/i })).toBeVisible({ - timeout: 15_000, - }); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Device Plugins' }) + ).toBeVisible({ timeout: 15_000 }); const hasTable = await page.locator('table').first().isVisible().catch(() => false); const hasEmptyState = await page @@ -61,18 +63,24 @@ test.describe('Intel GPU plugin smoke tests', () => { // not after clicking the parent entry from the overview. Test route // accessibility via direct navigation — each route must render its heading. await page.goto('/c/main/intel-gpu'); - await expect(page.getByRole('heading', { name: /Intel GPU — Overview/i })).toBeVisible({ - timeout: 15_000, - }); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Overview' }) + ).toBeVisible({ timeout: 15_000 }); await page.goto('/c/main/intel-gpu/nodes'); - await expect(page.getByRole('heading', { name: /Intel GPU — Nodes/i })).toBeVisible({ timeout: 15_000 }); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Nodes' }) + ).toBeVisible({ timeout: 15_000 }); await page.goto('/c/main/intel-gpu/pods'); - await expect(page.getByRole('heading', { name: /Intel GPU — Pods/i })).toBeVisible({ timeout: 15_000 }); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Pods' }) + ).toBeVisible({ timeout: 15_000 }); await page.goto('/c/main/intel-gpu/metrics'); - await expect(page.getByRole('heading', { name: /Intel GPU — Metrics/i })).toBeVisible({ timeout: 15_000 }); + await expect( + page.locator('main').getByRole('heading', { name: 'Intel GPU — Metrics' }) + ).toBeVisible({ timeout: 15_000 }); }); test('plugin settings page shows intel-gpu plugin entry', async ({ page }) => { -- 2.52.0