From 417dbfff73c380d816193eee9afaaf1e0806d77d Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 8 Dec 2025 13:17:08 -0800 Subject: [PATCH] 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}`)