Skip to content

Commit ba2886c

Browse files
authored
feat: Danger - check for unpinned actions (#39)
* feat: Danger - check for unpinned actions * chore: update changelog * chore: 2.2.0 in changelog
1 parent c06302f commit ba2886c

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Unreleased
44

5+
## 2.2.0
6+
7+
### Features
8+
9+
- Danger - check for that actions are pinned to a commit ([#39](https://github.com/getsentry/github-workflows/pull/39))
10+
511
## 2.1.1
612

713
### Fixes

danger/CONTRIBUTING.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Contributing
2+
3+
## How to run dangerfile locally
4+
5+
- [Working on your Dangerfile](https://danger.systems/js/guides/the_dangerfile.html#working-on-your-dangerfile)
6+
- [Using danger and Faking being on a CI](https://danger.systems/js/guides/the_dangerfile.html#using-danger-and-faking-being-on-a-ci)
7+
8+
## TLDR
9+
10+
```shell-script
11+
export DANGER_GITHUB_API_TOKEN='XXX'
12+
export DANGER_FAKE_CI="YEP"
13+
export DANGER_TEST_REPO='username/reponame'
14+
cd reponame
15+
export DANGER_TEST_PR='1234'
16+
git checkout branch-for-pr-1234
17+
npx danger ci --text-only --failOnErrors --dangerfile=../github-workflows/danger/dangerfile.js
18+
```

danger/dangerfile.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 = /^\+? *uses:/;
135+
const usesActionRegex =
136+
/^\+? *uses: *(?<user>[^\/]+)\/(?<action>[^@]+)@(?<ref>.*)/;
137+
const shaRegex = /^[a-f0-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+
121181
async function checkAll() {
122182
await checkDocs();
123183
await checkChangelog();
184+
await checkActionsArePinned();
124185
}
125186

126187
schedule(checkAll);

0 commit comments

Comments
 (0)