Skip to content

ci: Vitest + ESLint + npm audit (Chrome parity)#5

Merged
BartM82 merged 1 commit into
mainfrom
ci/vitest-eslint-audit
May 15, 2026
Merged

ci: Vitest + ESLint + npm audit (Chrome parity)#5
BartM82 merged 1 commit into
mainfrom
ci/vitest-eslint-audit

Conversation

@sebdraven

@sebdraven sebdraven commented May 15, 2026

Copy link
Copy Markdown
Member

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=high qui fait échouer la CI si une CVE high ou critical est connue dans le graphe de dépendances.

Pipeline CI (après cette PR)

Job Outils Échoue sur
test npm cinpm run lint (ESLint) → npm test (Vitest) → npm audit --audit-level=high Erreur ESLint, test rouge, CVE high/critical dans les deps
amo-lint web-ext lint (Mozilla addons-linter, même outil qu'AMO à la soumission) Violations CSP MV3, manifest invalide

npm audit consulte 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, scope tests/**/*.test.js.
  • tests/helpers/loadScript.js : loader eval indirect qui expose les classes sur window comme à l'exécution, stubs browser.runtime.getURL / chrome.runtime.getURL.
  • 5 fichiers de tests : manifest, techniqueAnalyzer (23), uiManager (security helpers PR Fix potential XSS in showSuspiciousSiteAlert and dead code #3), contentExtractor, suspiciousSitesManager — 58 tests passants, 4 todos documentés comme gaps de parité avec Chrome (Cyrillic, x.com, <nav> tag skip, frontières de mots sur classes).

Une modif source minime

modules/Suspicioussitesmanager.js : expose window.SuspiciousSitesManager à l'évaluation du module (en plus de l'instance window.suspiciousSitesManager après setTimeout). Permet aux tests d'instancier la classe directement. Comportement runtime inchangé.

Résultats locaux

npm run ci → 58/58 tests + 4 todos
npm audit --audit-level=high → exit 0

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

  • La CI tourne et est verte sur cette PR
  • Un `npm audit fix --force` qui casserait happy-dom serait attrapé par les tests (smoke)
  • Un déclassement de `happy-dom` à `^15.x` serait attrapé par l'audit step (smoke à vérifier sur une PR ultérieure)

Suite logique (PRs séparées)

  • Parité source avec Chrome : corriger les 4 todos (cleanText Unicode, x.com social, tag-level skip, word boundaries) + accessibilité du badge, namespacing des @keyframes, init synchrone du SuspiciousSitesManager
  • Workflow release.yml pour automatiser la soumission AMO sur tag

🤖 Generated with Claude Code

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>
@sebdraven
sebdraven requested review from BartM82 and Copilot and removed request for Copilot May 15, 2026 12:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 lint job.
  • Adds Vitest coverage for manifest validation, content extraction, technique analysis, UI helpers, and suspicious-site matching; exposes SuspiciousSitesManager for 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.

Comment thread package.json
"vitest": "^2.1.8"
},
"engines": {
"node": ">=20"
Comment thread tests/manifest.test.js

it('has a non-empty name, version, description', () => {
expect(manifest.name).toBeTruthy();
expect(manifest.version).toMatch(/^\d+\.\d+\.\d+$/);
Comment thread tests/README.md
Comment on lines +9 to +13
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)
@BartM82
BartM82 merged commit 90e409c into main May 15, 2026
3 checks passed
@sebdraven

Copy link
Copy Markdown
Member Author

Merci à Copilot — les trois remarques sont valides, corrigées dans 3012fa1 :

  1. engines.node : >=20 → >=20.11. import.meta.dirname est arrivé en Node 20.11 (janvier 2024). `actions/setup-node@v4` avec `node-version: '20'` résout vers la dernière 20.x donc la CI passait, mais un contributeur sur 20.0–20.10 (dans la fenêtre que `>=20` autorisait) aurait eu un `ReferenceError`. Resserrement de la contrainte.

  2. Regex de version dans `manifest.test.js` : ^\d+\.\d+\.\d+$ rejetait `2.0.0.1` (4 composants), incompatible avec l'AMO et avec le validateur CI lui-même. Aligné sur ^\d+\.\d+\.\d+(\.\d+)?$ — même contrainte que .github/workflows/ci.yml.

  3. npm run ci ne lançait pas l'audit : la doc et le job GitHub Actions divergeaient. Ajouté un script audit explicite, et `ci` est maintenant `lint && test && audit` — un développeur qui tourne npm run ci localement obtient le même go/no-go que la CI. README mis à jour.

sebdraven added a commit that referenced this pull request May 15, 2026
- 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>
BartM82 added a commit that referenced this pull request Jul 17, 2026
ci: address Copilot review on PR #5 (Node engine, version regex, audit in ci script)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants