@@ -118,9 +118,70 @@ If none of the above apply, you can opt out of this check by adding \`#skip-chan
118118 ) ;
119119}
120120
121+ async function checkActionsArePinned ( ) {
122+ const workflowFiles = danger . git . created_files
123+ . concat ( danger . git . modified_files )
124+ . filter ( ( path ) => path . startsWith ( ".github/workflows/" ) ) ;
125+
126+ if ( workflowFiles . length == 0 ) {
127+ return ;
128+ }
129+
130+ console . log (
131+ `::debug:: Some workflow files have been changed - checking whether actions are pinned: ${ workflowFiles } `
132+ ) ;
133+
134+ const usesRegex = / ^ \+ ? * u s e s : / ;
135+ const usesActionRegex =
136+ / ^ \+ ? * u s e s : * (?< user > [ ^ \/ ] + ) \/ (?< action > [ ^ @ ] + ) @ (?< ref > .* ) / ;
137+ const shaRegex = / ^ [ a - f 0 - 9 ] { 40 } $ / ;
138+ const whitelistedUsers = [ "getsentry" , "actions" ] ;
139+
140+ for ( const path of workflowFiles ) {
141+ const diff = await danger . git . structuredDiffForFile ( path ) ;
142+ for ( const chunk of diff . chunks ) {
143+ for ( const change of chunk . changes ) {
144+ if ( change . add ) {
145+ const match = change . content . match ( usesActionRegex ) ;
146+ // Example of `match.groups`:
147+ // [Object: null prototype] {
148+ // user: 'getsentry',
149+ // action: 'action-prepare-release',
150+ // ref: 'v1'
151+ // }
152+ if ( match && match . groups ) {
153+ if ( ! match . groups . ref . match ( shaRegex ) ) {
154+ if ( whitelistedUsers . includes ( match . groups . user ) ) {
155+ message (
156+ "Consider pinning the action by specifying a commit SHA instead of a tag/branch." ,
157+ path ,
158+ change . ln
159+ ) ;
160+ } else {
161+ fail (
162+ "Please pin the action by specifying a commit SHA instead of a tag/branch." ,
163+ path ,
164+ change . ln
165+ ) ;
166+ }
167+ }
168+ } else if ( change . content . match ( usesRegex ) ) {
169+ warn (
170+ "Couldn't parse 'uses:' declaration while checking for action pinning." ,
171+ path ,
172+ change . ln
173+ ) ;
174+ }
175+ }
176+ }
177+ }
178+ }
179+ }
180+
121181async function checkAll ( ) {
122182 await checkDocs ( ) ;
123183 await checkChangelog ( ) ;
184+ await checkActionsArePinned ( ) ;
124185}
125186
126187schedule ( checkAll ) ;
0 commit comments