From 9a2ff00ec780e40067a252c00a4aac888726e3ca Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 11:47:08 +0200 Subject: [PATCH 1/7] fix(security): patch vulnerable transitive deps via npm audit fix Bumps within existing semver ranges (lockfile only, no package.json change): - postcss -> 8.5.25 (fixes GHSA-r28c-9q8g-f849, high: source-map path traversal) - brace-expansion -> 1.1.18 / 2.1.4 (fixes GHSA-*, high: ReDoS/OOM DoS) - dompurify -> 3.4.12 (fixes GHSA-c2j3-45gr-mqc4, low: custom-element bypass) - ajv -> 6.15.0 (fixes moderate ReDoS with $data) Closes the 4 open Dependabot alerts. Lint + build verified green. Co-Authored-By: Claude AI --- package-lock.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5201b43..9f7d693 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1385,9 +1385,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -1510,9 +1510,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1595,9 +1595,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -1853,9 +1853,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.11", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", - "integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", "license": "(MPL-2.0 OR Apache-2.0)", "optional": true, "optionalDependencies": { @@ -2900,9 +2900,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "dev": true, "funding": [ { @@ -3092,9 +3092,9 @@ } }, "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", "dev": true, "funding": [ { @@ -3112,7 +3112,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, From 694cd1c19a55cae837d8872cbf3ad0d0b79b2297 Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 11:49:58 +0200 Subject: [PATCH 2/7] ci(security): harden build-and-deploy workflow - Pin all actions to full-length commit SHAs (with version comments) to prevent mutable-tag supply-chain attacks; Dependabot keeps them current. - Add per-job least-privilege `permissions` and `timeout-minutes`. Co-Authored-By: Claude AI --- .github/workflows/build-and-deploy.yml | 31 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 066ec2f..33d78b4 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -15,6 +15,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# Least privilege by default; jobs opt into more where needed. permissions: contents: read @@ -22,11 +23,14 @@ jobs: lint: name: Lint runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "22.x" cache: "npm" @@ -41,23 +45,26 @@ jobs: name: Build runs-on: ubuntu-latest needs: lint + timeout-minutes: 15 + permissions: + contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: fetch-depth: 0 - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v3.2.1 + uses: gittools/actions/gitversion/setup@51d325634925d7d9ce0a7efc2c586c0bc2b9eee6 # v3.2.1 - name: Determine Version id: gitversion - uses: gittools/actions/gitversion/execute@v3.2.1 + uses: gittools/actions/gitversion/execute@51d325634925d7d9ce0a7efc2c586c0bc2b9eee6 # v3.2.1 with: useConfigFile: true configFilePath: GitVersion.yml - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "22.x" cache: "npm" @@ -72,7 +79,7 @@ jobs: run: npm run build - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: "dist" path: "./dist" @@ -86,6 +93,7 @@ jobs: runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' + timeout-minutes: 10 environment: name: preview url: ${{ steps.netlify.outputs.deploy-url }} @@ -94,14 +102,14 @@ jobs: deployments: write steps: - name: Download artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: "dist" path: "./dist" - name: Deploy preview to Netlify id: netlify - uses: nwtgck/actions-netlify@v3.0 + uses: nwtgck/actions-netlify@4cbaf4c08f1a7bfa537d6113472ef4424e4eb654 # v3.0 with: publish-dir: "./dist" production-deploy: false @@ -116,6 +124,7 @@ jobs: runs-on: ubuntu-latest needs: build if: startsWith(github.ref, 'refs/tags/') + timeout-minutes: 10 environment: name: production url: ${{ steps.netlify.outputs.deploy-url }} @@ -124,14 +133,14 @@ jobs: deployments: write steps: - name: Download artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: "dist" path: "./dist" - name: Deploy to Netlify id: netlify - uses: nwtgck/actions-netlify@v3.0 + uses: nwtgck/actions-netlify@4cbaf4c08f1a7bfa537d6113472ef4424e4eb654 # v3.0 with: publish-dir: "./dist" production-deploy: true From a00f351ff07883db6e6ecabbdeaf7a80af0cb071 Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 11:49:58 +0200 Subject: [PATCH 3/7] ci: add CodeQL code scanning (security-and-quality suite) Static analysis for JavaScript/TypeScript on push, PR, and weekly schedule, using GitHub's extended "security-and-quality" query suite. Actions pinned to SHA. Co-Authored-By: Claude AI --- .github/workflows/codeql.yml | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..58d4378 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,46 @@ +name: CodeQL + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + schedule: + - cron: "27 3 * * 1" # weekly, Monday 03:27 UTC + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + security-events: write # upload analysis results to code scanning + contents: read + actions: read + strategy: + fail-fast: false + matrix: + language: ["javascript-typescript"] + steps: + - name: Checkout + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@a2983b8bed1923f44751c5c43237f479442827b3 # v3 + with: + languages: ${{ matrix.language }} + # "security-and-quality" is the extended suite: security queries plus + # maintainability/reliability ("quality") checks. + queries: security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@a2983b8bed1923f44751c5c43237f479442827b3 # v3 + with: + category: "/language:${{ matrix.language }}" From b04fc57de8b0030e0a691bfd62cbdcf413f0d421 Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 11:49:59 +0200 Subject: [PATCH 4/7] ci: add Dependabot version updates for npm and github-actions Weekly updates, grouped to reduce PR noise (npm minor/patch grouped; majors individual). Complements the existing automatic Dependabot security updates. Co-Authored-By: Claude AI --- .github/dependabot.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..dbc62b7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +# Dependabot version updates (in addition to Dependabot security updates, +# which run automatically). Docs: https://docs.github.com/code-security/dependabot +version: 2 +updates: + # npm dependencies + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + groups: + # One grouped PR for routine minor/patch bumps to keep noise low; + # major bumps still come as individual PRs so they can be reviewed on their own. + npm-minor-patch: + patterns: ["*"] + update-types: ["minor", "patch"] + + # GitHub Actions used by the workflows (keeps the pinned SHAs current) + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + groups: + github-actions: + patterns: ["*"] From 6aa140c244c1748ce3103d316cd94b0f4ddb3546 Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 12:15:59 +0200 Subject: [PATCH 5/7] ci: pin actions to version tags instead of commit SHAs Per preference, use readable major/version tags (@v4, @v3, @v3.2.1) rather than full-length SHA pins. Kept the other hardening (per-job timeouts, least-privilege permissions on deploy jobs). Dependabot still tracks updates. Co-Authored-By: Claude AI --- .github/workflows/build-and-deploy.yml | 27 +++++++++++--------------- .github/workflows/codeql.yml | 6 +++--- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 33d78b4..0ab7200 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -15,7 +15,6 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -# Least privilege by default; jobs opt into more where needed. permissions: contents: read @@ -24,13 +23,11 @@ jobs: name: Lint runs-on: ubuntu-latest timeout-minutes: 10 - permissions: - contents: read steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + uses: actions/setup-node@v4 with: node-version: "22.x" cache: "npm" @@ -46,25 +43,23 @@ jobs: runs-on: ubuntu-latest needs: lint timeout-minutes: 15 - permissions: - contents: read steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install GitVersion - uses: gittools/actions/gitversion/setup@51d325634925d7d9ce0a7efc2c586c0bc2b9eee6 # v3.2.1 + uses: gittools/actions/gitversion/setup@v3.2.1 - name: Determine Version id: gitversion - uses: gittools/actions/gitversion/execute@51d325634925d7d9ce0a7efc2c586c0bc2b9eee6 # v3.2.1 + uses: gittools/actions/gitversion/execute@v3.2.1 with: useConfigFile: true configFilePath: GitVersion.yml - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + uses: actions/setup-node@v4 with: node-version: "22.x" cache: "npm" @@ -79,7 +74,7 @@ jobs: run: npm run build - name: Upload artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@v4 with: name: "dist" path: "./dist" @@ -102,14 +97,14 @@ jobs: deployments: write steps: - name: Download artifact - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + uses: actions/download-artifact@v4 with: name: "dist" path: "./dist" - name: Deploy preview to Netlify id: netlify - uses: nwtgck/actions-netlify@4cbaf4c08f1a7bfa537d6113472ef4424e4eb654 # v3.0 + uses: nwtgck/actions-netlify@v3.0 with: publish-dir: "./dist" production-deploy: false @@ -133,14 +128,14 @@ jobs: deployments: write steps: - name: Download artifact - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + uses: actions/download-artifact@v4 with: name: "dist" path: "./dist" - name: Deploy to Netlify id: netlify - uses: nwtgck/actions-netlify@4cbaf4c08f1a7bfa537d6113472ef4424e4eb654 # v3.0 + uses: nwtgck/actions-netlify@v3.0 with: publish-dir: "./dist" production-deploy: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 58d4378..2f17faa 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,10 +30,10 @@ jobs: language: ["javascript-typescript"] steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@a2983b8bed1923f44751c5c43237f479442827b3 # v3 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # "security-and-quality" is the extended suite: security queries plus @@ -41,6 +41,6 @@ jobs: queries: security-and-quality - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@a2983b8bed1923f44751c5c43237f479442827b3 # v3 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" From 678c0a1bbc5b8b35d113d18e0c660620a9e6b00a Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 12:35:19 +0200 Subject: [PATCH 6/7] ci: drop codeql.yml and dependabot.yml (use GitHub settings instead) Code scanning is enabled via CodeQL "default setup" (Security and quality suite) in repo settings, not a workflow file. Dependency version updates are not configured. Keeps only the security dependency patch in this PR. Co-Authored-By: Claude AI --- .github/dependabot.yml | 26 -------------------- .github/workflows/codeql.yml | 46 ------------------------------------ 2 files changed, 72 deletions(-) delete mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index dbc62b7..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Dependabot version updates (in addition to Dependabot security updates, -# which run automatically). Docs: https://docs.github.com/code-security/dependabot -version: 2 -updates: - # npm dependencies - - package-ecosystem: "npm" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 10 - groups: - # One grouped PR for routine minor/patch bumps to keep noise low; - # major bumps still come as individual PRs so they can be reviewed on their own. - npm-minor-patch: - patterns: ["*"] - update-types: ["minor", "patch"] - - # GitHub Actions used by the workflows (keeps the pinned SHAs current) - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 5 - groups: - github-actions: - patterns: ["*"] diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 2f17faa..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: CodeQL - -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - schedule: - - cron: "27 3 * * 1" # weekly, Monday 03:27 UTC - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - analyze: - name: Analyze (${{ matrix.language }}) - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - security-events: write # upload analysis results to code scanning - contents: read - actions: read - strategy: - fail-fast: false - matrix: - language: ["javascript-typescript"] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - # "security-and-quality" is the extended suite: security queries plus - # maintainability/reliability ("quality") checks. - queries: security-and-quality - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{ matrix.language }}" From df7b156462d6731f85e33aebbc039a161641ec13 Mon Sep 17 00:00:00 2001 From: Davide Piccinini Date: Fri, 31 Jul 2026 12:43:17 +0200 Subject: [PATCH 7/7] ci: drop timeout-minutes from workflow (not needed) Reduces PR #17 to only the security dependency patch. Co-Authored-By: Claude AI --- .github/workflows/build-and-deploy.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 0ab7200..066ec2f 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -22,7 +22,6 @@ jobs: lint: name: Lint runs-on: ubuntu-latest - timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -42,7 +41,6 @@ jobs: name: Build runs-on: ubuntu-latest needs: lint - timeout-minutes: 15 steps: - uses: actions/checkout@v4 with: @@ -88,7 +86,6 @@ jobs: runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' - timeout-minutes: 10 environment: name: preview url: ${{ steps.netlify.outputs.deploy-url }} @@ -119,7 +116,6 @@ jobs: runs-on: ubuntu-latest needs: build if: startsWith(github.ref, 'refs/tags/') - timeout-minutes: 10 environment: name: production url: ${{ steps.netlify.outputs.deploy-url }}