mirror of https://github.com/actions/toolkit
Handle tags containing "@" character in `buildSLSAProvenancePredicate`
When using some monorepo-related tools (like [changesets](https://github.com/changesets/changesets)), the produced tags have a special format that includes `@` character. For example, a `foo` package on a monorepo will produce Git tags looking like `foo@1.0.0` if using changesets. When used in combination with `actions/attest-build-provenance`, the action was not properly re-crafting the tag in `buildSLSAProvenancePredicate` because it was always splitting the workflow ref by `@` and taking the second element. This result in this error on CI: ``` Error: Error: Failed to persist attestation: Invalid Argument - values do not match: refs/tags/foo != refs/tags/foo@1.0.0 - https://docs.github.com/rest/repos/repos#create-an-attestation ```` This PR slightly update the logic there, and rather take "everything located after the first '@'". This shouldn't introduce any breaking change, while giving support for custom tags. I've added the corresponding test case, it passes, however I couldn't successfully run the full test suite (neither on `main`). Looking forward for CI outcome. Thanks in advance for the review 🙏.pull/1863/head
parent
7f5921cddd
commit
717ba9d9a4
|
@ -1,5 +1,47 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`provenance functions buildSLSAProvenancePredicate handle tags including "@" character 1`] = `
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"buildDefinition": {
|
||||||
|
"buildType": "https://actions.github.io/buildtypes/workflow/v1",
|
||||||
|
"externalParameters": {
|
||||||
|
"workflow": {
|
||||||
|
"path": ".github/workflows/main.yml",
|
||||||
|
"ref": "foo@1.0.0",
|
||||||
|
"repository": "https://foo.ghe.com/owner/repo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"internalParameters": {
|
||||||
|
"github": {
|
||||||
|
"event_name": "push",
|
||||||
|
"repository_id": "repo-id",
|
||||||
|
"repository_owner_id": "owner-id",
|
||||||
|
"runner_environment": "github-hosted",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"resolvedDependencies": [
|
||||||
|
{
|
||||||
|
"digest": {
|
||||||
|
"gitCommit": "babca52ab0c93ae16539e5923cb0d7403b9a093b",
|
||||||
|
},
|
||||||
|
"uri": "git+https://foo.ghe.com/owner/repo@refs/heads/main",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"runDetails": {
|
||||||
|
"builder": {
|
||||||
|
"id": "https://foo.ghe.com/owner/workflows/.github/workflows/publish.yml@main",
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"invocationId": "https://foo.ghe.com/owner/repo/actions/runs/run-id/attempts/run-attempt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": "https://slsa.dev/provenance/v1",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`provenance functions buildSLSAProvenancePredicate returns a provenance hydrated from an OIDC token 1`] = `
|
exports[`provenance functions buildSLSAProvenancePredicate returns a provenance hydrated from an OIDC token 1`] = `
|
||||||
{
|
{
|
||||||
"params": {
|
"params": {
|
||||||
|
|
|
@ -33,15 +33,7 @@ describe('provenance functions', () => {
|
||||||
runner_environment: 'github-hosted'
|
runner_environment: 'github-hosted'
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async () => {
|
const mockIssuer = async (claims: jose.JWTPayload): Promise<void> => {
|
||||||
process.env = {
|
|
||||||
...originalEnv,
|
|
||||||
ACTIONS_ID_TOKEN_REQUEST_URL: `${issuer}${tokenPath}?`,
|
|
||||||
ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token',
|
|
||||||
GITHUB_SERVER_URL: 'https://foo.ghe.com',
|
|
||||||
GITHUB_REPOSITORY: claims.repository
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate JWT signing key
|
// Generate JWT signing key
|
||||||
const key = await jose.generateKeyPair('PS256')
|
const key = await jose.generateKeyPair('PS256')
|
||||||
|
|
||||||
|
@ -60,6 +52,18 @@ describe('provenance functions', () => {
|
||||||
|
|
||||||
// Mock OIDC token endpoint for populating the provenance
|
// Mock OIDC token endpoint for populating the provenance
|
||||||
nock(issuer).get(tokenPath).query({audience}).reply(200, {value: jwt})
|
nock(issuer).get(tokenPath).query({audience}).reply(200, {value: jwt})
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
ACTIONS_ID_TOKEN_REQUEST_URL: `${issuer}${tokenPath}?`,
|
||||||
|
ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token',
|
||||||
|
GITHUB_SERVER_URL: 'https://foo.ghe.com',
|
||||||
|
GITHUB_REPOSITORY: claims.repository
|
||||||
|
}
|
||||||
|
|
||||||
|
await mockIssuer(claims)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -71,6 +75,16 @@ describe('provenance functions', () => {
|
||||||
const predicate = await buildSLSAProvenancePredicate()
|
const predicate = await buildSLSAProvenancePredicate()
|
||||||
expect(predicate).toMatchSnapshot()
|
expect(predicate).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('handle tags including "@" character', async () => {
|
||||||
|
nock.cleanAll()
|
||||||
|
await mockIssuer({
|
||||||
|
...claims,
|
||||||
|
workflow_ref: 'owner/repo/.github/workflows/main.yml@foo@1.0.0'
|
||||||
|
})
|
||||||
|
const predicate = await buildSLSAProvenancePredicate()
|
||||||
|
expect(predicate).toMatchSnapshot()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('attestProvenance', () => {
|
describe('attestProvenance', () => {
|
||||||
|
|
|
@ -30,9 +30,11 @@ export const buildSLSAProvenancePredicate = async (
|
||||||
// Split just the path and ref from the workflow string.
|
// Split just the path and ref from the workflow string.
|
||||||
// owner/repo/.github/workflows/main.yml@main =>
|
// owner/repo/.github/workflows/main.yml@main =>
|
||||||
// .github/workflows/main.yml, main
|
// .github/workflows/main.yml, main
|
||||||
const [workflowPath, workflowRef] = claims.workflow_ref
|
const [workflowPath, ...workflowRefChunks] = claims.workflow_ref
|
||||||
.replace(`${claims.repository}/`, '')
|
.replace(`${claims.repository}/`, '')
|
||||||
.split('@')
|
.split('@')
|
||||||
|
// Handle case where tag contains `@` (e.g: when using changesets in a monorepo context),
|
||||||
|
const workflowRef = workflowRefChunks.join('@')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: SLSA_PREDICATE_V1_TYPE,
|
type: SLSA_PREDICATE_V1_TYPE,
|
||||||
|
|
Loading…
Reference in New Issue