From bbd47a1061fe1ee9e78787fe5ad28ac0799c25ce Mon Sep 17 00:00:00 2001 From: Alex Hochheiden Date: Wed, 9 Sep 2026 23:19:16 +0000 Subject: [PATCH] Bug 2065363 - Check the licenses of the vendored node packages r=firefox-build-system-reviewers,linter-reviewers,Standard8,sergesanspaille The `node-licenses` lint normally reinstalls `node_modules` with `npm`. For vendored trees that `pnpm` manages, it checks the existing tree instead and reports an error when it is missing. Differential Revision: https://phabricator.services.mozilla.com/D320324 --- taskcluster/kinds/source-test/mozlint.yml | 1 + tools/lint/node-licenses.yml | 1 + tools/lint/node-licenses/__init__.py | 17 +++++++++ .../node-licenses/pnpm-missing/package.json | 6 +++ .../node-licenses/pnpm-missing/pnpm-lock.yaml | 2 + .../@mozilla/unknown-license/package.json | 6 +++ .../node-licenses/pnpm-unknown/package.json | 6 +++ .../node-licenses/pnpm-unknown/pnpm-lock.yaml | 2 + .../@mozilla/known-license/package.json | 6 +++ .../node-licenses/pnpm-vendored/package.json | 6 +++ .../pnpm-vendored/pnpm-lock.yaml | 2 + tools/lint/test/test_node_licenses.py | 37 +++++++++++++++++++ 12 files changed, 92 insertions(+) create mode 100644 tools/lint/test/files/node-licenses/pnpm-missing/package.json create mode 100644 tools/lint/test/files/node-licenses/pnpm-missing/pnpm-lock.yaml create mode 100644 tools/lint/test/files/node-licenses/pnpm-unknown/node_modules/@mozilla/unknown-license/package.json create mode 100644 tools/lint/test/files/node-licenses/pnpm-unknown/package.json create mode 100644 tools/lint/test/files/node-licenses/pnpm-unknown/pnpm-lock.yaml create mode 100644 tools/lint/test/files/node-licenses/pnpm-vendored/node_modules/@mozilla/known-license/package.json create mode 100644 tools/lint/test/files/node-licenses/pnpm-vendored/package.json create mode 100644 tools/lint/test/files/node-licenses/pnpm-vendored/pnpm-lock.yaml diff --git a/taskcluster/kinds/source-test/mozlint.yml b/taskcluster/kinds/source-test/mozlint.yml index b33d7f56814b..c604ff52acb8 100644 --- a/taskcluster/kinds/source-test/mozlint.yml +++ b/taskcluster/kinds/source-test/mozlint.yml @@ -354,6 +354,7 @@ node-licenses: - tools/lint/eslint/eslint-plugin-mozilla/package.json - tools/lint/stylelint/stylelint-plugin-mozilla/package.json - tools/terser/package.json + - third_party/node/** fetches: toolchain: - linux64-node diff --git a/tools/lint/node-licenses.yml b/tools/lint/node-licenses.yml index aaa8a88ffa6b..76ed6fb3ee37 100644 --- a/tools/lint/node-licenses.yml +++ b/tools/lint/node-licenses.yml @@ -8,6 +8,7 @@ node-licenses: - tools/lint/eslint/eslint-plugin-mozilla/package.json - tools/lint/stylelint/stylelint-plugin-mozilla/package.json - tools/terser/package.json + - third_party/node/package.json exclude: [] extensions: - json diff --git a/tools/lint/node-licenses/__init__.py b/tools/lint/node-licenses/__init__.py index f8a56cd08872..b9f46fe21dee 100644 --- a/tools/lint/node-licenses/__init__.py +++ b/tools/lint/node-licenses/__init__.py @@ -61,10 +61,13 @@ def lint(paths, config, binary=None, skip_reinstall=False, **lintargs): # - When the package is the top-level package.json, because the top level # node_modules is looked after by the setup, and we don't want to be # removing it from underneath ourselves. + # - When a pnpm-lock.yaml shows that pnpm owns the node_modules, which + # npm cannot safely reinstall. if ( not skip_reinstall and not os.environ.get("MOZ_AUTOMATION") and dirname != lintargs["root"] + and not os.path.exists(os.path.join(dirname, "pnpm-lock.yaml")) ): status = setup_helper.package_setup( dirname, os.path.basename(dirname), skip_logging=True @@ -80,6 +83,20 @@ def lint(paths, config, binary=None, skip_reinstall=False, **lintargs): }, ) ) + elif not skip_reinstall and not os.path.isdir( + os.path.join(dirname, "node_modules") + ): + issues.append( + result.from_config( + config, + **{ + "path": path, + "message": "No node_modules to check for this package, so no dependency was checked", + "level": "error", + }, + ) + ) + continue output = run_license_checker(binary, path, lintargs) if output == 1: diff --git a/tools/lint/test/files/node-licenses/pnpm-missing/package.json b/tools/lint/test/files/node-licenses/pnpm-missing/package.json new file mode 100644 index 000000000000..bb1f30a86ada --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-missing/package.json @@ -0,0 +1,6 @@ +{ + "description": "vendored with pnpm, tree absent", + "devDependencies": { + "@mozilla/known-license": "0.0.1" + } +} diff --git a/tools/lint/test/files/node-licenses/pnpm-missing/pnpm-lock.yaml b/tools/lint/test/files/node-licenses/pnpm-missing/pnpm-lock.yaml new file mode 100644 index 000000000000..a4554809f9ec --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-missing/pnpm-lock.yaml @@ -0,0 +1,2 @@ +--- +lockfileVersion: '9.0' diff --git a/tools/lint/test/files/node-licenses/pnpm-unknown/node_modules/@mozilla/unknown-license/package.json b/tools/lint/test/files/node-licenses/pnpm-unknown/node_modules/@mozilla/unknown-license/package.json new file mode 100644 index 000000000000..c7a68681fcca --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-unknown/node_modules/@mozilla/unknown-license/package.json @@ -0,0 +1,6 @@ +{ + "name": "@mozilla/unknown-license", + "version": "0.0.1", + "description": "A test module for testing only", + "license": "UnknownForTest" +} diff --git a/tools/lint/test/files/node-licenses/pnpm-unknown/package.json b/tools/lint/test/files/node-licenses/pnpm-unknown/package.json new file mode 100644 index 000000000000..f69675dcf142 --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-unknown/package.json @@ -0,0 +1,6 @@ +{ + "description": "vendored with pnpm, unknown license", + "devDependencies": { + "@mozilla/unknown-license": "0.0.1" + } +} diff --git a/tools/lint/test/files/node-licenses/pnpm-unknown/pnpm-lock.yaml b/tools/lint/test/files/node-licenses/pnpm-unknown/pnpm-lock.yaml new file mode 100644 index 000000000000..a4554809f9ec --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-unknown/pnpm-lock.yaml @@ -0,0 +1,2 @@ +--- +lockfileVersion: '9.0' diff --git a/tools/lint/test/files/node-licenses/pnpm-vendored/node_modules/@mozilla/known-license/package.json b/tools/lint/test/files/node-licenses/pnpm-vendored/node_modules/@mozilla/known-license/package.json new file mode 100644 index 000000000000..c1088eef16e9 --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-vendored/node_modules/@mozilla/known-license/package.json @@ -0,0 +1,6 @@ +{ + "name": "@mozilla/known-license", + "version": "0.0.1", + "description": "A test module for testing only", + "license": "MIT" +} diff --git a/tools/lint/test/files/node-licenses/pnpm-vendored/package.json b/tools/lint/test/files/node-licenses/pnpm-vendored/package.json new file mode 100644 index 000000000000..389e2d91cdb0 --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-vendored/package.json @@ -0,0 +1,6 @@ +{ + "description": "vendored with pnpm", + "devDependencies": { + "@mozilla/known-license": "0.0.1" + } +} diff --git a/tools/lint/test/files/node-licenses/pnpm-vendored/pnpm-lock.yaml b/tools/lint/test/files/node-licenses/pnpm-vendored/pnpm-lock.yaml new file mode 100644 index 000000000000..a4554809f9ec --- /dev/null +++ b/tools/lint/test/files/node-licenses/pnpm-vendored/pnpm-lock.yaml @@ -0,0 +1,2 @@ +--- +lockfileVersion: '9.0' diff --git a/tools/lint/test/test_node_licenses.py b/tools/lint/test/test_node_licenses.py index 2a1d7299a355..77c86037f791 100644 --- a/tools/lint/test/test_node_licenses.py +++ b/tools/lint/test/test_node_licenses.py @@ -37,5 +37,42 @@ def test_lint_known_license(lint, paths): assert len(results) == 0 +def test_lint_pnpm_vendored_tree(lint, paths): + results = lint( + paths(os.path.join("pnpm-vendored", "package.json")), + root=build.topsrcdir, + ) + + assert len(results) == 0 + + +def test_lint_pnpm_vendored_tree_unknown_license(lint, paths): + results = lint( + paths(os.path.join("pnpm-unknown", "package.json")), + root=build.topsrcdir, + ) + + assert len(results) == 1 + assert results[0].level == "error" + assert ( + "Included (sub-)dependency @mozilla/unknown-license@0.0.1 needs license UNKNOWN checking for acceptability" + in results[0].message + ) + assert "pnpm-unknown/package.json" in results[0].relpath + assert results[0].lineno == 0 + + +def test_lint_pnpm_vendored_tree_missing(lint, paths): + results = lint( + paths(os.path.join("pnpm-missing", "package.json")), + root=build.topsrcdir, + ) + + assert len(results) == 1 + assert results[0].level == "error" + assert "No node_modules to check for this package" in results[0].message + assert "pnpm-missing/package.json" in results[0].relpath + + if __name__ == "__main__": mozunit.main()