mirror of
https://github.com/gradle/actions.git
synced 2026-11-08 19:14:54 +00:00
Merge commit from fork
A dependency graph file downloaded from another workflow run may come from an untrusted fork. Passing the parsed file whole to octokit.request() let keys such as 'url' override the request destination and leak the token.
This commit is contained in:
1 parent
bf74269609
commit
dcf6f72a92
2 files changed
+29
-4
No files matched your search
@@ -218,14 +218,28 @@ async function submitDependencyGraphFile(jsonFile: string): Promise<void> {
|
||||
const octokit = getOctokit()
|
||||
const jsonContent = fs.readFileSync(jsonFile, 'utf8')
|
||||
|
||||
const jsonObject = JSON.parse(jsonContent)
|
||||
jsonObject.owner = github.context.repo.owner
|
||||
jsonObject.repo = github.context.repo.repo
|
||||
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject)
|
||||
const snapshot = toSnapshotRequest(JSON.parse(jsonContent), github.context.repo.owner, github.context.repo.repo)
|
||||
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', snapshot)
|
||||
|
||||
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
|
||||
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
|
||||
}
|
||||
|
||||
// Only the snapshot fields are copied into the request: the file may come from an untrusted artifact,
|
||||
// and any other key (such as 'url', 'baseUrl' or 'headers') would be interpreted as a request option.
|
||||
const SNAPSHOT_FIELDS = ['version', 'job', 'sha', 'ref', 'detector', 'metadata', 'manifests', 'scanned'] as const
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function toSnapshotRequest(jsonObject: Record<string, unknown>, owner: string, repo: string): any {
|
||||
const snapshot: Record<string, unknown> = {owner, repo}
|
||||
for (const field of SNAPSHOT_FIELDS) {
|
||||
if (jsonObject[field] !== undefined) {
|
||||
snapshot[field] = jsonObject[field]
|
||||
}
|
||||
}
|
||||
return snapshot
|
||||
}
|
||||
|
||||
function getReportDirectory(): string {
|
||||
return process.env.DEPENDENCY_GRAPH_REPORT_DIR!
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
|
||||
import {DependencyGraphConfig} from "../../src/configuration"
|
||||
import {toSnapshotRequest} from "../../src/dependency-graph"
|
||||
|
||||
describe('dependency-graph', () => {
|
||||
describe('constructs job correlator', () => {
|
||||
@@ -33,4 +34,14 @@ describe('dependency-graph', () => {
|
||||
expect(id).toBe('workflow-jobid-windows-211-value_with_comma')
|
||||
})
|
||||
})
|
||||
describe('constructs snapshot request', () => {
|
||||
it('copies snapshot fields and sets owner and repo', () => {
|
||||
const snapshot = {version: 0, job: {correlator: 'c', id: '1'}, sha: 'abc', ref: 'refs/heads/main', detector: {name: 'd'}, scanned: '2026-10-27T00:00:00Z', manifests: {}}
|
||||
expect(toSnapshotRequest(snapshot, 'owner', 'repo')).toEqual({owner: 'owner', repo: 'repo', ...snapshot})
|
||||
})
|
||||
it('drops request options supplied by the file', () => {
|
||||
const request = toSnapshotRequest({version: 0, url: 'https://attacker.example', baseUrl: 'https://attacker.example', headers: {}, method: 'GET', request: {}, owner: 'other', repo: 'other'}, 'owner', 'repo')
|
||||
expect(request).toEqual({owner: 'owner', repo: 'repo', version: 0})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user