security(deps): bump @sveltejs/kit + vite to clear 5 high CVEs #625

Merged
marcel merged 7 commits from feat/issue-458-security-dep-bump into main 2026-05-19 16:29:44 +02:00
6 changed files with 1517 additions and 1409 deletions

View File

@@ -13,7 +13,7 @@ jobs:
name: Unit & Component Tests name: Unit & Component Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: mcr.microsoft.com/playwright:v1.58.2-noble image: mcr.microsoft.com/playwright:v1.60.0-noble
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -29,6 +29,10 @@ jobs:
run: npm ci run: npm ci
working-directory: frontend working-directory: frontend
- name: Security audit (no dev deps)
run: npm audit --audit-level=high --omit=dev
working-directory: frontend
- name: Compile Paraglide i18n - name: Compile Paraglide i18n
run: npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide run: npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide
working-directory: frontend working-directory: frontend

View File

@@ -276,6 +276,9 @@ services:
# SSR fetches go inside the docker network; clients hit https://${APP_DOMAIN} # SSR fetches go inside the docker network; clients hit https://${APP_DOMAIN}
API_INTERNAL_URL: http://backend:8080 API_INTERNAL_URL: http://backend:8080
ORIGIN: https://${APP_DOMAIN} ORIGIN: https://${APP_DOMAIN}
# Enforce upload size limit in the adapter-node layer (fixes GHSA-2crg-3p73-43xp bypass).
# Must be ≤ client_max_body_size in the Caddy reverse proxy to avoid 413 mismatches.
BODY_SIZE_LIMIT: 50M
networks: networks:
- archiv-net - archiv-net
healthcheck: healthcheck:

View File

@@ -228,6 +228,9 @@ services:
API_INTERNAL_URL: http://backend:8080 API_INTERNAL_URL: http://backend:8080
# Vite dev proxy forwards /api from browser to the backend container # Vite dev proxy forwards /api from browser to the backend container
API_PROXY_TARGET: http://backend:8080 API_PROXY_TARGET: http://backend:8080
# Upload size limit for adapter-node (production target). Not enforced by Vite dev server
# but kept here to match docker-compose.prod.yml and prevent config drift.
BODY_SIZE_LIMIT: 50M
ports: ports:
- "${PORT_FRONTEND}:5173" - "${PORT_FRONTEND}:5173"
networks: networks:

File diff suppressed because it is too large Load Diff

View File

