Compare commits

...

13 Commits

Author SHA1 Message Date
Ashely Tenesaca b4604a3cd9 npm audit fix --force 2025-10-02 15:07:22 +00:00
Barry Gordon 56339e523c Merge pull request #988 from actions/brrygrdn/rc-4.8.0
Bump to 4.8.0
2025-09-26 16:05:17 +01:00
Barry Gordon 1688b745f3 Bump to a 4.8.0 2025-09-26 15:45:28 +01:00
Barry Gordon 31c9f175b9 Merge pull request #987 from actions/rc-4.7.4
Prepare release of v4.7.4
2025-09-26 15:20:06 +01:00
Barry Gordon eacde7836e Update version 2025-09-26 14:42:22 +01:00
Barry Gordon 81510090e4 Merge pull request #986 from actions/brrygrdn/rc-4.7.4
Batch some contributions for release
2025-09-26 14:32:46 +01:00
Barry Gordon b472ec914b Add a quick regression test for the artefact summary 2025-09-26 13:34:03 +01:00
Matt Mencel e0cedc52dc feat: add large summary handling with artifact upload
When the dependency review summary exceeds GitHub's size limit (1024k), upload it as an artifact and provide a link in the comment. This ensures users can still access the full review details even when the summary is too large to display directly.
2025-09-26 12:55:14 +01:00
Jasper Kamerling e3fdf0f899 This ensures large allow or deny lists don't create huge comments 2025-09-26 12:49:38 +01:00
Lewis Jones 6fad417932 Merge pull request #978 from actions/ljones140/make-ruby-code-scannable
Make Ruby Code Scannable
2025-08-29 10:39:17 +01:00
Lewis Jones e86e9692ad Update scripts/scan_pr_lib.rb
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-28 16:24:02 +01:00
Lewis Jones 85c8e53ab7 Scan ruby 2025-08-28 16:12:23 +01:00
Lewis Jones c6a7eb7252 Extract ruby code
So can be scanned by code scanning
2025-08-28 16:11:56 +01:00
12 changed files with 103549 additions and 1879 deletions
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'javascript-typescript', 'actions' ]
language: [ 'javascript-typescript', 'actions', 'ruby' ]
steps:
- name: Checkout repository
@@ -38,7 +38,7 @@ jobs:
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
config: |
paths-ignore:
paths-ignore:
- dist/index.js
- dist/sourcemap-register.js
+153
View File
@@ -0,0 +1,153 @@
import {
afterEach,
beforeEach,
describe,
expect,
jest,
test
} from '@jest/globals'
import * as fs from 'fs'
import * as core from '@actions/core'
import {DefaultArtifactClient} from '@actions/artifact'
import type {SpyInstance} from 'jest-mock'
import {handleLargeSummary} from '../src/main'
jest.mock('ansi-styles', () => ({
__esModule: true,
default: {
color: {
red: {open: '', close: ''},
yellow: {open: '', close: ''},
grey: {open: '', close: ''},
green: {open: '', close: ''}
},
bold: {open: '', close: ''}
}
}))
jest.mock('../src/dependency-graph', () => ({}))
jest.mock('@actions/core', () => {
const summary = {
addRaw: jest.fn().mockReturnThis(),
addHeading: jest.fn().mockReturnThis(),
addTable: jest.fn().mockReturnThis(),
addSeparator: jest.fn().mockReturnThis(),
addImage: jest.fn().mockReturnThis(),
addList: jest.fn().mockReturnThis(),
addBreak: jest.fn().mockReturnThis(),
addLink: jest.fn().mockReturnThis(),
addDetails: jest.fn().mockReturnThis(),
addSection: jest.fn().mockReturnThis(),
addCodeBlock: jest.fn().mockReturnThis(),
addFields: jest.fn().mockReturnThis(),
addEol: jest.fn().mockReturnThis(),
write: jest.fn(async () => undefined),
emptyBuffer: jest.fn(),
stringify: jest.fn(() => '')
}
return {
__esModule: true,
getInput: jest.fn((name: string) =>
name === 'repo-token' ? 'gh_test_token' : ''
),
setOutput: jest.fn(),
setFailed: jest.fn(),
warning: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn(async (_name: string, fn: () => Promise<unknown>) => fn()),
summary
}
})
jest.mock('@actions/artifact', () => ({
DefaultArtifactClient: jest.fn()
}))
const ORIGINAL_ENV = {...process.env}
type ArtifactClientInstance = {
uploadArtifact: jest.Mock
}
const DefaultArtifactClientMock = DefaultArtifactClient as unknown as jest.Mock
const createArtifactClient = (): ArtifactClientInstance => ({
uploadArtifact: jest.fn(async () => undefined)
})
describe('handleLargeSummary', () => {
let writeFileSpy: SpyInstance<typeof fs.promises.writeFile>
beforeEach(() => {
process.env = {...ORIGINAL_ENV}
writeFileSpy = jest
.spyOn(fs.promises, 'writeFile')
.mockImplementation(async () => undefined)
DefaultArtifactClientMock.mockClear()
DefaultArtifactClientMock.mockImplementation(() => createArtifactClient())
})
afterEach(() => {
writeFileSpy.mockRestore()
jest.clearAllMocks()
process.env = {...ORIGINAL_ENV}
})
test('returns original summary when under size threshold', async () => {
const summaryContent = 'short summary'
const result = await handleLargeSummary(summaryContent)
expect(result).toBe(summaryContent)
expect(writeFileSpy).not.toHaveBeenCalled()
expect(DefaultArtifactClientMock).not.toHaveBeenCalled()
})
test('uploads artifact and returns minimal summary when summary is too large', async () => {
process.env.GITHUB_SERVER_URL = 'https://github.com'
process.env.GITHUB_REPOSITORY = 'owner/repo'
process.env.GITHUB_RUN_ID = '12345'
const largeSummary = 'a'.repeat(1024 * 1024 + 1)
const result = await handleLargeSummary(largeSummary)
expect(writeFileSpy).toHaveBeenCalledTimes(1)
expect(writeFileSpy).toHaveBeenCalledWith('summary.md', largeSummary)
expect(DefaultArtifactClientMock).toHaveBeenCalledTimes(1)
const artifactInstance = DefaultArtifactClientMock.mock.results[0]
?.value as ArtifactClientInstance
expect(artifactInstance.uploadArtifact).toHaveBeenCalledWith(
'dependency-review-summary',
['summary.md'],
'.',
{retentionDays: 1}
)
expect(result).toContain('# Dependency Review Summary')
expect(result).toContain('dependency-review-summary')
expect(result).toContain('actions/runs/12345')
})
test('returns original summary and logs a warning when artifact handling fails', async () => {
const warningMock = core.warning as jest.Mock
warningMock.mockClear()
const largeSummary = 'b'.repeat(1024 * 1024 + 1)
DefaultArtifactClientMock.mockImplementation(() => ({
uploadArtifact: jest.fn(async () => {
throw new Error('upload failed')
})
}))
const result = await handleLargeSummary(largeSummary)
expect(result).toBe(largeSummary)
expect(warningMock).toHaveBeenCalledWith(
expect.stringContaining('Failed to handle large summary')
)
})
})
+27 -3
View File
@@ -464,7 +464,9 @@ test('addLicensesToSummary() - includes list of configured allowed licenses', ()
summary.addLicensesToSummary(licenseIssues, config)
const text = core.summary.stringify()
expect(text).toContain('<strong>Allowed Licenses</strong>: MIT, Apache-2.0')
expect(text).toContain(
'<details><summary><strong>Allowed Licenses</strong>:</summary> MIT, Apache-2.0</details>'
)
})
test('addLicensesToSummary() - includes configured denied license', () => {
@@ -476,11 +478,33 @@ test('addLicensesToSummary() - includes configured denied license', () => {
const config: ConfigurationOptions = {
...defaultConfig,
deny_licenses: ['MIT']
deny_licenses: ['MIT', 'Apache-2.0']
}
summary.addLicensesToSummary(licenseIssues, config)
const text = core.summary.stringify()
expect(text).toContain('<strong>Denied Licenses</strong>: MIT')
expect(text).toContain(
'<details><summary><strong>Denied Licenses</strong>:</summary> MIT, Apache-2.0</details>'
)
})
test('addLicensesToSummary() - includes allowed dependency licences', () => {
const licenseIssues = {
forbidden: [createTestChange()],
unresolved: [],
unlicensed: []
}
const config: ConfigurationOptions = {
...defaultConfig,
allow_dependencies_licenses: ['MIT', 'Apache-2.0']
}
summary.addLicensesToSummary(licenseIssues, config)
const text = core.summary.stringify()
expect(text).toContain(
'<details><summary><strong>Excluded from license check</strong>:</summary> MIT, Apache-2.0</details>'
)
})
Generated Vendored
+100222 -1305
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
Generated Vendored
+2911
View File
File diff suppressed because it is too large Load Diff
+55 -478
View File
@@ -1,14 +1,15 @@
{
"name": "dependency-review-action",
"version": "4.7.3",
"version": "4.8.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "dependency-review-action",
"version": "4.7.3",
"version": "4.8.0",
"license": "MIT",
"dependencies": {
"@actions/artifact": "^1.1.2",
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1",
"@octokit/plugin-retry": "^6.1.0",
@@ -52,6 +53,18 @@
"node": ">=0.10.0"
}
},
"node_modules/@actions/artifact": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-1.1.2.tgz",
"integrity": "sha512-1gLONA4xw3/Q/9vGxKwkFdV9u1LE2RWGx/IpAqg28ZjprCnJFjwn4pA7LtShqg5mg5WhMek2fjpyH1leCmOlQQ==",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.9.1",
"@actions/http-client": "^2.0.1",
"tmp": "^0.2.1",
"tmp-promise": "^3.0.2"
}
},
"node_modules/@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
@@ -517,13 +530,11 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
"integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@@ -588,78 +599,6 @@
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
@@ -678,366 +617,6 @@
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -3110,22 +2689,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/chalk/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/chalk/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/char-regex": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
@@ -3227,6 +2790,24 @@
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
"integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q=="
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -7007,12 +6588,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==",
"dev": true
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
@@ -7578,6 +7153,24 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/tmp": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
"license": "MIT",
"engines": {
"node": ">=14.14"
}
},
"node_modules/tmp-promise": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz",
"integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==",
"license": "MIT",
"dependencies": {
"tmp": "^0.2.0"
}
},
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -8084,22 +7677,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/wrap-ansi/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "dependency-review-action",
"version": "4.7.3",
"version": "4.8.0",
"private": true,
"description": "A GitHub Action for Dependency Review",
"main": "lib/main.js",
@@ -25,6 +25,7 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
"@actions/artifact": "^1.1.2",
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1",
"@octokit/plugin-retry": "^6.1.0",
+5 -84
View File
@@ -1,87 +1,8 @@
#!/usr/bin/env ruby
require 'json'
require 'tempfile'
require 'open3'
require 'bundler/inline'
require 'optparse'
gemfile do
source 'https://rubygems.org'
gem 'octokit'
end
# Load the scan_pr library
require_relative 'scan_pr_lib'
config_file = nil
github_token = ENV["GITHUB_TOKEN"]
if !github_token || github_token.empty?
puts "Please set the GITHUB_TOKEN environment variable"
exit -1
end
op = OptionParser.new do |opts|
usage = <<EOF
Run Dependency Review on a repository.
\e[1mUsage:\e[22m
scripts/scan_pr [options] <pr_url>
\e[1mExample:\e[22m
scripts/scan_pr https://github.com/actions/dependency-review-action/pull/294
EOF
opts.banner = usage
opts.on('-c', '--config-file <FILE>', 'Use an external configuration file') do |cf|
config_file = cf
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end
op.parse!
# make sure we have a NWO somewhere in the parameters
arg = /(?<repo_nwo>[\w\-]+\/[\w\-]+)\/pull\/(?<pr_number>\d+)/.match(ARGV.join(" "))
if arg.nil?
puts op
exit -1
end
repo_nwo = arg[:repo_nwo]
pr_number = arg[:pr_number]
octo = Octokit::Client.new(access_token: github_token)
pr = octo.pull_request(repo_nwo, pr_number)
event_file = Tempfile.new
event_file.write("{ \"pull_request\": #{pr.to_h.to_json}}")
event_file.close
action_inputs = {
"repo-token": github_token,
"config-file": config_file
}
dev_cmd_env = {
"GITHUB_REPOSITORY" => repo_nwo,
"GITHUB_EVENT_NAME" => "pull_request",
"GITHUB_EVENT_PATH" => event_file.path,
"GITHUB_STEP_SUMMARY" => "/dev/null"
}
# bash does not like variable names with dashes like the ones Actions
# uses (e.g. INPUT_REPO-TOKEN). Passing them through `env` instead of
# manually setting them does the job.
action_inputs_env_str = action_inputs.map { |name, value| "\"INPUT_#{name.upcase}=#{value}\"" }.join(" ")
dev_cmd = "./node_modules/.bin/nodemon --exec \"env #{action_inputs_env_str} node -r esbuild-register\" src/main.ts"
Open3.popen2e(dev_cmd_env, dev_cmd) do |stdin, out|
while line = out.gets
puts line.gsub(github_token, "<REDACTED>")
end
end
# Create and run the scanner
scanner = ScanPr.new
scanner.run(ARGV)
+128
View File
@@ -0,0 +1,128 @@
require 'json'
require 'tempfile'
require 'open3'
require 'bundler/inline'
require 'optparse'
gemfile do
source 'https://rubygems.org'
gem 'octokit'
end
class ScanPr
def initialize
@config_file = nil
@github_token = ENV["GITHUB_TOKEN"]
validate_token
end
def run(args)
parse_options(args)
repo_nwo, pr_number = extract_repo_and_pr(args)
pr = fetch_pull_request(repo_nwo, pr_number)
event_file = create_event_file(pr)
execute_dependency_review(repo_nwo, event_file)
ensure
event_file&.unlink
end
private
def validate_token
if !@github_token || @github_token.empty?
puts "Please set the GITHUB_TOKEN environment variable"
exit -1
end
end
def parse_options(args)
op = OptionParser.new do |opts|
usage = <<EOF
Run Dependency Review on a repository.
\e[1mUsage:\e[22m
scripts/scan_pr [options] <pr_url>
\e[1mExample:\e[22m
scripts/scan_pr https://github.com/actions/dependency-review-action/pull/294
EOF
opts.banner = usage
opts.on('-c', '--config-file <FILE>', 'Use an external configuration file') do |cf|
@config_file = cf
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end
op.parse!(args)
@option_parser = op
end
def extract_repo_and_pr(args)
# make sure we have a NWO somewhere in the parameters
arg = /(?<repo_nwo>[\w\-]+\/[\w\-]+)\/pull\/(?<pr_number>\d+)/.match(args.join(" "))
if arg.nil?
puts @option_parser
exit -1
end
[arg[:repo_nwo], arg[:pr_number]]
end
def fetch_pull_request(repo_nwo, pr_number)
octo = Octokit::Client.new(access_token: @github_token)
octo.pull_request(repo_nwo, pr_number)
end
def create_event_file(pr)
event_file = Tempfile.new
event_file.write("{ \"pull_request\": #{pr.to_h.to_json}}")
event_file.close
event_file
end
def execute_dependency_review(repo_nwo, event_file)
action_inputs = {
"repo-token": @github_token,
"config-file": @config_file
}
dev_cmd_env = {
"GITHUB_REPOSITORY" => repo_nwo,
"GITHUB_EVENT_NAME" => "pull_request",
"GITHUB_EVENT_PATH" => event_file.path,
"GITHUB_STEP_SUMMARY" => "/dev/null"
}
# Merge action inputs into environment, formatting keys as INPUT_...
action_inputs_env = action_inputs.each_with_object({}) do |(name, value), h|
h["INPUT_#{name.to_s.upcase}"] = value unless value.nil?
end
env = dev_cmd_env.merge(action_inputs_env)
dev_cmd = [
"./node_modules/.bin/nodemon",
"--exec",
"node",
"-r",
"esbuild-register",
"src/main.ts"
]
Open3.popen2e(env, *dev_cmd) do |stdin, out|
while line = out.gets
puts line.gsub(@github_token, "<REDACTED>")
end
end
end
end
+40
View File
@@ -24,6 +24,8 @@ import {getRefs} from './git-refs'
import {groupDependenciesByManifest} from './utils'
import {commentPr, MAX_COMMENT_LENGTH} from './comment-pr'
import {getDeniedChanges} from './deny'
import * as artifact from '@actions/artifact'
import * as fs from 'fs'
async function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
@@ -61,6 +63,41 @@ async function getComparison(
return comparison
}
export async function handleLargeSummary(
summaryContent: string
): Promise<string> {
const MAX_SUMMARY_SIZE = 1024 * 1024 // 1024k in bytes
if (Buffer.byteLength(summaryContent, 'utf8') <= MAX_SUMMARY_SIZE) {
return summaryContent
}
const artifactClient = new artifact.DefaultArtifactClient()
const artifactName = 'dependency-review-summary'
const files = ['summary.md']
try {
// Write the summary to a file
await fs.promises.writeFile('summary.md', summaryContent)
// Upload the artifact
await artifactClient.uploadArtifact(artifactName, files, '.', {
retentionDays: 1
})
// Return a minimal summary with a link to the artifact
return `# Dependency Review Summary
The full dependency review summary is too large to display here. 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})`
} catch (error) {
core.warning(
`Failed to handle large summary: ${error instanceof Error ? error.message : 'Unknown error'}`
)
return summaryContent
}
}
async function run(): Promise<void> {
try {
const config = await readConfig()
@@ -179,6 +216,9 @@ async function run(): Promise<void> {
let rendered = core.summary.stringify()
core.setOutput('comment-content', rendered)
// Handle large summaries by uploading as artifact
rendered = await handleLargeSummary(rendered)
// if the summary is oversized, replace with minimal version
if (rendered.length >= MAX_COMMENT_LENGTH) {
core.debug(
+3 -5
View File
@@ -206,19 +206,17 @@ export function addLicensesToSummary(
if (config.allow_licenses && config.allow_licenses.length > 0) {
core.summary.addQuote(
`<strong>Allowed Licenses</strong>: ${config.allow_licenses.join(', ')}`
`<details><summary><strong>Allowed Licenses</strong>:</summary> ${config.allow_licenses.join(', ')}</details>`
)
}
if (config.deny_licenses && config.deny_licenses.length > 0) {
core.summary.addQuote(
`<strong>Denied Licenses</strong>: ${config.deny_licenses.join(', ')}`
`<details><summary><strong>Denied Licenses</strong>:</summary> ${config.deny_licenses.join(', ')}</details>`
)
}
if (config.allow_dependencies_licenses) {
core.summary.addQuote(
`<strong>Excluded from license check</strong>: ${config.allow_dependencies_licenses.join(
', '
)}`
`<details><summary><strong>Excluded from license check</strong>:</summary> ${config.allow_dependencies_licenses.join(', ')}</details>`
)
}