From ec072a1cb2a95a9fb38f16ee92f72e0270cbf263 Mon Sep 17 00:00:00 2001 From: Brian DeHamer Date: Thu, 26 Feb 2026 12:38:12 -0800 Subject: [PATCH] add new subject-version input (#364) Signed-off-by: Brian DeHamer --- __tests__/index.test.ts | 2 ++ __tests__/integration/attest.test.ts | 22 ++++++++++++++++++++-- __tests__/integration/main.test.ts | 1 + action.yml | 5 +++++ dist/index.js | 5 ++++- package-lock.json | 4 ++-- package.json | 2 +- src/attest.ts | 4 +++- src/index.ts | 1 + src/main.ts | 2 ++ 10 files changed, 41 insertions(+), 7 deletions(-) diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 8038e57..9681388 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -30,6 +30,7 @@ describe('index', () => { 'subject-name': 'my-artifact', 'subject-digest': '', 'subject-checksums': '', + 'subject-version': '', 'predicate-type': 'https://example.com/predicate', predicate: '{}', 'predicate-path': '', @@ -57,6 +58,7 @@ describe('index', () => { subjectName: 'my-artifact', subjectDigest: '', subjectChecksums: '', + subjectVersion: '', predicateType: 'https://example.com/predicate', predicate: '{}', predicatePath: '', diff --git a/__tests__/integration/attest.test.ts b/__tests__/integration/attest.test.ts index 438c667..522c42c 100644 --- a/__tests__/integration/attest.test.ts +++ b/__tests__/integration/attest.test.ts @@ -145,7 +145,8 @@ describe('createAttestation', () => { const storageOpts = { ...defaultOpts, pushToRegistry: true, - createStorageRecord: true + createStorageRecord: true, + subjectVersion: '1.2.3' } it('should create storage record when enabled and owner is org', async () => { @@ -157,10 +158,27 @@ describe('createAttestation', () => { storageOpts ) - expect(mockCreateStorageRecord).toHaveBeenCalled() + expect(mockCreateStorageRecord).toHaveBeenCalledWith( + expect.objectContaining({ version: '1.2.3' }), + expect.anything(), + expect.anything() + ) expect(result.storageRecordIds).toEqual([12345]) }) + it('should omit version from storage record when subjectVersion is empty', async () => { + const subjects = [TEST_SUBJECT_WITH_REGISTRY] + const opts = { ...storageOpts, subjectVersion: '' } + + await createAttestation(subjects, TEST_PREDICATE, opts) + + expect(mockCreateStorageRecord).toHaveBeenCalledWith( + expect.objectContaining({ version: undefined }), + expect.anything(), + expect.anything() + ) + }) + it('should skip storage record when owner is User', async () => { mockGetOctokit.mockReturnValue(createOctokitMock('User')) const subjects = [TEST_SUBJECT_WITH_REGISTRY] diff --git a/__tests__/integration/main.test.ts b/__tests__/integration/main.test.ts index 61d7e33..8d32073 100644 --- a/__tests__/integration/main.test.ts +++ b/__tests__/integration/main.test.ts @@ -101,6 +101,7 @@ const defaultInputs: RunInputs = { subjectChecksums: '', pushToRegistry: false, createStorageRecord: false, + subjectVersion: '', showSummary: false, githubToken: 'test-token', privateSigning: false diff --git a/action.yml b/action.yml index 18bce0d..4f8c8b0 100644 --- a/action.yml +++ b/action.yml @@ -30,6 +30,11 @@ inputs: attestation. Must specify exactly one of "subject-path", "subject-digest", or "subject-checksums". required: false + subject-version: + description: > + Version of the subject for the attestation. Only used when + "push-to-registry" and "create-storage-record" are both set to true. + required: false sbom-path: description: > Path to the JSON-formatted SBOM file (SPDX or CycloneDX) to attest. diff --git a/dist/index.js b/dist/index.js index 271e009..6cddbf3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -120899,7 +120899,8 @@ const createAttestation = async (subjects, predicate, opts) => { const registryUrl = getRegistryURL(subject.name); const artifactOpts = { name: subject.name, - digest: subjectDigest + digest: subjectDigest, + version: opts.subjectVersion || undefined }; const packageRegistryOpts = { registryUrl @@ -121157,6 +121158,7 @@ async function run(inputs) { sigstoreInstance, pushToRegistry: inputs.pushToRegistry, createStorageRecord: inputs.createStorageRecord, + subjectVersion: inputs.subjectVersion, githubToken: inputs.githubToken }); logAttestation(subjects, att, sigstoreInstance); @@ -121298,6 +121300,7 @@ const inputs = { predicatePath: getInput('predicate-path'), pushToRegistry: getBooleanInput('push-to-registry'), createStorageRecord: getBooleanInput('create-storage-record'), + subjectVersion: getInput('subject-version'), showSummary: getBooleanInput('show-summary'), githubToken: getInput('github-token'), // undocumented -- not part of public interface diff --git a/package-lock.json b/package-lock.json index cd95c2f..a02db08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "actions/attest", - "version": "4.0.0", + "version": "4.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "actions/attest", - "version": "4.0.0", + "version": "4.1.0", "license": "MIT", "dependencies": { "@actions/attest": "^3.2.0", diff --git a/package.json b/package.json index 7c7e325..46c56cd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "actions/attest", "description": "Generate signed attestations for workflow artifacts", - "version": "4.0.0", + "version": "4.1.0", "author": "", "private": true, "type": "module", diff --git a/src/attest.ts b/src/attest.ts index 56c626b..e927732 100644 --- a/src/attest.ts +++ b/src/attest.ts @@ -26,6 +26,7 @@ export const createAttestation = async ( sigstoreInstance: SigstoreInstance pushToRegistry: boolean createStorageRecord: boolean + subjectVersion?: string githubToken: string } ): Promise => { @@ -77,7 +78,8 @@ export const createAttestation = async ( const registryUrl = getRegistryURL(subject.name) const artifactOpts = { name: subject.name, - digest: subjectDigest + digest: subjectDigest, + version: opts.subjectVersion || undefined } const packageRegistryOpts = { registryUrl diff --git a/src/index.ts b/src/index.ts index 3759673..def53e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ const inputs: RunInputs = { predicatePath: core.getInput('predicate-path'), pushToRegistry: core.getBooleanInput('push-to-registry'), createStorageRecord: core.getBooleanInput('create-storage-record'), + subjectVersion: core.getInput('subject-version'), showSummary: core.getBooleanInput('show-summary'), githubToken: core.getInput('github-token'), // undocumented -- not part of public interface diff --git a/src/main.ts b/src/main.ts index e803d61..54d7fea 100644 --- a/src/main.ts +++ b/src/main.ts @@ -35,6 +35,7 @@ export type RunInputs = SubjectInputs & SBOMInputs & { pushToRegistry: boolean createStorageRecord: boolean + subjectVersion: string githubToken: string showSummary: boolean privateSigning: boolean @@ -97,6 +98,7 @@ export async function run(inputs: RunInputs): Promise { sigstoreInstance, pushToRegistry: inputs.pushToRegistry, createStorageRecord: inputs.createStorageRecord, + subjectVersion: inputs.subjectVersion, githubToken: inputs.githubToken })