Merge pull request #2196 from actions/update-attest-storage-record-params

Refactor attest package createStorageRecord function params
This commit is contained in:
Meredith Lancaster
2025-12-09 11:49:14 -08:00
committed by GitHub
3 changed files with 103 additions and 99 deletions
+30 -34
View File
@@ -189,7 +189,7 @@ async function run() {
// repository write permissions.
const ghToken = core.getInput('gh-token');
const record = await createStorageRecord({
const record = await createStorageRecord(
artifactOptions: {
name: 'my-artifact-name',
digest: { 'sha256': '36ab4667...'},
@@ -199,7 +199,7 @@ async function run() {
registryUrl: "https://my-fave-pkg-registry.com"
},
token: ghToken
});
);
console.log(record);
}
@@ -210,39 +210,35 @@ 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
}
// Artifact details to associate the record with
export type 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
export type 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.
// The number of times to retry the request.
retryAttempts?: number
// HTTP headers to include in request to Artifact Metadata API.
headers?: RequestHeaders
```
## Sigstore Instance
@@ -6,17 +6,13 @@ describe('createStorageRecord', () => {
const token = 'token'
const headers = {'X-GitHub-Foo': 'true'}
const options = {
artifactOptions: {
name: 'my-lib',
version: '1.0.0',
digest: `sha256:${'a'.repeat(64)}`
},
packageRegistryOptions: {
registryUrl: 'https://my-registry.org'
},
token,
writeOptions: {headers}
const artifactOptions = {
name: 'my-lib',
version: '1.0.0',
digest: `sha256:${'a'.repeat(64)}`
}
const packageRegistryOptions = {
registryUrl: 'https://my-registry.org'
}
const mockAgent = new MockAgent()
@@ -52,7 +48,15 @@ describe('createStorageRecord', () => {
})
it('persists the storage record', async () => {
await expect(createStorageRecord(options)).resolves.toEqual([123, 456])
await expect(
createStorageRecord(
artifactOptions,
packageRegistryOptions,
token,
undefined,
headers
)
).resolves.toEqual([123, 456])
})
})
@@ -76,10 +80,13 @@ describe('createStorageRecord', () => {
it('throws an error', async () => {
await expect(
createStorageRecord({
...options,
writeOptions: {retry: 0}
})
createStorageRecord(
artifactOptions,
packageRegistryOptions,
token,
0,
headers
)
).rejects.toThrow(/oops/)
})
})
@@ -94,8 +101,8 @@ describe('createStorageRecord', () => {
method: 'POST',
headers: {authorization: `token ${token}`},
body: JSON.stringify({
...options.artifactOptions,
registry_url: options.packageRegistryOptions.registryUrl
...artifactOptions,
registry_url: packageRegistryOptions.registryUrl
})
})
.reply(500, 'oops')
@@ -107,8 +114,8 @@ describe('createStorageRecord', () => {
method: 'POST',
headers: {authorization: `token ${token}`},
body: JSON.stringify({
...options.artifactOptions,
registry_url: options.packageRegistryOptions.registryUrl
...artifactOptions,
registry_url: packageRegistryOptions.registryUrl
})
})
.reply(200, {storage_records: [{id: 123}, {id: 456}]})
@@ -117,10 +124,13 @@ describe('createStorageRecord', () => {
it('persists the storage record', async () => {
await expect(
createStorageRecord({
...options,
writeOptions: {}
})
createStorageRecord(
artifactOptions,
packageRegistryOptions,
token,
undefined,
headers
)
).resolves.toEqual([123, 456])
})
})
+39 -41
View File
@@ -9,57 +9,54 @@ const DEFAULT_RETRY_COUNT = 5
/**
* Options for creating a storage record for an attested artifact.
*/
export type StorageRecordOptions = {
export type ArtifactOptions = {
// 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
}
// 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
export type 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
}
/**
* Writes a storage record on behalf of an artifact that has been attested
* @param StorageRecordOptions - parameters for the storage record API request.
* @param artifactOptions - parameters for the storage record API request.
* @param packageRegistryOptions - parameters for the package registry API request.
* @param token - GitHub token used to authenticate the request.
* @param retryAttempts - The number of retries to attempt if the request fails.
* @param headers - Additional headers to include in the request.
*
* @returns The ID of the storage record.
* @throws Error if the storage record fails to persist.
*/
export async function createStorageRecord(
options: StorageRecordOptions
artifactOptions: ArtifactOptions,
packageRegistryOptions: PackageRegistryOptions,
token: string,
retryAttempts?: number,
headers?: RequestHeaders
): Promise<number[]> {
const retries = options.writeOptions.retry ?? DEFAULT_RETRY_COUNT
const octokit = github.getOctokit(options.token, {retry: {retries}}, retry)
const retries = retryAttempts ?? 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,
headers: options.writeOptions.headers,
...buildRequestParams(options)
headers,
...buildRequestParams(artifactOptions, packageRegistryOptions)
})
const data =
@@ -75,11 +72,12 @@ export async function createStorageRecord(
}
function buildRequestParams(
options: StorageRecordOptions
artifactOptions: ArtifactOptions,
packageRegistryOptions: PackageRegistryOptions
): Record<string, unknown> {
const {registryUrl, artifactUrl, ...rest} = options.packageRegistryOptions
const {registryUrl, artifactUrl, ...rest} = packageRegistryOptions
return {
...options.artifactOptions,
...artifactOptions,
registry_url: registryUrl,
artifact_url: artifactUrl,
...rest