@@ -57,9 +57,7 @@ async function run() {
57
57
const intermediates = core . getInput ( "intermediates" ) . split ( " " ) ;
58
58
const key = core . getInput ( "key" ) ;
59
59
let outfile = core . getInput ( "outfile" ) ;
60
- outfile = outfile
61
- ? outfile
62
- : path . join ( os . tmpdir ( ) , step + "-attestation.json" ) ;
60
+ outfile = outfile ? outfile : path . join ( os . tmpdir ( ) , step + "-attestation.json" ) ;
63
61
const productExcludeGlob = core . getInput ( "product-exclude-glob" ) ;
64
62
const productIncludeGlob = core . getInput ( "product-include-glob" ) ;
65
63
const spiffeSocket = core . getInput ( "spiffe-socket" ) ;
@@ -107,40 +105,21 @@ async function run() {
107
105
108
106
for ( const gitOID of gitOIDs ) {
109
107
console . log ( "Extracted GitOID:" , gitOID ) ;
110
-
111
- // Print the GitOID to the output
112
108
core . setOutput ( "git_oid" , gitOID ) ;
113
-
114
- // Construct the artifact URL using Archivista server and GitOID
115
109
const artifactURL = `${ archivistaServer } /download/${ gitOID } ` ;
116
-
117
- // Add Job Summary with Markdown content
118
110
const summaryHeader = `
119
111
## Attestations Created
120
112
| Step | Attestors Run | Attestation GitOID
121
113
| --- | --- | --- |
122
114
` ;
123
-
124
- // Try to access the step summary file
125
115
try {
126
116
if ( process . env . GITHUB_STEP_SUMMARY ) {
127
- // Read the contents of the file
128
- const summaryFile = fs . readFileSync ( process . env . GITHUB_STEP_SUMMARY , {
129
- encoding : "utf-8" ,
130
- } ) ;
131
-
132
- // Check if the file contains the header
117
+ const summaryFile = fs . readFileSync ( process . env . GITHUB_STEP_SUMMARY , { encoding : "utf-8" } ) ;
133
118
const headerExists = summaryFile . includes ( summaryHeader . trim ( ) ) ;
134
-
135
- // If the header does not exist, append it to the file
136
119
if ( ! headerExists ) {
137
120
fs . appendFileSync ( process . env . GITHUB_STEP_SUMMARY , summaryHeader ) ;
138
121
}
139
-
140
- // Construct the table row for the current step
141
122
const tableRow = `| ${ step } | ${ attestations . join ( ", " ) } | [${ gitOID } ](${ artifactURL } ) |\n` ;
142
-
143
- // Append the table row to the file
144
123
fs . appendFileSync ( process . env . GITHUB_STEP_SUMMARY , tableRow ) ;
145
124
}
146
125
} catch ( error ) {
@@ -155,102 +134,63 @@ async function run() {
155
134
}
156
135
}
157
136
158
- // Download and install Witness
159
137
async function downloadWitness ( version , installDir ) {
160
- // Check if Witness is already in the tool cache
161
138
let witnessPath = tc . find ( "witness" , version ) ;
162
139
console . log ( "Cached Witness Path: " + witnessPath ) ;
163
-
164
140
if ( ! witnessPath ) {
165
141
console . log ( "Witness not found in cache, downloading now" ) ;
166
142
let witnessTar ;
167
-
168
- // Determine the OS-specific download URL
169
143
if ( process . platform === "win32" ) {
170
144
witnessTar = await tc . downloadTool (
171
- "https://github.com/in-toto/witness/releases/download/v" +
172
- version +
173
- "/witness_" +
174
- version +
175
- "_windows_amd64.tar.gz"
145
+ "https://github.com/in-toto/witness/releases/download/v" + version + "/witness_" + version + "_windows_amd64.tar.gz"
176
146
) ;
177
147
} else if ( process . platform === "darwin" ) {
178
148
witnessTar = await tc . downloadTool (
179
- "https://github.com/in-toto/witness/releases/download/v" +
180
- version +
181
- "/witness_" +
182
- version +
183
- "_darwin_amd64.tar.gz"
149
+ "https://github.com/in-toto/witness/releases/download/v" + version + "/witness_" + version + "_darwin_amd64.tar.gz"
184
150
) ;
185
151
} else {
186
152
witnessTar = await tc . downloadTool (
187
- "https://github.com/in-toto/witness/releases/download/v" +
188
- version +
189
- "/witness_" +
190
- version +
191
- "_linux_amd64.tar.gz"
153
+ "https://github.com/in-toto/witness/releases/download/v" + version + "/witness_" + version + "_linux_amd64.tar.gz"
192
154
) ;
193
155
}
194
-
195
- // Create the install directory if it doesn't exist
196
156
if ( ! fs . existsSync ( installDir ) ) {
197
157
console . log ( "Creating witness install directory at " + installDir ) ;
198
158
fs . mkdirSync ( installDir , { recursive : true } ) ;
199
159
}
200
-
201
- // Extract and cache Witness
202
160
console . log ( "Extracting witness at: " + installDir ) ;
203
161
witnessPath = await tc . extractTar ( witnessTar , installDir ) ;
204
-
205
162
const cachedPath = await tc . cacheFile (
206
163
path . join ( witnessPath , "witness" ) ,
207
164
"witness" ,
208
165
"witness" ,
209
166
version
210
167
) ;
211
168
console . log ( "Witness cached at: " + cachedPath ) ;
212
-
213
169
witnessPath = cachedPath ;
214
170
}
215
-
216
- // Add Witness to the PATH
217
171
core . addPath ( witnessPath ) ;
218
172
return witnessPath ;
219
173
}
220
174
221
- // Download and extract a GitHub Action
222
175
async function downloadAndExtractAction ( actionRef ) {
223
- // Parse action-ref (expects format: owner/repo@ref)
224
176
const [ repo , ref ] = parseActionRef ( actionRef ) ;
225
177
core . info ( `Parsed repo: ${ repo } , ref: ${ ref } ` ) ;
226
-
227
- // Construct URL for the repository zip archive
228
- // Use proper URL format for GitHub archives (handle both branches and tags)
229
178
const isTag = ! ref . includes ( '/' ) ;
230
179
const zipUrl = isTag
231
180
? `https://github.com/${ repo } /archive/refs/tags/${ ref } .zip`
232
181
: `https://github.com/${ repo } /archive/refs/heads/${ ref } .zip` ;
233
-
234
182
core . info ( `Downloading action from: ${ zipUrl } ` ) ;
235
-
236
- // Create a temporary directory for extraction
237
183
const tempDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "nested-action-" ) ) ;
238
-
239
184
try {
240
- // Download and extract the zip archive
241
185
const response = await axios ( {
242
186
url : zipUrl ,
243
187
method : "GET" ,
244
188
responseType : "stream" ,
245
- validateStatus : function ( status ) {
246
- return status >= 200 && status < 300 ; // Default
247
- } ,
248
- maxRedirects : 5 // Handle redirects
189
+ validateStatus : function ( status ) { return status >= 200 && status < 300 ; } ,
190
+ maxRedirects : 5
249
191
} ) ;
250
-
251
192
await new Promise ( ( resolve , reject ) => {
252
- response . data
253
- . pipe ( unzipper . Extract ( { path : tempDir } ) )
193
+ response . data . pipe ( unzipper . Extract ( { path : tempDir } ) )
254
194
. on ( "close" , resolve )
255
195
. on ( "error" , reject ) ;
256
196
} ) ;
@@ -259,21 +199,17 @@ async function downloadAndExtractAction(actionRef) {
259
199
if ( error . response ) {
260
200
core . error ( `Download failed with status ${ error . response . status } ` ) ;
261
201
if ( isTag ) {
262
- // Try alternative URL format if first attempt failed
263
202
core . info ( "Attempting alternative download URL for branches..." ) ;
264
203
const altZipUrl = `https://github.com/${ repo } /archive/refs/heads/${ ref } .zip` ;
265
204
core . info ( `Trying alternative URL: ${ altZipUrl } ` ) ;
266
-
267
205
const altResponse = await axios ( {
268
206
url : altZipUrl ,
269
207
method : "GET" ,
270
208
responseType : "stream" ,
271
209
maxRedirects : 5
272
210
} ) ;
273
-
274
211
await new Promise ( ( resolve , reject ) => {
275
- altResponse . data
276
- . pipe ( unzipper . Extract ( { path : tempDir } ) )
212
+ altResponse . data . pipe ( unzipper . Extract ( { path : tempDir } ) )
277
213
. on ( "close" , resolve )
278
214
. on ( "error" , reject ) ;
279
215
} ) ;
@@ -285,30 +221,22 @@ async function downloadAndExtractAction(actionRef) {
285
221
throw error ;
286
222
}
287
223
}
288
-
289
- // List contents of the temp directory for diagnostic purposes
290
224
core . debug ( `Temporary directory contents: ${ fs . readdirSync ( tempDir ) . join ( ', ' ) } ` ) ;
291
-
292
- // GitHub archives typically extract to a folder named "repo-ref"
293
225
const repoName = repo . split ( "/" ) [ 1 ] ;
294
226
const extractedFolder = path . join ( tempDir , `${ repoName } -${ ref } ` ) ;
295
227
if ( ! fs . existsSync ( extractedFolder ) ) {
296
- // If default folder name doesn't exist, try finding based on content
297
228
const tempContents = fs . readdirSync ( tempDir ) ;
298
229
if ( tempContents . length === 1 && fs . lstatSync ( path . join ( tempDir , tempContents [ 0 ] ) ) . isDirectory ( ) ) {
299
- // If there's only one directory, use that one
300
230
const alternateFolder = path . join ( tempDir , tempContents [ 0 ] ) ;
301
231
core . info ( `Using alternative extracted folder: ${ alternateFolder } ` ) ;
302
232
return alternateFolder ;
303
233
} else {
304
234
throw new Error ( `Extracted folder ${ extractedFolder } not found and could not determine alternative.` ) ;
305
235
}
306
236
}
307
-
308
237
return extractedFolder ;
309
238
}
310
239
311
- // Run an action with Witness
312
240
async function runActionWithWitness ( actionDir , witnessOptions ) {
313
241
let {
314
242
step,
@@ -335,13 +263,9 @@ async function runActionWithWitness(actionDir, witnessOptions) {
335
263
mavenPOM,
336
264
} = witnessOptions ;
337
265
338
- // Read action.yml from the downloaded action
339
266
const actionYmlPath = path . join ( actionDir , "action.yml" ) ;
340
- // Some actions use action.yaml instead of action.yml
341
267
const actionYamlPath = path . join ( actionDir , "action.yaml" ) ;
342
-
343
268
let actionConfig ;
344
-
345
269
if ( fs . existsSync ( actionYmlPath ) ) {
346
270
actionConfig = yaml . load ( fs . readFileSync ( actionYmlPath , "utf8" ) ) ;
347
271
} else if ( fs . existsSync ( actionYamlPath ) ) {
@@ -356,36 +280,30 @@ async function runActionWithWitness(actionDir, witnessOptions) {
356
280
}
357
281
core . info ( `Nested action entry point: ${ entryPoint } ` ) ;
358
282
359
- // Construct full path to the nested action's entry file
360
283
const entryFile = path . join ( actionDir , entryPoint ) ;
361
284
if ( ! fs . existsSync ( entryFile ) ) {
362
285
throw new Error ( `Entry file ${ entryFile } does not exist.` ) ;
363
286
}
364
287
365
- // Optionally, install dependencies if package.json exists
366
288
const pkgJsonPath = path . join ( actionDir , "package.json" ) ;
367
289
if ( fs . existsSync ( pkgJsonPath ) ) {
368
290
core . info ( "Installing dependencies for nested action..." ) ;
369
291
await exec . exec ( "npm" , [ "install" ] , { cwd : actionDir } ) ;
370
292
}
371
293
372
- // Instead of filtering, pass all environment variables to the nested action
373
294
const envVars = { ...process . env } ;
374
-
375
295
// For testing, force the nested action to see a value for INPUT_WHO_TO_GREET
376
296
envVars [ "INPUT_WHO_TO_GREET" ] = envVars [ "INPUT_WHO_TO_GREET" ] || "Sigstore" ;
377
297
core . info ( `For testing, setting INPUT_WHO_TO_GREET to: ${ envVars [ "INPUT_WHO_TO_GREET" ] } ` ) ;
378
298
379
299
// Build the witness run command
380
300
const cmd = [ "run" ] ;
381
-
382
301
if ( enableSigstore ) {
383
302
fulcio = fulcio || "https://fulcio.sigstore.dev" ;
384
303
fulcioOidcClientId = fulcioOidcClientId || "sigstore" ;
385
304
fulcioOidcIssuer = fulcioOidcIssuer || "https://oauth2.sigstore.dev/auth" ;
386
305
timestampServers = "https://freetsa.org/tsr " + timestampServers ;
387
306
}
388
-
389
307
if ( attestations . length ) {
390
308
attestations . forEach ( ( attestation ) => {
391
309
attestation = attestation . trim ( ) ;
@@ -394,21 +312,17 @@ async function runActionWithWitness(actionDir, witnessOptions) {
394
312
}
395
313
} ) ;
396
314
}
397
-
398
315
if ( exportLink ) cmd . push ( `--attestor-link-export` ) ;
399
316
if ( exportSBOM ) cmd . push ( `--attestor-sbom-export` ) ;
400
317
if ( exportSLSA ) cmd . push ( `--attestor-slsa-export` ) ;
401
-
402
318
if ( mavenPOM ) cmd . push ( `--attestor-maven-pom-path=${ mavenPOM } ` ) ;
403
-
404
319
if ( certificate ) cmd . push ( `--certificate=${ certificate } ` ) ;
405
320
if ( enableArchivista ) cmd . push ( `--enable-archivista=${ enableArchivista } ` ) ;
406
321
if ( archivistaServer ) cmd . push ( `--archivista-server=${ archivistaServer } ` ) ;
407
322
if ( fulcio ) cmd . push ( `--signer-fulcio-url=${ fulcio } ` ) ;
408
323
if ( fulcioOidcClientId ) cmd . push ( `--signer-fulcio-oidc-client-id=${ fulcioOidcClientId } ` ) ;
409
324
if ( fulcioOidcIssuer ) cmd . push ( `--signer-fulcio-oidc-issuer=${ fulcioOidcIssuer } ` ) ;
410
325
if ( fulcioToken ) cmd . push ( `--signer-fulcio-token=${ fulcioToken } ` ) ;
411
-
412
326
if ( intermediates . length ) {
413
327
intermediates . forEach ( ( intermediate ) => {
414
328
intermediate = intermediate . trim ( ) ;
@@ -417,13 +331,11 @@ async function runActionWithWitness(actionDir, witnessOptions) {
417
331
}
418
332
} ) ;
419
333
}
420
-
421
334
if ( key ) cmd . push ( `--key=${ key } ` ) ;
422
335
if ( productExcludeGlob ) cmd . push ( `--attestor-product-exclude-glob=${ productExcludeGlob } ` ) ;
423
336
if ( productIncludeGlob ) cmd . push ( `--attestor-product-include-glob=${ productIncludeGlob } ` ) ;
424
337
if ( spiffeSocket ) cmd . push ( `--spiffe-socket=${ spiffeSocket } ` ) ;
425
338
if ( step ) cmd . push ( `-s=${ step } ` ) ;
426
-
427
339
if ( timestampServers ) {
428
340
const timestampServerValues = timestampServers . split ( " " ) ;
429
341
timestampServerValues . forEach ( ( timestampServer ) => {
@@ -433,39 +345,27 @@ async function runActionWithWitness(actionDir, witnessOptions) {
433
345
}
434
346
} ) ;
435
347
}
436
-
437
348
if ( trace ) cmd . push ( `--trace=${ trace } ` ) ;
438
349
if ( outfile ) cmd . push ( `--outfile=${ outfile } ` ) ;
439
350
440
- // Prepare the command to run the action
441
- const nodeCmd = 'node ' ;
442
- const nodeArgs = [ entryFile ] ;
443
-
444
- // Build the base command string from witness arguments
445
- const baseCommand = [ " witness" , ... cmd , "--" , nodeCmd , ... nodeArgs ] . join ( " " ) ;
351
+ // Instead of invoking node directly, run a shell command that exports the variable before running node
352
+ const newNodeCmd = 'sh ' ;
353
+ const newNodeArgs = [ '-c' , `export INPUT_WHO_TO_GREET= ${ envVars [ "INPUT_WHO_TO_GREET" ] } && node ${ entryFile } ` ] ;
354
+ const runArray = [ "witness" , ... cmd , "--" , newNodeCmd , ... newNodeArgs ] ;
355
+ const commandString = runArray . join ( " " ) ;
356
+ core . info ( `Running witness command: ${ commandString } ` ) ;
446
357
447
- // For testing, explicitly prepend the environment assignment for INPUT_WHO_TO_GREET
448
- const prefixedCommand = `INPUT_WHO_TO_GREET=${ envVars [ "INPUT_WHO_TO_GREET" ] } ${ baseCommand } ` ;
449
- core . info ( `Running witness command: ${ prefixedCommand } ` ) ;
450
-
451
- // Set up options for execution
452
358
const execOptions = {
453
359
cwd : actionDir ,
454
360
env : envVars ,
455
361
listeners : {
456
- stdout : ( data ) => {
457
- process . stdout . write ( data . toString ( ) ) ;
458
- } ,
459
- stderr : ( data ) => {
460
- process . stderr . write ( data . toString ( ) ) ;
461
- }
362
+ stdout : ( data ) => { process . stdout . write ( data . toString ( ) ) ; } ,
363
+ stderr : ( data ) => { process . stderr . write ( data . toString ( ) ) ; }
462
364
}
463
365
} ;
464
366
465
- // Execute and capture output
466
367
let output = '' ;
467
-
468
- await exec . exec ( 'sh' , [ '-c' , prefixedCommand ] , {
368
+ await exec . exec ( 'sh' , [ '-c' , commandString ] , {
469
369
...execOptions ,
470
370
listeners : {
471
371
...execOptions . listeners ,
@@ -485,11 +385,9 @@ async function runActionWithWitness(actionDir, witnessOptions) {
485
385
return output ;
486
386
}
487
387
488
- // Extract GitOIDs from witness output
489
388
function extractDesiredGitOIDs ( output ) {
490
389
const lines = output . split ( "\n" ) ;
491
390
const desiredSubstring = "Stored in archivista as " ;
492
-
493
391
const matchArray = [ ] ;
494
392
console . log ( "Looking for GitOID in the output" ) ;
495
393
for ( const line of lines ) {
@@ -503,7 +401,6 @@ function extractDesiredGitOIDs(output) {
503
401
}
504
402
}
505
403
}
506
-
507
404
return matchArray ;
508
405
}
509
406
@@ -518,15 +415,13 @@ function parseActionRef(refString) {
518
415
run ( )
519
416
. then ( ( ) => {
520
417
core . debug ( 'Action wrapper completed successfully' ) ;
521
- // Force exit to ensure we don't hang
522
418
setTimeout ( ( ) => {
523
419
core . debug ( 'Forcing process exit to prevent hanging' ) ;
524
420
process . exit ( 0 ) ;
525
421
} , 500 ) ;
526
422
} )
527
423
. catch ( error => {
528
424
core . setFailed ( `Action wrapper failed: ${ error . message } ` ) ;
529
- // Force exit to ensure we don't hang
530
425
setTimeout ( ( ) => {
531
426
core . debug ( 'Forcing process exit to prevent hanging' ) ;
532
427
process . exit ( 1 ) ;
0 commit comments