mirror of https://github.com/actions/toolkit
utilize client, fetch IDs
parent
92695f58da
commit
73ad88882e
|
@ -12,6 +12,7 @@
|
|||
"@actions/core": "^1.10.0",
|
||||
"@actions/http-client": "^2.1.0",
|
||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"twirp-ts": "^2.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -198,6 +199,11 @@
|
|||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/jwt-decode": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
|
||||
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
"@actions/core": "^1.10.0",
|
||||
"@actions/http-client": "^2.1.0",
|
||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"twirp-ts": "^2.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import {getRetentionDays, getRuntimeToken} from './config'
|
||||
import jwt_decode from 'jwt-decode'
|
||||
import {Timestamp} from 'src/generated'
|
||||
|
||||
export interface BackendIds {
|
||||
workflowRunBackendId: string
|
||||
workflowJobRunBackendId: string
|
||||
}
|
||||
|
||||
interface ActionsToken {
|
||||
scp: string
|
||||
}
|
||||
|
||||
// uses the JWT token claims to get the
|
||||
// workflow run and workflow job run backend ids
|
||||
export function getBackendIdsFromToken(): BackendIds {
|
||||
const token = getRuntimeToken()
|
||||
const decoded = jwt_decode<ActionsToken>(token)
|
||||
if (!decoded.scp) {
|
||||
throw new Error('No scp claim in JWT token')
|
||||
}
|
||||
|
||||
/*
|
||||
* example decoded:
|
||||
* {
|
||||
* scp: "Actions.ExampleScope Actions.Results:ce7f54c7-61c7-4aae-887f-30da475f5f1a:ca395085-040a-526b-2ce8-bdc85f692774"
|
||||
* }
|
||||
*/
|
||||
|
||||
const scpParts = decoded.scp.split(' ')
|
||||
if (scpParts.length === 0) {
|
||||
throw new Error('No scp parts in JWT token')
|
||||
}
|
||||
/*
|
||||
* example scpParts:
|
||||
* ["Actions.ExampleScope", "Actions.Results:ce7f54c7-61c7-4aae-887f-30da475f5f1a:ca395085-040a-526b-2ce8-bdc85f692774"]
|
||||
*/
|
||||
|
||||
for (const scopes of scpParts) {
|
||||
const scopeParts = scopes.split(':')
|
||||
/*
|
||||
* example scopeParts:
|
||||
* ["Actions.Results", "ce7f54c7-61c7-4aae-887f-30da475f5f1a", "ca395085-040a-526b-2ce8-bdc85f692774"]
|
||||
*/
|
||||
if (scopeParts.length !== 3) {
|
||||
// not the Actions.Results scope
|
||||
continue
|
||||
}
|
||||
|
||||
if (scopeParts[0] !== 'Actions.Results') {
|
||||
// not the Actions.Results scope
|
||||
continue
|
||||
}
|
||||
|
||||
return {
|
||||
workflowRunBackendId: scopeParts[1],
|
||||
workflowJobRunBackendId: scopeParts[2]
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('No valid Actions.Results scope in JWT token')
|
||||
}
|
||||
|
||||
export function getExpiration(retentionDays?: number): Timestamp | undefined {
|
||||
if (!retentionDays) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const expirationDate = new Date()
|
||||
expirationDate.setDate(expirationDate.getDate() + retentionDays)
|
||||
|
||||
return Timestamp.fromDate(expirationDate)
|
||||
}
|
|
@ -2,11 +2,18 @@ import * as core from '@actions/core'
|
|||
import {UploadOptions} from './upload-options'
|
||||
import {UploadResponse} from './upload-response'
|
||||
import {validateArtifactName} from './path-and-artifact-name-validation'
|
||||
import {createArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||
import {
|
||||
UploadZipSpecification,
|
||||
getUploadZipSpecification,
|
||||
validateRootDirectory
|
||||
} from './upload-zip-specification'
|
||||
import {BackendIds, getBackendIdsFromToken, getExpiration} from '../shared/util'
|
||||
import {
|
||||
CreateArtifactRequest,
|
||||
CreateArtifactResponse,
|
||||
FinalizeArtifactResponse
|
||||
} from 'src/generated'
|
||||
|
||||
export async function uploadArtifact(
|
||||
name: string,
|
||||
|
@ -14,8 +21,17 @@ export async function uploadArtifact(
|
|||
rootDirectory: string,
|
||||
options?: UploadOptions | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): Promise<UploadResponse> {
|
||||
try {
|
||||
validateArtifactName(name)
|
||||
validateRootDirectory(rootDirectory)
|
||||
} catch (error) {
|
||||
core.warning(
|
||||
`Received error trying to validate artifact name or root directory: ${error}`
|
||||
)
|
||||
return {
|
||||
success: false
|
||||
}
|
||||
}
|
||||
|
||||
const zipSpecification: UploadZipSpecification[] = getUploadZipSpecification(
|
||||
files,
|
||||
|
@ -28,13 +44,97 @@ export async function uploadArtifact(
|
|||
}
|
||||
}
|
||||
|
||||
// get the IDs needed for the artifact creation
|
||||
const backendIds = getBackendIds()
|
||||
if (!backendIds.workflowRunBackendId || !backendIds.workflowJobRunBackendId) {
|
||||
core.warning(`Failed to get backend ids`)
|
||||
return {
|
||||
success: false
|
||||
}
|
||||
}
|
||||
|
||||
// create the artifact client
|
||||
const artifactClient = createArtifactTwirpClient('upload')
|
||||
|
||||
// create the artifact
|
||||
const createArtifactReq: CreateArtifactRequest = {
|
||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
||||
name: name,
|
||||
version: 4
|
||||
}
|
||||
|
||||
// if there is a retention period, add it to the request
|
||||
const expiresAt = getExpiration(options?.retentionDays)
|
||||
if (expiresAt) {
|
||||
createArtifactReq.expiresAt = expiresAt
|
||||
}
|
||||
const createArtifactResp = await createArtifact(() =>
|
||||
artifactClient.CreateArtifact(createArtifactReq)
|
||||
)
|
||||
if (!createArtifactResp || !createArtifactResp.ok) {
|
||||
core.warning(`Failed to create artifact`)
|
||||
return {
|
||||
success: false
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - Implement upload functionality
|
||||
|
||||
// finalize the artifact
|
||||
const finalizeArtifactResp = await finalizeArtifact(() =>
|
||||
artifactClient.FinalizeArtifact({
|
||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
||||
name: name,
|
||||
size: '0' // TODO - Add size
|
||||
})
|
||||
)
|
||||
if (!finalizeArtifactResp || !finalizeArtifactResp.ok) {
|
||||
core.warning(`Failed to finalize artifact`)
|
||||
return {
|
||||
success: false
|
||||
}
|
||||
}
|
||||
const uploadResponse: UploadResponse = {
|
||||
success: true,
|
||||
size: 0,
|
||||
id: 0
|
||||
id: parseInt(finalizeArtifactResp.artifactId) // TODO - will this be a problem due to the id being a bigint?
|
||||
}
|
||||
|
||||
return uploadResponse
|
||||
}
|
||||
|
||||
async function createArtifact(
|
||||
operation: () => Promise<CreateArtifactResponse>
|
||||
): Promise<CreateArtifactResponse | undefined> {
|
||||
try {
|
||||
return await operation()
|
||||
} catch (error) {
|
||||
core.warning(`Received error trying to create artifact: ${error}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
async function finalizeArtifact(
|
||||
operation: () => Promise<FinalizeArtifactResponse>
|
||||
): Promise<FinalizeArtifactResponse | undefined> {
|
||||
try {
|
||||
return await operation()
|
||||
} catch (error) {
|
||||
core.warning(`Received error trying to create artifact: ${error}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function getBackendIds(): BackendIds {
|
||||
try {
|
||||
return getBackendIdsFromToken()
|
||||
} catch (error) {
|
||||
core.warning(`Received error trying to get backend ids: ${error}`)
|
||||
return {
|
||||
workflowRunBackendId: '',
|
||||
workflowJobRunBackendId: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue