github.com/yogeshkumararora/slsa-github-generator@v1.10.1-0.20240520161934-11278bd5afb4/actions/delegator/setup-generic/src/main.ts (about) 1 /* 2 Copyright 2022 SLSA Authors 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 https://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WIHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 import * as github from "@actions/github"; 15 import * as core from "@actions/core"; 16 import * as process from "process"; 17 import { sign } from "sigstore"; 18 import * as tscommon from "tscommon"; 19 20 async function run(): Promise<void> { 21 try { 22 /* Test locally: 23 $ env INPUT_SLSA-WORKFLOW-RECIPIENT="laurentsimon/slsa-delegated-tool" \ 24 INPUT_SLSA-REKOR-LOG-PUBLIC=true \ 25 INPUT_SLSA-RUNNER-LABEL="ubuntu-latest" \ 26 INPUT_SLSA-BUILD-ACTION-PATH="./actions/build-artifacts-composite" \ 27 INPUT_SLSA-WORKFLOW-INPUTS="{\"name1\":\"value1\",\"name2\":\"value2\",\"name3\":\"value3\",\"name4\":\"value4\"}" \ 28 INPUT_SLSA-WORKFLOW-INPUTS-MASK="name2, name4" \ 29 INPUT_SLSA-CHECKOUT-FETCH-DEPTH="2" \ 30 INPUT_SLSA-CHECKOUT-REPOSITORY-SHA1="abcdef" \ 31 INPUT_SLSA-VERSION="v1" \ 32 nodejs ./dist/index.js 33 */ 34 35 const slsaVersion = core.getInput("slsa-version"); 36 if (!["v1.0", "v0.2"].includes(slsaVersion)) { 37 throw new Error(`Unsupported slsa-version: ${slsaVersion}`); 38 } 39 const workflowRecipient = core.getInput("slsa-workflow-recipient"); 40 const rekorLogPublic = core.getInput("slsa-rekor-log-public"); 41 const runnerLabel = core.getInput("slsa-runner-label"); 42 // Checkout options. 43 const checkoutDepth = core.getInput("slsa-checkout-fetch-depth"); 44 const checkoutSha1 = core.getInput("slsa-checkout-sha1"); 45 const buildArtifactsActionPath = core.getInput("slsa-build-action-path"); 46 const workflowsInputsMask = core.getInput("slsa-workflow-masked-inputs"); 47 // The workflow inputs are represented as a JSON object theselves. 48 const workflowsInputsText = core.getInput("slsa-workflow-inputs"); 49 50 // Log the inputs for troubleshooting. 51 core.debug(`workflowsInputsText: ${workflowsInputsText}`); 52 core.debug(`workfowInputs: `); 53 const workflowInputs = JSON.parse(workflowsInputsText); 54 const workflowInputsMap = new Map(Object.entries(workflowInputs)); 55 for (const [key, value] of workflowInputsMap) { 56 core.info(` ${key}: ${value}`); 57 } 58 59 const workflowMaskedInputs = getMaskedInputs(workflowsInputsMask); 60 core.info(`maskedInputs: `); 61 for (const value of workflowMaskedInputs) { 62 core.info(` ${value}`); 63 } 64 65 const payload = JSON.stringify(github.context.payload, undefined, 2); 66 core.debug(`The event payload: ${payload}`); 67 68 // Construct an unsigned SLSA token. 69 const unsignedSlsaToken = { 70 version: 1, 71 slsaVersion, 72 context: "SLSA delegator framework", 73 builder: { 74 rekor_log_public: rekorLogPublic, 75 runner_label: runnerLabel, 76 audience: workflowRecipient, 77 }, 78 source: { 79 checkout: { 80 fetch_depth: checkoutDepth, 81 sha1: checkoutSha1, 82 }, 83 // TODO(#2043): add digests. 84 }, 85 github: { 86 actor_id: process.env.GITHUB_ACTOR_ID, 87 event_name: process.env.GITHUB_EVENT_NAME, 88 event_payload_sha256: tscommon.safeFileSha256( 89 process.env.GITHUB_EVENT_PATH || "", 90 ), 91 base_ref: process.env.GITHUB_BASE_REF, 92 ref: process.env.GITHUB_REF, 93 ref_type: process.env.GITHUB_REF_TYPE, 94 repository: process.env.GITHUB_REPOSITORY, 95 repository_id: process.env.GITHUB_REPOSITORY_ID, 96 repository_owner_id: process.env.GITHUB_REPOSITORY_OWNER_ID, 97 run_attempt: process.env.GITHUB_RUN_ATTEMPT, 98 run_id: process.env.GITHUB_RUN_ID, 99 run_number: process.env.GITHUB_RUN_NUMBER, 100 sha: process.env.GITHUB_SHA, 101 workflow_ref: process.env.GITHUB_WORKFLOW_REF, 102 workflow_sha: process.env.GITHUB_WORKFLOW_SHA, 103 }, 104 image: { 105 os: process.env.ImageOS, 106 version: process.env.ImageVersion, 107 }, 108 runner: { 109 arch: process.env.RUNNER_ARCH, 110 name: process.env.RUNNER_NAME, 111 os: process.env.RUNNER_OS, 112 }, 113 tool: { 114 actions: { 115 build_artifacts: { 116 path: buildArtifactsActionPath, 117 }, 118 }, 119 inputs: workflowInputs, 120 masked_inputs: workflowMaskedInputs, 121 }, 122 }; 123 124 // Prepare the base64 unsigned token. 125 const unsignedToken = JSON.stringify(unsignedSlsaToken, undefined); 126 const unsignedB64Token = Buffer.from(unsignedToken).toString("base64"); 127 core.info(`unsignedToken: ${unsignedToken}`); 128 core.info(`unsignedB64Token: ${unsignedB64Token}`); 129 130 // Sign and prepare the base64 bundle. 131 const bundle = await sign(Buffer.from(unsignedB64Token)); 132 133 // Verify just to double check. 134 // NOTE: this is an offline verification. 135 // TODO(#1668): re-enable verification. 136 // await sigstore.verify(bundle, Buffer.from(unsignedB64Token)); 137 const bundleStr = JSON.stringify(bundle); 138 139 const bundleB64 = Buffer.from(bundleStr).toString("base64"); 140 core.info(`bundleStr: ${bundleStr}`); 141 core.info(`bundleB64: ${bundleB64}`); 142 // Output the signed token. 143 core.info(`slsa-token: ${bundleB64}.${unsignedB64Token}`); 144 core.setOutput("slsa-token", `${bundleB64}.${unsignedB64Token}`); 145 } catch (error) { 146 if (error instanceof Error) { 147 core.setFailed(error.message); 148 } else { 149 core.setFailed(`Unexpected error: ${error}`); 150 } 151 } 152 } 153 154 function getMaskedInputs(inputsStr: string): string[] { 155 const ret = []; 156 const inputArr = inputsStr.split(","); 157 for (const input of inputArr) { 158 ret.push(input.trim()); 159 } 160 return ret; 161 } 162 163 run();