From: David Cho-Lerat Date: Wed, 16 Oct 2024 09:56:00 +0000 (+0200) Subject: SONAR-23205 Add rollup-plugin-license like in SC (serve 3rd-party licenses at /vendor... X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c33a6b9956802dfa00133e304326887b901af901;p=sonarqube.git SONAR-23205 Add rollup-plugin-license like in SC (serve 3rd-party licenses at /vendor.LICENSE.txt) --- diff --git a/server/sonar-web/config/license.ts b/server/sonar-web/config/license.ts new file mode 100644 index 00000000000..066d4e4cad0 --- /dev/null +++ b/server/sonar-web/config/license.ts @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { Dependency } from 'rollup-plugin-license'; + +// To be always synced with https://saas-eu.whitesourcesoftware.com/Wss/WSS.html#!policyDetails;policy=3131;org=318388 +// Below is the list of approved front-end licenses extracted from Mend +export const ALLOWED_LICENSES = [ + '(MPL-2.0 OR Apache-2.0)', // Multiple licenses. Added specifically for dompurify as we have ignored this in Mend + '0BSD', + 'Apache-2.0', + 'BSD-2-Clause', + 'BSD-3-Clause', + 'ISC', + 'LGPL-3.0', + 'MIT', +]; + +// Just for Sprig currently, it has an Apache-2 license that isn't correctly parsed by the plugin +export const ALLOWED_LICENSE_TEXT = ['http://www.apache.org/licenses/LICENSE-2.0']; + +// Generates license information with necessary details. +// A package which has a valid license that the plugin is unable read will default to MIT +export const generateLicenseText = (dependency: Dependency) => { + const { author, homepage, license, licenseText, name, repository, version } = dependency; + const lines: string[] = []; + + lines.push(`Name: ${name}`); + lines.push(`Version: ${version}`); + + if (license) { + lines.push(`License: ${license}`); + } + + if (typeof repository === 'string') { + lines.push(`Repository: ${repository}`); + } else if (repository?.url) { + lines.push(`Repository: ${repository.url}`); + } else if (homepage) { + lines.push(`Homepage: ${homepage}`); + } + + if (author) { + lines.push(`Author: ${author.text()}`); + } + + if (licenseText) { + lines.push(`License Copyright:`); + lines.push(`${licenseText}`); + } + + return lines.join('\n'); +}; diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index b8ccadcbde1..ca3163a31b7 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -121,6 +121,7 @@ "postcss-calc": "10.0.2", "prettier": "3.3.3", "prettier-plugin-organize-imports": "4.1.0", + "rollup-plugin-license": "3.5.3", "rollup-plugin-visualizer": "5.12.0", "tailwindcss": "3.4.13", "turbo": "2.1.3", diff --git a/server/sonar-web/vite.config.mjs b/server/sonar-web/vite.config.mjs index b0759c5f7f1..f5c3d1fcb2c 100644 --- a/server/sonar-web/vite.config.mjs +++ b/server/sonar-web/vite.config.mjs @@ -23,12 +23,14 @@ import autoprefixer from 'autoprefixer'; import browserslistToEsbuild from 'browserslist-to-esbuild'; import path, { resolve } from 'path'; import postCssCalc from 'postcss-calc'; +import license from 'rollup-plugin-license'; import { visualizer } from 'rollup-plugin-visualizer'; import tailwind from 'tailwindcss'; import { defineConfig, loadEnv } from 'vite'; import macrosPlugin from 'vite-plugin-babel-macros'; import requireTransform from 'vite-plugin-require-transform'; import babelConfig from './babel.config'; +import { ALLOWED_LICENSES, ALLOWED_LICENSE_TEXT, generateLicenseText } from './config/license'; import { viteDevServerHtmlPlugin } from './config/vite-dev-server-html-plugin.mjs'; const DEFAULT_DEV_SERVER_PORT = 3000; @@ -58,7 +60,7 @@ export default ({ mode }) => { return { runtime: `window.__assetsPath(${JSON.stringify(filename)})` }; } else { // Other files (css, images, etc.) are loaded relatively to the current url, - // automatically taking into accound the WEB_CONTEXT + // automatically taking into account the WEB_CONTEXT return { relative: filename }; } }, @@ -90,7 +92,29 @@ export default ({ mode }) => { lodash: ['lodash/lodash.js'], }, }, - plugins: [], + plugins: [ + // a tool used to concatenate all of our 3rd party licenses together for legal reasons + license({ + thirdParty: { + allow: { + test: ({ license, licenseText }) => + ALLOWED_LICENSES.includes(license) || + ALLOWED_LICENSE_TEXT.some((text) => (licenseText ?? '').includes(text)), + failOnUnlicensed: false, // default is false. valid-url package has missing license + failOnViolation: true, // Fail if a dependency specifies a license that does not match requirements + }, + output: { + // Output file into build/webapp directory which is included in the build output + file: path.join(__dirname, 'build/webapp', 'vendor.LICENSE.txt'), + template(dependencies) { + return dependencies + .map((dependency) => generateLicenseText(dependency)) + .join('\n'); + }, + }, + }, + }), + ], }, sourcemap: isProduction, // enable source maps for production }, diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index d62c34d11e1..f1fe0bcdf7d 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -7613,6 +7613,7 @@ __metadata: react-select: "npm:5.7.7" react-virtualized: "npm:9.22.5" regenerator-runtime: "npm:0.14.1" + rollup-plugin-license: "npm:3.5.3" rollup-plugin-visualizer: "npm:5.12.0" shared-store-hook: "npm:0.0.4" tailwindcss: "npm:3.4.13" @@ -8009,6 +8010,13 @@ __metadata: languageName: node linkType: hard +"array-find-index@npm:^1.0.2": + version: 1.0.2 + resolution: "array-find-index@npm:1.0.2" + checksum: 10/aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081 + languageName: node + linkType: hard + "array-includes@npm:^3.1.2": version: 3.1.2 resolution: "array-includes@npm:3.1.2" @@ -8951,6 +8959,13 @@ __metadata: languageName: node linkType: hard +"commenting@npm:~1.1.0": + version: 1.1.0 + resolution: "commenting@npm:1.1.0" + checksum: 10/e172a2b6234c089ae826a1ff7c42811b88e8cf7166ebde461ad0b6cddd3822c16996b8175ce1d3c1a49d1475b1c1d8acdc906c18d3126cb4b0432df29529f232 + languageName: node + linkType: hard + "compare-versions@npm:^6.1.1": version: 6.1.1 resolution: "compare-versions@npm:6.1.1" @@ -11082,6 +11097,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:6.3.0": + version: 6.3.0 + resolution: "fdir@npm:6.3.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10/baa3a476a8407cc77bc77e3c946aea5ca0aa48f080f2c434b70196a37ddcd57bbc4c12d75164f9e6d947f6e148c297c9fa65f507178d0e9204d98ef83d776dcc + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -13881,7 +13908,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.17.21, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.21, lodash@npm:~4.17.15": +"lodash@npm:4.17.21, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.21, lodash@npm:~4.17.15, lodash@npm:~4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 @@ -13963,6 +13990,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:~0.30.0": + version: 0.30.12 + resolution: "magic-string@npm:0.30.12" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + checksum: 10/98016180a52b28efc1362152b45671067facccdaead6b70c1c14c566cba98491bc2e1336474b0996397730dca24400e85649da84d3da62b2560ed03c067573e6 + languageName: node + linkType: hard + "make-dir@npm:^3.0.0": version: 3.0.2 resolution: "make-dir@npm:3.0.2" @@ -14610,6 +14646,13 @@ __metadata: languageName: node linkType: hard +"moment@npm:~2.30.1": + version: 2.30.1 + resolution: "moment@npm:2.30.1" + checksum: 10/ae42d876d4ec831ef66110bdc302c0657c664991e45cf2afffc4b0f6cd6d251dde11375c982a5c0564ccc0fa593fc564576ddceb8c8845e87c15f58aa6baca69 + languageName: node + linkType: hard + "ms@npm:2.1.2, ms@npm:^2.1.1": version: 2.1.2 resolution: "ms@npm:2.1.2" @@ -15129,6 +15172,13 @@ __metadata: languageName: node linkType: hard +"package-name-regex@npm:~2.0.6": + version: 2.0.6 + resolution: "package-name-regex@npm:2.0.6" + checksum: 10/a889d52cdd860dd4feafebb3b9a2fed47d36408fd62bfab07f6386a80395d66e89f9c913bc8ea8ff62108f23d6e6470e5342e20e660a2743465cd4c45f676d4e + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -16549,6 +16599,24 @@ __metadata: languageName: node linkType: hard +"rollup-plugin-license@npm:3.5.3": + version: 3.5.3 + resolution: "rollup-plugin-license@npm:3.5.3" + dependencies: + commenting: "npm:~1.1.0" + fdir: "npm:6.3.0" + lodash: "npm:~4.17.21" + magic-string: "npm:~0.30.0" + moment: "npm:~2.30.1" + package-name-regex: "npm:~2.0.6" + spdx-expression-validate: "npm:~2.0.0" + spdx-satisfies: "npm:~5.0.1" + peerDependencies: + rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 + checksum: 10/53444d334b21e69ff38f6b223f53f6459ea70cb4d0ba674a9573b967d7bdd1cadc042e97bfe92e9cd5fe8a396fa7857de94e5aeb877cc0a0b8641c4d1d58e195 + languageName: node + linkType: hard + "rollup-plugin-visualizer@npm:5.12.0": version: 5.12.0 resolution: "rollup-plugin-visualizer@npm:5.12.0" @@ -17067,6 +17135,68 @@ __metadata: languageName: node linkType: hard +"spdx-compare@npm:^1.0.0": + version: 1.0.0 + resolution: "spdx-compare@npm:1.0.0" + dependencies: + array-find-index: "npm:^1.0.2" + spdx-expression-parse: "npm:^3.0.0" + spdx-ranges: "npm:^2.0.0" + checksum: 10/7d8b55b31163ba8e7abeaf69d8d7accba5aee324dd55e22a796a685ec4d5e3c3cbc2683b9a2edff5543ee6f6242f4ec22c15dc2e493eb807690fb65e1051e5eb + languageName: node + linkType: hard + +"spdx-exceptions@npm:^2.1.0": + version: 2.5.0 + resolution: "spdx-exceptions@npm:2.5.0" + checksum: 10/bb127d6e2532de65b912f7c99fc66097cdea7d64c10d3ec9b5e96524dbbd7d20e01cba818a6ddb2ae75e62bb0c63d5e277a7e555a85cbc8ab40044984fa4ae15 + languageName: node + linkType: hard + +"spdx-expression-parse@npm:^3.0.0": + version: 3.0.1 + resolution: "spdx-expression-parse@npm:3.0.1" + dependencies: + spdx-exceptions: "npm:^2.1.0" + spdx-license-ids: "npm:^3.0.0" + checksum: 10/a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde + languageName: node + linkType: hard + +"spdx-expression-validate@npm:~2.0.0": + version: 2.0.0 + resolution: "spdx-expression-validate@npm:2.0.0" + dependencies: + spdx-expression-parse: "npm:^3.0.0" + checksum: 10/c100f949afeb529b3b519a70b86d64c3c35be8bf1ef30db32e48936f0c52a0339b3c88c283c97c55f372ea3c347165c9360aae7905cd8f303b817cfef49032c1 + languageName: node + linkType: hard + +"spdx-license-ids@npm:^3.0.0": + version: 3.0.20 + resolution: "spdx-license-ids@npm:3.0.20" + checksum: 10/30e566ea74b04232c64819d1f5313c00d92e9c73d054541650331fc794499b3bcc4991bcd90fa3c2fc4d040006f58f63104706255266e87a9d452e6574afc60c + languageName: node + linkType: hard + +"spdx-ranges@npm:^2.0.0": + version: 2.1.1 + resolution: "spdx-ranges@npm:2.1.1" + checksum: 10/f807bd915aa2975bcebd9c4b4805661f248efcd4953ee62557626452fcd2933183f5b1a307d65507d8be6b9519b4e46dce05b61db0fbd5fce253b8f6d69bbbad + languageName: node + linkType: hard + +"spdx-satisfies@npm:~5.0.1": + version: 5.0.1 + resolution: "spdx-satisfies@npm:5.0.1" + dependencies: + spdx-compare: "npm:^1.0.0" + spdx-expression-parse: "npm:^3.0.0" + spdx-ranges: "npm:^2.0.0" + checksum: 10/7f28a6ac492afbfc4794602b5d43957451b7afdd42506dc52dbeeed875d9b5f5b94f8f3deab1da4e2815111f57f916d135c7bd24f40245be6dab5dda09d41e91 + languageName: node + linkType: hard + "specificity@npm:^0.4.1": version: 0.4.1 resolution: "specificity@npm:0.4.1" diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/ws/StaticResources.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/ws/StaticResources.java index 193d44b4a01..967e635bf01 100644 --- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/ws/StaticResources.java +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/ws/StaticResources.java @@ -25,7 +25,7 @@ import java.util.List; public class StaticResources { private static final Collection STATIC_RESOURCES = List.of("*.css", "*.css.map", "*.ico", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.js", "*.js.map", "*.pdf", "/json/*", "*.woff2", "/static/*", - "/robots.txt", "/favicon.ico", "/apple-touch-icon*", "/mstile*"); + "/robots.txt", "/favicon.ico", "/apple-touch-icon*", "/mstile*", "/vendor.LICENSE.txt"); private StaticResources() { // only static