2025-12-08 10:49:24 -08:00
|
|
|
import * as github from '@actions/github'
|
|
|
|
|
import {retry} from '@octokit/plugin-retry'
|
|
|
|
|
import {RequestHeaders} from '@octokit/types'
|
|
|
|
|
|
2025-12-08 16:22:59 -08:00
|
|
|
const CREATE_STORAGE_RECORD_REQUEST =
|
|
|
|
|
'POST /orgs/{owner}/artifacts/metadata/storage-record'
|
2025-12-08 10:49:24 -08:00
|
|
|
const DEFAULT_RETRY_COUNT = 5
|
|
|
|
|
|
2025-12-08 15:25:34 -08:00
|
|
|
/**
|
|
|
|
|
* 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
|
2025-12-08 16:22:59 -08:00
|
|
|
}
|
2025-12-08 15:25:34 -08:00
|
|
|
// 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
|
2025-12-08 16:22:59 -08:00
|
|
|
}
|
2025-12-08 15:25:34 -08:00
|
|
|
// GitHub token for writing attestations.
|
|
|
|
|
token: string
|
|
|
|
|
// Optional parameters for the write operation.
|
|
|
|
|
writeOptions: {
|
|
|
|
|
// The number of times to retry the request.
|
|
|
|
|
retry?: number
|
2025-12-08 16:22:59 -08:00
|
|
|
// HTTP headers to include in request to Artifact Metadata API.
|
2025-12-08 15:25:34 -08:00
|
|
|
headers?: RequestHeaders
|
|
|
|
|
}
|
2025-12-08 10:49:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-12-08 11:02:59 -08:00
|
|
|
* Writes a storage record on behalf of an artifact that has been attested
|
2025-12-08 15:33:01 -08:00
|
|
|
* @param StorageRecordOptions - parameters for the storage record API request.
|
2025-12-08 10:49:24 -08:00
|
|
|
* @returns The ID of the storage record.
|
|
|
|
|
* @throws Error if the storage record fails to persist.
|
|
|
|
|
*/
|
2025-12-08 16:22:59 -08:00
|
|
|
export async function createStorageRecord(
|
|
|
|
|
options: StorageRecordOptions
|
|
|
|
|
): Promise<string[]> {
|
2025-12-08 15:25:34 -08:00
|
|
|
const retries = options.writeOptions.retry ?? DEFAULT_RETRY_COUNT
|
|
|
|
|
const octokit = github.getOctokit(options.token, {retry: {retries}}, retry)
|
2025-12-08 10:49:24 -08:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, {
|
|
|
|
|
owner: github.context.repo.owner,
|
2025-12-08 15:25:34 -08:00
|
|
|
headers: options.writeOptions.headers,
|
2025-12-08 16:22:59 -08:00
|
|
|
...buildRequestParams(options)
|
2025-12-08 10:49:24 -08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const data =
|
|
|
|
|
typeof response.data == 'string'
|
|
|
|
|
? JSON.parse(response.data)
|
|
|
|
|
: response.data
|
2025-12-08 13:17:08 -08:00
|
|
|
|
2025-12-08 16:22:59 -08:00
|
|
|
return data?.storage_records.map((r: {id: number}) => String(r.id))
|
2025-12-08 10:49:24 -08:00
|
|
|
} catch (err) {
|
|
|
|
|
const message = err instanceof Error ? err.message : err
|
|
|
|
|
throw new Error(`Failed to persist storage record: ${message}`)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-08 15:39:26 -08:00
|
|
|
|
2025-12-08 16:30:37 -08:00
|
|
|
function buildRequestParams(options: StorageRecordOptions): Record<string, unknown> {
|
2025-12-08 16:22:59 -08:00
|
|
|
const {registryUrl, artifactUrl, ...rest} = options.packageRegistryOptions
|
2025-12-08 15:39:26 -08:00
|
|
|
return {
|
|
|
|
|
...options.artifactOptions,
|
|
|
|
|
registry_url: registryUrl,
|
|
|
|
|
artifact_url: artifactUrl,
|
2025-12-08 16:22:59 -08:00
|
|
|
...rest
|
2025-12-08 15:39:26 -08:00
|
|
|
}
|
|
|
|
|
}
|