ci: Vitest + ESLint + npm audit (Chrome parity)#5
Conversation
Mirrors the security CI/CD setup that landed on the DIMA_Plugin_Chrome repo (PR #28). The goal is to fail the CI on supply-chain CVEs and to ground every regression in a unit test instead of manual checks. ## What lands - package.json + package-lock.json with Vitest 2, ESLint 9, happy-dom >=20.9.0 (skips the critical CVE GHSA-37j7-fg3j-429f that the Chrome audit step caught on happy-dom <=20.8.8). - eslint.config.js: flat config, browser globals for source, Node + Vitest globals for tests/. no-redeclare and no-undef are off because source files share state via window globals declared as `const X = [...]` at top level. - vitest.config.js: happy-dom environment, v8 coverage, scans tests/**. - tests/helpers/loadScript.js: indirect-eval loader that exposes the classes on `window` exactly as Firefox would at runtime, with a browser/chrome runtime stub for code that reads `_extensionAPI` at module load time. - tests/manifest.test.js: validates JSON, MV3, the AMO listing ID (dima@m82-project.org), and that every declared content_scripts, icons and web_accessible_resources path exists on disk. - tests/techniqueAnalyzer.test.js: 23 tests covering risk bands, color bands, word-boundary keyword matching, contextual/dynamic weighting, performAnalysis cap and clean-content baseline. - tests/uiManager.test.js: locks down the security helpers added by PR #3 — sanitizeHexColor (#RRGGBB only, fallback on injection), isSafeHttpUrl (http/https only, rejects javascript:/data:/file:/ relative URLs), adjustColor clamping, generateTooltip rendering. - tests/contentExtractor.test.js: cleanText, detectPageType, extractTitle, shouldSkipElement. Four `it.todo` mark known parity gaps with the Chrome plugin (Cyrillic stripping, x.com social, <nav> tag-level skip, class-name word boundaries) as a follow-up. - tests/suspiciousSitesManager.test.js: checkSite across the three matchType formats (exact / contains / pattern) plus getRiskConfig. ## CI changes (.github/workflows/ci.yml) Replaces the prior syntax + manifest validation jobs (now subsumed by ESLint and tests/manifest.test.js) with a single `test` job that runs: npm ci → npm run lint → npm test → npm audit --audit-level=high The audit step is the actual security improvement: fails the build on any high/critical CVE in the dep tree, consulting GitHub Advisory at each run with no maintenance on our side. `web-ext lint` (Mozilla addons-linter) stays in a separate job since it's Firefox-specific and doesn't need npm. Its ignore list is extended to skip the new tooling files (package.json, tests/, etc.). ## Source change modules/Suspicioussitesmanager.js: expose `window.SuspiciousSitesManager` at module evaluation time (in addition to the deferred instance `window.suspiciousSitesManager` after setTimeout). This is purely for tests and hot-reload — the runtime behaviour is unchanged. ## Local results - npm run ci: lint clean (1 pre-existing warning), 58 tests pass + 4 todos. - npm audit --audit-level=high: exit 0. Six moderate vulnerabilities remain in the vite/vite-node/esbuild tooling chain — under the threshold; to revisit if they escalate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a Node-based CI/testing toolchain to the Firefox extension, aligning it with the Chrome plugin hardening approach: ESLint, Vitest unit tests, dependency audit, and AMO linting.
Changes:
- Adds npm project metadata, lockfile, ESLint flat config, Vitest config, and
.gitignore. - Reworks GitHub Actions into a test/lint/audit job plus a separate
web-ext lintjob. - Adds Vitest coverage for manifest validation, content extraction, technique analysis, UI helpers, and suspicious-site matching; exposes
SuspiciousSitesManagerfor direct test instantiation.
Reviewed changes
Copilot reviewed 12 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/ci.yml |
Defines npm install, ESLint, Vitest, audit, and AMO lint jobs. |
.gitignore |
Ignores local/tooling outputs and editor files. |
eslint.config.js |
Adds ESLint 9 flat config for browser scripts and test/tooling files. |
modules/Suspicioussitesmanager.js |
Exposes the manager class on window before delayed runtime instantiation. |
package.json |
Introduces npm scripts, dev dependencies, and Node engine metadata. |
package-lock.json |
Locks the new test/lint dependency graph. |
tests/README.md |
Documents test commands, coverage areas, loader behavior, and CI. |
tests/contentExtractor.test.js |
Adds unit coverage for text cleanup, page type detection, title extraction, and skip logic. |
tests/helpers/loadScript.js |
Adds a helper to load extension scripts into the Vitest DOM environment. |
tests/manifest.test.js |
Adds manifest structure, ID, version, and path existence checks. |
tests/suspiciousSitesManager.test.js |
Adds suspicious-domain matching and risk config tests. |
tests/techniqueAnalyzer.test.js |
Adds scoring, matching, weighting, and analysis tests. |
tests/uiManager.test.js |
Adds UI helper, URL safety, color, and tooltip tests. |
vitest.config.js |
Configures Vitest with happy-dom, test include patterns, and coverage settings. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "vitest": "^2.1.8" | ||
| }, | ||
| "engines": { | ||
| "node": ">=20" |
|
|
||
| it('has a non-empty name, version, description', () => { | ||
| expect(manifest.name).toBeTruthy(); | ||
| expect(manifest.version).toMatch(/^\d+\.\d+\.\d+$/); |
| npm test # un seul run | ||
| npm run test:watch # mode watch pour le dev | ||
| npm run test:coverage # avec rapport de couverture (text + html + lcov) | ||
| npm run lint # ESLint | ||
| npm run ci # lint + tests (= ce que tourne GitHub Actions) |
|
Merci à Copilot — les trois remarques sont valides, corrigées dans 3012fa1 :
|
- Regenerate package-lock.json so the embedded `engines.node` field matches the package.json bump from `>=20` to `>=20.11`. Without this, contributors and tooling reading the lockfile see a contradictory constraint. - tests/manifest.test.js: the inline comment claimed alignment with a CI-side regex that no longer exists (PR #5 replaced the inline Node validation step with this test file itself). Reworded to state that this assertion IS the validation. - tests/README.md: clarify that `npm run ci` matches only the `test` job of GitHub Actions; the `amo-lint` job (`web-ext lint`) runs in addition on CI but isn't part of this local script. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ci: address Copilot review on PR #5 (Node engine, version regex, audit in ci script)
Summary
Apporte au plugin Firefox le même durcissement CI/CD que le plugin Chrome (DIMA_Plugin_Chrome#28). L'étape sécurité-clé est
npm audit --audit-level=highqui fait échouer la CI si une CVE high ou critical est connue dans le graphe de dépendances.Pipeline CI (après cette PR)
testnpm ci→npm run lint(ESLint) →npm test(Vitest) →npm audit --audit-level=highamo-lintweb-ext lint(Mozilla addons-linter, même outil qu'AMO à la soumission)npm auditconsulte la base GitHub Advisory à chaque run, zéro maintenance côté repo.Ce qui arrive
package.json+package-lock.json: Vitest 2, ESLint 9,happy-dom ^20.9.0(skip d'office la CVE critical GHSA-37j7-fg3j-429f que l'audit step du Chrome avait attrapée sur happy-dom ≤ 20.8.8).eslint.config.js: flat config, globals browser pour la source, globals Node + Vitest pour les tests.vitest.config.js: env happy-dom, coverage v8, scopetests/**/*.test.js.tests/helpers/loadScript.js: loader eval indirect qui expose les classes surwindowcomme à l'exécution, stubsbrowser.runtime.getURL/chrome.runtime.getURL.<nav>tag skip, frontières de mots sur classes).Une modif source minime
modules/Suspicioussitesmanager.js: exposewindow.SuspiciousSitesManagerà l'évaluation du module (en plus de l'instancewindow.suspiciousSitesManageraprèssetTimeout). Permet aux tests d'instancier la classe directement. Comportement runtime inchangé.Résultats locaux
6 vulnérabilités moderate persistent dans la chaîne vite/vite-node/esbuild (tooling de tests uniquement, pas dans le code livré). Sous le seuil
high, l'audit les laisse passer. À revisiter si elles escaladent.Test plan
Suite logique (PRs séparées)
@keyframes, init synchrone du SuspiciousSitesManager🤖 Generated with Claude Code