@@ -24,9 +24,9 @@
}, },
"dependencies": { "dependencies": {
"@sentry/sveltekit": "^10.53.1", "@sentry/sveltekit": "^10.53.1",
"@tiptap/core": "3.22.5", "@tiptap/core": "3.23.4",
"@tiptap/extension-mention": "3.22.5", "@tiptap/extension-mention": "3.23.4",
"@tiptap/starter-kit": "3.22.5", "@tiptap/starter-kit": "3.23.4",
"diff": "^8.0.3", "diff": "^8.0.3",
"isomorphic-dompurify": "^3.12.0", "isomorphic-dompurify": "^3.12.0",
"openapi-fetch": "^0.13.5", "openapi-fetch": "^0.13.5",
@@ -37,9 +37,9 @@
"@eslint/compat": "^1.4.0", "@eslint/compat": "^1.4.0",
"@eslint/js": "^9.39.1", "@eslint/js": "^9.39.1",
"@inlang/paraglide-js": "^2.5.0", "@inlang/paraglide-js": "^2.5.0",
"@playwright/test": "^1.58.2", "@playwright/test": "^1.60.0",
"@sveltejs/adapter-node": "^5.4.0", "@sveltejs/adapter-node": "^5.5.4",
"@sveltejs/kit": "^2.48.5", "@sveltejs/kit": "^2.60.1",
"@sveltejs/vite-plugin-svelte": "^6.2.1", "@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
@@ -57,7 +57,7 @@
"globals": "^16.5.0", "globals": "^16.5.0",
"openapi-typescript": "^7.8.0", "openapi-typescript": "^7.8.0",
"patch-package": "^8.0.0", "patch-package": "^8.0.0",
"playwright": "^1.56.1", "playwright": "^1.60.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0", "prettier-plugin-svelte": "^3.4.0",
"prettier-plugin-tailwindcss": "^0.7.1", "prettier-plugin-tailwindcss": "^0.7.1",
@@ -66,7 +66,7 @@
"tailwindcss": "^4.1.17", "tailwindcss": "^4.1.17",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"typescript-eslint": "^8.47.0", "typescript-eslint": "^8.47.0",
"vite": "^7.2.2", "vite": "^7.3.3",
"vite-plugin-devtools-json": "^1.0.0", "vite-plugin-devtools-json": "^1.0.0",
"vitest": "^4.0.10", "vitest": "^4.0.10",
"vitest-browser-svelte": "^2.0.1" "vitest-browser-svelte": "^2.0.1"

View File

@@ -1,30 +1,30 @@
diff --git a/node_modules/@vitest/browser-playwright/dist/index.js b/node_modules/@vitest/browser-playwright/dist/index.js diff --git a/node_modules/@vitest/browser-playwright/dist/index.js b/node_modules/@vitest/browser-playwright/dist/index.js
index 5d0d37b..821d7b4 100644 index c01e754..f1bb7be 100644
--- a/node_modules/@vitest/browser-playwright/dist/index.js --- a/node_modules/@vitest/browser-playwright/dist/index.js
+++ b/node_modules/@vitest/browser-playwright/dist/index.js +++ b/node_modules/@vitest/browser-playwright/dist/index.js
@@ -935,7 +935,7 @@ class PlaywrightBrowserProvider { @@ -936,7 +936,7 @@ class PlaywrightBrowserProvider {
createMocker() { createMocker() {
const idPreficates = new Map(); const idPredicates = new Map();
const sessionIds = new Map(); const sessionIds = new Map();
- function createPredicate(sessionId, url) { - function createPredicate(sessionId, url) {
+ function createPredicate(url) { + function createPredicate(url) {
const moduleUrl = new URL(url, "http://localhost"); const moduleUrl = new URL(url, "http://localhost");
const predicate = (url) => { const predicate = (url) => {
if (url.searchParams.has("_vitest_original")) { if (url.searchParams.has("_vitest_original")) {
@@ -960,11 +960,7 @@ class PlaywrightBrowserProvider { @@ -961,11 +961,7 @@ class PlaywrightBrowserProvider {
} }
return true; return true;
}; };
- const ids = sessionIds.get(sessionId) || []; - const ids = sessionIds.get(sessionId) || [];
- ids.push(moduleUrl.href); - ids.push(moduleUrl.href);
- sessionIds.set(sessionId, ids); - sessionIds.set(sessionId, ids);
- idPreficates.set(predicateKey(sessionId, moduleUrl.href), predicate); - idPredicates.set(predicateKey(sessionId, moduleUrl.href), predicate);
- return predicate; - return predicate;
+ return { url: moduleUrl.href, predicate }; + return { url: moduleUrl.href, predicate };
} }
function predicateKey(sessionId, url) { function predicateKey(sessionId, url) {
return `${sessionId}:${url}`; return `${sessionId}:${url}`;
@@ -972,7 +968,23 @@ class PlaywrightBrowserProvider { @@ -973,7 +969,23 @@ class PlaywrightBrowserProvider {
return { return {
register: async (sessionId, module) => { register: async (sessionId, module) => {
const page = this.getPage(sessionId); const page = this.getPage(sessionId);
@@ -37,19 +37,19 @@ index 5d0d37b..821d7b4 100644
+ // duplicate-id mocks (e.g. '$lib/foo.svelte' + '$lib/foo.svelte.js') + // duplicate-id mocks (e.g. '$lib/foo.svelte' + '$lib/foo.svelte.js')
+ // leak an orphan route whose handler crashes after the next + // leak an orphan route whose handler crashes after the next
+ // session's birpc channel closes. + // session's birpc channel closes.
+ const existingPredicate = idPreficates.get(key); + const existingPredicate = idPredicates.get(key);
+ if (existingPredicate) { + if (existingPredicate) {
+ await page.context().unroute(existingPredicate); + await page.context().unroute(existingPredicate);
+ } + }
+ const ids = sessionIds.get(sessionId) ?? new Set(); + const ids = sessionIds.get(sessionId) ?? new Set();
+ ids.add(moduleUrl); + ids.add(moduleUrl);
+ sessionIds.set(sessionId, ids); + sessionIds.set(sessionId, ids);
+ idPreficates.set(key, predicate); + idPredicates.set(key, predicate);
+ await page.context().route(predicate, async (route) => { + await page.context().route(predicate, async (route) => {
if (module.type === "manual") { if (module.type === "manual") {
const exports$1 = Object.keys(await module.resolve()); const exports$1 = Object.keys(await module.resolve());
const body = createManualModuleSource(module.url, exports$1); const body = createManualModuleSource(module.url, exports$1);
@@ -1033,8 +1045,8 @@ class PlaywrightBrowserProvider { @@ -1034,8 +1046,8 @@ class PlaywrightBrowserProvider {
}, },
clear: async (sessionId) => { clear: async (sessionId) => {
const page = this.getPage(sessionId); const page = this.getPage(sessionId);
@@ -58,5 +58,5 @@ index 5d0d37b..821d7b4 100644
+ const ids = sessionIds.get(sessionId) ?? new Set(); + const ids = sessionIds.get(sessionId) ?? new Set();
+ const promises = [...ids].map((id) => { + const promises = [...ids].map((id) => {
const key = predicateKey(sessionId, id); const key = predicateKey(sessionId, id);
const predicate = idPreficates.get(key); const predicate = idPredicates.get(key);
if (predicate) { if (predicate) {