@@ -2,8 +2,12 @@ const core = require('@actions/core');
2
2
const github = require ( '@actions/github' ) ;
3
3
const AdmZip = require ( 'adm-zip' ) ;
4
4
5
+ let verbose = false ;
6
+ let log = null ;
7
+ let debug = ( msg ) => { if ( verbose ) { log ( msg ) ; } }
8
+
5
9
async function analyze ( name , count , token , owner , repo , branch ) {
6
- console . log ( `Analyzing ${ name } for the last ${ count } successful runs.\n` ) ;
10
+ log ( `Analyzing ${ name } for the last ${ count } successful runs.\n` ) ;
7
11
const octokit = github . getOctokit ( token )
8
12
9
13
const runs = await octokit . rest . actions . listWorkflowRuns ( {
@@ -20,57 +24,55 @@ async function analyze(name, count, token, owner, repo, branch) {
20
24
let wasUnknown = false ;
21
25
22
26
for ( const run of runs . data . workflow_runs ) {
23
- if ( process . env . RUNNER_DEBUG )
24
- console . log ( `Analyzing run ${ run . id } ...` ) ;
27
+ debug ( `Analyzing run ${ run . id } ...` ) ;
25
28
26
29
const jobs = await octokit . rest . actions . listJobsForWorkflowRun ( {
27
30
owner : owner ,
28
31
repo : repo ,
29
32
run_id : run . id ,
30
33
} ) ;
31
34
32
- if ( process . env . RUNNER_DEBUG )
33
- console . log ( `Found ${ jobs . data . jobs . length } jobs.` )
35
+ debug ( `Found ${ jobs . data . jobs . length } jobs.` )
34
36
35
37
const artifacts = await octokit . rest . actions . listWorkflowRunArtifacts ( {
36
38
owner : owner ,
37
39
repo : repo ,
38
40
run_id : run . id ,
39
41
} ) ;
40
42
41
- if ( process . env . RUNNER_DEBUG )
42
- console . log ( `${ artifacts . data . artifacts . length } artifacts...` )
43
+ debug ( `${ artifacts . data . artifacts . length } artifacts...` )
43
44
44
45
for ( const job of jobs . data . jobs ) {
45
46
if ( job . conclusion !== 'success' )
46
47
continue ;
47
48
48
- if ( process . env . RUNNER_DEBUG ) {
49
- console . log ( `${ job . name } ${ job . id } was successful...` ) ;
50
- console . log ( `Downloading logs for job id ${ job . id } ...` ) ;
51
- }
49
+ debug ( `${ job . name } ${ job . id } was successful...` ) ;
50
+ debug ( `Downloading logs for job id ${ job . id } ...` ) ;
52
51
53
- let log = null ;
52
+ let workflowRunLog = null ;
54
53
try {
55
- log = await octokit . rest . actions . downloadJobLogsForWorkflowRun ( {
54
+ workflowRunLog = await octokit . rest . actions . downloadJobLogsForWorkflowRun ( {
56
55
owner : owner ,
57
56
repo : repo ,
58
57
job_id : job . id ,
59
58
} ) ;
60
59
} catch ( e ) {
61
- if ( process . env . RUNNER_DEBUG )
62
- console . log ( `Logs for the job ${ job . id } are not available.` ) ;
60
+ debug ( `Logs for the job ${ job . id } are not available.` ) ;
63
61
continue ;
64
62
}
65
63
66
- const logUploadMatch = log . data . match ( / ^ .* C o n t a i n e r f o r a r t i f a c t \" ( .* - p e r m i s s i o n s - [ a - z 0 - 9 ] + ) \" s u c c e s s f u l l y c r e a t e d \. S t a r t i n g u p l o a d o f f i l e \( s \) $ / m) ;
67
- if ( ! logUploadMatch )
64
+ const logUploadMatch = workflowRunLog . data . match ( / ( [ ^ " ] + - p e r m i s s i o n s - [ a - z 0 - 9 ] { 32 } ) / m) ;
65
+ if ( ! logUploadMatch ) {
66
+ debug ( `Cannot find the magic string. Skipping.` ) ;
68
67
continue ;
68
+ }
69
69
const artifactName = logUploadMatch [ 1 ] ;
70
+ debug ( `Looking for artifactName ${ artifactName } ` ) ;
70
71
const jobName = artifactName . split ( '-' ) . slice ( 0 , - 2 ) . join ( '-' ) ;
71
72
72
73
for ( const artifact of artifacts . data . artifacts ) {
73
74
if ( artifact . name === artifactName ) {
75
+ debug ( `Downloading artifact id ${ artifact . id } ` ) ;
74
76
const download = await octokit . rest . actions . downloadArtifact ( {
75
77
owner : owner ,
76
78
repo : repo ,
@@ -110,62 +112,105 @@ async function analyze(name, count, token, owner, repo, branch) {
110
112
return [ permissions , wasUnknown ] ;
111
113
}
112
114
113
- async function run ( name , count , token , owner , repo , branch ) {
115
+ async function run ( token , name , count , owner , repo , branch , format ) {
114
116
const [ permissions , wasUnknown ] = await analyze ( name , count , token , owner , repo , branch ) ;
115
117
116
118
let summary = core . summary . addHeading ( `Minimal required permissions for ${ name } :` ) ;
117
- console . log ( `Minimal required permissions for ${ name } :` ) ;
119
+ log ( `Minimal required permissions for ${ name } :` ) ;
118
120
119
121
if ( wasUnknown ) {
120
122
summary . addRaw ( "\nAt least one call wasn't recognized. Some permissions are unknown. Check the workflow runs.\n" ) ;
121
123
}
122
124
123
- if ( permissions . size === 0 ) {
124
- summary = summary . addRaw ( 'No permissions logs were found.' ) ;
125
- console . log ( 'No permissions logs were found.' ) ;
126
- } else {
127
- for ( const [ jobName , jobPermissions ] of permissions ) {
128
- summary = summary . addHeading ( `${ jobName } :` , 2 ) ;
129
- console . log ( `---------------------= ${ jobName } =---------------------` ) ;
130
-
131
- let codeBlock = '' ;
132
- if ( jobPermissions . size === 0 ) {
133
- codeBlock += 'permissions: {}' ;
134
- console . log ( 'permissions: {}' ) ;
135
- } else {
136
- codeBlock += 'permissions:\n' ;
137
- console . log ( 'permissions:' ) ;
138
- for ( const [ kind , perm ] of jobPermissions ) {
139
- codeBlock += ` ${ kind } : ${ perm } \n` ;
140
- console . log ( ` ${ kind } : ${ perm } ` ) ;
125
+ try {
126
+ if ( permissions . size === 0 ) {
127
+ summary = summary . addRaw ( 'No permissions logs were found.' ) ;
128
+ throw new Error ( 'No permissions logs were found.' ) ;
129
+ } else {
130
+ let additionalIndent = '' ;
131
+ if ( format )
132
+ additionalIndent = ' ' ;
133
+
134
+ for ( const [ jobName , jobPermissions ] of permissions ) {
135
+ summary = summary . addHeading ( `${ jobName } :` , 2 ) ;
136
+ log ( `---------------------= ${ jobName } =---------------------` ) ;
137
+ if ( format )
138
+ console . log ( `${ jobName } :` ) ;
139
+
140
+ let codeBlock = '' ;
141
+ if ( jobPermissions . size === 0 ) {
142
+ codeBlock += `${ additionalIndent } permissions: {}` ;
143
+ } else {
144
+ codeBlock += `${ additionalIndent } permissions:\n` ;
145
+ for ( const [ kind , perm ] of jobPermissions ) {
146
+ codeBlock += `${ additionalIndent } ${ kind } : ${ perm } \n` ;
147
+ }
141
148
}
149
+
150
+ console . log ( codeBlock ) ; // write always
151
+ summary = summary . addCodeBlock ( codeBlock , 'yaml' ) ;
142
152
}
143
-
144
- summary = summary . addCodeBlock ( codeBlock , 'yaml' ) ;
145
153
}
146
- }
147
-
148
- if ( process . env . GITHUB_ACTIONS ) {
149
- await summary . write ( ) ;
154
+ } finally {
155
+ if ( process . env . GITHUB_ACTIONS ) {
156
+ await summary . write ( ) ;
157
+ }
150
158
}
151
159
}
152
160
153
- if ( ! process . env . GITHUB_ACTIONS && process . argv . length !== 7 ) {
154
- console . log ( 'Usage: node index.js <number_of_the_last_runs> <github_owner> <repo_name> <branch_name>' ) ;
155
- console . log ( 'For example: node index.js ci.yml 10 github actions-permissions main' ) ;
161
+ function printUsageAndExit ( ) {
162
+ console . log ( 'Usage: node index.js <number_of_the_last_runs> <github_owner> <repo_name> <branch_name> [--format yaml] [--verbose] ' ) ;
163
+ console . log ( 'For example: node index.js ci.yml 10 github actions-permissions main --format yaml --verbose ' ) ;
156
164
process . exit ( 1 ) ;
157
165
}
158
166
167
+ verbose = false ;
168
+ log = console . log ;
169
+
159
170
if ( process . env . GITHUB_ACTIONS ) {
160
171
const name = core . getInput ( 'name' ) ;
161
172
const count = core . getInput ( 'count' ) ;
162
173
const token = core . getInput ( 'token' ) ;
174
+ verbose = process . env . RUNNER_DEBUG ? true : false ;
175
+ const branch = github . context . ref . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
176
+ const format = null ;
163
177
164
- run ( name , count , token , github . context . repo . owner , github . context . repo . repo , github . context . ref . split ( '/' ) . slice ( - 1 ) [ 0 ] ) . catch ( error => {
178
+ run ( token , name , count , github . context . repo . owner , github . context . repo . repo , branch , format ) . catch ( error => {
165
179
core . setFailed ( error . message ) ;
166
180
} ) ;
167
181
} else {
168
- run ( process . argv [ 2 ] , process . argv [ 3 ] , process . env . GITHUB_TOKEN , process . argv [ 4 ] , process . argv [ 5 ] , process . argv [ 6 ] ) . catch ( error => {
169
- console . log ( `Error: ${ error . message } ` ) ;
182
+ const args = process . argv . slice ( 2 ) ;
183
+ const outputIndex = args . indexOf ( '--format' ) ;
184
+ let format = null ;
185
+
186
+ if ( outputIndex !== - 1 ) {
187
+ if ( outputIndex + 1 >= args . length ) {
188
+ printUsageAndExit ( ) ;
189
+ }
190
+ format = args [ outputIndex + 1 ] ;
191
+ if ( ! format || format !== 'yaml' ) {
192
+ printUsageAndExit ( ) ;
193
+ }
194
+ args . splice ( outputIndex , 2 ) ; // Remove --output and its value from args
195
+ }
196
+
197
+ const debugIndex = args . indexOf ( '--verbose' ) ;
198
+ if ( debugIndex !== - 1 ) {
199
+ verbose = true ;
200
+ args . splice ( debugIndex , 1 ) ; // Remove --verbose from args
201
+ }
202
+
203
+ if ( args . length !== 5 ) {
204
+ printUsageAndExit ( ) ;
205
+ }
206
+
207
+ const [ name , count , owner , repo , branch ] = args ;
208
+ if ( format !== null ) {
209
+ log = ( ) => { } ;
210
+ }
211
+
212
+ run ( process . env . GITHUB_TOKEN , name , count , owner , repo , branch , format ) . catch ( error => {
213
+ console . error ( `Error: ${ error . message } ` ) ;
214
+ exit ( 2 ) ;
170
215
} ) ;
171
216
}
0 commit comments