Merge upstream actions/dependency-review-action main

Syncs fork with upstream, resolving conflicts in package.json
(keeping semver + upgrading spdx-expression-parse to ^4.0.0),
regenerating package-lock.json and dist/ folder.

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Chad Bentz
2026-02-27 14:04:27 -05:00
co-authored by Copilot
11 changed files with 1376 additions and 233 deletions
+18 -23
View File
@@ -50,8 +50,7 @@ Before you begin, you need to have [Node.js](https://nodejs.org/en/) installed,
#### Manually testing for vulnerabilities #### Manually testing for vulnerabilities
We have a script to scan a given PR for vulnerabilities, this will We have a script to scan a given PR for vulnerabilities, which will help you test your local changes. Make sure to [grab a Personal Access Token (PAT)](https://github.com/settings/tokens) before proceeding (you'll need `repo` permissions for private repos):
help you test your local changes. Make sure to [grab a Personal Access Token (PAT)](https://github.com/settings/tokens) before proceeding (you'll need `repo` permissions for private repos):
<img width="480" alt="Screen to create a PAT with a note of `dr-token`, 30 day duration (expiring Jun 11, 2022), with `repo` scopes selected" src="https://user-images.githubusercontent.com/2161/168026161-16788a0a-b6c8-428e-bb6a-83ea2a403070.png"> <img width="480" alt="Screen to create a PAT with a note of `dr-token`, 30 day duration (expiring Jun 11, 2022), with `repo` scopes selected" src="https://user-images.githubusercontent.com/2161/168026161-16788a0a-b6c8-428e-bb6a-83ea2a403070.png">
@@ -106,38 +105,34 @@ Here are a few things you can do that will increase the likelihood of your pull
_Note: these instructions are for maintainers_ _Note: these instructions are for maintainers_
1. Update the version number in [package.json](https://github.com/actions/dependency-review-action/blob/main/package.json) and run `npm i` to update the lockfile. - Create a local branch based on the `main` of the upstream repo.
1. Update the dist files by running `npm run build` and `npm run package` - Update the version number in [package.json](https://github.com/actions/dependency-review-action/blob/main/package.json) and run `npm i` to update the lockfile.
1. Go to [Draft a new - Update the dist files by running `npm run build` and `npm run package`
release](https://github.com/actions/dependency-review-action/releases/new) - Go to [Draft a new release](https://github.com/actions/dependency-review-action/releases/new) in the Releases page.
in the Releases page. - Make sure that the `Publish this Action to the GitHub Marketplace` checkbox is enabled
1. Make sure that the `Publish this Action to the GitHub Marketplace`
checkbox is enabled
<img width="481" alt="Screen showing Release Action with Publish this Action to the GitHub Marketplace checked" src="https://user-images.githubusercontent.com/2161/173822484-4b60d8b4-c674-4bff-b5ff-b0c4a3650ab7.png"> <img width="481" alt="Screen showing Release Action with Publish this Action to the GitHub Marketplace checked" src="https://user-images.githubusercontent.com/2161/173822484-4b60d8b4-c674-4bff-b5ff-b0c4a3650ab7.png">
3. Click "Choose a tag" and then "Create new tag", where the tag name - Click "Choose a tag" and then "Create new tag", where the tag name
will be your version prefixed by a `v` (e.g. `v1.2.3`). will be your version prefixed by a `v` (e.g. `v1.2.3`).
4. Use a version number for the release title (e.g. "1.2.3"). - Use a version number for the release title (e.g. "1.2.3").
<img width="700" alt="Create an action release in categories Security + Dependency management from branch main creating tag v2.0.0 on publish" src="https://user-images.githubusercontent.com/2161/173822548-33ab3432-d679-4dc1-adf8-b50fdaf47de3.png"> <img width="700" alt="Create an action release in categories Security + Dependency management from branch main creating tag v2.0.0 on publish" src="https://user-images.githubusercontent.com/2161/173822548-33ab3432-d679-4dc1-adf8-b50fdaf47de3.png">
5. Add your release notes. If this is a major version make sure to - Add your release notes. If this is a major version make sure to include details about any breaking changes in the new version.
include a small description of the biggest changes in the new version. - Click "Publish Release".
6. Click "Publish Release".
You now have a tag and release using the semver version you used You now have a tag and release using the semver version you used above. The last remaining thing to do is to update the major version branch to match the current release. This allows users to adopt a major version number (e.g. `v4`) in their workflows while automatically getting all the minor/patch updates.
above. The last remaining thing to do is to move the dynamic version
identifier to match the current SHA. This allows users to adopt a
major version number (e.g. `v1`) in their workflows while
automatically getting all the
minor/patch updates.
To do this just checkout `main`, force-create a new annotated tag, and push it: As of v4.8.3, we use a **branch** (not a force-pushed tag) for the major version pointer. This is important because force-pushing tags breaks GitHub's auto-generated release changelog links (see [#1035](https://github.com/actions/dependency-review-action/issues/1035)) and violates git's (unenforced) expectation that tags are immutable.
To update the major version branch:
``` ```
git tag -fa v4 -m "Updating v4 to 4.0.1" git checkout main
git push origin v4 --force git pull origin main
git branch -f v4 HEAD
git push origin v4
``` ```
</details> </details>
+27
View File
@@ -253,6 +253,33 @@ test('it does not filter out changes that are on the exclusions list', async ()
expect(invalidLicenses.forbidden.length).toEqual(0) expect(invalidLicenses.forbidden.length).toEqual(0)
}) })
test('it excludes scoped npm packages when namespace separator is percent-encoded', async () => {
const scopedNpmChange: Change = {
manifest: 'package.json',
change_type: 'added',
ecosystem: 'npm',
name: '@lancedb/lancedb',
version: '0.14.3',
package_url: 'pkg:npm/%40lancedb/[email protected]',
license: 'Apache-2.0',
source_repository_url: 'github.com/lancedb/lancedb',
scope: 'runtime',
vulnerabilities: []
}
const changes: Changes = [scopedNpmChange, rubyChange]
const licensesConfig = {
allow: ['BSD-3-Clause'],
// user provides %2F-encoded version
licenseExclusions: ['pkg:npm/%40lancedb%2Flancedb']
}
const invalidLicenses = await getInvalidLicenseChanges(
changes,
licensesConfig
)
// scoped package should be excluded, only rubyChange remains (allowed)
expect(invalidLicenses.forbidden.length).toEqual(0)
})
test('it does not fail when the packages dont have a valid PURL', async () => { test('it does not fail when the packages dont have a valid PURL', async () => {
const emptyPurlChange = pipChange const emptyPurlChange = pipChange
emptyPurlChange.package_url = '' emptyPurlChange.package_url = ''
+14 -3
View File
@@ -132,9 +132,13 @@ describe('handleLargeSummary', () => {
expect(result).toContain('actions/runs/12345') expect(result).toContain('actions/runs/12345')
}) })
test('returns original summary and logs a warning when artifact handling fails', async () => { test('returns truncated summary and replaces buffer when artifact upload fails', async () => {
const warningMock = core.warning as jest.Mock const warningMock = core.warning as jest.Mock
const emptyBufferMock = core.summary.emptyBuffer as jest.Mock
const addRawMock = core.summary.addRaw as jest.Mock
warningMock.mockClear() warningMock.mockClear()
emptyBufferMock.mockClear()
addRawMock.mockClear()
const largeSummary = 'b'.repeat(1024 * 1024 + 1) const largeSummary = 'b'.repeat(1024 * 1024 + 1)
DefaultArtifactClientMock.mockImplementation(() => ({ DefaultArtifactClientMock.mockImplementation(() => ({
@@ -145,9 +149,16 @@ describe('handleLargeSummary', () => {
const result = await handleLargeSummary(largeSummary) const result = await handleLargeSummary(largeSummary)
expect(result).toBe(largeSummary) // Should NOT return the original oversized content
expect(result).not.toBe(largeSummary)
// Should return a truncated summary
expect(result).toContain('Dependency Review Summary')
expect(result).toContain('too large to display')
// Should replace the core.summary buffer to prevent write() from failing
expect(emptyBufferMock).toHaveBeenCalled()
expect(addRawMock).toHaveBeenCalledWith(result)
expect(warningMock).toHaveBeenCalledWith( expect(warningMock).toHaveBeenCalledWith(
expect.stringContaining('Failed to handle large summary') expect.stringContaining('Failed to upload large summary as artifact')
) )
}) })
}) })
+64 -1
View File
@@ -1,5 +1,5 @@
import {expect, test} from '@jest/globals' import {expect, test} from '@jest/globals'
import {parsePURL} from '../src/purl' import {parsePURL, purlsMatch} from '../src/purl'
test('parsePURL returns an error if the purl does not start with "pkg:"', () => { test('parsePURL returns an error if the purl does not start with "pkg:"', () => {
const purl = 'not-a-purl' const purl = 'not-a-purl'
@@ -184,3 +184,66 @@ test('parsePURL table test', () => {
expect(result).toEqual(example.expected) expect(result).toEqual(example.expected)
} }
}) })
test('purlsMatch matches identical PURLs', () => {
const a = parsePURL('pkg:npm/@scope/[email protected]')
const b = parsePURL('pkg:npm/@scope/[email protected]')
expect(purlsMatch(a, b)).toBe(true)
})
test('purlsMatch matches when namespace separator is percent-encoded', () => {
// %2F-encoded separator puts everything in name with no namespace
const encoded = parsePURL('pkg:npm/%40lancedb%2Flancedb')
// literal / splits into namespace + name
const literal = parsePURL('pkg:npm/%40lancedb/lancedb')
expect(purlsMatch(encoded, literal)).toBe(true)
})
test('purlsMatch matches scoped npm packages regardless of encoding', () => {
const a = parsePURL('pkg:npm/%40lancedb%2Flancedb')
const b = parsePURL('pkg:npm/@lancedb/lancedb')
const c = parsePURL('pkg:npm/%40lancedb/[email protected]')
expect(purlsMatch(a, b)).toBe(true)
expect(purlsMatch(a, c)).toBe(true)
expect(purlsMatch(b, c)).toBe(true)
})
test('purlsMatch does not match different packages', () => {
const a = parsePURL('pkg:npm/@scope/foo')
const b = parsePURL('pkg:npm/@scope/bar')
expect(purlsMatch(a, b)).toBe(false)
})
test('purlsMatch does not match different types', () => {
const a = parsePURL('pkg:npm/@scope/name')
const b = parsePURL('pkg:pypi/@scope/name')
expect(purlsMatch(a, b)).toBe(false)
})
test('purlsMatch matches packages without namespaces', () => {
const a = parsePURL('pkg:npm/[email protected]')
const b = parsePURL('pkg:npm/[email protected]')
expect(purlsMatch(a, b)).toBe(true)
})
test('purlsMatch is case-insensitive for GitHub Actions', () => {
const a = parsePURL('pkg:githubactions/MyOrg/[email protected]')
const b = parsePURL('pkg:githubactions/myorg/[email protected]')
expect(purlsMatch(a, b)).toBe(true)
})
test('purlsMatch is case-insensitive for scoped npm packages', () => {
const a = parsePURL('pkg:npm/@MyScope/MyPackage')
const b = parsePURL('pkg:npm/@myscope/mypackage')
expect(purlsMatch(a, b)).toBe(true)
})
test('purlsMatch is case-insensitive for GitHub Actions with file paths', () => {
const a = parsePURL(
'pkg:githubactions/MyOrg/MyWorkflows/.github/workflows/general.yml'
)
const b = parsePURL(
'pkg:githubactions/myorg/myworkflows/.github/workflows/general.yml'
)
expect(purlsMatch(a, b)).toBe(true)
})
Generated Vendored
+1124 -157
View File
File diff suppressed because one or more lines are too long
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+70 -30
View File
@@ -1,12 +1,12 @@
{ {
"name": "dependency-review-action", "name": "dependency-review-action",
"version": "4.8.2", "version": "4.8.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "dependency-review-action", "name": "dependency-review-action",
"version": "4.8.2", "version": "4.8.3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/artifact": "^5.0.1", "@actions/artifact": "^5.0.1",
@@ -21,7 +21,7 @@
"jest": "^29.7.0", "jest": "^29.7.0",
"octokit": "^3.1.2", "octokit": "^3.1.2",
"semver": "^7.7.4", "semver": "^7.7.4",
"spdx-expression-parse": "^3.0.1", "spdx-expression-parse": "^4.0.0",
"spdx-satisfies": "^6.0.0", "spdx-satisfies": "^6.0.0",
"ts-jest": "^29.4.1", "ts-jest": "^29.4.1",
"yaml": "^2.8.1", "yaml": "^2.8.1",
@@ -422,7 +422,6 @@
"version": "7.23.2", "version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
"integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.22.13", "@babel/code-frame": "^7.22.13",
@@ -913,6 +912,7 @@
"os": [ "os": [
"aix" "aix"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -930,6 +930,7 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -947,6 +948,7 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -964,6 +966,7 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -981,6 +984,7 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -998,6 +1002,7 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1015,6 +1020,7 @@
"os": [ "os": [
"freebsd" "freebsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1032,6 +1038,7 @@
"os": [ "os": [
"freebsd" "freebsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1049,6 +1056,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1066,6 +1074,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1083,6 +1092,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1100,6 +1110,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1117,6 +1128,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1134,6 +1146,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1151,6 +1164,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1168,6 +1182,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1185,6 +1200,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1202,6 +1218,7 @@
"os": [ "os": [
"netbsd" "netbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1219,6 +1236,7 @@
"os": [ "os": [
"netbsd" "netbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1236,6 +1254,7 @@
"os": [ "os": [
"openbsd" "openbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1253,6 +1272,7 @@
"os": [ "os": [
"openbsd" "openbsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1270,6 +1290,7 @@
"os": [ "os": [
"sunos" "sunos"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1287,6 +1308,7 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1304,6 +1326,7 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1321,6 +1344,7 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -1833,7 +1857,6 @@
"version": "29.7.0", "version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
"integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
"peer": true,
"dependencies": { "dependencies": {
"@babel/core": "^7.11.6", "@babel/core": "^7.11.6",
"@jest/types": "^29.6.3", "@jest/types": "^29.6.3",
@@ -1859,7 +1882,6 @@
"version": "29.6.3", "version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
"integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"peer": true,
"dependencies": { "dependencies": {
"@jest/schemas": "^29.6.3", "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-lib-coverage": "^2.0.0",
@@ -2067,7 +2089,6 @@
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz",
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@octokit/auth-token": "^4.0.0", "@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0", "@octokit/graphql": "^7.1.0",
@@ -2402,6 +2423,16 @@
"spdx-ranges": "^2.0.0" "spdx-ranges": "^2.0.0"
} }
}, },
"node_modules/@onebeyond/spdx-license-satisfies/node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"license": "MIT",
"dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/@pkgjs/parseargs": { "node_modules/@pkgjs/parseargs": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -2650,11 +2681,10 @@
} }
}, },
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.7.1", "version": "7.5.5",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz",
"integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==",
"dev": true, "dev": true
"license": "MIT"
}, },
"node_modules/@types/spdx-expression-parse": { "node_modules/@types/spdx-expression-parse": {
"version": "3.0.5", "version": "3.0.5",
@@ -2685,7 +2715,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
"integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.5.1", "@eslint-community/regexpp": "^4.5.1",
"@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/scope-manager": "6.21.0",
@@ -2721,7 +2750,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/scope-manager": "6.21.0",
"@typescript-eslint/types": "6.21.0", "@typescript-eslint/types": "6.21.0",
@@ -2961,7 +2989,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -3360,7 +3387,6 @@
"version": "29.7.0", "version": "29.7.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
"integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
"peer": true,
"dependencies": { "dependencies": {
"@jest/transform": "^29.7.0", "@jest/transform": "^29.7.0",
"@types/babel__core": "^7.1.14", "@types/babel__core": "^7.1.14",
@@ -3569,7 +3595,6 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001541", "caniuse-lite": "^1.0.30001541",
"electron-to-chromium": "^1.4.535", "electron-to-chromium": "^1.4.535",
@@ -4415,7 +4440,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
@@ -4650,7 +4674,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz",
"integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "7.4.0", "@typescript-eslint/scope-manager": "7.4.0",
"@typescript-eslint/types": "7.4.0", "@typescript-eslint/types": "7.4.0",
@@ -5230,9 +5253,9 @@
"dev": true "dev": true
}, },
"node_modules/fast-xml-parser": { "node_modules/fast-xml-parser": {
"version": "5.3.3", "version": "5.3.6",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.3.tgz", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz",
"integrity": "sha512-2O3dkPAAC6JavuMm8+4+pgTk+5hoAs+CjZ+sWcQLkX9+/tHRuTkQh/Oaifr8qDmZ8iEHb771Ea6G8CdwkrgvYA==", "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -5241,7 +5264,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"strnum": "^2.1.0" "strnum": "^2.1.2"
}, },
"bin": { "bin": {
"fxparser": "src/cli/cli.js" "fxparser": "src/cli/cli.js"
@@ -6356,7 +6379,6 @@
"version": "29.7.0", "version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "^29.7.0", "@jest/core": "^29.7.0",
"@jest/types": "^29.6.3", "@jest/types": "^29.6.3",
@@ -6795,7 +6817,6 @@
"version": "29.7.0", "version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
"integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
"peer": true,
"dependencies": { "dependencies": {
"@jest/types": "^29.6.3", "@jest/types": "^29.6.3",
"@types/node": "*", "@types/node": "*",
@@ -7852,7 +7873,6 @@
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
@@ -8396,15 +8416,26 @@
"spdx-ranges": "^2.0.0" "spdx-ranges": "^2.0.0"
} }
}, },
"node_modules/spdx-compare/node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"license": "MIT",
"dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/spdx-exceptions": { "node_modules/spdx-exceptions": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
}, },
"node_modules/spdx-expression-parse": { "node_modules/spdx-expression-parse": {
"version": "3.0.1", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"spdx-exceptions": "^2.1.0", "spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0" "spdx-license-ids": "^3.0.0"
@@ -8431,6 +8462,16 @@
"spdx-ranges": "^2.0.0" "spdx-ranges": "^2.0.0"
} }
}, },
"node_modules/spdx-satisfies/node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"license": "MIT",
"dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/sprintf-js": { "node_modules/sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -8983,7 +9024,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "dependency-review-action", "name": "dependency-review-action",
"version": "4.8.2", "version": "4.8.3",
"private": true, "private": true,
"description": "A GitHub Action for Dependency Review", "description": "A GitHub Action for Dependency Review",
"main": "lib/main.js", "main": "lib/main.js",
@@ -37,7 +37,7 @@
"jest": "^29.7.0", "jest": "^29.7.0",
"octokit": "^3.1.2", "octokit": "^3.1.2",
"semver": "^7.7.4", "semver": "^7.7.4",
"spdx-expression-parse": "^3.0.1", "spdx-expression-parse": "^4.0.0",
"spdx-satisfies": "^6.0.0", "spdx-satisfies": "^6.0.0",
"ts-jest": "^29.4.1", "ts-jest": "^29.4.1",
"yaml": "^2.8.1", "yaml": "^2.8.1",
+3 -6
View File
@@ -1,6 +1,6 @@
import {Change, Changes} from './schemas' import {Change, Changes} from './schemas'
import {octokitClient} from './utils' import {octokitClient} from './utils'
import {parsePURL, PackageURL} from './purl' import {parsePURL, PackageURL, purlsMatch} from './purl'
import * as spdx from './spdx' import * as spdx from './spdx'
/** /**
@@ -180,11 +180,8 @@ async function groupChanges(
// If it does, we want to filter it out and therefore return false // If it does, we want to filter it out and therefore return false
// If it doesn't, we want to keep it and therefore return true // If it doesn't, we want to keep it and therefore return true
if ( if (
licenseExclusions.findIndex( licenseExclusions.findIndex(exclusion =>
exclusion => purlsMatch(exclusion, changeAsPackageURL)
exclusion.type === changeAsPackageURL.type &&
exclusion.namespace === changeAsPackageURL.namespace &&
exclusion.name === changeAsPackageURL.name
) !== -1 ) !== -1
) { ) {
return false return false
+22 -4
View File
@@ -73,6 +73,13 @@ export async function handleLargeSummary(
return summaryContent return summaryContent
} }
const summarySize = Math.round(
Buffer.byteLength(summaryContent, 'utf8') / 1024
)
const truncatedSummary = `# Dependency Review Summary
The full dependency review summary was too large to display here (${summarySize}KB, limit is 1024KB).`
const artifactClient = new DefaultArtifactClient() const artifactClient = new DefaultArtifactClient()
const artifactName = 'dependency-review-summary' const artifactName = 'dependency-review-summary'
const files = ['summary.md'] const files = ['summary.md']
@@ -87,9 +94,9 @@ export async function handleLargeSummary(
}) })
// Return a shorter summary with a link to the artifact // Return a shorter summary with a link to the artifact
const shortSummary = `# Dependency Review Summary const shortSummary = `${truncatedSummary}
The full dependency review summary is too large to display here. Please download the artifact named "${artifactName}" to view the complete report. Please download the artifact named "${artifactName}" to view the complete report.
[View full job summary](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})` [View full job summary](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})`
@@ -99,9 +106,14 @@ The full dependency review summary is too large to display here. Please download
return shortSummary return shortSummary
} catch (error) { } catch (error) {
core.warning( core.warning(
`Failed to handle large summary: ${error instanceof Error ? error.message : 'Unknown error'}` `Failed to upload large summary as artifact: ${error instanceof Error ? error.message : 'Unknown error'}`
) )
return summaryContent // Even though artifact upload failed, we must still replace the buffer
// with a truncated summary to prevent core.summary.write() from failing
// with the oversized content (see issue #867)
core.summary.emptyBuffer()
core.summary.addRaw(truncatedSummary)
return truncatedSummary
} }
} }
@@ -271,7 +283,13 @@ async function run(): Promise<void> {
} }
} }
} finally { } finally {
try {
await core.summary.write() await core.summary.write()
} catch (error) {
core.warning(
`Failed to write job summary: ${error instanceof Error ? error.message : 'Unknown error'}`
)
}
} }
} }
+25
View File
@@ -70,3 +70,28 @@ export function parsePURL(purl: string): PackageURL {
// we don't parse subpath or attributes, so we're done here // we don't parse subpath or attributes, so we're done here
return result return result
} }
// Returns the full name of a package, combining namespace and name.
// This normalizes PURLs where the namespace separator '/' may have been
// percent-encoded as '%2F', causing it to be parsed as part of the name
// rather than splitting namespace and name.
function fullName(purl: PackageURL): string | null {
if (purl.namespace && purl.name) {
return `${purl.namespace}/${purl.name}`
}
return purl.name ?? purl.namespace
}
// Compare two PackageURLs for equality, ignoring version and normalizing
// namespace/name splits. This handles the case where a PURL like
// 'pkg:npm/%40scope%2Fname' is parsed as {namespace: null, name: '@scope/name'}
// while 'pkg:npm/%40scope/name' is parsed as {namespace: '@scope', name: 'name'}.
//
// The comparison is case-insensitive because most ecosystems and registries
// treat names that way (npm, PyPI, GitHub org/repo names, etc.).
export function purlsMatch(a: PackageURL, b: PackageURL): boolean {
if (a.type.toLowerCase() !== b.type.toLowerCase()) {
return false
}
return fullName(a)?.toLowerCase() === fullName(b)?.toLowerCase()
}