@@ -9,13 +9,9 @@ const yaml = require("js-yaml");
99
1010async function run ( ) {
1111 try {
12- // Get inputs: action-ref, wrapper-command and extra-args
12+ // Get core inputs
1313 const actionRef = core . getInput ( "action-ref" ) ;
14- const wrapperCommand = core . getInput ( "wrapper-command" ) || "" ;
15- const extraArgs = core . getInput ( "extra-args" ) || "" ;
16- core . info ( `Wrapper command: ${ wrapperCommand || "none" } ` ) ;
17- core . info ( `Extra args: ${ extraArgs } ` ) ;
18-
14+
1915 // Parse action-ref (expected format: owner/repo@ref)
2016 const [ repo , ref ] = parseActionRef ( actionRef ) ;
2117 core . info ( `Parsed repo: ${ repo } , ref: ${ ref } ` ) ;
@@ -29,19 +25,55 @@ async function run() {
2925
3026 // Create a temporary directory and download/extract the ZIP archive
3127 const tempDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "nested-action-" ) ) ;
32- const response = await axios ( {
33- url : zipUrl ,
34- method : "GET" ,
35- responseType : "stream" ,
36- maxRedirects : 5 ,
37- } ) ;
38- await new Promise ( ( resolve , reject ) => {
39- response . data
40- . pipe ( unzipper . Extract ( { path : tempDir } ) )
41- . on ( "close" , resolve )
42- . on ( "error" , reject ) ;
43- } ) ;
44- core . info ( `Downloaded and extracted to ${ tempDir } ` ) ;
28+
29+ try {
30+ const response = await axios ( {
31+ url : zipUrl ,
32+ method : "GET" ,
33+ responseType : "stream" ,
34+ maxRedirects : 5 ,
35+ } ) ;
36+
37+ await new Promise ( ( resolve , reject ) => {
38+ response . data
39+ . pipe ( unzipper . Extract ( { path : tempDir } ) )
40+ . on ( "close" , resolve )
41+ . on ( "error" , reject ) ;
42+ } ) ;
43+
44+ core . info ( `Downloaded and extracted to ${ tempDir } ` ) ;
45+ } catch ( error ) {
46+ if ( error . response && error . response . status === 404 ) {
47+ core . error ( `Download failed with status 404` ) ;
48+
49+ // Try alternative URL format if first attempt failed
50+ if ( isTag ) {
51+ core . info ( "Attempting alternative download URL for branches..." ) ;
52+ const altZipUrl = `https://github.com/${ repo } /archive/refs/heads/${ ref } .zip` ;
53+ core . info ( `Trying alternative URL: ${ altZipUrl } ` ) ;
54+
55+ const altResponse = await axios ( {
56+ url : altZipUrl ,
57+ method : "GET" ,
58+ responseType : "stream" ,
59+ maxRedirects : 5
60+ } ) ;
61+
62+ await new Promise ( ( resolve , reject ) => {
63+ altResponse . data
64+ . pipe ( unzipper . Extract ( { path : tempDir } ) )
65+ . on ( "close" , resolve )
66+ . on ( "error" , reject ) ;
67+ } ) ;
68+
69+ core . info ( `Downloaded and extracted from alternative URL to ${ tempDir } ` ) ;
70+ } else {
71+ throw error ;
72+ }
73+ } else {
74+ throw error ;
75+ }
76+ }
4577
4678 // Determine the extracted folder.
4779 const repoName = repo . split ( "/" ) [ 1 ] ;
@@ -72,6 +104,15 @@ async function run() {
72104 throw new Error ( `Neither action.yml nor action.yaml found in ${ actionDir } ` ) ;
73105 }
74106
107+ // Debug: Log the action's inputs section
108+ if ( actionConfig . inputs ) {
109+ core . info ( `Nested action inputs: ${ JSON . stringify ( Object . keys ( actionConfig . inputs ) ) } ` ) ;
110+ // Check specifically for the who-to-greet input
111+ if ( actionConfig . inputs [ 'who-to-greet' ] ) {
112+ core . info ( `Found 'who-to-greet' input in action definition. Required: ${ actionConfig . inputs [ 'who-to-greet' ] . required } ` ) ;
113+ }
114+ }
115+
75116 const entryPoint = actionConfig . runs && actionConfig . runs . main ;
76117 if ( ! entryPoint ) {
77118 throw new Error ( "Entry point (runs.main) not defined in action metadata" ) ;
@@ -90,34 +131,81 @@ async function run() {
90131 await exec . exec ( "npm" , [ "install" ] , { cwd : actionDir , env : process . env } ) ;
91132 }
92133
93- // Prepare the nested action command: node <entryFile> <extraArgs>
94- const nodeCmd = "node" ;
95- const args = extraArgs . split ( / \s + / ) . filter ( Boolean ) ;
96- const nodeArgs = [ entryFile , ...args ] ;
134+ // Define a list of inputs that are specific to the wrapper action
135+ const wrapperInputs = [
136+ 'ACTION_REF' , 'COMMAND' , 'WITNESS_VERSION' , 'WITNESS_INSTALL_DIR' ,
137+ 'STEP' , 'ATTESTATIONS' , 'OUTFILE' , 'ENABLE_ARCHIVISTA' , 'ARCHIVISTA_SERVER' ,
138+ 'CERTIFICATE' , 'KEY' , 'INTERMEDIATES' , 'ENABLE_SIGSTORE' , 'FULCIO' ,
139+ 'FULCIO_OIDC_CLIENT_ID' , 'FULCIO_OIDC_ISSUER' , 'FULCIO_TOKEN' ,
140+ 'TIMESTAMP_SERVERS' , 'TRACE' , 'SPIFFE_SOCKET' , 'PRODUCT_EXCLUDE_GLOB' ,
141+ 'PRODUCT_INCLUDE_GLOB' , 'ATTESTOR_LINK_EXPORT' , 'ATTESTOR_SBOM_EXPORT' ,
142+ 'ATTESTOR_SLSA_EXPORT' , 'ATTESTOR_MAVEN_POM_PATH'
143+ ] ;
97144
145+ // Process inputs for nested action
146+ const envVars = { ...process . env } ;
147+
148+ // Log what we're doing
149+ core . info ( "Forwarding inputs to nested action:" ) ;
150+
151+ // For each INPUT_* environment variable
152+ Object . keys ( process . env )
153+ . filter ( key => key . startsWith ( 'INPUT_' ) )
154+ . forEach ( key => {
155+ // Get just the input name part (after INPUT_ prefix)
156+ const inputName = key . substring ( 6 ) ;
157+
158+ // If this is not a wrapper-specific input, preserve it for the nested action
159+ if ( ! wrapperInputs . includes ( inputName ) ) {
160+ // The name GitHub Actions would use (replace hyphens with underscores)
161+ const normalizedKey = 'INPUT_' + inputName . replace ( / - / g, '_' ) ;
162+
163+ // Passthrough any input that isn't specific to the wrapper
164+ core . info ( `➡️ Forwarding ${ normalizedKey } ="${ process . env [ key ] } " to nested action` ) ;
165+
166+ // Re-set it in the environment with proper naming (underscores, not hyphens)
167+ envVars [ normalizedKey ] = process . env [ key ] ;
168+ } else {
169+ core . debug ( `Skipping wrapper-specific input: ${ key } ` ) ;
170+ }
171+ } ) ;
172+
173+ // Specifically check for who-to-greet which is often required
174+ const whoToGreetInput = process . env [ 'INPUT_WHO_TO_GREET' ] || process . env [ 'INPUT_WHO-TO-GREET' ] ;
175+ if ( whoToGreetInput ) {
176+ envVars [ 'INPUT_WHO_TO_GREET' ] = whoToGreetInput ;
177+ core . info ( `✅ Set INPUT_WHO_TO_GREET="${ whoToGreetInput } "` ) ;
178+ }
179+
180+ // Prepare the nested action command
181+ const nodeCmd = "node" ;
182+ const nodeArgs = [ entryFile ] ;
183+
184+ // Execute the nested action
185+ core . info ( `Executing nested action: ${ nodeCmd } ${ entryFile } ` ) ;
186+
98187 // All environment variables are passed along
99188 const execOptions = {
100189 cwd : actionDir ,
101- env : process . env ,
190+ env : envVars ,
102191 listeners : {
103192 stdout : ( data ) => process . stdout . write ( data . toString ( ) ) ,
104193 stderr : ( data ) => process . stderr . write ( data . toString ( ) ) ,
105194 } ,
106195 } ;
107-
108- // Execute the nested action, optionally using a wrapper command
109- if ( wrapperCommand ) {
110- const wrapperParts = wrapperCommand . trim ( ) . split ( / \s + / ) ;
111- const wrapperCmd = wrapperParts [ 0 ] ;
112- const wrapperArgs = wrapperParts . slice ( 1 ) ;
113- core . info ( `Executing with wrapper: ${ wrapperCmd } ${ wrapperArgs . join ( " " ) } ` ) ;
114- await exec . exec ( wrapperCmd , [ ...wrapperArgs , nodeCmd , ...nodeArgs ] , execOptions ) ;
115- } else {
116- core . info ( `Executing nested action directly: ${ nodeCmd } ${ nodeArgs . join ( " " ) } ` ) ;
117- await exec . exec ( nodeCmd , nodeArgs , execOptions ) ;
118- }
196+
197+ await exec . exec ( nodeCmd , nodeArgs , execOptions ) ;
198+
119199 } catch ( error ) {
120200 core . setFailed ( `Action failed: ${ error . message } ` ) ;
201+
202+ // Provide more detailed error information
203+ if ( error . response ) {
204+ core . error ( `HTTP status: ${ error . response . status } ` ) ;
205+ if ( error . response . data ) {
206+ core . error ( `Response data: ${ JSON . stringify ( error . response . data ) } ` ) ;
207+ }
208+ }
121209 }
122210}
123211
@@ -130,4 +218,4 @@ function parseActionRef(refString) {
130218 return parts ;
131219}
132220
133- run ( ) ;
221+ run ( ) ;
0 commit comments