From b81a61586207613b76f83657fad9407c74296ad4 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:47:20 +0000 Subject: [PATCH 01/12] Bump artifact version, do digest check --- .licenses/npm/@actions/artifact.dep.yml | 2 +- package-lock.json | 16 ++++++++-------- package.json | 4 ++-- src/download-artifact.ts | 12 +++++++++++- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.licenses/npm/@actions/artifact.dep.yml b/.licenses/npm/@actions/artifact.dep.yml index 33a2153..0305b13 100644 --- a/.licenses/npm/@actions/artifact.dep.yml +++ b/.licenses/npm/@actions/artifact.dep.yml @@ -1,6 +1,6 @@ --- name: "@actions/artifact" -version: 2.2.2 +version: 2.3.1 type: npm summary: Actions artifact lib homepage: https://github.com/actions/toolkit/tree/main/packages/artifact diff --git a/package-lock.json b/package-lock.json index d038224..46995c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "download-artifact", - "version": "4.1.9", + "version": "4.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "download-artifact", - "version": "4.1.9", + "version": "4.2.0", "license": "MIT", "dependencies": { "@actions/artifact": "^2.2.2", @@ -36,9 +36,9 @@ } }, "node_modules/@actions/artifact": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.2.2.tgz", - "integrity": "sha512-UtS1kcINiPRkI3/hDKkO/XdrtKo89kn8s81J67QNBU6RRMWSSXrrfCCbQVThuxcdW2boOLv51NVCEKyo954A2A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.1.tgz", + "integrity": "sha512-3uW25BNAqbMBcasNK+DX4I0Vl8aQdo65K6DRufJiNYjqfhSMfeRE4YGjWLaKmF+H+7bp1ADlQ5NksC61fpvYbQ==", "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", @@ -6032,9 +6032,9 @@ "dev": true }, "@actions/artifact": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.2.2.tgz", - "integrity": "sha512-UtS1kcINiPRkI3/hDKkO/XdrtKo89kn8s81J67QNBU6RRMWSSXrrfCCbQVThuxcdW2boOLv51NVCEKyo954A2A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.1.tgz", + "integrity": "sha512-3uW25BNAqbMBcasNK+DX4I0Vl8aQdo65K6DRufJiNYjqfhSMfeRE4YGjWLaKmF+H+7bp1ADlQ5NksC61fpvYbQ==", "requires": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", diff --git a/package.json b/package.json index 3b19587..1a7cbb5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "download-artifact", - "version": "4.1.9", + "version": "4.2.0", "description": "Download an Actions Artifact from a workflow run", "main": "dist/index.js", "scripts": { @@ -28,7 +28,7 @@ }, "homepage": "https://github.com/actions/download-artifact#readme", "dependencies": { - "@actions/artifact": "^2.2.2", + "@actions/artifact": "^2.3.1", "@actions/core": "^1.10.1", "@actions/github": "^5.1.1", "minimatch": "^9.0.3" diff --git a/src/download-artifact.ts b/src/download-artifact.ts index aedfe12..71852f3 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -117,7 +117,8 @@ async function run(): Promise { path: isSingleArtifactDownload || inputs.mergeMultiple ? resolvedPath - : path.join(resolvedPath, artifact.name) + : path.join(resolvedPath, artifact.name), + expectedHash: artifact.digest }) ) @@ -126,6 +127,15 @@ async function run(): Promise { await Promise.all(chunk) } + for (const dlPromise of downloadPromises) { + const outcome = await dlPromise + if (outcome.digestMismatch) { + core.warning( + `Artifact digest validation failed. Please verify the integrity of the artifact.` + ) + } + } + core.info(`Total of ${artifacts.length} artifact(s) downloaded`) core.setOutput(Outputs.DownloadPath, resolvedPath) core.info('Download artifact has finished successfully') From 24aef17bbf89f5b5e0b9792461a8d49e99b693c7 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:02:51 +0000 Subject: [PATCH 02/12] Refactor loop --- src/download-artifact.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/download-artifact.ts b/src/download-artifact.ts index 71852f3..68471c0 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -124,15 +124,13 @@ async function run(): Promise { const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS) for (const chunk of chunkedPromises) { - await Promise.all(chunk) - } - - for (const dlPromise of downloadPromises) { - const outcome = await dlPromise - if (outcome.digestMismatch) { - core.warning( - `Artifact digest validation failed. Please verify the integrity of the artifact.` - ) + const result = await Promise.all(chunk) + for (const outcome of result) { + if (outcome.digestMismatch) { + core.warning( + `Artifact digest validation failed. Please verify the integrity of the artifact.` + ) + } } } From a8a786b09748597c3fda97559758c9d91365f086 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:13:07 +0000 Subject: [PATCH 03/12] update dist --- dist/index.js | 344 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 315 insertions(+), 29 deletions(-) diff --git a/dist/index.js b/dist/index.js index b7f308c..2f24cb9 100644 --- a/dist/index.js +++ b/dist/index.js @@ -824,7 +824,7 @@ __exportStar(__nccwpck_require__(49773), exports); "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.ArtifactService = exports.DeleteArtifactResponse = exports.DeleteArtifactRequest = exports.GetSignedArtifactURLResponse = exports.GetSignedArtifactURLRequest = exports.ListArtifactsResponse_MonolithArtifact = exports.ListArtifactsResponse = exports.ListArtifactsRequest = exports.FinalizeArtifactResponse = exports.FinalizeArtifactRequest = exports.CreateArtifactResponse = exports.CreateArtifactRequest = void 0; +exports.ArtifactService = exports.DeleteArtifactResponse = exports.DeleteArtifactRequest = exports.GetSignedArtifactURLResponse = exports.GetSignedArtifactURLRequest = exports.ListArtifactsResponse_MonolithArtifact = exports.ListArtifactsResponse = exports.ListArtifactsRequest = exports.FinalizeArtifactResponse = exports.FinalizeArtifactRequest = exports.CreateArtifactResponse = exports.CreateArtifactRequest = exports.FinalizeMigratedArtifactResponse = exports.FinalizeMigratedArtifactRequest = exports.MigrateArtifactResponse = exports.MigrateArtifactRequest = void 0; // @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies // @generated from protobuf file "results/api/v1/artifact.proto" (package "github.actions.results.api.v1", syntax proto3) // tslint:disable @@ -838,6 +838,236 @@ const wrappers_1 = __nccwpck_require__(8626); const wrappers_2 = __nccwpck_require__(8626); const timestamp_1 = __nccwpck_require__(54622); // @generated message type with reflection information, may provide speed optimized methods +class MigrateArtifactRequest$Type extends runtime_5.MessageType { + constructor() { + super("github.actions.results.api.v1.MigrateArtifactRequest", [ + { no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "expires_at", kind: "message", T: () => timestamp_1.Timestamp } + ]); + } + create(value) { + const message = { workflowRunBackendId: "", name: "" }; + globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + (0, runtime_3.reflectionMergePartial)(this, message, value); + return message; + } + internalBinaryRead(reader, length, options, target) { + let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string workflow_run_backend_id */ 1: + message.workflowRunBackendId = reader.string(); + break; + case /* string name */ 2: + message.name = reader.string(); + break; + case /* google.protobuf.Timestamp expires_at */ 3: + message.expiresAt = timestamp_1.Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.expiresAt); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message, writer, options) { + /* string workflow_run_backend_id = 1; */ + if (message.workflowRunBackendId !== "") + writer.tag(1, runtime_1.WireType.LengthDelimited).string(message.workflowRunBackendId); + /* string name = 2; */ + if (message.name !== "") + writer.tag(2, runtime_1.WireType.LengthDelimited).string(message.name); + /* google.protobuf.Timestamp expires_at = 3; */ + if (message.expiresAt) + timestamp_1.Timestamp.internalBinaryWrite(message.expiresAt, writer.tag(3, runtime_1.WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message github.actions.results.api.v1.MigrateArtifactRequest + */ +exports.MigrateArtifactRequest = new MigrateArtifactRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class MigrateArtifactResponse$Type extends runtime_5.MessageType { + constructor() { + super("github.actions.results.api.v1.MigrateArtifactResponse", [ + { no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value) { + const message = { ok: false, signedUploadUrl: "" }; + globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + (0, runtime_3.reflectionMergePartial)(this, message, value); + return message; + } + internalBinaryRead(reader, length, options, target) { + let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bool ok */ 1: + message.ok = reader.bool(); + break; + case /* string signed_upload_url */ 2: + message.signedUploadUrl = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message, writer, options) { + /* bool ok = 1; */ + if (message.ok !== false) + writer.tag(1, runtime_1.WireType.Varint).bool(message.ok); + /* string signed_upload_url = 2; */ + if (message.signedUploadUrl !== "") + writer.tag(2, runtime_1.WireType.LengthDelimited).string(message.signedUploadUrl); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message github.actions.results.api.v1.MigrateArtifactResponse + */ +exports.MigrateArtifactResponse = new MigrateArtifactResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class FinalizeMigratedArtifactRequest$Type extends runtime_5.MessageType { + constructor() { + super("github.actions.results.api.v1.FinalizeMigratedArtifactRequest", [ + { no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ } + ]); + } + create(value) { + const message = { workflowRunBackendId: "", name: "", size: "0" }; + globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + (0, runtime_3.reflectionMergePartial)(this, message, value); + return message; + } + internalBinaryRead(reader, length, options, target) { + let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string workflow_run_backend_id */ 1: + message.workflowRunBackendId = reader.string(); + break; + case /* string name */ 2: + message.name = reader.string(); + break; + case /* int64 size */ 3: + message.size = reader.int64().toString(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message, writer, options) { + /* string workflow_run_backend_id = 1; */ + if (message.workflowRunBackendId !== "") + writer.tag(1, runtime_1.WireType.LengthDelimited).string(message.workflowRunBackendId); + /* string name = 2; */ + if (message.name !== "") + writer.tag(2, runtime_1.WireType.LengthDelimited).string(message.name); + /* int64 size = 3; */ + if (message.size !== "0") + writer.tag(3, runtime_1.WireType.Varint).int64(message.size); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeMigratedArtifactRequest + */ +exports.FinalizeMigratedArtifactRequest = new FinalizeMigratedArtifactRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class FinalizeMigratedArtifactResponse$Type extends runtime_5.MessageType { + constructor() { + super("github.actions.results.api.v1.FinalizeMigratedArtifactResponse", [ + { no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 2, name: "artifact_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ } + ]); + } + create(value) { + const message = { ok: false, artifactId: "0" }; + globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + (0, runtime_3.reflectionMergePartial)(this, message, value); + return message; + } + internalBinaryRead(reader, length, options, target) { + let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bool ok */ 1: + message.ok = reader.bool(); + break; + case /* int64 artifact_id */ 2: + message.artifactId = reader.int64().toString(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message, writer, options) { + /* bool ok = 1; */ + if (message.ok !== false) + writer.tag(1, runtime_1.WireType.Varint).bool(message.ok); + /* int64 artifact_id = 2; */ + if (message.artifactId !== "0") + writer.tag(2, runtime_1.WireType.Varint).int64(message.artifactId); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeMigratedArtifactResponse + */ +exports.FinalizeMigratedArtifactResponse = new FinalizeMigratedArtifactResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods class CreateArtifactRequest$Type extends runtime_5.MessageType { constructor() { super("github.actions.results.api.v1.CreateArtifactRequest", [ @@ -1219,7 +1449,8 @@ class ListArtifactsResponse_MonolithArtifact$Type extends runtime_5.MessageType { no: 3, name: "database_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }, { no: 4, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 5, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ }, - { no: 6, name: "created_at", kind: "message", T: () => timestamp_1.Timestamp } + { no: 6, name: "created_at", kind: "message", T: () => timestamp_1.Timestamp }, + { no: 7, name: "digest", kind: "message", T: () => wrappers_2.StringValue } ]); } create(value) { @@ -1252,6 +1483,9 @@ class ListArtifactsResponse_MonolithArtifact$Type extends runtime_5.MessageType case /* google.protobuf.Timestamp created_at */ 6: message.createdAt = timestamp_1.Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.createdAt); break; + case /* google.protobuf.StringValue digest */ 7: + message.digest = wrappers_2.StringValue.internalBinaryRead(reader, reader.uint32(), options, message.digest); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -1282,6 +1516,9 @@ class ListArtifactsResponse_MonolithArtifact$Type extends runtime_5.MessageType /* google.protobuf.Timestamp created_at = 6; */ if (message.createdAt) timestamp_1.Timestamp.internalBinaryWrite(message.createdAt, writer.tag(6, runtime_1.WireType.LengthDelimited).fork(), options).join(); + /* google.protobuf.StringValue digest = 7; */ + if (message.digest) + wrappers_2.StringValue.internalBinaryWrite(message.digest, writer.tag(7, runtime_1.WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -1523,7 +1760,9 @@ exports.ArtifactService = new runtime_rpc_1.ServiceType("github.actions.results. { name: "FinalizeArtifact", options: {}, I: exports.FinalizeArtifactRequest, O: exports.FinalizeArtifactResponse }, { name: "ListArtifacts", options: {}, I: exports.ListArtifactsRequest, O: exports.ListArtifactsResponse }, { name: "GetSignedArtifactURL", options: {}, I: exports.GetSignedArtifactURLRequest, O: exports.GetSignedArtifactURLResponse }, - { name: "DeleteArtifact", options: {}, I: exports.DeleteArtifactRequest, O: exports.DeleteArtifactResponse } + { name: "DeleteArtifact", options: {}, I: exports.DeleteArtifactRequest, O: exports.DeleteArtifactResponse }, + { name: "MigrateArtifact", options: {}, I: exports.MigrateArtifactRequest, O: exports.MigrateArtifactResponse }, + { name: "FinalizeMigratedArtifact", options: {}, I: exports.FinalizeMigratedArtifactRequest, O: exports.FinalizeMigratedArtifactResponse } ]); //# sourceMappingURL=artifact.js.map @@ -1920,6 +2159,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.downloadArtifactInternal = exports.downloadArtifactPublic = exports.streamExtractExternal = void 0; const promises_1 = __importDefault(__nccwpck_require__(73292)); +const crypto = __importStar(__nccwpck_require__(6113)); +const stream = __importStar(__nccwpck_require__(12781)); const github = __importStar(__nccwpck_require__(95438)); const core = __importStar(__nccwpck_require__(42186)); const httpClient = __importStar(__nccwpck_require__(96255)); @@ -1956,8 +2197,7 @@ function streamExtract(url, directory) { let retryCount = 0; while (retryCount < 5) { try { - yield streamExtractExternal(url, directory); - return; + return yield streamExtractExternal(url, directory); } catch (error) { retryCount++; @@ -1977,12 +2217,18 @@ function streamExtractExternal(url, directory) { throw new Error(`Unexpected HTTP response from blob storage: ${response.message.statusCode} ${response.message.statusMessage}`); } const timeout = 30 * 1000; // 30 seconds + let sha256Digest = undefined; return new Promise((resolve, reject) => { const timerFn = () => { response.message.destroy(new Error(`Blob storage chunk did not respond in ${timeout}ms`)); }; const timer = setTimeout(timerFn, timeout); - response.message + const hashStream = crypto.createHash('sha256').setEncoding('hex'); + const passThrough = new stream.PassThrough(); + response.message.pipe(passThrough); + passThrough.pipe(hashStream); + const extractStream = passThrough; + extractStream .on('data', () => { timer.refresh(); }) @@ -1994,7 +2240,12 @@ function streamExtractExternal(url, directory) { .pipe(unzip_stream_1.default.Extract({ path: directory })) .on('close', () => { clearTimeout(timer); - resolve(); + if (hashStream) { + hashStream.end(); + sha256Digest = hashStream.read(); + core.info(`SHA256 digest of downloaded artifact is ${sha256Digest}`); + } + resolve({ sha256Digest: `sha256:${sha256Digest}` }); }) .on('error', (error) => { reject(error); @@ -2007,6 +2258,7 @@ function downloadArtifactPublic(artifactId, repositoryOwner, repositoryName, tok return __awaiter(this, void 0, void 0, function* () { const downloadPath = yield resolveOrCreateDirectory(options === null || options === void 0 ? void 0 : options.path); const api = github.getOctokit(token); + let digestMismatch = false; core.info(`Downloading artifact '${artifactId}' from '${repositoryOwner}/${repositoryName}'`); const { headers, status } = yield api.rest.actions.downloadArtifact({ owner: repositoryOwner, @@ -2027,13 +2279,20 @@ function downloadArtifactPublic(artifactId, repositoryOwner, repositoryName, tok core.info(`Redirecting to blob download url: ${scrubQueryParameters(location)}`); try { core.info(`Starting download of artifact to: ${downloadPath}`); - yield streamExtract(location, downloadPath); + const extractResponse = yield streamExtract(location, downloadPath); core.info(`Artifact download completed successfully.`); + if (options === null || options === void 0 ? void 0 : options.expectedHash) { + if ((options === null || options === void 0 ? void 0 : options.expectedHash) !== extractResponse.sha256Digest) { + digestMismatch = true; + core.debug(`Computed digest: ${extractResponse.sha256Digest}`); + core.debug(`Expected digest: ${options.expectedHash}`); + } + } } catch (error) { throw new Error(`Unable to download and extract artifact: ${error.message}`); } - return { downloadPath }; + return { downloadPath, digestMismatch }; }); } exports.downloadArtifactPublic = downloadArtifactPublic; @@ -2041,6 +2300,7 @@ function downloadArtifactInternal(artifactId, options) { return __awaiter(this, void 0, void 0, function* () { const downloadPath = yield resolveOrCreateDirectory(options === null || options === void 0 ? void 0 : options.path); const artifactClient = (0, artifact_twirp_client_1.internalArtifactTwirpClient)(); + let digestMismatch = false; const { workflowRunBackendId, workflowJobRunBackendId } = (0, util_1.getBackendIdsFromToken)(); const listReq = { workflowRunBackendId, @@ -2063,13 +2323,20 @@ function downloadArtifactInternal(artifactId, options) { core.info(`Redirecting to blob download url: ${scrubQueryParameters(signedUrl)}`); try { core.info(`Starting download of artifact to: ${downloadPath}`); - yield streamExtract(signedUrl, downloadPath); + const extractResponse = yield streamExtract(signedUrl, downloadPath); core.info(`Artifact download completed successfully.`); + if (options === null || options === void 0 ? void 0 : options.expectedHash) { + if ((options === null || options === void 0 ? void 0 : options.expectedHash) !== extractResponse.sha256Digest) { + digestMismatch = true; + core.debug(`Computed digest: ${extractResponse.sha256Digest}`); + core.debug(`Expected digest: ${options.expectedHash}`); + } + } } catch (error) { throw new Error(`Unable to download and extract artifact: ${error.message}`); } - return { downloadPath }; + return { downloadPath, digestMismatch }; }); } exports.downloadArtifactInternal = downloadArtifactInternal; @@ -2175,13 +2442,17 @@ function getArtifactPublic(artifactName, workflowRunId, repositoryOwner, reposit name: artifact.name, id: artifact.id, size: artifact.size_in_bytes, - createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined + createdAt: artifact.created_at + ? new Date(artifact.created_at) + : undefined, + digest: artifact.digest } }; }); } exports.getArtifactPublic = getArtifactPublic; function getArtifactInternal(artifactName) { + var _a; return __awaiter(this, void 0, void 0, function* () { const artifactClient = (0, artifact_twirp_client_1.internalArtifactTwirpClient)(); const { workflowRunBackendId, workflowJobRunBackendId } = (0, util_1.getBackendIdsFromToken)(); @@ -2208,7 +2479,8 @@ function getArtifactInternal(artifactName) { size: Number(artifact.size), createdAt: artifact.createdAt ? generated_1.Timestamp.toDate(artifact.createdAt) - : undefined + : undefined, + digest: (_a = artifact.digest) === null || _a === void 0 ? void 0 : _a.value } }; }); @@ -2262,7 +2534,7 @@ function listArtifactsPublic(workflowRunId, repositoryOwner, repositoryName, tok }; const github = (0, github_1.getOctokit)(token, opts, plugin_retry_1.retry, plugin_request_log_1.requestLog); let currentPageNumber = 1; - const { data: listArtifactResponse } = yield github.rest.actions.listWorkflowRunArtifacts({ + const { data: listArtifactResponse } = yield github.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', { owner: repositoryOwner, repo: repositoryName, run_id: workflowRunId, @@ -2281,14 +2553,18 @@ function listArtifactsPublic(workflowRunId, repositoryOwner, repositoryName, tok name: artifact.name, id: artifact.id, size: artifact.size_in_bytes, - createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined + createdAt: artifact.created_at + ? new Date(artifact.created_at) + : undefined, + digest: artifact.digest }); } + // Move to the next page + currentPageNumber++; // Iterate over any remaining pages for (currentPageNumber; currentPageNumber < numberOfPages; currentPageNumber++) { - currentPageNumber++; (0, core_1.debug)(`Fetching page ${currentPageNumber} of artifact list`); - const { data: listArtifactResponse } = yield github.rest.actions.listWorkflowRunArtifacts({ + const { data: listArtifactResponse } = yield github.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', { owner: repositoryOwner, repo: repositoryName, run_id: workflowRunId, @@ -2302,7 +2578,8 @@ function listArtifactsPublic(workflowRunId, repositoryOwner, repositoryName, tok size: artifact.size_in_bytes, createdAt: artifact.created_at ? new Date(artifact.created_at) - : undefined + : undefined, + digest: artifact.digest }); } } @@ -2325,14 +2602,18 @@ function listArtifactsInternal(latest = false) { workflowJobRunBackendId }; const res = yield artifactClient.ListArtifacts(req); - let artifacts = res.artifacts.map(artifact => ({ - name: artifact.name, - id: Number(artifact.databaseId), - size: Number(artifact.size), - createdAt: artifact.createdAt - ? generated_1.Timestamp.toDate(artifact.createdAt) - : undefined - })); + let artifacts = res.artifacts.map(artifact => { + var _a; + return ({ + name: artifact.name, + id: Number(artifact.databaseId), + size: Number(artifact.size), + createdAt: artifact.createdAt + ? generated_1.Timestamp.toDate(artifact.createdAt) + : undefined, + digest: (_a = artifact.digest) === null || _a === void 0 ? void 0 : _a.value + }); + }); if (latest) { artifacts = filterLatest(artifacts); } @@ -118490,10 +118771,15 @@ function run() { } const downloadPromises = artifacts.map(artifact => artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || inputs.mergeMultiple ? resolvedPath - : path.join(resolvedPath, artifact.name) }))); + : path.join(resolvedPath, artifact.name), expectedHash: artifact.digest }))); const chunkedPromises = (0, exports.chunk)(downloadPromises, PARALLEL_DOWNLOADS); for (const chunk of chunkedPromises) { - yield Promise.all(chunk); + const result = yield Promise.all(chunk); + for (const outcome of result) { + if (outcome.digestMismatch) { + core.warning(`Artifact digest validation failed. Please verify the integrity of the artifact.`); + } + } } core.info(`Total of ${artifacts.length} artifact(s) downloaded`); core.setOutput(constants_1.Outputs.DownloadPath, resolvedPath); @@ -128475,7 +128761,7 @@ module.exports = index; /***/ ((module) => { "use strict"; -module.exports = JSON.parse('{"name":"@actions/artifact","version":"2.2.2","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","main":"lib/artifact.js","types":"lib/artifact.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.10.0","@actions/github":"^5.1.1","@actions/http-client":"^2.1.0","@azure/storage-blob":"^12.15.0","@octokit/core":"^3.5.1","@octokit/plugin-request-log":"^1.0.4","@octokit/plugin-retry":"^3.0.9","@octokit/request-error":"^5.0.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","archiver":"^7.0.1","jwt-decode":"^3.1.2","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^5.3.2","@types/unzip-stream":"^0.3.4","typedoc":"^0.25.4","typedoc-plugin-markdown":"^3.17.1","typescript":"^5.2.2"}}'); +module.exports = JSON.parse('{"name":"@actions/artifact","version":"2.3.1","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","main":"lib/artifact.js","types":"lib/artifact.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.10.0","@actions/github":"^5.1.1","@actions/http-client":"^2.1.0","@azure/storage-blob":"^12.15.0","@octokit/core":"^3.5.1","@octokit/plugin-request-log":"^1.0.4","@octokit/plugin-retry":"^3.0.9","@octokit/request-error":"^5.0.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","archiver":"^7.0.1","jwt-decode":"^3.1.2","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^5.3.2","@types/unzip-stream":"^0.3.4","typedoc":"^0.25.4","typedoc-plugin-markdown":"^3.17.1","typescript":"^5.2.2"}}'); /***/ }), From 503e7a18ae78e3d5a5fc4a3deabf32389c50d18b Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:40:05 +0000 Subject: [PATCH 04/12] Refactor loop, break for testing --- dist/index.js | 26 ++++++++++++++++---------- src/download-artifact.ts | 28 +++++++++++++++++----------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/dist/index.js b/dist/index.js index 2f24cb9..55201cc 100644 --- a/dist/index.js +++ b/dist/index.js @@ -118769,21 +118769,27 @@ function run() { core.info(`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size})`); }); } - const downloadPromises = artifacts.map(artifact => artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || inputs.mergeMultiple - ? resolvedPath - : path.join(resolvedPath, artifact.name), expectedHash: artifact.digest }))); + const downloadPromises = artifacts.map(artifact => ({ + name: artifact.name, + promise: artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || inputs.mergeMultiple + ? resolvedPath + : path.join(resolvedPath, artifact.name), expectedHash: artifact.digest })) + })); const chunkedPromises = (0, exports.chunk)(downloadPromises, PARALLEL_DOWNLOADS); for (const chunk of chunkedPromises) { - const result = yield Promise.all(chunk); - for (const outcome of result) { - if (outcome.digestMismatch) { - core.warning(`Artifact digest validation failed. Please verify the integrity of the artifact.`); + const chunkPromises = chunk.map(item => item.promise); + const results = yield Promise.all(chunkPromises); + for (let i = 0; i < results.length; i++) { + const outcome = results[i]; + const artifactName = chunk[i].name; + if (!outcome.digestMismatch) { + core.warning(`Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`); } } + core.info(`Total of ${artifacts.length} artifact(s) downloaded`); + core.setOutput(constants_1.Outputs.DownloadPath, resolvedPath); + core.info('Download artifact has finished successfully'); } - core.info(`Total of ${artifacts.length} artifact(s) downloaded`); - core.setOutput(constants_1.Outputs.DownloadPath, resolvedPath); - core.info('Download artifact has finished successfully'); }); } run().catch(err => core.setFailed(`Unable to download artifact(s): ${err.message}`)); diff --git a/src/download-artifact.ts b/src/download-artifact.ts index 68471c0..8ca8bb1 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -111,8 +111,9 @@ async function run(): Promise { }) } - const downloadPromises = artifacts.map(artifact => - artifactClient.downloadArtifact(artifact.id, { + const downloadPromises = artifacts.map(artifact => ({ + name: artifact.name, + promise: artifactClient.downloadArtifact(artifact.id, { ...options, path: isSingleArtifactDownload || inputs.mergeMultiple @@ -120,23 +121,28 @@ async function run(): Promise { : path.join(resolvedPath, artifact.name), expectedHash: artifact.digest }) - ) + })) const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS) for (const chunk of chunkedPromises) { - const result = await Promise.all(chunk) - for (const outcome of result) { - if (outcome.digestMismatch) { + const chunkPromises = chunk.map(item => item.promise) + const results = await Promise.all(chunkPromises) + + for (let i = 0; i < results.length; i++) { + const outcome = results[i] + const artifactName = chunk[i].name + + if (!outcome.digestMismatch) { core.warning( - `Artifact digest validation failed. Please verify the integrity of the artifact.` + `Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.` ) } } - } - core.info(`Total of ${artifacts.length} artifact(s) downloaded`) - core.setOutput(Outputs.DownloadPath, resolvedPath) - core.info('Download artifact has finished successfully') + core.info(`Total of ${artifacts.length} artifact(s) downloaded`) + core.setOutput(Outputs.DownloadPath, resolvedPath) + core.info('Download artifact has finished successfully') + } } run().catch(err => From 049eba1e9a28da1d0c4e70f64ccfc1750dc8506e Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:04:02 +0000 Subject: [PATCH 05/12] unbreak testing code --- src/download-artifact.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/download-artifact.ts b/src/download-artifact.ts index 8ca8bb1..1dfef71 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -132,7 +132,7 @@ async function run(): Promise { const outcome = results[i] const artifactName = chunk[i].name - if (!outcome.digestMismatch) { + if (outcome.digestMismatch) { core.warning( `Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.` ) From 9ff67cb2d239dc1b22dd32e6fb397baf426fbd81 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:17:52 +0000 Subject: [PATCH 06/12] Break the thing, also log the expected digest --- src/download-artifact.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/download-artifact.ts b/src/download-artifact.ts index 1dfef71..dda08c6 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -106,7 +106,7 @@ async function run(): Promise { core.info(`Preparing to download the following artifacts:`) artifacts.forEach(artifact => { core.info( - `- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size})` + `- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size}, Expected Digest: ${artifact.digest})` ) }) } @@ -132,7 +132,7 @@ async function run(): Promise { const outcome = results[i] const artifactName = chunk[i].name - if (outcome.digestMismatch) { + if (!outcome.digestMismatch) { core.warning( `Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.` ) From 7797bfcd595a02c92db44bc6b4bc430d99c32597 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:20:09 +0000 Subject: [PATCH 07/12] run release --- dist/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/index.js b/dist/index.js index 55201cc..17963f0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -118766,7 +118766,7 @@ function run() { if (artifacts.length) { core.info(`Preparing to download the following artifacts:`); artifacts.forEach(artifact => { - core.info(`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size})`); + core.info(`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size}, Expected Digest: ${artifact.digest})`); }); } const downloadPromises = artifacts.map(artifact => ({ From 56c2d7ea8c430519f69356bfcb0aeb31318fd416 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:21:59 +0000 Subject: [PATCH 08/12] Make work as intended --- dist/index.js | 2 +- src/download-artifact.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index 17963f0..594cdff 100644 --- a/dist/index.js +++ b/dist/index.js @@ -118782,7 +118782,7 @@ function run() { for (let i = 0; i < results.length; i++) { const outcome = results[i]; const artifactName = chunk[i].name; - if (!outcome.digestMismatch) { + if (outcome.digestMismatch) { core.warning(`Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`); } } diff --git a/src/download-artifact.ts b/src/download-artifact.ts index dda08c6..e149804 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -132,7 +132,7 @@ async function run(): Promise { const outcome = results[i] const artifactName = chunk[i].name - if (!outcome.digestMismatch) { + if (outcome.digestMismatch) { core.warning( `Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.` ) From 4dd97f8f21aed9460a305363be117e6eb81f4e71 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Tue, 18 Mar 2025 11:57:35 +0000 Subject: [PATCH 09/12] Bump artifact package --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 46995c6..e9120f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "4.2.0", "license": "MIT", "dependencies": { - "@actions/artifact": "^2.2.2", + "@actions/artifact": "^2.3.1", "@actions/core": "^1.10.1", "@actions/github": "^5.1.1", "minimatch": "^9.0.3" @@ -36,9 +36,9 @@ } }, "node_modules/@actions/artifact": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.1.tgz", - "integrity": "sha512-3uW25BNAqbMBcasNK+DX4I0Vl8aQdo65K6DRufJiNYjqfhSMfeRE4YGjWLaKmF+H+7bp1ADlQ5NksC61fpvYbQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.2.tgz", + "integrity": "sha512-uX2Mr5KEPcwnzqa0Og9wOTEKIae6C/yx9P/m8bIglzCS5nZDkcQC/zRWjjoEsyVecL6oQpBx5BuqQj/yuVm0gw==", "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", @@ -6032,9 +6032,9 @@ "dev": true }, "@actions/artifact": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.1.tgz", - "integrity": "sha512-3uW25BNAqbMBcasNK+DX4I0Vl8aQdo65K6DRufJiNYjqfhSMfeRE4YGjWLaKmF+H+7bp1ADlQ5NksC61fpvYbQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.2.tgz", + "integrity": "sha512-uX2Mr5KEPcwnzqa0Og9wOTEKIae6C/yx9P/m8bIglzCS5nZDkcQC/zRWjjoEsyVecL6oQpBx5BuqQj/yuVm0gw==", "requires": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", From af3c6d3e5bec47a4ed550166bf99c21d1c8910e2 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:23:53 +0000 Subject: [PATCH 10/12] Update artifact license --- .licenses/npm/@actions/artifact.dep.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.licenses/npm/@actions/artifact.dep.yml b/.licenses/npm/@actions/artifact.dep.yml index 0305b13..5325bd1 100644 --- a/.licenses/npm/@actions/artifact.dep.yml +++ b/.licenses/npm/@actions/artifact.dep.yml @@ -1,6 +1,6 @@ --- name: "@actions/artifact" -version: 2.3.1 +version: 2.3.2 type: npm summary: Actions artifact lib homepage: https://github.com/actions/toolkit/tree/main/packages/artifact From 956811a5036424e19dca26cd12ba80898ca81910 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:21:17 +0000 Subject: [PATCH 11/12] Update artifact to 2.3.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e9120f4..de8e8e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "4.2.0", "license": "MIT", "dependencies": { - "@actions/artifact": "^2.3.1", + "@actions/artifact": "^2.3.2", "@actions/core": "^1.10.1", "@actions/github": "^5.1.1", "minimatch": "^9.0.3" diff --git a/package.json b/package.json index 1a7cbb5..634c402 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ }, "homepage": "https://github.com/actions/download-artifact#readme", "dependencies": { - "@actions/artifact": "^2.3.1", + "@actions/artifact": "^2.3.2", "@actions/core": "^1.10.1", "@actions/github": "^5.1.1", "minimatch": "^9.0.3" From c5804ef743f29971d8bf6f8007121527d340ce33 Mon Sep 17 00:00:00 2001 From: Ryan Ghadimi <114221941+GhadimiR@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:23:08 +0000 Subject: [PATCH 12/12] Update dist --- dist/index.js | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/dist/index.js b/dist/index.js index 594cdff..64e3212 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2725,6 +2725,7 @@ const generated_1 = __nccwpck_require__(49960); const config_1 = __nccwpck_require__(74610); const user_agent_1 = __nccwpck_require__(85164); const errors_1 = __nccwpck_require__(38182); +const util_1 = __nccwpck_require__(63062); class ArtifactHttpClient { constructor(userAgent, maxAttempts, baseRetryIntervalMilliseconds, retryMultiplier) { this.maxAttempts = 5; @@ -2777,6 +2778,7 @@ class ArtifactHttpClient { (0, core_1.debug)(`[Response] - ${response.message.statusCode}`); (0, core_1.debug)(`Headers: ${JSON.stringify(response.message.headers, null, 2)}`); const body = JSON.parse(rawBody); + (0, util_1.maskSecretUrls)(body); (0, core_1.debug)(`Body: ${JSON.stringify(body, null, 2)}`); if (this.isSuccessStatusCode(statusCode)) { return { response, body }; @@ -3093,10 +3095,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getBackendIdsFromToken = void 0; +exports.maskSecretUrls = exports.maskSigUrl = exports.getBackendIdsFromToken = void 0; const core = __importStar(__nccwpck_require__(42186)); const config_1 = __nccwpck_require__(74610); const jwt_decode_1 = __importDefault(__nccwpck_require__(84329)); +const core_1 = __nccwpck_require__(42186); const InvalidJwtError = new Error('Failed to get backend IDs: The provided JWT token is invalid and/or missing claims'); // uses the JWT token claims to get the // workflow run and workflow job run backend ids @@ -3145,6 +3148,74 @@ function getBackendIdsFromToken() { throw InvalidJwtError; } exports.getBackendIdsFromToken = getBackendIdsFromToken; +/** + * Masks the `sig` parameter in a URL and sets it as a secret. + * + * @param url - The URL containing the signature parameter to mask + * @remarks + * This function attempts to parse the provided URL and identify the 'sig' query parameter. + * If found, it registers both the raw and URL-encoded signature values as secrets using + * the Actions `setSecret` API, which prevents them from being displayed in logs. + * + * The function handles errors gracefully if URL parsing fails, logging them as debug messages. + * + * @example + * ```typescript + * // Mask a signature in an Azure SAS token URL + * maskSigUrl('https://example.blob.core.windows.net/container/file.txt?sig=abc123&se=2023-01-01'); + * ``` + */ +function maskSigUrl(url) { + if (!url) + return; + try { + const parsedUrl = new URL(url); + const signature = parsedUrl.searchParams.get('sig'); + if (signature) { + (0, core_1.setSecret)(signature); + (0, core_1.setSecret)(encodeURIComponent(signature)); + } + } + catch (error) { + (0, core_1.debug)(`Failed to parse URL: ${url} ${error instanceof Error ? error.message : String(error)}`); + } +} +exports.maskSigUrl = maskSigUrl; +/** + * Masks sensitive information in URLs containing signature parameters. + * Currently supports masking 'sig' parameters in the 'signed_upload_url' + * and 'signed_download_url' properties of the provided object. + * + * @param body - The object should contain a signature + * @remarks + * This function extracts URLs from the object properties and calls maskSigUrl + * on each one to redact sensitive signature information. The function doesn't + * modify the original object; it only marks the signatures as secrets for + * logging purposes. + * + * @example + * ```typescript + * const responseBody = { + * signed_upload_url: 'https://example.com?sig=abc123', + * signed_download_url: 'https://example.com?sig=def456' + * }; + * maskSecretUrls(responseBody); + * ``` + */ +function maskSecretUrls(body) { + if (typeof body !== 'object' || body === null) { + (0, core_1.debug)('body is not an object or is null'); + return; + } + if ('signed_upload_url' in body && + typeof body.signed_upload_url === 'string') { + maskSigUrl(body.signed_upload_url); + } + if ('signed_url' in body && typeof body.signed_url === 'string') { + maskSigUrl(body.signed_url); + } +} +exports.maskSecretUrls = maskSecretUrls; //# sourceMappingURL=util.js.map /***/ }), @@ -3251,7 +3322,7 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) { core.info('Finished uploading artifact content to blob storage!'); hashStream.end(); sha256Hash = hashStream.read(); - core.info(`SHA256 hash of uploaded artifact zip is ${sha256Hash}`); + core.info(`SHA256 digest of uploaded artifact zip is ${sha256Hash}`); if (uploadByteCount === 0) { core.warning(`No data was uploaded to blob storage. Reported upload byte count is 0.`); } @@ -128767,7 +128838,7 @@ module.exports = index; /***/ ((module) => { "use strict"; -module.exports = JSON.parse('{"name":"@actions/artifact","version":"2.3.1","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","main":"lib/artifact.js","types":"lib/artifact.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.10.0","@actions/github":"^5.1.1","@actions/http-client":"^2.1.0","@azure/storage-blob":"^12.15.0","@octokit/core":"^3.5.1","@octokit/plugin-request-log":"^1.0.4","@octokit/plugin-retry":"^3.0.9","@octokit/request-error":"^5.0.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","archiver":"^7.0.1","jwt-decode":"^3.1.2","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^5.3.2","@types/unzip-stream":"^0.3.4","typedoc":"^0.25.4","typedoc-plugin-markdown":"^3.17.1","typescript":"^5.2.2"}}'); +module.exports = JSON.parse('{"name":"@actions/artifact","version":"2.3.2","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","main":"lib/artifact.js","types":"lib/artifact.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.10.0","@actions/github":"^5.1.1","@actions/http-client":"^2.1.0","@azure/storage-blob":"^12.15.0","@octokit/core":"^3.5.1","@octokit/plugin-request-log":"^1.0.4","@octokit/plugin-retry":"^3.0.9","@octokit/request-error":"^5.0.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","archiver":"^7.0.1","jwt-decode":"^3.1.2","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^5.3.2","@types/unzip-stream":"^0.3.4","typedoc":"^0.25.4","typedoc-plugin-markdown":"^3.17.1","typescript":"^5.2.2"}}'); /***/ }),