Compare commits

..

7 Commits

Author SHA1 Message Date
Brian DeHamer d58ddf9f24 dynamic construction of oidc issuer (#195)
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-09 07:42:36 -07:00
dependabot[bot] f9d4126c51 Bump @typescript-eslint/parser from 7.17.0 to 7.18.0 (#188)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.17.0 to 7.18.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.18.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-06 09:30:32 -07:00
dependabot[bot] 588eda318e Bump the npm-development group with 3 updates (#187)
Bumps the npm-development group with 3 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) and [ts-jest](https://github.com/kulshekhar/ts-jest).


Updates `@types/node` from 22.0.0 to 22.1.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint-plugin-jest` from 28.6.0 to 28.7.0
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.6.0...v28.7.0)

Updates `ts-jest` from 29.2.3 to 29.2.4
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.2.3...v29.2.4)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development
- dependency-name: ts-jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-06 09:13:42 -07:00
Brian DeHamer 48f71d5e11 disable typescript-standard super linter (#191)
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-06 09:08:02 -07:00
Brian DeHamer 210c191353 bump actions/attest from 1.3.3 to 1.4.0 (#183)
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-07-30 12:55:08 -07:00
Brian DeHamer 1cb5f7640f bump predicate action from 1.1.0 to 1.1.1 (#182)
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-07-30 12:41:18 -07:00
Brian DeHamer 9ff3713ef1 Bump @actions/attest from 1.3.0 to 1.3.1 (#181)
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-07-30 11:16:49 -07:00
10 changed files with 49383 additions and 71930 deletions
+1
View File
@@ -46,4 +46,5 @@ jobs:
TYPESCRIPT_DEFAULT_STYLE: prettier
VALIDATE_ALL_CODEBASE: true
VALIDATE_JAVASCRIPT_STANDARD: false
VALIDATE_TYPESCRIPT_STANDARD: false
VALIDATE_JSCPD: false
+4
View File
@@ -77,6 +77,10 @@ See [action.yml](action.yml)
# the "subject-digest" parameter be specified. Defaults to false.
push-to-registry:
# Whether to attach a list of generated attestations to the workflow run
# summary page. Defaults to true.
show-summary:
# The GitHub token used to make authenticated API requests. Default is
# ${{ github.token }}
github-token:
+40 -1
View File
@@ -1,6 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`main successfully run main 1`] = `
exports[`main when a non-default OIDC issuer is used successfully run main 1`] = `
{
"buildDefinition": {
"buildType": "https://actions.github.io/buildtypes/workflow/v1",
"externalParameters": {
"workflow": {
"path": ".github/workflows/main.yml",
"ref": "main",
"repository": "https://example-01.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://example-01.ghe.com/owner/repo@refs/heads/main",
},
],
},
"runDetails": {
"builder": {
"id": "https://example-01.ghe.com/owner/shared/.github/workflows/build.yml@main",
},
"metadata": {
"invocationId": "https://example-01.ghe.com/owner/repo/actions/runs/run-id/attempts/run-attempt",
},
},
}
`;
exports[`main when the default OIDC issuer is used successfully run main 1`] = `
{
"buildDefinition": {
"buildType": "https://actions.github.io/buildtypes/workflow/v1",
+125 -56
View File
@@ -13,61 +13,13 @@ setFailedMock.mockImplementation(() => {})
describe('main', () => {
let outputs = {} as Record<string, string>
const originalEnv = process.env
const issuer = 'https://token.actions.githubusercontent.com'
const audience = 'nobody'
const jwksPath = '/.well-known/jwks.json'
const tokenPath = '/token'
const claims = {
iss: issuer,
aud: 'nobody',
repository: 'owner/repo',
ref: 'refs/heads/main',
sha: 'babca52ab0c93ae16539e5923cb0d7403b9a093b',
workflow_ref: 'owner/repo/.github/workflows/main.yml@main',
job_workflow_ref: 'owner/shared/.github/workflows/build.yml@main',
event_name: 'push',
repository_id: 'repo-id',
repository_owner_id: 'owner-id',
run_id: 'run-id',
run_attempt: 'run-attempt',
runner_environment: 'github-hosted'
}
beforeEach(async () => {
beforeEach(() => {
jest.resetAllMocks()
setOutputMock.mockImplementation((key, value) => {
outputs[key] = value
})
process.env = {
...originalEnv,
ACTIONS_ID_TOKEN_REQUEST_URL: `${issuer}${tokenPath}?`,
ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token',
GITHUB_SERVER_URL: 'https://github.com',
GITHUB_REPOSITORY: claims.repository
}
// Generate JWT signing key
const key = await jose.generateKeyPair('PS256')
// Create JWK, JWKS, and JWT
const kid = '12345'
const jwk = await jose.exportJWK(key.publicKey)
const jwks = { keys: [{ ...jwk, kid }] }
const jwt = await new jose.SignJWT(claims)
.setProtectedHeader({ alg: 'PS256', kid })
.sign(key.privateKey)
// Mock OpenID configuration and JWKS endpoints
nock(issuer)
.get('/.well-known/openid-configuration')
.reply(200, { jwks_uri: `${issuer}${jwksPath}` })
nock(issuer).get(jwksPath).reply(200, jwks)
// Mock OIDC token endpoint for populating the provenance
nock(issuer).get(tokenPath).query({ audience }).reply(200, { value: jwt })
})
afterEach(() => {
@@ -75,14 +27,131 @@ describe('main', () => {
process.env = originalEnv
})
it('successfully run main', async () => {
// Run the main function
await main.run()
describe('when the default OIDC issuer is used', () => {
const issuer = 'https://token.actions.githubusercontent.com'
const audience = 'nobody'
const jwksPath = '/.well-known/jwks.json'
const tokenPath = '/token'
// Verify that outputs were set correctly
expect(setOutputMock).toHaveBeenCalledTimes(2)
const claims = {
iss: issuer,
aud: 'nobody',
repository: 'owner/repo',
ref: 'refs/heads/main',
sha: 'babca52ab0c93ae16539e5923cb0d7403b9a093b',
workflow_ref: 'owner/repo/.github/workflows/main.yml@main',
job_workflow_ref: 'owner/shared/.github/workflows/build.yml@main',
event_name: 'push',
repository_id: 'repo-id',
repository_owner_id: 'owner-id',
run_id: 'run-id',
run_attempt: 'run-attempt',
runner_environment: 'github-hosted'
}
expect(outputs['predicate']).toMatchSnapshot()
expect(outputs['predicate-type']).toBe('https://slsa.dev/provenance/v1')
beforeEach(async () => {
process.env = {
...originalEnv,
ACTIONS_ID_TOKEN_REQUEST_URL: `${issuer}${tokenPath}?`,
ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token',
GITHUB_SERVER_URL: 'https://github.com',
GITHUB_REPOSITORY: claims.repository
}
// Generate JWT signing key
const key = await jose.generateKeyPair('PS256')
// Create JWK, JWKS, and JWT
const kid = '12345'
const jwk = await jose.exportJWK(key.publicKey)
const jwks = { keys: [{ ...jwk, kid }] }
const jwt = await new jose.SignJWT(claims)
.setProtectedHeader({ alg: 'PS256', kid })
.sign(key.privateKey)
// Mock OpenID configuration and JWKS endpoints
nock(issuer)
.get('/.well-known/openid-configuration')
.reply(200, { jwks_uri: `${issuer}${jwksPath}` })
nock(issuer).get(jwksPath).reply(200, jwks)
// Mock OIDC token endpoint for populating the provenance
nock(issuer).get(tokenPath).query({ audience }).reply(200, { value: jwt })
})
it('successfully run main', async () => {
// Run the main function
await main.run()
// Verify that outputs were set correctly
expect(setOutputMock).toHaveBeenCalledTimes(2)
expect(outputs['predicate']).toMatchSnapshot()
expect(outputs['predicate-type']).toBe('https://slsa.dev/provenance/v1')
})
})
describe('when a non-default OIDC issuer is used', () => {
const issuer = 'https://token.actions.example-01.ghe.com'
const audience = 'nobody'
const jwksPath = '/.well-known/jwks.json'
const tokenPath = '/token'
const claims = {
iss: issuer,
aud: 'nobody',
repository: 'owner/repo',
ref: 'refs/heads/main',
sha: 'babca52ab0c93ae16539e5923cb0d7403b9a093b',
workflow_ref: 'owner/repo/.github/workflows/main.yml@main',
job_workflow_ref: 'owner/shared/.github/workflows/build.yml@main',
event_name: 'push',
repository_id: 'repo-id',
repository_owner_id: 'owner-id',
run_id: 'run-id',
run_attempt: 'run-attempt',
runner_environment: 'github-hosted'
}
beforeEach(async () => {
process.env = {
...originalEnv,
ACTIONS_ID_TOKEN_REQUEST_URL: `${issuer}${tokenPath}?`,
ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token',
GITHUB_SERVER_URL: 'https://example-01.ghe.com',
GITHUB_REPOSITORY: claims.repository
}
// Generate JWT signing key
const key = await jose.generateKeyPair('PS256')
// Create JWK, JWKS, and JWT
const kid = '12345'
const jwk = await jose.exportJWK(key.publicKey)
const jwks = { keys: [{ ...jwk, kid }] }
const jwt = await new jose.SignJWT(claims)
.setProtectedHeader({ alg: 'PS256', kid })
.sign(key.privateKey)
// Mock OpenID configuration and JWKS endpoints
nock(issuer)
.get('/.well-known/openid-configuration')
.reply(200, { jwks_uri: `${issuer}${jwksPath}` })
nock(issuer).get(jwksPath).reply(200, jwks)
// Mock OIDC token endpoint for populating the provenance
nock(issuer).get(tokenPath).query({ audience }).reply(200, { value: jwt })
})
it('successfully run main', async () => {
// Run the main function
await main.run()
// Verify that outputs were set correctly
expect(setOutputMock).toHaveBeenCalledTimes(2)
expect(outputs['predicate']).toMatchSnapshot()
expect(outputs['predicate-type']).toBe('https://slsa.dev/provenance/v1')
})
})
})
+9 -2
View File
@@ -30,6 +30,12 @@ inputs:
and that the "subject-digest" parameter be specified. Defaults to false.
default: false
required: false
show-summary:
description: >
Whether to attach a list of generated attestations to the workflow run
summary page. Defaults to true.
default: true
required: false
github-token:
description: >
The GitHub token used to make authenticated API requests.
@@ -44,9 +50,9 @@ outputs:
runs:
using: 'composite'
steps:
- uses: actions/attest-build-provenance/predicate@test
- uses: actions/attest-build-provenance/predicate@9ff3713ef183e028b07415e8a740b634c054a663 # predicate@1.1.1
id: generate-build-provenance-predicate
- uses: actions/attest@7305951e905fb742188aa16c1d23409b13565e26 # v1.3.3
- uses: actions/attest@2da0b136720d14f01f4dbeeafd1d5a4d76cbe21d # v1.4.0
id: attest
with:
subject-path: ${{ inputs.subject-path }}
@@ -55,4 +61,5 @@ runs:
predicate-type: ${{ steps.generate-build-provenance-predicate.outputs.predicate-type }}
predicate: ${{ steps.generate-build-provenance-predicate.outputs.predicate }}
push-to-registry: ${{ inputs.push-to-registry }}
show-summary: ${{ inputs.show-summary }}
github-token: ${{ inputs.github-token }}
Generated Vendored
+48254 -71768
View File
File diff suppressed because one or more lines are too long
Generated Vendored
+1 -1
View File
@@ -2389,7 +2389,7 @@ supports-color
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+917 -95
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "actions/attest-build-provenance",
"description": "Generate signed build provenance attestations",
"version": "1.1.0",
"version": "1.1.2",
"author": "",
"private": true,
"homepage": "https://github.com/actions/attest-build-provenance",
@@ -70,18 +70,18 @@
]
},
"dependencies": {
"@actions/attest": "file:../toolkit/packages/attest",
"@actions/attest": "^1.3.1",
"@actions/core": "^1.10.1"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/node": "^22.0.0",
"@types/node": "^22.1.0",
"@typescript-eslint/eslint-plugin": "^7.17.0",
"@typescript-eslint/parser": "^7.17.0",
"@typescript-eslint/parser": "^7.18.0",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0",
"eslint-plugin-github": "^5.0.1",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-jest": "^28.7.0",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-prettier": "^5.2.1",
"jest": "^29.7.0",
@@ -90,7 +90,7 @@
"nock": "^13.5.4",
"prettier": "^3.3.3",
"prettier-eslint": "^16.3.0",
"ts-jest": "^29.2.3",
"ts-jest": "^29.2.4",
"typescript": "^5.5.4"
}
}
+26 -1
View File
@@ -1,14 +1,21 @@
import { buildSLSAProvenancePredicate } from '@actions/attest'
import * as core from '@actions/core'
const VALID_SERVER_URLS = [
'https://github.com',
new RegExp('^https://[a-z0-9-]+\\.ghe\\.com$')
] as const
/**
* The main function for the action.
* @returns {Promise<void>} Resolves when the action is complete.
*/
export async function run(): Promise<void> {
try {
const issuer = getIssuer()
// Calculate subject from inputs and generate provenance
const predicate = await buildSLSAProvenancePredicate()
const predicate = await buildSLSAProvenancePredicate(issuer)
core.setOutput('predicate', predicate.params)
core.setOutput('predicate-type', predicate.type)
@@ -18,3 +25,21 @@ export async function run(): Promise<void> {
core.setFailed(error.message)
}
}
// Derive the current OIDC issuer based on the server URL
function getIssuer(): string {
const serverURL = process.env.GITHUB_SERVER_URL || 'https://github.com'
// Ensure the server URL is a valid GitHub server URL
if (!VALID_SERVER_URLS.some(valid_url => serverURL.match(valid_url))) {
throw new Error(`Invalid server URL: ${serverURL}`)
}
let host = new URL(serverURL).hostname
if (host === 'github.com') {
host = 'githubusercontent.com'
}
return `https://token.actions.${host}`
}