From e8c242695d65487b9182a14c1b74f18371c09e9f Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 10:49:24 -0800 Subject: [PATCH 01/22] add function for creating storage record Signed-off-by: Meredith Lancaster --- packages/attest/src/artifact-metadata.ts | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 packages/attest/src/artifact-metadata.ts diff --git a/packages/attest/src/artifact-metadata.ts b/packages/attest/src/artifact-metadata.ts new file mode 100644 index 00000000..6aa11a96 --- /dev/null +++ b/packages/attest/src/artifact-metadata.ts @@ -0,0 +1,48 @@ +import * as github from '@actions/github' +import {retry} from '@octokit/plugin-retry' +import {RequestHeaders} from '@octokit/types' + +const CREATE_STORAGE_RECORD_REQUEST = 'POST /orgs/{owner}/artifacts/metadata/storage-record' +const DEFAULT_RETRY_COUNT = 5 + +export type WriteOptions = { + retry?: number + headers?: RequestHeaders +} + +/** + * Writes a storage record on behalf of an artifact + * @param artifactName - The name of the artifact. + * @param artifactDigest - The digest of the artifact. + * @param token - The GitHub token for authentication. + * @returns The ID of the storage record. + * @throws Error if the storage record fails to persist. + */ +export const createStorageRecord = async ( + artifactName: string, + artifactDigest: string, + token: string, + options: WriteOptions = {} +): Promise => { + const retries = options.retry ?? DEFAULT_RETRY_COUNT + const octokit = github.getOctokit(token, {retry: {retries}}, retry) + + try { + const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, { + owner: github.context.repo.owner, + repo: github.context.repo.repo, + headers: options.headers, + artifact_name: artifactName, + artifact_digest: artifactDigest, + }) + + const data = + typeof response.data == 'string' + ? JSON.parse(response.data) + : response.data + return data?.id + } catch (err) { + const message = err instanceof Error ? err.message : err + throw new Error(`Failed to persist storage record: ${message}`) + } +} From 79efd648ac1bd41fee581d6d01cf8ed8c1aceb14 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 11:02:59 -0800 Subject: [PATCH 02/22] condense parameters Signed-off-by: Meredith Lancaster --- packages/attest/src/artifact-metadata.ts | 35 +++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/attest/src/artifact-metadata.ts b/packages/attest/src/artifact-metadata.ts index 6aa11a96..95519b85 100644 --- a/packages/attest/src/artifact-metadata.ts +++ b/packages/attest/src/artifact-metadata.ts @@ -5,22 +5,37 @@ import {RequestHeaders} from '@octokit/types' const CREATE_STORAGE_RECORD_REQUEST = 'POST /orgs/{owner}/artifacts/metadata/storage-record' const DEFAULT_RETRY_COUNT = 5 +export type ArtifactParams = { + name: string + digest: string + version?: string + status?: string +} + +export type PackageRegistryParams = { + registryUrl: string + artifactUrl?: string + registryRepo?: string + path?: string +} + export type WriteOptions = { retry?: number headers?: RequestHeaders } /** - * Writes a storage record on behalf of an artifact - * @param artifactName - The name of the artifact. - * @param artifactDigest - The digest of the artifact. + * Writes a storage record on behalf of an artifact that has been attested + * @param artifactParams - parameters for the artifact. + * @param packageRegistryParams - parameters for the package registry. * @param token - The GitHub token for authentication. + * @param options - Optional parameters for the write operation. * @returns The ID of the storage record. * @throws Error if the storage record fails to persist. */ export const createStorageRecord = async ( - artifactName: string, - artifactDigest: string, + artifactParams: ArtifactParams, + packageRegistryParams: PackageRegistryParams, token: string, options: WriteOptions = {} ): Promise => { @@ -32,8 +47,14 @@ export const createStorageRecord = async ( owner: github.context.repo.owner, repo: github.context.repo.repo, headers: options.headers, - artifact_name: artifactName, - artifact_digest: artifactDigest, + artifact_name: artifactParams.name, + artifact_digest: artifactParams.digest, + artifact_version: artifactParams.version, + artifact_status: artifactParams.status, + registry_url: packageRegistryParams.registryUrl, + artifact_url: packageRegistryParams.artifactUrl, + registry_repo: packageRegistryParams.registryRepo, + path: packageRegistryParams.path }) const data = From 417dbfff73c380d816193eee9afaaf1e0806d77d Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 13:17:08 -0800 Subject: [PATCH 03/22] use parameter objects and add tests Signed-off-by: Meredith Lancaster --- .../__tests__/artifact-metadata.test.ts | 112 ++++++++++++++++++ packages/attest/src/artifact-metadata.ts | 13 +- 2 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 packages/attest/__tests__/artifact-metadata.test.ts diff --git a/packages/attest/__tests__/artifact-metadata.test.ts b/packages/attest/__tests__/artifact-metadata.test.ts new file mode 100644 index 00000000..0ce309bc --- /dev/null +++ b/packages/attest/__tests__/artifact-metadata.test.ts @@ -0,0 +1,112 @@ +import {MockAgent, setGlobalDispatcher} from 'undici' +import {createStorageRecord} from '../src/attest' + +describe('createStorageRecord', () => { + const originalEnv = process.env + const attestation = {foo: 'bar '} + const token = 'token' + const headers = {'X-GitHub-Foo': 'true'} + const artifactParams = { + name: "my-lib", + version: "1.0.0", + digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + } + const registryParams = { + registry_url: "https://my-registry.org", + } + + + const mockAgent = new MockAgent() + setGlobalDispatcher(mockAgent) + + beforeEach(() => { + process.env = { + ...originalEnv, + GITHUB_REPOSITORY: 'foo/bar' + } + }) + + afterEach(() => { + process.env = originalEnv + }) + + describe('when the api call is successful', () => { + beforeEach(() => { + mockAgent + .get('https://api.github.com') + .intercept({ + path: '/orgs/foo/artifacts/metadata/storage-record', + method: 'POST', + headers: {authorization: `token ${token}`, ...headers}, + body: JSON.stringify({ + name: "my-lib", + version: "1.0.0", + digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + registry_url: "https://my-registry.org" + }) + }) + .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) + }) + + it('persists the storage record', async () => { + await expect( + createStorageRecord(artifactParams, registryParams, token, {headers}) + ).resolves.toEqual(['123', '456']) + }) + }) + + describe('when the api call fails', () => { + beforeEach(() => { + mockAgent + .get('https://api.github.com') + .intercept({ + path: '/orgs/foo/artifacts/metadata/storage-record', + method: 'POST', + headers: {authorization: `token ${token}`}, + body: JSON.stringify({ + name: "my-lib", + version: "1.0.0", + digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + registry_url: "https://my-registry.org" + }) + }) + .reply(500, 'oops') + }) + + it('throws an error', async () => { + await expect( + createStorageRecord(artifactParams, registryParams, token, {retry: 0}) + ).rejects.toThrow(/oops/) + }) + }) + + describe('when the api call fails but succeeds on retry', () => { + beforeEach(() => { + const pool = mockAgent.get('https://api.github.com') + + pool + .intercept({ + path: '/repos/foo/bar/attestations', + method: 'POST', + headers: {authorization: `token ${token}`}, + body: JSON.stringify({...artifactParams, ...registryParams}) + }) + .reply(500, 'oops') + .times(1) + + pool + .intercept({ + path: '/repos/foo/bar/attestations', + method: 'POST', + headers: {authorization: `token ${token}`}, + body: JSON.stringify({}) + }) + .reply(201, {id: '123'}) + .times(1) + }) + + it('persists the attestation', async () => { + await expect(createStorageRecord(artifactParams, registryParams, token)).resolves.toEqual('123') + }) + }) +}) diff --git a/packages/attest/src/artifact-metadata.ts b/packages/attest/src/artifact-metadata.ts index 95519b85..d1b867c4 100644 --- a/packages/attest/src/artifact-metadata.ts +++ b/packages/attest/src/artifact-metadata.ts @@ -38,7 +38,7 @@ export const createStorageRecord = async ( packageRegistryParams: PackageRegistryParams, token: string, options: WriteOptions = {} -): Promise => { +): Promise> => { const retries = options.retry ?? DEFAULT_RETRY_COUNT const octokit = github.getOctokit(token, {retry: {retries}}, retry) @@ -47,21 +47,22 @@ export const createStorageRecord = async ( owner: github.context.repo.owner, repo: github.context.repo.repo, headers: options.headers, - artifact_name: artifactParams.name, artifact_digest: artifactParams.digest, - artifact_version: artifactParams.version, + artifact_name: artifactParams.name, artifact_status: artifactParams.status, - registry_url: packageRegistryParams.registryUrl, artifact_url: packageRegistryParams.artifactUrl, + artifact_version: artifactParams.version, + path: packageRegistryParams.path, registry_repo: packageRegistryParams.registryRepo, - path: packageRegistryParams.path + registry_url: packageRegistryParams.registryUrl, }) const data = typeof response.data == 'string' ? JSON.parse(response.data) : response.data - return data?.id + + return data?.storage_records.map((r: { id: any }) => r.id) } catch (err) { const message = err instanceof Error ? err.message : err throw new Error(`Failed to persist storage record: ${message}`) From 9ca26d49468bbca8f00d6d3eb97b8b0f2862abfa Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 13:17:18 -0800 Subject: [PATCH 04/22] regenerate package lock Signed-off-by: Meredith Lancaster --- packages/attest/package-lock.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/attest/package-lock.json b/packages/attest/package-lock.json index 985d44c4..97242457 100644 --- a/packages/attest/package-lock.json +++ b/packages/attest/package-lock.json @@ -192,7 +192,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", From c034e764881b18c5f7e0575da1d27d1fa29341ba Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 13:49:54 -0800 Subject: [PATCH 05/22] fix function exporting and test results Signed-off-by: Meredith Lancaster --- .../__tests__/artifact-metadata.test.ts | 8 +++--- packages/attest/src/artifact-metadata.ts | 27 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/attest/__tests__/artifact-metadata.test.ts b/packages/attest/__tests__/artifact-metadata.test.ts index 0ce309bc..c1a15025 100644 --- a/packages/attest/__tests__/artifact-metadata.test.ts +++ b/packages/attest/__tests__/artifact-metadata.test.ts @@ -1,5 +1,5 @@ import {MockAgent, setGlobalDispatcher} from 'undici' -import {createStorageRecord} from '../src/attest' +import {createStorageRecord} from '../src/artifact-metadata' describe('createStorageRecord', () => { const originalEnv = process.env @@ -12,7 +12,7 @@ describe('createStorageRecord', () => { digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", } const registryParams = { - registry_url: "https://my-registry.org", + registryUrl: 'https://my-registry.org', } @@ -89,7 +89,7 @@ describe('createStorageRecord', () => { path: '/repos/foo/bar/attestations', method: 'POST', headers: {authorization: `token ${token}`}, - body: JSON.stringify({...artifactParams, ...registryParams}) + body: JSON.stringify({...artifactParams, registry_url: registryParams.registryUrl}) }) .reply(500, 'oops') .times(1) @@ -101,7 +101,7 @@ describe('createStorageRecord', () => { headers: {authorization: `token ${token}`}, body: JSON.stringify({}) }) - .reply(201, {id: '123'}) + .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) .times(1) }) diff --git a/packages/attest/src/artifact-metadata.ts b/packages/attest/src/artifact-metadata.ts index d1b867c4..bbe267b0 100644 --- a/packages/attest/src/artifact-metadata.ts +++ b/packages/attest/src/artifact-metadata.ts @@ -15,7 +15,7 @@ export type ArtifactParams = { export type PackageRegistryParams = { registryUrl: string artifactUrl?: string - registryRepo?: string + repo?: string path?: string } @@ -33,28 +33,20 @@ export type WriteOptions = { * @returns The ID of the storage record. * @throws Error if the storage record fails to persist. */ -export const createStorageRecord = async ( +export async function createStorageRecord( artifactParams: ArtifactParams, packageRegistryParams: PackageRegistryParams, token: string, options: WriteOptions = {} -): Promise> => { +): Promise> { const retries = options.retry ?? DEFAULT_RETRY_COUNT const octokit = github.getOctokit(token, {retry: {retries}}, retry) try { const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, { owner: github.context.repo.owner, - repo: github.context.repo.repo, headers: options.headers, - artifact_digest: artifactParams.digest, - artifact_name: artifactParams.name, - artifact_status: artifactParams.status, - artifact_url: packageRegistryParams.artifactUrl, - artifact_version: artifactParams.version, - path: packageRegistryParams.path, - registry_repo: packageRegistryParams.registryRepo, - registry_url: packageRegistryParams.registryUrl, + ...buildRequestParams(artifactParams, packageRegistryParams), }) const data = @@ -68,3 +60,14 @@ export const createStorageRecord = async ( throw new Error(`Failed to persist storage record: ${message}`) } } + +const buildRequestParams = (artifactParams: ArtifactParams, registryParams: PackageRegistryParams) => { + const { registryUrl, artifactUrl, ...rest } = registryParams + return { + ...artifactParams, + ...rest, + // rename parameters to match API expectations + artifact_url: artifactUrl, + registry_url: registryUrl, + } +} From f01262913d4563d27696d9bf7ff1551e1e6e1a3f Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 13:55:24 -0800 Subject: [PATCH 06/22] table of contents Signed-off-by: Meredith Lancaster --- packages/attest/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/attest/README.md b/packages/attest/README.md index e6761ea6..c75b78b7 100644 --- a/packages/attest/README.md +++ b/packages/attest/README.md @@ -15,6 +15,14 @@ initiated. See [Using artifact attestations to establish provenance for builds](https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds) for more information on artifact attestations. +## Table of Contents +- [Usage](#usage) + - [attest](#attest) + - [attestProvenance](#attest-provenance) + - [Attestation](#attestation) +- [Sigstore Instance](#sigstore-instance) +- [Storage](#storage) + ## Usage ### `attest` From dd097c7f4e83d9cd5f0601fc9e2bae03769f4549 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 13:57:00 -0800 Subject: [PATCH 07/22] add section on createStorageRecord func Signed-off-by: Meredith Lancaster --- packages/attest/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/attest/README.md b/packages/attest/README.md index c75b78b7..33639b29 100644 --- a/packages/attest/README.md +++ b/packages/attest/README.md @@ -173,6 +173,13 @@ export type Attestation = { For details about the Sigstore bundle format, see the [Bundle protobuf specification](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto). +### createStorageRecord + +The `createStorageRecord` function accepts parameters defining artifact +and package registry details and creates a storage record on behalf of the artifact. +The storage record contains metadata about where the artifact is stored on a given +package registry. + ## Sigstore Instance When generating the signed attestation there are two different Sigstore From ed78411ffba53680068d7b3d313d3c7f06b58a5a Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 14:03:23 -0800 Subject: [PATCH 08/22] fix expected response Signed-off-by: Meredith Lancaster --- packages/attest/__tests__/artifact-metadata.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/attest/__tests__/artifact-metadata.test.ts b/packages/attest/__tests__/artifact-metadata.test.ts index c1a15025..af4b1144 100644 --- a/packages/attest/__tests__/artifact-metadata.test.ts +++ b/packages/attest/__tests__/artifact-metadata.test.ts @@ -106,7 +106,7 @@ describe('createStorageRecord', () => { }) it('persists the attestation', async () => { - await expect(createStorageRecord(artifactParams, registryParams, token)).resolves.toEqual('123') + await expect(createStorageRecord(artifactParams, registryParams, token)).resolves.toEqual(['123', '456']) }) }) }) From 136f9dfe376649d76527ff5ff77af9e2fd08d8c2 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 14:07:17 -0800 Subject: [PATCH 09/22] fix header link Signed-off-by: Meredith Lancaster --- packages/attest/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/attest/README.md b/packages/attest/README.md index 33639b29..b157d5a1 100644 --- a/packages/attest/README.md +++ b/packages/attest/README.md @@ -18,7 +18,7 @@ for more information on artifact attestations. ## Table of Contents - [Usage](#usage) - [attest](#attest) - - [attestProvenance](#attest-provenance) + - [attestProvenance](#attestprovenance) - [Attestation](#attestation) - [Sigstore Instance](#sigstore-instance) - [Storage](#storage) From 0a988d204ed418d48b4d8a9ecb5db04f1932476d Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 15:16:26 -0800 Subject: [PATCH 10/22] rename file Signed-off-by: Meredith Lancaster --- .../{artifact-metadata.test.ts => artifactMetadata.test.ts} | 2 +- .../attest/src/{artifact-metadata.ts => artifactMetadata.ts} | 0 packages/attest/src/index.ts | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) rename packages/attest/__tests__/{artifact-metadata.test.ts => artifactMetadata.test.ts} (98%) rename packages/attest/src/{artifact-metadata.ts => artifactMetadata.ts} (100%) diff --git a/packages/attest/__tests__/artifact-metadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts similarity index 98% rename from packages/attest/__tests__/artifact-metadata.test.ts rename to packages/attest/__tests__/artifactMetadata.test.ts index af4b1144..192978af 100644 --- a/packages/attest/__tests__/artifact-metadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -1,5 +1,5 @@ import {MockAgent, setGlobalDispatcher} from 'undici' -import {createStorageRecord} from '../src/artifact-metadata' +import {createStorageRecord} from '../src/artifactMetadata' describe('createStorageRecord', () => { const originalEnv = process.env diff --git a/packages/attest/src/artifact-metadata.ts b/packages/attest/src/artifactMetadata.ts similarity index 100% rename from packages/attest/src/artifact-metadata.ts rename to packages/attest/src/artifactMetadata.ts diff --git a/packages/attest/src/index.ts b/packages/attest/src/index.ts index 43c0a472..54846dbf 100644 --- a/packages/attest/src/index.ts +++ b/packages/attest/src/index.ts @@ -1,3 +1,4 @@ +export {createStorageRecord} from '.artifactMetadata' export {AttestOptions, attest} from './attest' export { AttestProvenanceOptions, From b8933d04957cf25df1332829104ff6cf36470d7b Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 15:25:34 -0800 Subject: [PATCH 11/22] reorganize function options and document Signed-off-by: Meredith Lancaster --- packages/attest/README.md | 69 +++++++++++++++++-- .../attest/__tests__/artifactMetadata.test.ts | 22 ++++-- packages/attest/src/artifactMetadata.ts | 67 ++++++++++-------- 3 files changed, 123 insertions(+), 35 deletions(-) diff --git a/packages/attest/README.md b/packages/attest/README.md index b157d5a1..6331d86a 100644 --- a/packages/attest/README.md +++ b/packages/attest/README.md @@ -175,10 +175,71 @@ specification](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigst ### createStorageRecord -The `createStorageRecord` function accepts parameters defining artifact -and package registry details and creates a storage record on behalf of the artifact. -The storage record contains metadata about where the artifact is stored on a given -package registry. +The `createStorageRecord` function creates an +[artifact metadata storage record](https://docs.github.com/en/rest/orgs/artifact-metadata?apiVersion=2022-11-28#create-artifact-metadata-storage-record) +on behalf of an attested artifact. It accepts parameters defining artifact +and package registry details. The storage record contains metadata about where the artifact is stored on a given package registry. + +```js +const { createStorageRecord } = require('@actions/attest'); +const core = require('@actions/core'); + +async function run() { + // In order to persist attestations to the repo, this should be a token with + // repository write permissions. + const ghToken = core.getInput('gh-token'); + + const record = await createStorageRecord({ + name: 'my-artifact-name', + digest: { 'sha256': '36ab4667...'}, + version: "v1.0.0", + registry_url: "https://my-fave-pkg-registry.com", + token: ghToken + }); + + console.log(record); +} + +run(); +``` + +The `createStorageRecord` function supports the following options: + +```typescript +export type StorageRecordOptions = { + // Includes details about the attested artifact + artifactOptions: { + // The name of the artifact + name: string + // The digest of the artifact + digest: string + // The version of the artifact + version?: string + // The status of the artifact + status?: string + }, + // Includes details about the package registry the artifact was published to + packageRegistryOptions: { + // The URL of the package registry + registryUrl: string + // The URL of the artifact in the package registry + artifactUrl?: string + // The package registry repository the artifact was published to. + repo?: string + // The path of the artifact in the package registry repository. + path?: string + }, + // GitHub token for writing attestations. + token: string + // Optional parameters for the write operation. + writeOptions: { + // The number of times to retry the request. + retry?: number + // HTTP headers to include in request to Artifact Metadata API. + headers?: RequestHeaders + } +} +``` ## Sigstore Instance diff --git a/packages/attest/__tests__/artifactMetadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts index 192978af..ab63c3f1 100644 --- a/packages/attest/__tests__/artifactMetadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -15,7 +15,6 @@ describe('createStorageRecord', () => { registryUrl: 'https://my-registry.org', } - const mockAgent = new MockAgent() setGlobalDispatcher(mockAgent) @@ -50,7 +49,12 @@ describe('createStorageRecord', () => { it('persists the storage record', async () => { await expect( - createStorageRecord(artifactParams, registryParams, token, {headers}) + createStorageRecord({ + artifactOptions: artifactParams, + packageRegistryOptions: registryParams, + token, + writeOptions: {headers}, + }) ).resolves.toEqual(['123', '456']) }) }) @@ -75,7 +79,12 @@ describe('createStorageRecord', () => { it('throws an error', async () => { await expect( - createStorageRecord(artifactParams, registryParams, token, {retry: 0}) + createStorageRecord({ + artifactOptions: artifactParams, + packageRegistryOptions: registryParams, + token, + writeOptions: {retry: 0}, + }) ).rejects.toThrow(/oops/) }) }) @@ -106,7 +115,12 @@ describe('createStorageRecord', () => { }) it('persists the attestation', async () => { - await expect(createStorageRecord(artifactParams, registryParams, token)).resolves.toEqual(['123', '456']) + await expect(createStorageRecord({ + artifactOptions: artifactParams, + packageRegistryOptions: registryParams, + token, + writeOptions: {}, + })).resolves.toEqual(['123', '456']) }) }) }) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index bbe267b0..5e4bf10f 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -5,23 +5,41 @@ import {RequestHeaders} from '@octokit/types' const CREATE_STORAGE_RECORD_REQUEST = 'POST /orgs/{owner}/artifacts/metadata/storage-record' const DEFAULT_RETRY_COUNT = 5 -export type ArtifactParams = { - name: string - digest: string - version?: string - status?: string -} - -export type PackageRegistryParams = { - registryUrl: string - artifactUrl?: string - repo?: string - path?: string -} - -export type WriteOptions = { - retry?: number - headers?: RequestHeaders +/** + * Options for creating a storage record for an attested artifact. + */ +export type StorageRecordOptions = { + // Includes details about the attested artifact + artifactOptions: { + // The name of the artifact + name: string + // The digest of the artifact + digest: string + // The version of the artifact + version?: string + // The status of the artifact + status?: string + }, + // Includes details about the package registry the artifact was published to + packageRegistryOptions: { + // The URL of the package registry + registryUrl: string + // The URL of the artifact in the package registry + artifactUrl?: string + // The package registry repository the artifact was published to. + repo?: string + // The path of the artifact in the package registry repository. + path?: string + }, + // GitHub token for writing attestations. + token: string + // Optional parameters for the write operation. + writeOptions: { + // The number of times to retry the request. + retry?: number + // HTTP headers to include in request to Artifact Metadata API. + headers?: RequestHeaders + } } /** @@ -33,20 +51,15 @@ export type WriteOptions = { * @returns The ID of the storage record. * @throws Error if the storage record fails to persist. */ -export async function createStorageRecord( - artifactParams: ArtifactParams, - packageRegistryParams: PackageRegistryParams, - token: string, - options: WriteOptions = {} -): Promise> { - const retries = options.retry ?? DEFAULT_RETRY_COUNT - const octokit = github.getOctokit(token, {retry: {retries}}, retry) +export async function createStorageRecord(options: StorageRecordOptions): Promise> { + const retries = options.writeOptions.retry ?? DEFAULT_RETRY_COUNT + const octokit = github.getOctokit(options.token, {retry: {retries}}, retry) try { const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, { owner: github.context.repo.owner, - headers: options.headers, - ...buildRequestParams(artifactParams, packageRegistryParams), + headers: options.writeOptions.headers, + ...buildRequestParams(options.artifactOptions, options.packageRegistryOptions), }) const data = From d1f9584cda66ff4509437966e843a1bc43348ad3 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 15:33:01 -0800 Subject: [PATCH 12/22] fix test calls Signed-off-by: Meredith Lancaster --- .../attest/__tests__/artifactMetadata.test.ts | 20 ++++++++++--------- packages/attest/src/artifactMetadata.ts | 16 +-------------- packages/attest/src/index.ts | 2 +- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/packages/attest/__tests__/artifactMetadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts index ab63c3f1..b3cf6542 100644 --- a/packages/attest/__tests__/artifactMetadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -6,12 +6,12 @@ describe('createStorageRecord', () => { const attestation = {foo: 'bar '} const token = 'token' const headers = {'X-GitHub-Foo': 'true'} - const artifactParams = { + const artifactOptions = { name: "my-lib", version: "1.0.0", digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", } - const registryParams = { + const registryOptions = { registryUrl: 'https://my-registry.org', } @@ -50,8 +50,8 @@ describe('createStorageRecord', () => { it('persists the storage record', async () => { await expect( createStorageRecord({ - artifactOptions: artifactParams, - packageRegistryOptions: registryParams, + artifactOptions: artifactOptions, + packageRegistryOptions: registryOptions, token, writeOptions: {headers}, }) @@ -80,8 +80,8 @@ describe('createStorageRecord', () => { it('throws an error', async () => { await expect( createStorageRecord({ - artifactOptions: artifactParams, - packageRegistryOptions: registryParams, + artifactOptions: artifactOptions, + packageRegistryOptions: registryOptions, token, writeOptions: {retry: 0}, }) @@ -98,7 +98,7 @@ describe('createStorageRecord', () => { path: '/repos/foo/bar/attestations', method: 'POST', headers: {authorization: `token ${token}`}, - body: JSON.stringify({...artifactParams, registry_url: registryParams.registryUrl}) + body: JSON.stringify({...artifactOptions, registry_url: registryOptions.registryUrl}) }) .reply(500, 'oops') .times(1) @@ -115,9 +115,11 @@ describe('createStorageRecord', () => { }) it('persists the attestation', async () => { + const { registryUrl, ...rest } = registryOptions await expect(createStorageRecord({ - artifactOptions: artifactParams, - packageRegistryOptions: registryParams, + ...artifactOptions, + ...rest, + registry_url: registryUrl, token, writeOptions: {}, })).resolves.toEqual(['123', '456']) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index 5e4bf10f..26c4fc4a 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -44,10 +44,7 @@ export type StorageRecordOptions = { /** * Writes a storage record on behalf of an artifact that has been attested - * @param artifactParams - parameters for the artifact. - * @param packageRegistryParams - parameters for the package registry. - * @param token - The GitHub token for authentication. - * @param options - Optional parameters for the write operation. + * @param StorageRecordOptions - parameters for the storage record API request. * @returns The ID of the storage record. * @throws Error if the storage record fails to persist. */ @@ -73,14 +70,3 @@ export async function createStorageRecord(options: StorageRecordOptions): Promis throw new Error(`Failed to persist storage record: ${message}`) } } - -const buildRequestParams = (artifactParams: ArtifactParams, registryParams: PackageRegistryParams) => { - const { registryUrl, artifactUrl, ...rest } = registryParams - return { - ...artifactParams, - ...rest, - // rename parameters to match API expectations - artifact_url: artifactUrl, - registry_url: registryUrl, - } -} diff --git a/packages/attest/src/index.ts b/packages/attest/src/index.ts index 54846dbf..78384d32 100644 --- a/packages/attest/src/index.ts +++ b/packages/attest/src/index.ts @@ -1,4 +1,4 @@ -export {createStorageRecord} from '.artifactMetadata' +export {createStorageRecord} from './artifactMetadata' export {AttestOptions, attest} from './attest' export { AttestProvenanceOptions, From 6ec87f46b72f0c38c48a4d8aa62c737eb4d18fde Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 15:39:26 -0800 Subject: [PATCH 13/22] add back param parsing function Signed-off-by: Meredith Lancaster --- packages/attest/src/artifactMetadata.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index 26c4fc4a..40f1705d 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -70,3 +70,13 @@ export async function createStorageRecord(options: StorageRecordOptions): Promis throw new Error(`Failed to persist storage record: ${message}`) } } + +const buildRequestParams = (options: StorageRecordOptions) => { + const { registryUrl, artifactUrl, ...rest } = options.packageRegistryOptions + return { + ...options.artifactOptions, + registry_url: registryUrl, + artifact_url: artifactUrl, + ...rest, + } +} From 8eca440361a4a26069246e00efcd84ad619ebb9e Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 15:59:25 -0800 Subject: [PATCH 14/22] fix test and function calls Signed-off-by: Meredith Lancaster --- .../attest/__tests__/artifactMetadata.test.ts | 50 +++++++++---------- packages/attest/src/artifactMetadata.ts | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/attest/__tests__/artifactMetadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts index b3cf6542..3416eed1 100644 --- a/packages/attest/__tests__/artifactMetadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -6,13 +6,18 @@ describe('createStorageRecord', () => { const attestation = {foo: 'bar '} const token = 'token' const headers = {'X-GitHub-Foo': 'true'} - const artifactOptions = { - name: "my-lib", - version: "1.0.0", - digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", - } - const registryOptions = { - registryUrl: 'https://my-registry.org', + + const options = { + artifactOptions: { + name: "my-lib", + version: "1.0.0", + digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + }, + packageRegistryOptions: { + registryUrl: 'https://my-registry.org', + }, + token, + writeOptions: {headers}, } const mockAgent = new MockAgent() @@ -49,12 +54,7 @@ describe('createStorageRecord', () => { it('persists the storage record', async () => { await expect( - createStorageRecord({ - artifactOptions: artifactOptions, - packageRegistryOptions: registryOptions, - token, - writeOptions: {headers}, - }) + createStorageRecord(options) ).resolves.toEqual(['123', '456']) }) }) @@ -80,9 +80,7 @@ describe('createStorageRecord', () => { it('throws an error', async () => { await expect( createStorageRecord({ - artifactOptions: artifactOptions, - packageRegistryOptions: registryOptions, - token, + ...options, writeOptions: {retry: 0}, }) ).rejects.toThrow(/oops/) @@ -95,32 +93,34 @@ describe('createStorageRecord', () => { pool .intercept({ - path: '/repos/foo/bar/attestations', + path: '/orgs/foo/artifacts/metadata/storage-record', method: 'POST', headers: {authorization: `token ${token}`}, - body: JSON.stringify({...artifactOptions, registry_url: registryOptions.registryUrl}) + body: JSON.stringify({ + ...options.artifactOptions, + registry_url: options.packageRegistryOptions.registryUrl, + }) }) .reply(500, 'oops') .times(1) pool .intercept({ - path: '/repos/foo/bar/attestations', + path: '/orgs/foo/artifacts/metadata/storage-record', method: 'POST', headers: {authorization: `token ${token}`}, - body: JSON.stringify({}) + body: JSON.stringify({ + ...options.artifactOptions, + registry_url: options.packageRegistryOptions.registryUrl, + }) }) .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) .times(1) }) it('persists the attestation', async () => { - const { registryUrl, ...rest } = registryOptions await expect(createStorageRecord({ - ...artifactOptions, - ...rest, - registry_url: registryUrl, - token, + ...options, writeOptions: {}, })).resolves.toEqual(['123', '456']) }) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index 40f1705d..6b94dc20 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -56,7 +56,7 @@ export async function createStorageRecord(options: StorageRecordOptions): Promis const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, { owner: github.context.repo.owner, headers: options.writeOptions.headers, - ...buildRequestParams(options.artifactOptions, options.packageRegistryOptions), + ...buildRequestParams(options), }) const data = From 10d3b034e071972608dbd4dd0f25c5edcde154f7 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 16:22:59 -0800 Subject: [PATCH 15/22] fix linter issues Signed-off-by: Meredith Lancaster --- .../attest/__tests__/artifactMetadata.test.ts | 52 ++++++++++--------- packages/attest/src/artifactMetadata.ts | 23 ++++---- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/packages/attest/__tests__/artifactMetadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts index 3416eed1..051ea314 100644 --- a/packages/attest/__tests__/artifactMetadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -3,21 +3,20 @@ import {createStorageRecord} from '../src/artifactMetadata' describe('createStorageRecord', () => { const originalEnv = process.env - const attestation = {foo: 'bar '} const token = 'token' const headers = {'X-GitHub-Foo': 'true'} const options = { artifactOptions: { - name: "my-lib", - version: "1.0.0", - digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + name: 'my-lib', + version: '1.0.0', + digest: `sha256:${'a'.repeat(64)}` }, packageRegistryOptions: { - registryUrl: 'https://my-registry.org', + registryUrl: 'https://my-registry.org' }, token, - writeOptions: {headers}, + writeOptions: {headers} } const mockAgent = new MockAgent() @@ -43,19 +42,20 @@ describe('createStorageRecord', () => { method: 'POST', headers: {authorization: `token ${token}`, ...headers}, body: JSON.stringify({ - name: "my-lib", - version: "1.0.0", - digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", - registry_url: "https://my-registry.org" + name: 'my-lib', + version: '1.0.0', + digest: `sha256:${'a'.repeat(64)}`, + registry_url: 'https://my-registry.org' }) }) .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) }) it('persists the storage record', async () => { - await expect( - createStorageRecord(options) - ).resolves.toEqual(['123', '456']) + await expect(createStorageRecord(options)).resolves.toEqual([ + '123', + '456' + ]) }) }) @@ -68,10 +68,10 @@ describe('createStorageRecord', () => { method: 'POST', headers: {authorization: `token ${token}`}, body: JSON.stringify({ - name: "my-lib", - version: "1.0.0", - digest: "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", - registry_url: "https://my-registry.org" + name: 'my-lib', + version: '1.0.0', + digest: `sha256:${'a'.repeat(64)}`, + registry_url: 'https://my-registry.org' }) }) .reply(500, 'oops') @@ -81,7 +81,7 @@ describe('createStorageRecord', () => { await expect( createStorageRecord({ ...options, - writeOptions: {retry: 0}, + writeOptions: {retry: 0} }) ).rejects.toThrow(/oops/) }) @@ -98,7 +98,7 @@ describe('createStorageRecord', () => { headers: {authorization: `token ${token}`}, body: JSON.stringify({ ...options.artifactOptions, - registry_url: options.packageRegistryOptions.registryUrl, + registry_url: options.packageRegistryOptions.registryUrl }) }) .reply(500, 'oops') @@ -111,18 +111,20 @@ describe('createStorageRecord', () => { headers: {authorization: `token ${token}`}, body: JSON.stringify({ ...options.artifactOptions, - registry_url: options.packageRegistryOptions.registryUrl, + registry_url: options.packageRegistryOptions.registryUrl }) }) .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) .times(1) }) - it('persists the attestation', async () => { - await expect(createStorageRecord({ - ...options, - writeOptions: {}, - })).resolves.toEqual(['123', '456']) + it('persists the storage record', async () => { + await expect( + createStorageRecord({ + ...options, + writeOptions: {} + }) + ).resolves.toEqual(['123', '456']) }) }) }) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index 6b94dc20..f24b6806 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -2,7 +2,8 @@ import * as github from '@actions/github' import {retry} from '@octokit/plugin-retry' import {RequestHeaders} from '@octokit/types' -const CREATE_STORAGE_RECORD_REQUEST = 'POST /orgs/{owner}/artifacts/metadata/storage-record' +const CREATE_STORAGE_RECORD_REQUEST = + 'POST /orgs/{owner}/artifacts/metadata/storage-record' const DEFAULT_RETRY_COUNT = 5 /** @@ -19,7 +20,7 @@ export type StorageRecordOptions = { version?: string // The status of the artifact status?: string - }, + } // Includes details about the package registry the artifact was published to packageRegistryOptions: { // The URL of the package registry @@ -30,14 +31,14 @@ export type StorageRecordOptions = { repo?: string // The path of the artifact in the package registry repository. path?: string - }, + } // GitHub token for writing attestations. token: string // Optional parameters for the write operation. writeOptions: { // The number of times to retry the request. retry?: number - // HTTP headers to include in request to Artifact Metadata API. + // HTTP headers to include in request to Artifact Metadata API. headers?: RequestHeaders } } @@ -48,7 +49,9 @@ export type StorageRecordOptions = { * @returns The ID of the storage record. * @throws Error if the storage record fails to persist. */ -export async function createStorageRecord(options: StorageRecordOptions): Promise> { +export async function createStorageRecord( + options: StorageRecordOptions +): Promise { const retries = options.writeOptions.retry ?? DEFAULT_RETRY_COUNT const octokit = github.getOctokit(options.token, {retry: {retries}}, retry) @@ -56,7 +59,7 @@ export async function createStorageRecord(options: StorageRecordOptions): Promis const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, { owner: github.context.repo.owner, headers: options.writeOptions.headers, - ...buildRequestParams(options), + ...buildRequestParams(options) }) const data = @@ -64,19 +67,19 @@ export async function createStorageRecord(options: StorageRecordOptions): Promis ? JSON.parse(response.data) : response.data - return data?.storage_records.map((r: { id: any }) => r.id) + return data?.storage_records.map((r: {id: number}) => String(r.id)) } catch (err) { const message = err instanceof Error ? err.message : err throw new Error(`Failed to persist storage record: ${message}`) } } -const buildRequestParams = (options: StorageRecordOptions) => { - const { registryUrl, artifactUrl, ...rest } = options.packageRegistryOptions +function buildRequestParams(options: StorageRecordOptions): Object { + const {registryUrl, artifactUrl, ...rest} = options.packageRegistryOptions return { ...options.artifactOptions, registry_url: registryUrl, artifact_url: artifactUrl, - ...rest, + ...rest } } From 7847d316962c080a2ed9b865704f4af2c6841536 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 16:30:25 -0800 Subject: [PATCH 16/22] Update packages/attest/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/attest/README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/attest/README.md b/packages/attest/README.md index 6331d86a..49903437 100644 --- a/packages/attest/README.md +++ b/packages/attest/README.md @@ -190,10 +190,14 @@ async function run() { const ghToken = core.getInput('gh-token'); const record = await createStorageRecord({ - name: 'my-artifact-name', - digest: { 'sha256': '36ab4667...'}, - version: "v1.0.0", - registry_url: "https://my-fave-pkg-registry.com", + artifactOptions: { + name: 'my-artifact-name', + digest: { 'sha256': '36ab4667...'}, + version: "v1.0.0" + }, + packageRegistryOptions: { + registryUrl: "https://my-fave-pkg-registry.com" + }, token: ghToken }); From dc9f635a0d93dc81c58566b1eaae743eb046064d Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 16:30:37 -0800 Subject: [PATCH 17/22] Update packages/attest/src/artifactMetadata.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/attest/src/artifactMetadata.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index f24b6806..503606af 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -74,7 +74,7 @@ export async function createStorageRecord( } } -function buildRequestParams(options: StorageRecordOptions): Object { +function buildRequestParams(options: StorageRecordOptions): Record { const {registryUrl, artifactUrl, ...rest} = options.packageRegistryOptions return { ...options.artifactOptions, From c40fa0d905f48bebdc6706f377da2e776caf4f15 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 19:19:11 -0800 Subject: [PATCH 18/22] formatting Signed-off-by: Meredith Lancaster --- packages/attest/src/artifactMetadata.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index 503606af..bb20bf68 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -74,7 +74,9 @@ export async function createStorageRecord( } } -function buildRequestParams(options: StorageRecordOptions): Record { +function buildRequestParams( + options: StorageRecordOptions +): Record { const {registryUrl, artifactUrl, ...rest} = options.packageRegistryOptions return { ...options.artifactOptions, From 87afd16bb24271ad8fcb5d88ab37939e8d8b9247 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 19:19:29 -0800 Subject: [PATCH 19/22] bump to next minor version Signed-off-by: Meredith Lancaster --- packages/attest/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/attest/package.json b/packages/attest/package.json index d8b70ee8..371c553f 100644 --- a/packages/attest/package.json +++ b/packages/attest/package.json @@ -1,6 +1,6 @@ { "name": "@actions/attest", - "version": "2.0.0", + "version": "2.1.0", "description": "Actions attestation lib", "keywords": [ "github", @@ -55,4 +55,4 @@ "@octokit/core": "^5.2.0" } } -} \ No newline at end of file +} From 97b7fa81c896cb070bc1a2294cdc1b9abc9878a2 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 19:22:04 -0800 Subject: [PATCH 20/22] regenerate package lock Signed-off-by: Meredith Lancaster --- packages/attest/package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/attest/package-lock.json b/packages/attest/package-lock.json index 97242457..a3309fcd 100644 --- a/packages/attest/package-lock.json +++ b/packages/attest/package-lock.json @@ -1,12 +1,12 @@ { "name": "@actions/attest", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@actions/attest", - "version": "2.0.0", + "version": "2.1.0", "license": "MIT", "dependencies": { "@actions/core": "^1.11.1", From 0380590fdd9cc05882974277c52b8647873fb676 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Tue, 9 Dec 2025 08:02:38 -0800 Subject: [PATCH 21/22] fix expected endpoint response Signed-off-by: Meredith Lancaster --- packages/attest/__tests__/artifactMetadata.test.ts | 10 +++++----- packages/attest/src/artifactMetadata.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/attest/__tests__/artifactMetadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts index 051ea314..0b578945 100644 --- a/packages/attest/__tests__/artifactMetadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -48,13 +48,13 @@ describe('createStorageRecord', () => { registry_url: 'https://my-registry.org' }) }) - .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) + .reply(200, {storage_records: [{id: 123}, {id: 456}]}) }) it('persists the storage record', async () => { await expect(createStorageRecord(options)).resolves.toEqual([ - '123', - '456' + 123, + 456 ]) }) }) @@ -114,7 +114,7 @@ describe('createStorageRecord', () => { registry_url: options.packageRegistryOptions.registryUrl }) }) - .reply(201, {storage_records: [{id: '123'}, {id: '456'}]}) + .reply(200, {storage_records: [{id: 123}, {id: 456}]}) .times(1) }) @@ -124,7 +124,7 @@ describe('createStorageRecord', () => { ...options, writeOptions: {} }) - ).resolves.toEqual(['123', '456']) + ).resolves.toEqual([123, 456]) }) }) }) diff --git a/packages/attest/src/artifactMetadata.ts b/packages/attest/src/artifactMetadata.ts index bb20bf68..6a5c514f 100644 --- a/packages/attest/src/artifactMetadata.ts +++ b/packages/attest/src/artifactMetadata.ts @@ -51,7 +51,7 @@ export type StorageRecordOptions = { */ export async function createStorageRecord( options: StorageRecordOptions -): Promise { +): Promise { const retries = options.writeOptions.retry ?? DEFAULT_RETRY_COUNT const octokit = github.getOctokit(options.token, {retry: {retries}}, retry) @@ -67,7 +67,7 @@ export async function createStorageRecord( ? JSON.parse(response.data) : response.data - return data?.storage_records.map((r: {id: number}) => String(r.id)) + return data?.storage_records.map((r: {id: number}) => r.id) } catch (err) { const message = err instanceof Error ? err.message : err throw new Error(`Failed to persist storage record: ${message}`) From d795a0ad0d7cc17a81a616dcafd59a250ced66d9 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Tue, 9 Dec 2025 08:32:31 -0800 Subject: [PATCH 22/22] linter fix Signed-off-by: Meredith Lancaster --- packages/attest/__tests__/artifactMetadata.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/attest/__tests__/artifactMetadata.test.ts b/packages/attest/__tests__/artifactMetadata.test.ts index 0b578945..c447ba55 100644 --- a/packages/attest/__tests__/artifactMetadata.test.ts +++ b/packages/attest/__tests__/artifactMetadata.test.ts @@ -52,10 +52,7 @@ describe('createStorageRecord', () => { }) it('persists the storage record', async () => { - await expect(createStorageRecord(options)).resolves.toEqual([ - 123, - 456 - ]) + await expect(createStorageRecord(options)).resolves.toEqual([123, 456]) }) })