mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-19 07:36:52 +00:00
chore: Standardize license metadata across all first-party packages and tighten SBOM pipeline (no-changelog) (#31880)
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,10 @@ const REPO_ROOT = path.resolve(scriptDir, '..', '..');
|
||||
const CDXGEN = path.join(scriptDir, 'node_modules', '.bin', 'cdxgen');
|
||||
const ENRICH = path.join(REPO_ROOT, 'scripts', 'licenses', 'enrich-sbom.mjs');
|
||||
const CHECK = path.join(REPO_ROOT, 'scripts', 'licenses', 'check-sbom-licenses.mjs');
|
||||
const ALLOW_REF = '--allow-ref=LicenseRef-n8n-sustainable-use';
|
||||
const ALLOW_REFS = [
|
||||
'--allow-ref=LicenseRef-n8n-sustainable-use',
|
||||
'--allow-ref=LicenseRef-n8n-enterprise',
|
||||
];
|
||||
|
||||
export function parseTargets(env) {
|
||||
return [
|
||||
@@ -43,12 +46,15 @@ function attest({ label, image, digest }) {
|
||||
|
||||
// Pull the (host-arch) image and scan its filesystem: OS packages + npm.
|
||||
run('docker', ['pull', ref]);
|
||||
// FETCH_LICENSE=true would make cdxgen call the npm registry for every package
|
||||
// to resolve missing license data. In practice it resolves nothing — packages
|
||||
// without a license field in their tarball also have no license in the registry —
|
||||
// and adds hundreds of sequential HTTP requests. License gaps are covered by
|
||||
// enrich-sbom.mjs (license-overrides.json + first-party detection) below.
|
||||
run(
|
||||
CDXGEN,
|
||||
['-t', 'docker', '--no-install-deps', '--profile', 'license-compliance', '-o', out, ref],
|
||||
{
|
||||
FETCH_LICENSE: 'true',
|
||||
},
|
||||
['-t', 'docker', '--no-install-deps', '--profile', 'license-compliance', '--spec-version', '1.6', '-o', out, ref],
|
||||
{ CDXGEN_NO_BANNER: '1' },
|
||||
);
|
||||
|
||||
// Resolve first-party + override licenses (lenient: this image holds only a
|
||||
@@ -58,7 +64,7 @@ function attest({ label, image, digest }) {
|
||||
|
||||
// Release-blocking gate, scoped to npm — OS packages carry upstream-distro
|
||||
// license strings we don't control, so they're inventoried but not gated.
|
||||
run(process.execPath, [CHECK, out, ALLOW_REF, '--enforce-prefix=pkg:npm/']);
|
||||
run(process.execPath, [CHECK, out, ...ALLOW_REFS, '--enforce-prefix=pkg:npm/']);
|
||||
|
||||
run('cosign', ['attest', '--yes', '--type', 'cyclonedx', '--predicate', out, ref]);
|
||||
console.log('::endgroup::');
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"name": "workflow-scripts",
|
||||
"scripts": {
|
||||
"test": "node --test --experimental-test-module-mocks ./*.test.mjs ./quality/*.test.mjs ./slack/*.test.mjs ./stale/*.test.mjs ../../scripts/licenses/*.test.mjs",
|
||||
"generate-sbom": "FETCH_LICENSE=true cdxgen -t pnpm --no-install-deps --profile license-compliance -o ../../sbom-source.cdx.json ../../compiled/",
|
||||
"generate-sbom": "FETCH_LICENSE=true cdxgen -t pnpm --no-install-deps --profile license-compliance --spec-version 1.6 -o ../../sbom-source.cdx.json ../../compiled/",
|
||||
"enrich-sbom": "node ../../scripts/licenses/enrich-sbom.mjs ../../sbom-source.cdx.json",
|
||||
"render-licenses-md": "node ../../scripts/licenses/render-licenses-md.mjs ../../sbom-source.cdx.json ../../packages/cli/THIRD_PARTY_LICENSES.md ../../compiled/node_modules",
|
||||
"check-licenses": "node ../../scripts/licenses/check-sbom-licenses.mjs ../../sbom-source.cdx.json --allow-ref=LicenseRef-n8n-sustainable-use",
|
||||
"check-licenses": "node ../../scripts/licenses/check-sbom-licenses.mjs ../../sbom-source.cdx.json --allow-ref=LicenseRef-n8n-sustainable-use --allow-ref=LicenseRef-n8n-enterprise",
|
||||
"generate-licenses": "pnpm generate-sbom && pnpm enrich-sbom && pnpm render-licenses-md && pnpm check-licenses"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
run: |
|
||||
node scripts/licenses/check-sbom-licenses.mjs \
|
||||
sbom-source.cdx.json \
|
||||
--allow-ref=LicenseRef-n8n-sustainable-use
|
||||
--allow-ref=LicenseRef-n8n-sustainable-use --allow-ref=LicenseRef-n8n-enterprise
|
||||
|
||||
- name: Attest SBOM for release
|
||||
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
|
||||
|
||||
@@ -99,5 +99,6 @@
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -38,5 +38,6 @@
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -109,5 +109,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"n8n-workflow": "*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -92,5 +92,6 @@
|
||||
"p-limit": "^3.1.0",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -38,5 +38,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -45,5 +45,6 @@
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:",
|
||||
"zod": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -36,5 +36,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -53,5 +53,6 @@
|
||||
"bin": "n8n-benchmark",
|
||||
"commands": "./dist/commands",
|
||||
"topicSeparator": " "
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -30,5 +30,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@n8n/api-types": "workspace:*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@n8n/cli",
|
||||
"version": "0.6.0",
|
||||
"description": "[beta] Client CLI for n8n — manage workflows, executions, and credentials from the terminal",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"license": "LicenseRef-n8n-sustainable-use",
|
||||
"bin": {
|
||||
"n8n-cli": "bin/n8n-cli.mjs"
|
||||
},
|
||||
|
||||
@@ -31,5 +31,6 @@
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -60,5 +60,6 @@
|
||||
"@types/yargs-parser": "21.0.0",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -34,5 +34,6 @@
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -22,5 +22,6 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -39,5 +39,6 @@
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
"vitest": "catalog:",
|
||||
"vitest-websocket-mock": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -54,5 +54,6 @@
|
||||
"typescript": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -37,5 +37,6 @@
|
||||
"@n8n/permissions": "workspace:*",
|
||||
"lodash": "catalog:",
|
||||
"n8n-workflow": "workspace:*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -31,5 +31,6 @@
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:",
|
||||
"@n8n/typescript-config": "workspace:*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -36,5 +36,6 @@
|
||||
"@types/supertest": "^6.0.3",
|
||||
"supertest": "^7.1.1",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"callsites": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -55,5 +55,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -59,5 +59,6 @@
|
||||
"☑️"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"web-worker",
|
||||
"security"
|
||||
],
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"license": "LicenseRef-n8n-sustainable-use",
|
||||
"dependencies": {
|
||||
"@n8n/errors": "workspace:*",
|
||||
"@n8n/tournament": "workspace:*",
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"zod-to-json-schema": "catalog:",
|
||||
"tsx": "catalog:"
|
||||
},
|
||||
"license": "https://docs.n8n.io/sustainable-use-license/",
|
||||
"license": "LicenseRef-n8n-sustainable-use",
|
||||
"dependencies": {
|
||||
"zod": "catalog:"
|
||||
}
|
||||
|
||||
@@ -35,5 +35,6 @@
|
||||
"@types/quoted-printable": "^1.0.2",
|
||||
"@types/utf8": "^3.0.3",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -93,5 +93,6 @@
|
||||
"tsx": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -38,5 +38,6 @@
|
||||
"electron-builder": "^26.9.0",
|
||||
"rimraf": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -60,5 +60,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@modelcontextprotocol/sdk": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
{
|
||||
"name": "@n8n/mcp-browser-extension",
|
||||
"version": "0.0.3",
|
||||
"private": true,
|
||||
"description": "Chrome extension that lets n8n AI control browser tabs via CDP",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist .turbo",
|
||||
"build": "vite build --config vite.sw.config.mts && vite build --config vite.ui.config.mts",
|
||||
"build:unchecked": "pnpm run build",
|
||||
"bundle": "pnpm build && node scripts/bundle.mjs",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "eslint . --quiet",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run",
|
||||
"test:dev": "vitest",
|
||||
"format": "biome format --write src",
|
||||
"format:check": "biome ci src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@n8n/design-system": "workspace:*",
|
||||
"vue": "catalog:frontend"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
"@types/chrome": "0.0.300",
|
||||
"@vitejs/plugin-vue": "catalog:frontend",
|
||||
"@vue/test-utils": "catalog:frontend",
|
||||
"unplugin-icons": "catalog:frontend",
|
||||
"vite": "catalog:",
|
||||
"vite-svg-loader": "catalog:frontend",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
"name": "@n8n/mcp-browser-extension",
|
||||
"version": "0.0.3",
|
||||
"private": true,
|
||||
"description": "Chrome extension that lets n8n AI control browser tabs via CDP",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist .turbo",
|
||||
"build": "vite build --config vite.sw.config.mts && vite build --config vite.ui.config.mts",
|
||||
"build:unchecked": "pnpm run build",
|
||||
"bundle": "pnpm build && node scripts/bundle.mjs",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "eslint . --quiet",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run",
|
||||
"test:dev": "vitest",
|
||||
"format": "biome format --write src",
|
||||
"format:check": "biome ci src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@n8n/design-system": "workspace:*",
|
||||
"vue": "catalog:frontend"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
"@types/chrome": "0.0.300",
|
||||
"@vitejs/plugin-vue": "catalog:frontend",
|
||||
"@vue/test-utils": "catalog:frontend",
|
||||
"unplugin-icons": "catalog:frontend",
|
||||
"vite": "catalog:",
|
||||
"vite-svg-loader": "catalog:frontend",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -46,5 +46,6 @@
|
||||
"@types/yargs-parser": "21.0.0",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -75,5 +75,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -311,5 +311,6 @@
|
||||
"weaviate-client": "3.9.0",
|
||||
"zod": "catalog:",
|
||||
"zod-to-json-schema": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -31,5 +31,6 @@
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@n8n/scan-community-package",
|
||||
"version": "0.21.0",
|
||||
"description": "Static code analyser for n8n community packages",
|
||||
"license": "none",
|
||||
"license": "LicenseRef-n8n-sustainable-use",
|
||||
"bin": "scanner/cli.mjs",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
|
||||
@@ -44,5 +44,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"stylelint": ">= 16"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -32,5 +32,6 @@
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:",
|
||||
"get-port": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -57,5 +57,6 @@
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
"./tsconfig.frontend.json": "./tsconfig.frontend.json",
|
||||
"./*": "./*"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -55,5 +55,5 @@
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -48,5 +48,5 @@
|
||||
"format:check": "biome ci .",
|
||||
"watch": "tsc -p tsconfig.build.json --watch"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -101,5 +101,6 @@
|
||||
"n8n-workflow": "workspace:*",
|
||||
"uuid": "catalog:",
|
||||
"zod": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -235,5 +235,6 @@
|
||||
"yargs-parser": "21.1.1",
|
||||
"zod": "catalog:",
|
||||
"zod-to-json-schema": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -91,5 +91,6 @@
|
||||
"uuid": "catalog:",
|
||||
"winston": "3.14.2",
|
||||
"xml2js": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -60,5 +60,6 @@
|
||||
"vue": "catalog:frontend",
|
||||
"vue-router": "catalog:frontend",
|
||||
"vue-tsc": "catalog:frontend"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -66,5 +66,6 @@
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
]
|
||||
],
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@
|
||||
"@vueuse/core": "catalog:frontend",
|
||||
"vue": "catalog:frontend"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -86,5 +86,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vueuse/core": "*"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -60,5 +60,5 @@
|
||||
"peerDependencies": {
|
||||
"vue": "catalog:frontend"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -58,5 +58,5 @@
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -62,5 +62,5 @@
|
||||
"pinia": "catalog:frontend",
|
||||
"vue": "catalog:frontend"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -51,5 +51,6 @@
|
||||
"extends": [
|
||||
"plugin:storybook/recommended"
|
||||
]
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -154,5 +154,6 @@
|
||||
"vitest-mock-extended": "catalog:",
|
||||
"vue-tsc": "catalog:frontend",
|
||||
"z-vue-scan": "^0.0.35"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -53,5 +53,6 @@
|
||||
"n8n-workflow": "workspace:*",
|
||||
"replace-in-file": "^6.0.0",
|
||||
"tmp-promise": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -982,5 +982,6 @@
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz",
|
||||
"xml2js": "catalog:",
|
||||
"xmlhttprequest-ssl": "3.1.0"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"name": "@n8n/performance",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"bench": "vitest bench --run",
|
||||
"bench:baseline": "node scripts/save-baseline.mjs",
|
||||
"bench:compare": "vitest bench --run --outputJson ./profiles/benchmark-results.json && node scripts/check-regression.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codspeed/vitest-plugin": "^5.2.0",
|
||||
"name": "@n8n/performance",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"bench": "vitest bench --run",
|
||||
"bench:baseline": "node scripts/save-baseline.mjs",
|
||||
"bench:compare": "vitest bench --run --outputJson ./profiles/benchmark-results.json && node scripts/check-regression.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codspeed/vitest-plugin": "^5.2.0",
|
||||
"@n8n/expression-runtime": "workspace:*",
|
||||
"vitest": "catalog:",
|
||||
"n8n-workflow": "workspace:*"
|
||||
}
|
||||
"n8n-workflow": "workspace:*"
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -83,5 +83,6 @@
|
||||
"tsx": "catalog:",
|
||||
"zod": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -81,5 +81,6 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "catalog:"
|
||||
}
|
||||
},
|
||||
"license": "LicenseRef-n8n-sustainable-use"
|
||||
}
|
||||
|
||||
@@ -191,6 +191,23 @@ if (excludeTestController) {
|
||||
}
|
||||
|
||||
await $`cd ${config.rootDir} && NODE_ENV=production DOCKER_BUILD=true pnpm --filter=n8n --prod --legacy deploy --no-optional ./compiled`;
|
||||
|
||||
// Strip test/example/benchmark dirs shipped inside production deps that lack a
|
||||
// `files` field in their package.json. These are valid runtime deps but their
|
||||
// authors published full source trees; syft inventories the subdirs as phantom
|
||||
// packages with no license, which fails enterprise SBOM license gates.
|
||||
echo(chalk.yellow('INFO: Stripping test/example/benchmark dirs from production closure...'));
|
||||
const phantomDirs = [
|
||||
'resolve/*/test',
|
||||
'import-in-the-middle/*/test',
|
||||
'github-from-package/*/example',
|
||||
'tedious/*/benchmarks',
|
||||
];
|
||||
for (const pattern of phantomDirs) {
|
||||
await $`find ${config.compiledAppDir}/node_modules/.pnpm -type d -path "*/${pattern}" -exec rm -rf {} + 2>/dev/null || true`;
|
||||
}
|
||||
echo(chalk.green('✅ Phantom dirs stripped'));
|
||||
|
||||
await fs.ensureDir(config.compiledTaskRunnerDir);
|
||||
|
||||
echo(
|
||||
|
||||
@@ -201,6 +201,36 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"group": "",
|
||||
"name": "wa-sqlite",
|
||||
"version": "1.0.9",
|
||||
"scope": "optional",
|
||||
"purl": "pkg:npm/wa-sqlite@1.0.9",
|
||||
"properties": [
|
||||
{
|
||||
"name": "SrcFile",
|
||||
"value": "/home/runner/work/n8n/n8n/compiled/node_modules/wa-sqlite/package.json"
|
||||
}
|
||||
],
|
||||
"evidence": {
|
||||
"identity": [
|
||||
{
|
||||
"field": "purl",
|
||||
"confidence": 0.7,
|
||||
"methods": [
|
||||
{
|
||||
"technique": "manifest-analysis",
|
||||
"confidence": 0.7,
|
||||
"value": "/home/runner/work/n8n/n8n/compiled/node_modules/wa-sqlite/package.json"
|
||||
}
|
||||
],
|
||||
"concludedValue": "/home/runner/work/n8n/n8n/compiled/node_modules/wa-sqlite/package.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"group": "@n8n",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"_comment": "Hand-resolved licenses for packages cdxgen + FETCH_LICENSE cannot resolve. 'overrides' are PURL-pinned (pkg:npm/<name>@<version>, exact match) and drive the release-closure SBOM — a pin that stops matching fails loudly so the license is re-verified on the bump. 'byName' is version-agnostic (keyed by package name) for licenses stable across versions; it resolves the same package at whatever version a container image installed (e.g. ssh2 ships both 1.15.0 and 1.16.0 in the image, both MIT). 'elections' record which license n8n elects for a validly dual-licensed (OR) dependency so a copyleft policy gate reads the elected term. 'source' records where each was verified. Optional 'skipDiskText: true' opts out of on-disk LICENSE text lookup when the file disagrees with the overridden id.",
|
||||
"overrides": {
|
||||
"pkg:npm/wa-sqlite@1.0.9": {
|
||||
"license": "MIT",
|
||||
"source": "https://github.com/rhashimoto/wa-sqlite — LICENSE file in published tarball confirms MIT. Package is installed via GitHub tarball URL so npm registry metadata is absent; no license field in package.json.",
|
||||
"skipDiskText": true
|
||||
},
|
||||
"pkg:npm/nub@0.0.0": {
|
||||
"license": "MIT",
|
||||
"source": "https://www.npmjs.com/package/nub — package.json declares non-SPDX 'MIT/X11'; X11 is the historical alias for the MIT license. Normalised to the canonical SPDX id."
|
||||
@@ -58,6 +63,16 @@
|
||||
"ssh2": {
|
||||
"license": "MIT",
|
||||
"source": "compiled/node_modules/ssh2/LICENSE — MIT; package.json uses a legacy licenses[] array so cdxgen leaves it unresolved. Version-agnostic: a container image can install more than one ssh2 (e.g. 1.15.0 and 1.16.0 side by side), and the license is MIT across versions."
|
||||
},
|
||||
"@n8n_io/license-sdk": {
|
||||
"license": "LicenseRef-n8n-enterprise",
|
||||
"source": "n8n-io/license-management — ships LICENSE_EE.md (n8n Enterprise License). EE-only runtime component; not under the Sustainable Use License. Version-agnostic: license is stable across SDK versions. FIRST_PARTY_PATTERNS would otherwise incorrectly stamp it as LicenseRef-n8n-sustainable-use.",
|
||||
"skipDiskText": true
|
||||
},
|
||||
"@n8n_io/ai-assistant-sdk": {
|
||||
"license": "LicenseRef-n8n-enterprise",
|
||||
"source": "n8n-io/ai-assistant-service — ships LICENSE_EE.md (n8n Enterprise License). EE-only runtime component; not under the Sustainable Use License. Version-agnostic: license is stable across SDK versions.",
|
||||
"skipDiskText": true
|
||||
}
|
||||
},
|
||||
"elections": {
|
||||
|
||||
@@ -19,7 +19,10 @@ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const FIXTURE = path.join(scriptDir, '__fixtures__', 'sample.cdx.json');
|
||||
const ENRICH = path.join(scriptDir, 'enrich-sbom.mjs');
|
||||
const CHECK = path.join(scriptDir, 'check-sbom-licenses.mjs');
|
||||
const ALLOW_REF = '--allow-ref=LicenseRef-n8n-sustainable-use';
|
||||
const ALLOW_REFS = [
|
||||
'--allow-ref=LicenseRef-n8n-sustainable-use',
|
||||
'--allow-ref=LicenseRef-n8n-enterprise',
|
||||
];
|
||||
|
||||
const run = (script, args) => spawnSync(process.execPath, [script, ...args], { encoding: 'utf-8' });
|
||||
|
||||
@@ -36,7 +39,7 @@ describe('license-generation chain (real CLIs end-to-end)', () => {
|
||||
});
|
||||
|
||||
it('rejects the raw (un-enriched) SBOM at the gate (exit 1)', () => {
|
||||
const r = run(CHECK, [raw, ALLOW_REF]);
|
||||
const r = run(CHECK, [raw, ...ALLOW_REFS]);
|
||||
assert.equal(r.status, 1, r.stderr);
|
||||
assert.match(r.stderr, /binascii/); // empty-license component is named
|
||||
});
|
||||
@@ -66,7 +69,7 @@ describe('license-generation chain (real CLIs end-to-end)', () => {
|
||||
});
|
||||
|
||||
it('passes the gate on the enriched SBOM (exit 0, dual-license warning only)', () => {
|
||||
const r = run(CHECK, [enriched, ALLOW_REF]);
|
||||
const r = run(CHECK, [enriched, ...ALLOW_REFS]);
|
||||
assert.equal(r.status, 0, r.stderr);
|
||||
assert.match(r.stderr, /jszip/); // surfaced as a dual-license warning, not a failure
|
||||
});
|
||||
|
||||
@@ -374,6 +374,7 @@ describe('renderSbom — edge cases', () => {
|
||||
'pkg:npm/nub@0.0.0',
|
||||
'pkg:npm/xml-escape@1.1.0',
|
||||
'pkg:npm/duck@0.1.12',
|
||||
'pkg:npm/wa-sqlite@1.0.9',
|
||||
];
|
||||
const sbom = {
|
||||
components: purls.map((purl) => {
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# Software Composition Analysis (SCA)
|
||||
|
||||
## Posture
|
||||
|
||||
Every component in the enriched release SBOM carries a valid SPDX license
|
||||
identifier. The two dual-licensed packages in the tree (`jszip`, `mailsplit`)
|
||||
offer MIT as an alternative to their copyleft option; n8n elects MIT for both,
|
||||
recorded as `cdx:license:elected` in the SBOM. No copyleft license is in force.
|
||||
|
||||
---
|
||||
|
||||
## License picture
|
||||
|
||||
| Scope | License | Notes |
|
||||
|---|---|---|
|
||||
| `@n8n/*`, `n8n`, `n8n-core`, `n8n-nodes-base`, `n8n-workflow`, `n8n-editor-ui` | `LicenseRef-n8n-sustainable-use` | Full text at https://docs.n8n.io/sustainable-use-license/ |
|
||||
| Community tooling, codemirror extensions | `MIT` / `Apache-2.0` / `ISC` | Intentionally OSI-licensed |
|
||||
| `@n8n_io/license-sdk`, `@n8n_io/ai-assistant-sdk` | `LicenseRef-n8n-enterprise` | EE-only runtime components; require enterprise contract |
|
||||
| All third-party npm dependencies | Permissive OSI | No copyleft; dual-licensed packages elect MIT |
|
||||
|
||||
A human-readable rendering is at `/rest/third-party-licenses` on any running
|
||||
n8n instance and as `THIRD_PARTY_LICENSES.md` attached to each GitHub release.
|
||||
|
||||
---
|
||||
|
||||
## SBOM pipelines
|
||||
|
||||
### Release SBOM (authoritative)
|
||||
|
||||
Produced by `sbom-generation-callable.yml` on every release. This is the
|
||||
artifact to use for compliance review.
|
||||
|
||||
```
|
||||
pnpm build:deploy (N8N_GENERATE_LICENSES=true)
|
||||
└─ cdxgen → sbom-source.cdx.json
|
||||
└─ enrich-sbom.mjs → resolves first-party + override licenses
|
||||
└─ check-sbom-licenses.mjs → SPDX gate (release-blocking)
|
||||
└─ actions/attest → signed attestation against package.json
|
||||
└─ gh release upload
|
||||
```
|
||||
|
||||
### Docker image SBOM
|
||||
|
||||
Produced by the `sbom-attestation` job in `docker-build-push.yml` on
|
||||
`stable`/`rc`/`nightly` builds.
|
||||
|
||||
```
|
||||
docker push
|
||||
└─ cdxgen -t docker → OS + npm scan of the pushed image
|
||||
└─ enrich-sbom.mjs → resolves licenses
|
||||
└─ check-sbom-licenses.mjs → SPDX gate (npm only)
|
||||
└─ cosign attest → attested to image digest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verifying the SBOM
|
||||
|
||||
The enriched, attested SBOM is attached to every published Docker image via
|
||||
cosign. Pull it once and run all checks against the file — this gives the
|
||||
enriched picture with 0 unlicensed and 0 license failures.
|
||||
|
||||
```bash
|
||||
# Pull the attested SBOM from any published image
|
||||
cosign download attestation ghcr.io/n8n-io/n8n:<version> \
|
||||
--predicate-type https://cyclonedx.org/bom \
|
||||
| jq -r '.payload' | base64 -d | jq '.predicate' > sbom.cdx.json
|
||||
|
||||
# Verify it was produced by n8n's CI (not tampered with)
|
||||
cosign verify-attestation ghcr.io/n8n-io/n8n:<version> \
|
||||
--type cyclonedx \
|
||||
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
|
||||
--certificate-identity-regexp "https://github.com/n8n-io/n8n/.github/workflows/"
|
||||
|
||||
# Check for unlicensed packages — expect 0
|
||||
grant check --unlicensed sbom.cdx.json
|
||||
|
||||
# Full license list
|
||||
grant list sbom.cdx.json
|
||||
|
||||
# n8n's SPDX gate — expect 0 failures
|
||||
node scripts/licenses/check-sbom-licenses.mjs sbom.cdx.json \
|
||||
--allow-ref=LicenseRef-n8n-sustainable-use \
|
||||
--allow-ref=LicenseRef-n8n-enterprise \
|
||||
--enforce-prefix=pkg:npm/
|
||||
|
||||
# Vulnerability scan
|
||||
grype sbom:sbom.cdx.json
|
||||
|
||||
# Full audit — vulnerabilities + licenses
|
||||
trivy sbom sbom.cdx.json
|
||||
```
|
||||
|
||||
Replace `<version>` with `nightly`, `latest`, or a specific version tag
|
||||
(e.g. `n8n@2.25.0`). The same image is available on both
|
||||
`ghcr.io/n8n-io/n8n` and `docker.io/n8nio/n8n`.
|
||||
|
||||
---
|
||||
|
||||
## Copyleft explainer
|
||||
|
||||
The Docker image SBOM will show GPL/LGPL entries in `grant list`. These come
|
||||
entirely from Alpine OS system packages (`busybox`, `git`, `libgcc`,
|
||||
`libstdc++`, etc.). GPL in an OS binary has no effect on n8n's licensing
|
||||
obligations or your use of n8n; they are inventoried in the SBOM for
|
||||
completeness but are not gated by the license pipeline.
|
||||
|
||||
The npm layer contains no copyleft in force. The two dual-licensed packages
|
||||
(`jszip`: MIT OR GPL-3.0-or-later, `mailsplit`: MIT OR EUPL-1.1+) elect MIT;
|
||||
this election is recorded as `cdx:license:elected` in the SBOM.
|
||||
|
||||
---
|
||||
|
||||
## Release SBOM
|
||||
|
||||
For source-level compliance review, download from the GitHub release page:
|
||||
|
||||
```bash
|
||||
gh release download n8n@<version> \
|
||||
--repo n8n-io/n8n \
|
||||
--pattern sbom-source.cdx.json
|
||||
|
||||
gh attestation verify sbom-source.cdx.json \
|
||||
--repo n8n-io/n8n \
|
||||
--owner n8n-io
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tooling
|
||||
|
||||
| Tool | Role |
|
||||
|---|---|
|
||||
| cdxgen | SBOM generation (CycloneDX 1.6) |
|
||||
| enrich-sbom.mjs | License enrichment (`scripts/licenses/`) |
|
||||
| check-sbom-licenses.mjs | SPDX compliance gate (`scripts/licenses/`) |
|
||||
| grant | License listing and unlicensed check |
|
||||
| grype | Vulnerability scanning against SBOM |
|
||||
| trivy | Full audit — vulnerabilities + licenses |
|
||||
| cosign / actions/attest | SBOM attestation |
|
||||
|
||||
See `security/vex.openvex.json` for the VEX document attested alongside the image.
|
||||
Reference in New Issue
Block a user