diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts new file mode 100644 index 0000000..34a4dfe --- /dev/null +++ b/__tests__/index.test.ts @@ -0,0 +1,17 @@ +/** + * Unit tests for the action's entrypoint, src/index.ts + */ + +import * as main from '../src/main' + +// Mock the action's entrypoint +const runMock = jest.spyOn(main, 'run').mockImplementation() + +describe('index', () => { + it('calls run when imported', async () => { + // eslint-disable-next-line @typescript-eslint/no-require-imports + require('../src/index') + + expect(runMock).toHaveBeenCalled() + }) +}) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts new file mode 100644 index 0000000..5ccc623 --- /dev/null +++ b/__tests__/main.test.ts @@ -0,0 +1,273 @@ +/** + * Unit tests for the action's main functionality, src/main.ts + * + * These should be run as if the action was called from a workflow. + * Specifically, the inputs listed in `action.yml` should be set as environment + * variables following the pattern `INPUT_`. + */ + +import * as core from '@actions/core' +import * as github from '@actions/github' +import { mockFulcio, mockRekor, mockTSA } from '@sigstore/mock' +import nock from 'nock' +import { SEARCH_PUBLIC_GOOD_URL } from '../src/endpoints' +import * as main from '../src/main' + +// Mock the GitHub Actions core library +const infoMock = jest.spyOn(core, 'info') +const startGroupMock = jest.spyOn(core, 'startGroup') +const getInputMock = jest.spyOn(core, 'getInput') +const getBooleanInputMock = jest.spyOn(core, 'getBooleanInput') +const setOutputMock = jest.spyOn(core, 'setOutput') +const setFailedMock = jest.spyOn(core, 'setFailed') + +const summaryWriteMock = jest.spyOn(core.summary, 'write') +summaryWriteMock.mockImplementation(async () => Promise.resolve(core.summary)) + +// Mock the action's main function +const runMock = jest.spyOn(main, 'run') + +describe('action', () => { + // Capture original environment variables and GitHub context so we can restore + // them after each test + const originalEnv = process.env + const originalContext = { ...github.context } + + // Fake an OIDC token + const oidcSubject = 'foo@bar.com' + const oidcPayload = { sub: oidcSubject, iss: '' } + const oidcToken = `.${Buffer.from(JSON.stringify(oidcPayload)).toString( + 'base64' + )}.}` + + const subjectName = 'subject' + const subjectDigest = + 'sha256:7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32' + const predicate = '{}' + const predicateType = 'https://in-toto.io/attestation/release/v0.1' + + const attestationID = '1234567890' + + beforeEach(() => { + jest.clearAllMocks() + + // Mock OIDC token endpoint + const tokenURL = 'https://token.url' + + nock(tokenURL) + .get('/') + .query({ audience: 'sigstore' }) + .reply(200, { value: oidcToken }) + + nock('https://api.github.com') + .post(/^\/repos\/.*\/.*\/attestations$/) + .reply(201, { id: attestationID }) + + process.env = { + ...originalEnv, + ACTIONS_ID_TOKEN_REQUEST_URL: tokenURL, + ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token', + RUNNER_TEMP: process.env.RUNNER_TEMP || '/tmp' + } + }) + + afterEach(() => { + // Restore the original environment + process.env = originalEnv + + // Restore the original github.context + setGHContext(originalContext) + }) + + describe('when ACTIONS_ID_TOKEN_REQUEST_URL is not set', () => { + const inputs = { + 'subject-digest': subjectDigest, + 'subject-name': subjectName, + 'predicate-type': predicateType, + predicate, + 'github-token': 'gh-token' + } + + beforeEach(() => { + // Nullify the OIDC token URL + process.env.ACTIONS_ID_TOKEN_REQUEST_URL = '' + + getInputMock.mockImplementation(mockInput(inputs)) + getBooleanInputMock.mockImplementation(() => false) + }) + + it('sets a failed status', async () => { + await main.run() + + expect(runMock).toHaveReturned() + expect(setFailedMock).toHaveBeenCalledWith( + expect.stringMatching(/missing "id-token" permission/) + ) + }) + }) + + describe('when no inputs are provided', () => { + beforeEach(() => { + getInputMock.mockImplementation(() => '') + }) + + it('sets a failed status', async () => { + await main.run() + + expect(runMock).toHaveReturned() + expect(setFailedMock).toHaveBeenCalledWith( + expect.stringMatching( + /one of subject-path or subject-digest must be provided/i + ) + ) + }) + }) + + describe('when the repository is private', () => { + const inputs = { + 'subject-digest': subjectDigest, + 'subject-name': subjectName, + 'predicate-type': predicateType, + predicate, + 'github-token': 'gh-token' + } + + beforeEach(async () => { + // Set the GH context with private repository visibility and a repo owner. + setGHContext({ + payload: { repository: { visibility: 'private' } }, + repo: { owner: 'foo', repo: 'bar' } + }) + + getInputMock.mockImplementation(mockInput(inputs)) + getBooleanInputMock.mockImplementation(() => false) + + await mockFulcio({ + baseURL: 'https://fulcio.githubapp.com', + strict: false + }) + await mockTSA({ baseURL: 'https://timestamp.githubapp.com' }) + }) + + it('invokes the action w/o error', async () => { + await main.run() + + expect(runMock).toHaveReturned() + expect(setFailedMock).not.toHaveBeenCalledWith() + expect(infoMock).toHaveBeenNthCalledWith( + 1, + expect.stringMatching( + `Attestation created for ${subjectName}@${subjectDigest}` + ) + ) + expect(startGroupMock).toHaveBeenNthCalledWith( + 1, + expect.stringMatching('GitHub Sigstore') + ) + expect(infoMock).toHaveBeenNthCalledWith( + 2, + expect.stringMatching('-----BEGIN CERTIFICATE-----') + ) + expect(infoMock).toHaveBeenNthCalledWith( + 3, + expect.stringMatching(/attestation uploaded/i) + ) + expect(infoMock).toHaveBeenNthCalledWith( + 4, + expect.stringMatching(attestationID) + ) + expect(setOutputMock).toHaveBeenNthCalledWith( + 1, + 'bundle-path', + expect.stringMatching('attestation.jsonl') + ) + expect(setFailedMock).not.toHaveBeenCalled() + }) + }) + + describe('when the repository is public', () => { + const inputs = { + 'subject-digest': subjectDigest, + 'subject-name': subjectName, + 'predicate-type': predicateType, + predicate, + 'github-token': 'gh-token' + } + + beforeEach(async () => { + // Set the GH context with public repository visibility and a repo owner. + setGHContext({ + payload: { repository: { visibility: 'public' } }, + repo: { owner: 'foo', repo: 'bar' } + }) + + // Mock the action's inputs + getInputMock.mockImplementation(mockInput(inputs)) + getBooleanInputMock.mockImplementation(() => false) + + await mockFulcio({ + baseURL: 'https://fulcio.sigstore.dev', + strict: false + }) + await mockRekor({ baseURL: 'https://rekor.sigstore.dev' }) + }) + + it('invokes the action w/o error', async () => { + await main.run() + + expect(runMock).toHaveReturned() + expect(setFailedMock).not.toHaveBeenCalled() + expect(infoMock).toHaveBeenNthCalledWith( + 1, + expect.stringMatching( + `Attestation created for ${subjectName}@${subjectDigest}` + ) + ) + expect(startGroupMock).toHaveBeenNthCalledWith( + 1, + expect.stringMatching('Public Good Sigstore') + ) + expect(infoMock).toHaveBeenNthCalledWith( + 2, + expect.stringMatching('-----BEGIN CERTIFICATE-----') + ) + expect(infoMock).toHaveBeenNthCalledWith( + 3, + expect.stringMatching(/signature uploaded/i) + ) + expect(infoMock).toHaveBeenNthCalledWith( + 4, + expect.stringMatching(SEARCH_PUBLIC_GOOD_URL) + ) + expect(infoMock).toHaveBeenNthCalledWith( + 5, + expect.stringMatching(/attestation uploaded/i) + ) + expect(infoMock).toHaveBeenNthCalledWith( + 6, + expect.stringMatching(attestationID) + ) + expect(setOutputMock).toHaveBeenNthCalledWith( + 1, + 'bundle-path', + expect.stringMatching('attestation.jsonl') + ) + expect(setFailedMock).not.toHaveBeenCalled() + }) + }) +}) + +function mockInput(inputs: Record): typeof core.getInput { + return (name: string): string => { + if (name in inputs) { + return inputs[name] + } + return '' + } +} + +// Stubbing the GitHub context is a bit tricky. We need to use +// `Object.defineProperty` because `github.context` is read-only. +function setGHContext(context: object): void { + Object.defineProperty(github, 'context', { value: context }) +} diff --git a/dist/index.js b/dist/index.js index a05e465..1190dca 100644 --- a/dist/index.js +++ b/dist/index.js @@ -64928,12 +64928,8 @@ function wrappy (fn, cb) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.TSA_INTERNAL_URL = exports.FULCIO_INTERNAL_URL = exports.SEARCH_PUBLIC_GOOD_URL = exports.REKOR_PUBLIC_GOOD_URL = exports.FULCIO_PUBLIC_GOOD_URL = void 0; -exports.FULCIO_PUBLIC_GOOD_URL = 'https://fulcio.sigstore.dev'; -exports.REKOR_PUBLIC_GOOD_URL = 'https://rekor.sigstore.dev'; +exports.SEARCH_PUBLIC_GOOD_URL = void 0; exports.SEARCH_PUBLIC_GOOD_URL = 'https://search.sigstore.dev'; -exports.FULCIO_INTERNAL_URL = 'https://fulcio.githubapp.com'; -exports.TSA_INTERNAL_URL = 'https://timestamp.githubapp.com'; /***/ }), @@ -64985,14 +64981,6 @@ const subject_1 = __nccwpck_require__(5206); const COLOR_CYAN = '\x1B[36m'; const COLOR_DEFAULT = '\x1B[39m'; const ATTESTATION_FILE_NAME = 'attestation.jsonl'; -const SIGSTORE_PUBLIC_GOOD_ENDPOINTS = { - fulcioURL: endpoints_1.FULCIO_PUBLIC_GOOD_URL, - rekorURL: endpoints_1.REKOR_PUBLIC_GOOD_URL -}; -const SIGSTORE_INTERNAL_ENDPOINTS = { - fulcioURL: endpoints_1.FULCIO_INTERNAL_URL, - tsaServerURL: endpoints_1.TSA_INTERNAL_URL -}; /** * The main function for the action. * @returns {Promise} Resolves when the action is complete. @@ -65001,18 +64989,21 @@ async function run() { // Provenance visibility will be public ONLY if we can confirm that the // repository is public AND the undocumented "private-signing" arg is NOT set. // Otherwise, it will be private. - const endpoints = github.context.payload.repository?.visibility === 'public' && + const sigstoreInstance = github.context.payload.repository?.visibility === 'public' && core.getInput('private-signing') !== 'true' - ? SIGSTORE_PUBLIC_GOOD_ENDPOINTS - : SIGSTORE_INTERNAL_ENDPOINTS; + ? 'public-good' + : 'github'; try { + if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) { + throw new Error('missing "id-token" permission. Please add "permissions: id-token: write" to your workflow.'); + } // Calculate subject from inputs and generate provenance const subjects = await (0, subject_1.subjectFromInputs)(); const predicate = (0, predicate_1.predicateFromInputs)(); const outputPath = path_1.default.join(tempDir(), ATTESTATION_FILE_NAME); // Generate attestations for each subject serially for (const subject of subjects) { - const att = await createAttestation(subject, predicate, endpoints); + const att = await createAttestation(subject, predicate, sigstoreInstance); // Write attestation bundle to output file fs_1.default.writeFileSync(outputPath, JSON.stringify(att.bundle) + os_1.default.EOL, { encoding: 'utf-8', @@ -65039,17 +65030,19 @@ async function run() { } } exports.run = run; -const createAttestation = async (subject, predicate, endpoints) => { +const createAttestation = async (subject, predicate, sigstoreInstance) => { // Sign provenance w/ Sigstore const attestation = await (0, attest_1.attest)({ - ...endpoints, subjectName: subject.name, subjectDigest: subject.digest, predicateType: predicate.type, predicate: predicate.params, + sigstore: sigstoreInstance, token: core.getInput('github-token') }); - core.startGroup(highlight(`Attestation signed using ephemeral certificate from ${endpoints.fulcioURL}`)); + core.info(`Attestation created for ${subject.name}@${subjectDigest(subject)}`); + const instanceName = sigstoreInstance === 'public-good' ? 'Public Good' : 'GitHub'; + core.startGroup(highlight(`Attestation signed using certificate from ${instanceName} Sigstore instance`)); core.info(attestation.certificate); core.endGroup(); if (attestation.tlogID) { @@ -65080,6 +65073,7 @@ const createAttestation = async (subject, predicate, endpoints) => { const highlight = (str) => `${COLOR_CYAN}${str}${COLOR_DEFAULT}`; const tempDir = () => { const basePath = process.env['RUNNER_TEMP']; + /* istanbul ignore if */ if (!basePath) { throw new Error('Missing RUNNER_TEMP environment variable'); } diff --git a/package-lock.json b/package-lock.json index c315ff3..a3d878c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@sigstore/oci": "^0.1.0" }, "devDependencies": { + "@sigstore/mock": "^0.6.5", "@types/jest": "^29.5.12", "@types/make-fetch-happen": "^10.0.4", "@types/node": "^20.11.21", @@ -27,6 +28,7 @@ "eslint-plugin-prettier": "^5.1.3", "jest": "^29.7.0", "js-yaml": "^4.1.0", + "nock": "^13.5.4", "prettier": "^3.2.5", "prettier-eslint": "^16.3.0", "ts-jest": "^29.1.2", @@ -1464,6 +1466,180 @@ "@octokit/openapi-types": "^19.1.0" } }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.3.8.tgz", + "integrity": "sha512-Wtk9R7yQxGaIaawHorWKP2OOOm/RZzamOmSWwaqGphIuU6TcKYih0slL6asZlSSZtVoYTrBfrddSOD/jTu9vuQ==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "@peculiar/asn1-x509-attr": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.3.8.tgz", + "integrity": "sha512-ZmAaP2hfzgIGdMLcot8gHTykzoI+X/S53x1xoGbTmratETIaAbSWMiPGvZmXRA0SNEIydpMkzYtq4fQBxN1u1w==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.3.8.tgz", + "integrity": "sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.3.8.tgz", + "integrity": "sha512-XhdnCVznMmSmgy68B9pVxiZ1XkKoE1BjO4Hv+eUGiY1pM14msLsFZ3N7K46SoITIVZLq92kKkXpGiTfRjlNLyg==", + "dev": true, + "dependencies": { + "@peculiar/asn1-cms": "^2.3.8", + "@peculiar/asn1-pkcs8": "^2.3.8", + "@peculiar/asn1-rsa": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.3.8.tgz", + "integrity": "sha512-rL8k2x59v8lZiwLRqdMMmOJ30GHt6yuHISFIuuWivWjAJjnxzZBVzMTQ72sknX5MeTSSvGwPmEFk2/N8+UztFQ==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.3.8.tgz", + "integrity": "sha512-+nONq5tcK7vm3qdY7ZKoSQGQjhJYMJbwJGbXLFOhmqsFIxEWyQPHyV99+wshOjpOjg0wUSSkEEzX2hx5P6EKeQ==", + "dev": true, + "dependencies": { + "@peculiar/asn1-cms": "^2.3.8", + "@peculiar/asn1-pfx": "^2.3.8", + "@peculiar/asn1-pkcs8": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "@peculiar/asn1-x509-attr": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.3.8.tgz", + "integrity": "sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", + "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "dev": true, + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.8.tgz", + "integrity": "sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "asn1js": "^3.0.5", + "ipaddr.js": "^2.1.0", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.3.8.tgz", + "integrity": "sha512-4Z8mSN95MOuX04Aku9BUyMdsMKtVQUqWnr627IheiWnwFoheUhX3R4Y2zh23M7m80r4/WG8MOAckRKc77IRv6g==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", + "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.7.8" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.9.7.tgz", + "integrity": "sha512-O+fR1ge6U8upO52q5b3d4tF4SxUdK4IQ0y++Z/Wlqq+ySZUf+deHnbMlDB1YZsIQ/DXU0i5M7Y1DyF5kwpXouQ==", + "dev": true, + "dependencies": { + "@peculiar/asn1-cms": "^2.3.8", + "@peculiar/asn1-csr": "^2.3.8", + "@peculiar/asn1-ecc": "^2.3.8", + "@peculiar/asn1-pkcs9": "^2.3.8", + "@peculiar/asn1-rsa": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "pvtsutils": "^1.3.5", + "reflect-metadata": "^0.2.1", + "tslib": "^2.6.2", + "tsyringe": "^4.8.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "license": "MIT", @@ -1500,6 +1676,27 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@sigstore/mock": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@sigstore/mock/-/mock-0.6.5.tgz", + "integrity": "sha512-mMWj6SNmM+yGVZ9Qk2sDsVPZuwoPaLGzMFpVGdNeSYNC4HtzdrCihKYxJ+VSo0tdh+X6HwOUKaVtkRsjpY1ZbQ==", + "dev": true, + "dependencies": { + "@peculiar/webcrypto": "^1.4.5", + "@peculiar/x509": "^1.9.7", + "@sigstore/protobuf-specs": "^0.3.0", + "asn1js": "^3.0.5", + "bytestreamjs": "^2.0.1", + "canonicalize": "^2.0.0", + "jose": "^5.2.2", + "nock": "^13.5.1", + "pkijs": "^3.0.15", + "pvutils": "^1.1.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/@sigstore/oci": { "version": "0.1.0", "license": "Apache-2.0", @@ -2169,6 +2366,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/ast-types-flow": { "version": "0.0.7", "dev": true, @@ -2397,6 +2608,15 @@ "dev": true, "license": "MIT" }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/cacache": { "version": "18.0.2", "license": "ISC", @@ -2512,6 +2732,12 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canonicalize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-2.0.0.tgz", + "integrity": "sha512-ulDEYPv7asdKvqahuAY35c1selLdzDwHqugK92hfkzvlDCwXRRelDkR+Er33md/PtnpqHemgkuDPanZ4fiYZ8w==", + "dev": true + }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -4225,6 +4451,15 @@ "version": "1.1.3", "license": "BSD-3-Clause" }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/is-array-buffer": { "version": "3.0.2", "dev": true, @@ -5087,6 +5322,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jose": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.2.tgz", + "integrity": "sha512-/WByRr4jDcsKlvMd1dRJnPfS1GVO3WuKyaurJ/vvXcOaUQO8rnNObCQMlv/5uCceVQIq5Q4WLF44ohsdiTohdg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "dev": true, @@ -5138,6 +5382,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "dev": true, @@ -5642,6 +5892,20 @@ "node": ">= 0.6" } }, + "node_modules/nock": { + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.4.tgz", + "integrity": "sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "node_modules/node-int64": { "version": "0.4.0", "dev": true, @@ -6014,6 +6278,22 @@ "node": ">=8" } }, + "node_modules/pkijs": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.0.15.tgz", + "integrity": "sha512-n7nAl9JpqdeQsjy+rPmswkmZ3oO/Fu5uN9me45PPQVdWjd0X7HKfL8+HYwfxihqoDSSPUIajkOcqFxEUxMqhwQ==", + "dev": true, + "dependencies": { + "asn1js": "^3.0.5", + "bytestreamjs": "^2.0.0", + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -6128,6 +6408,15 @@ "node": ">= 6" } }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/punycode": { "version": "2.3.1", "dev": true, @@ -6151,6 +6440,24 @@ ], "license": "MIT" }, + "node_modules/pvtsutils": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", + "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "dev": true, + "dependencies": { + "tslib": "^2.6.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "dev": true, @@ -6175,6 +6482,12 @@ "dev": true, "license": "MIT" }, + "node_modules/reflect-metadata": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", + "dev": true + }, "node_modules/regenerator-runtime": { "version": "0.14.0", "dev": true, @@ -6881,6 +7194,24 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsyringe": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz", + "integrity": "sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==", + "dev": true, + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/tunnel": { "version": "0.0.6", "license": "MIT", @@ -7137,6 +7468,19 @@ "makeerror": "1.0.12" } }, + "node_modules/webcrypto-core": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", + "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, "node_modules/which": { "version": "2.0.2", "license": "ISC", @@ -8227,6 +8571,174 @@ "@octokit/openapi-types": "^19.1.0" } }, + "@peculiar/asn1-cms": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.3.8.tgz", + "integrity": "sha512-Wtk9R7yQxGaIaawHorWKP2OOOm/RZzamOmSWwaqGphIuU6TcKYih0slL6asZlSSZtVoYTrBfrddSOD/jTu9vuQ==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "@peculiar/asn1-x509-attr": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-csr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.3.8.tgz", + "integrity": "sha512-ZmAaP2hfzgIGdMLcot8gHTykzoI+X/S53x1xoGbTmratETIaAbSWMiPGvZmXRA0SNEIydpMkzYtq4fQBxN1u1w==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-ecc": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.3.8.tgz", + "integrity": "sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-pfx": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.3.8.tgz", + "integrity": "sha512-XhdnCVznMmSmgy68B9pVxiZ1XkKoE1BjO4Hv+eUGiY1pM14msLsFZ3N7K46SoITIVZLq92kKkXpGiTfRjlNLyg==", + "dev": true, + "requires": { + "@peculiar/asn1-cms": "^2.3.8", + "@peculiar/asn1-pkcs8": "^2.3.8", + "@peculiar/asn1-rsa": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-pkcs8": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.3.8.tgz", + "integrity": "sha512-rL8k2x59v8lZiwLRqdMMmOJ30GHt6yuHISFIuuWivWjAJjnxzZBVzMTQ72sknX5MeTSSvGwPmEFk2/N8+UztFQ==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-pkcs9": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.3.8.tgz", + "integrity": "sha512-+nONq5tcK7vm3qdY7ZKoSQGQjhJYMJbwJGbXLFOhmqsFIxEWyQPHyV99+wshOjpOjg0wUSSkEEzX2hx5P6EKeQ==", + "dev": true, + "requires": { + "@peculiar/asn1-cms": "^2.3.8", + "@peculiar/asn1-pfx": "^2.3.8", + "@peculiar/asn1-pkcs8": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "@peculiar/asn1-x509-attr": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-rsa": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.3.8.tgz", + "integrity": "sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-schema": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", + "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "dev": true, + "requires": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-x509": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.8.tgz", + "integrity": "sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "asn1js": "^3.0.5", + "ipaddr.js": "^2.1.0", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/asn1-x509-attr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.3.8.tgz", + "integrity": "sha512-4Z8mSN95MOuX04Aku9BUyMdsMKtVQUqWnr627IheiWnwFoheUhX3R4Y2zh23M7m80r4/WG8MOAckRKc77IRv6g==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5", + "tslib": "^2.6.2" + } + }, + "@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "requires": { + "tslib": "^2.0.0" + } + }, + "@peculiar/webcrypto": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", + "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.7.8" + } + }, + "@peculiar/x509": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.9.7.tgz", + "integrity": "sha512-O+fR1ge6U8upO52q5b3d4tF4SxUdK4IQ0y++Z/Wlqq+ySZUf+deHnbMlDB1YZsIQ/DXU0i5M7Y1DyF5kwpXouQ==", + "dev": true, + "requires": { + "@peculiar/asn1-cms": "^2.3.8", + "@peculiar/asn1-csr": "^2.3.8", + "@peculiar/asn1-ecc": "^2.3.8", + "@peculiar/asn1-pkcs9": "^2.3.8", + "@peculiar/asn1-rsa": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "pvtsutils": "^1.3.5", + "reflect-metadata": "^0.2.1", + "tslib": "^2.6.2", + "tsyringe": "^4.8.0" + } + }, "@pkgjs/parseargs": { "version": "0.11.0", "optional": true @@ -8244,6 +8756,24 @@ "@sigstore/core": { "version": "1.0.0" }, + "@sigstore/mock": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@sigstore/mock/-/mock-0.6.5.tgz", + "integrity": "sha512-mMWj6SNmM+yGVZ9Qk2sDsVPZuwoPaLGzMFpVGdNeSYNC4HtzdrCihKYxJ+VSo0tdh+X6HwOUKaVtkRsjpY1ZbQ==", + "dev": true, + "requires": { + "@peculiar/webcrypto": "^1.4.5", + "@peculiar/x509": "^1.9.7", + "@sigstore/protobuf-specs": "^0.3.0", + "asn1js": "^3.0.5", + "bytestreamjs": "^2.0.1", + "canonicalize": "^2.0.0", + "jose": "^5.2.2", + "nock": "^13.5.1", + "pkijs": "^3.0.15", + "pvutils": "^1.1.3" + } + }, "@sigstore/oci": { "version": "0.1.0", "requires": { @@ -8674,6 +9204,17 @@ "is-shared-array-buffer": "^1.0.2" } }, + "asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, + "requires": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + } + }, "ast-types-flow": { "version": "0.0.7", "dev": true @@ -8822,6 +9363,12 @@ "version": "1.1.2", "dev": true }, + "bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true + }, "cacache": { "version": "18.0.2", "requires": { @@ -8886,6 +9433,12 @@ "version": "1.0.30001524", "dev": true }, + "canonicalize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-2.0.0.tgz", + "integrity": "sha512-ulDEYPv7asdKvqahuAY35c1selLdzDwHqugK92hfkzvlDCwXRRelDkR+Er33md/PtnpqHemgkuDPanZ4fiYZ8w==", + "dev": true + }, "chalk": { "version": "4.1.2", "dev": true, @@ -9940,6 +10493,12 @@ } } }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true + }, "is-array-buffer": { "version": "3.0.2", "dev": true, @@ -10498,6 +11057,12 @@ } } }, + "jose": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.2.tgz", + "integrity": "sha512-/WByRr4jDcsKlvMd1dRJnPfS1GVO3WuKyaurJ/vvXcOaUQO8rnNObCQMlv/5uCceVQIq5Q4WLF44ohsdiTohdg==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "dev": true @@ -10532,6 +11097,12 @@ "version": "1.0.1", "dev": true }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, "json5": { "version": "2.2.3", "dev": true @@ -10859,6 +11430,17 @@ "negotiator": { "version": "0.6.3" }, + "nock": { + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.4.tgz", + "integrity": "sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + } + }, "node-int64": { "version": "0.4.0", "dev": true @@ -11080,6 +11662,19 @@ } } }, + "pkijs": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.0.15.tgz", + "integrity": "sha512-n7nAl9JpqdeQsjy+rPmswkmZ3oO/Fu5uN9me45PPQVdWjd0X7HKfL8+HYwfxihqoDSSPUIajkOcqFxEUxMqhwQ==", + "dev": true, + "requires": { + "asn1js": "^3.0.5", + "bytestreamjs": "^2.0.0", + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + } + }, "prelude-ls": { "version": "1.2.1", "dev": true @@ -11143,6 +11738,12 @@ "sisteransi": "^1.0.5" } }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, "punycode": { "version": "2.3.1", "dev": true @@ -11151,6 +11752,21 @@ "version": "6.0.3", "dev": true }, + "pvtsutils": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", + "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "dev": true, + "requires": { + "tslib": "^2.6.1" + } + }, + "pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true + }, "queue-microtask": { "version": "1.2.3", "dev": true @@ -11159,6 +11775,12 @@ "version": "18.2.0", "dev": true }, + "reflect-metadata": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", + "dev": true + }, "regenerator-runtime": { "version": "0.14.0", "dev": true @@ -11582,6 +12204,23 @@ } } }, + "tsyringe": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz", + "integrity": "sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==", + "dev": true, + "requires": { + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "tunnel": { "version": "0.0.6" }, @@ -11731,6 +12370,19 @@ "makeerror": "1.0.12" } }, + "webcrypto-core": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", + "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, "which": { "version": "2.0.2", "requires": { diff --git a/package.json b/package.json index 2ea8dc1..08959e6 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "@sigstore/oci": "^0.1.0" }, "devDependencies": { + "@sigstore/mock": "^0.6.5", "@types/jest": "^29.5.12", "@types/make-fetch-happen": "^10.0.4", "@types/node": "^20.11.21", @@ -83,6 +84,7 @@ "eslint-plugin-prettier": "^5.1.3", "jest": "^29.7.0", "js-yaml": "^4.1.0", + "nock": "^13.5.4", "prettier": "^3.2.5", "prettier-eslint": "^16.3.0", "ts-jest": "^29.1.2", diff --git a/src/endpoints.ts b/src/endpoints.ts index b821f1f..0793479 100644 --- a/src/endpoints.ts +++ b/src/endpoints.ts @@ -1,6 +1 @@ -export const FULCIO_PUBLIC_GOOD_URL = 'https://fulcio.sigstore.dev' -export const REKOR_PUBLIC_GOOD_URL = 'https://rekor.sigstore.dev' export const SEARCH_PUBLIC_GOOD_URL = 'https://search.sigstore.dev' - -export const FULCIO_INTERNAL_URL = 'https://fulcio.githubapp.com' -export const TSA_INTERNAL_URL = 'https://timestamp.githubapp.com' diff --git a/src/main.ts b/src/main.ts index 701c8da..486ba7b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,36 +6,16 @@ import { attachArtifactToImage, getRegistryCredentials } from '@sigstore/oci' import fs from 'fs' import os from 'os' import path from 'path' -import { - FULCIO_INTERNAL_URL, - FULCIO_PUBLIC_GOOD_URL, - REKOR_PUBLIC_GOOD_URL, - SEARCH_PUBLIC_GOOD_URL, - TSA_INTERNAL_URL -} from './endpoints' +import { SEARCH_PUBLIC_GOOD_URL } from './endpoints' import { predicateFromInputs } from './predicate' import { subjectFromInputs } from './subject' -type Endpoints = { - fulcioURL: string - rekorURL?: string - tsaServerURL?: string -} +type SigstoreInstance = 'public-good' | 'github' const COLOR_CYAN = '\x1B[36m' const COLOR_DEFAULT = '\x1B[39m' const ATTESTATION_FILE_NAME = 'attestation.jsonl' -const SIGSTORE_PUBLIC_GOOD_ENDPOINTS: Endpoints = { - fulcioURL: FULCIO_PUBLIC_GOOD_URL, - rekorURL: REKOR_PUBLIC_GOOD_URL -} - -const SIGSTORE_INTERNAL_ENDPOINTS: Endpoints = { - fulcioURL: FULCIO_INTERNAL_URL, - tsaServerURL: TSA_INTERNAL_URL -} - /** * The main function for the action. * @returns {Promise} Resolves when the action is complete. @@ -44,13 +24,19 @@ export async function run(): Promise { // Provenance visibility will be public ONLY if we can confirm that the // repository is public AND the undocumented "private-signing" arg is NOT set. // Otherwise, it will be private. - const endpoints = + const sigstoreInstance: SigstoreInstance = github.context.payload.repository?.visibility === 'public' && core.getInput('private-signing') !== 'true' - ? SIGSTORE_PUBLIC_GOOD_ENDPOINTS - : SIGSTORE_INTERNAL_ENDPOINTS + ? 'public-good' + : 'github' try { + if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) { + throw new Error( + 'missing "id-token" permission. Please add "permissions: id-token: write" to your workflow.' + ) + } + // Calculate subject from inputs and generate provenance const subjects = await subjectFromInputs() const predicate = predicateFromInputs() @@ -58,7 +44,7 @@ export async function run(): Promise { // Generate attestations for each subject serially for (const subject of subjects) { - const att = await createAttestation(subject, predicate, endpoints) + const att = await createAttestation(subject, predicate, sigstoreInstance) // Write attestation bundle to output file fs.writeFileSync(outputPath, JSON.stringify(att.bundle) + os.EOL, { @@ -97,21 +83,25 @@ export async function run(): Promise { const createAttestation = async ( subject: Subject, predicate: Predicate, - endpoints: Endpoints + sigstoreInstance: SigstoreInstance ): Promise => { // Sign provenance w/ Sigstore const attestation = await attest({ - ...endpoints, subjectName: subject.name, subjectDigest: subject.digest, predicateType: predicate.type, predicate: predicate.params, + sigstore: sigstoreInstance, token: core.getInput('github-token') }) + core.info(`Attestation created for ${subject.name}@${subjectDigest(subject)}`) + + const instanceName = + sigstoreInstance === 'public-good' ? 'Public Good' : 'GitHub' core.startGroup( highlight( - `Attestation signed using ephemeral certificate from ${endpoints.fulcioURL}` + `Attestation signed using certificate from ${instanceName} Sigstore instance` ) ) core.info(attestation.certificate) @@ -153,6 +143,7 @@ const highlight = (str: string): string => `${COLOR_CYAN}${str}${COLOR_DEFAULT}` const tempDir = (): string => { const basePath = process.env['RUNNER_TEMP'] + /* istanbul ignore if */ if (!basePath) { throw new Error('Missing RUNNER_TEMP environment variable') }