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/core": "^1.10.0",
|
||||||
"@actions/http-client": "^2.1.0",
|
"@actions/http-client": "^2.1.0",
|
||||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
"twirp-ts": "^2.5.0"
|
"twirp-ts": "^2.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -198,6 +199,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
"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": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/http-client": "^2.1.0",
|
"@actions/http-client": "^2.1.0",
|
||||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
"twirp-ts": "^2.5.0"
|
"twirp-ts": "^2.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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 {UploadOptions} from './upload-options'
|
||||||
import {UploadResponse} from './upload-response'
|
import {UploadResponse} from './upload-response'
|
||||||
import {validateArtifactName} from './path-and-artifact-name-validation'
|
import {validateArtifactName} from './path-and-artifact-name-validation'
|
||||||
|
import {createArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||||
import {
|
import {
|
||||||
UploadZipSpecification,
|
UploadZipSpecification,
|
||||||
getUploadZipSpecification,
|
getUploadZipSpecification,
|
||||||
validateRootDirectory
|
validateRootDirectory
|
||||||
} from './upload-zip-specification'
|
} from './upload-zip-specification'
|
||||||
|
import {BackendIds, getBackendIdsFromToken, getExpiration} from '../shared/util'
|
||||||
|
import {
|
||||||
|
CreateArtifactRequest,
|
||||||
|
CreateArtifactResponse,
|
||||||
|
FinalizeArtifactResponse
|
||||||
|
} from 'src/generated'
|
||||||
|
|
||||||
export async function uploadArtifact(
|
export async function uploadArtifact(
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -14,8 +21,17 @@ export async function uploadArtifact(
|
||||||
rootDirectory: string,
|
rootDirectory: string,
|
||||||
options?: UploadOptions | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
|
options?: UploadOptions | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
): Promise<UploadResponse> {
|
): Promise<UploadResponse> {
|
||||||
|
try {
|
||||||
validateArtifactName(name)
|
validateArtifactName(name)
|
||||||
validateRootDirectory(rootDirectory)
|
validateRootDirectory(rootDirectory)
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Received error trying to validate artifact name or root directory: ${error}`
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
success: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const zipSpecification: UploadZipSpecification[] = getUploadZipSpecification(
|
const zipSpecification: UploadZipSpecification[] = getUploadZipSpecification(
|
||||||
files,
|
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
|
// 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 = {
|
const uploadResponse: UploadResponse = {
|
||||||
success: true,
|
success: true,
|
||||||
size: 0,
|
size: 0,
|
||||||
id: 0
|
id: parseInt(finalizeArtifactResp.artifactId) // TODO - will this be a problem due to the id being a bigint?
|
||||||
}
|
}
|
||||||
|
|
||||||
return uploadResponse
|
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