Skip to content

Commit 90f6b1d

Browse files
committed
fix: update publish provenance entryPoint value
Updates the entryPoint in the generated provenance to contain just the repo-relative path to the triggering workflow. Signed-off-by: Brian DeHamer <bdehamer@github.com>
1 parent e819e9f commit 90f6b1d

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

workspaces/libnpmpublish/lib/provenance.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ const BUILD_TYPE_VERSION = 'v1'
1010

1111
const generateProvenance = async (subject, opts) => {
1212
const { env } = process
13+
const [workflowPath] = (env.GITHUB_WORKFLOW_REF || '')
14+
.replace(env.GITHUB_REPOSITORY + '/', '')
15+
.split('@')
1316
const payload = {
1417
_type: INTOTO_STATEMENT_TYPE,
1518
subject,
@@ -23,7 +26,7 @@ const generateProvenance = async (subject, opts) => {
2326
digest: {
2427
sha1: env.GITHUB_SHA,
2528
},
26-
entryPoint: env.GITHUB_WORKFLOW_REF,
29+
entryPoint: workflowPath,
2730
},
2831
parameters: {},
2932
environment: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
'use strict'
2+
3+
const t = require('tap')
4+
5+
const mockGlobals = require('../../../test/fixtures/mock-globals.js')
6+
7+
// Set-up a spy for the sigstore.attest function so we can inspect the
8+
// provenance payload
9+
const attestLog = []
10+
const { generateProvenance } = t.mock('../lib/provenance.js', {
11+
sigstore: {
12+
sigstore: {
13+
attest: (...any) => attestLog.push(any),
14+
},
15+
},
16+
})
17+
18+
// Environment variables
19+
const workflowPath = '.github/workflows/publish.yml'
20+
const repository = 'github/foo'
21+
const serverUrl = 'https://github.com'
22+
const ref = 'refs/heads/main'
23+
const sha = 'deadbeef'
24+
const runID = '123456'
25+
const runAttempt = '1'
26+
27+
// Provenance subject
28+
const subject = {
29+
name: 'npm',
30+
version: '7.0.0',
31+
digest: {
32+
sha1: 'deadbeef',
33+
},
34+
}
35+
36+
t.test('generateProvenance - GHA environment', async t => {
37+
// Reset the spy
38+
attestLog.length = 0
39+
40+
mockGlobals(t, {
41+
'process.env': {
42+
CI: true,
43+
GITHUB_ACTIONS: true,
44+
GITHUB_REPOSITORY: repository,
45+
GITHUB_REF: ref,
46+
GITHUB_SHA: sha,
47+
GITHUB_SERVER_URL: serverUrl,
48+
GITHUB_WORKFLOW_REF: `${repository}/${workflowPath}@${ref}`,
49+
GITHUB_RUN_ID: runID,
50+
GITHUB_RUN_ATTEMPT: runAttempt,
51+
},
52+
})
53+
54+
const options = { foo: 'bar' }
55+
await generateProvenance(subject, options)
56+
57+
const [payload, payloadType, opts] = attestLog[0]
58+
59+
t.equal(payloadType, 'application/vnd.in-toto+json')
60+
t.equal(opts, options)
61+
62+
const provenance = JSON.parse(payload.toString('utf8'))
63+
t.same(provenance.subject, subject)
64+
t.equal(provenance.predicate.invocation.configSource.uri, `git+${serverUrl}/${repository}@${ref}`)
65+
t.equal(provenance.predicate.invocation.configSource.digest.sha1, sha)
66+
t.equal(provenance.predicate.invocation.configSource.entryPoint, workflowPath)
67+
t.equal(provenance.predicate.metadata.buildInvocationId, `${runID}-${runAttempt}`)
68+
t.equal(provenance.predicate.materials[0].uri, `git+${serverUrl}/${repository}@${ref}`)
69+
t.equal(provenance.predicate.materials[0].digest.sha1, sha)
70+
})
71+
72+
t.test('generateProvenance - incomplete environment', async t => {
73+
// Reset the spy
74+
attestLog.length = 0
75+
76+
// Simulate running in a non-GHA environment
77+
mockGlobals(t, {
78+
'process.env': {
79+
CI: undefined,
80+
GITHUB_ACTIONS: undefined,
81+
GITHUB_REPOSITORY: undefined,
82+
GITHUB_REF: undefined,
83+
GITHUB_SHA: undefined,
84+
GITHUB_SERVER_URL: undefined,
85+
GITHUB_WORKFLOW_REF: undefined,
86+
GITHUB_RUN_ID: undefined,
87+
GITHUB_RUN_ATTEMPT: undefined,
88+
},
89+
})
90+
91+
t.doesNotThrow(async () => await generateProvenance(subject, {}))
92+
})

0 commit comments

Comments
 (0)