Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

## 2.2.0

### Features

- Danger - check for that actions are pinned to a commit ([#39](https://github.com/getsentry/github-workflows/pull/39))

## 2.1.1

### Fixes
Expand Down
18 changes: 18 additions & 0 deletions danger/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contributing

## How to run dangerfile locally

- [Working on your Dangerfile](https://danger.systems/js/guides/the_dangerfile.html#working-on-your-dangerfile)
- [Using danger and Faking being on a CI](https://danger.systems/js/guides/the_dangerfile.html#using-danger-and-faking-being-on-a-ci)

## TLDR

```shell-script
export DANGER_GITHUB_API_TOKEN='XXX'
export DANGER_FAKE_CI="YEP"
export DANGER_TEST_REPO='username/reponame'
cd reponame
export DANGER_TEST_PR='1234'
git checkout branch-for-pr-1234
npx danger ci --text-only --failOnErrors --dangerfile=../github-workflows/danger/dangerfile.js
```
61 changes: 61 additions & 0 deletions danger/dangerfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,70 @@ If none of the above apply, you can opt out of this check by adding \`#skip-chan
);
}

async function checkActionsArePinned() {
const workflowFiles = danger.git.created_files
.concat(danger.git.modified_files)
.filter((path) => path.startsWith(".github/workflows/"));

if (workflowFiles.length == 0) {
return;
}

console.log(
`::debug:: Some workflow files have been changed - checking whether actions are pinned: ${workflowFiles}`
);

const usesRegex = /^\+? *uses:/;
const usesActionRegex =
/^\+? *uses: *(?<user>[^\/]+)\/(?<action>[^@]+)@(?<ref>.*)/;
const shaRegex = /^[a-f0-9]{40}$/;
const whitelistedUsers = ["getsentry", "actions"];

for (const path of workflowFiles) {
const diff = await danger.git.structuredDiffForFile(path);
for (const chunk of diff.chunks) {
for (const change of chunk.changes) {
if (change.add) {
const match = change.content.match(usesActionRegex);
// Example of `match.groups`:
// [Object: null prototype] {
// user: 'getsentry',
// action: 'action-prepare-release',
// ref: 'v1'
// }
if (match && match.groups) {
if (!match.groups.ref.match(shaRegex)) {
if (whitelistedUsers.includes(match.groups.user)) {
message(
"Consider pinning the action by specifying a commit SHA instead of a tag/branch.",
path,
change.ln
);
} else {
fail(
"Please pin the action by specifying a commit SHA instead of a tag/branch.",
path,
change.ln
);
}
}
} else if (change.content.match(usesRegex)) {
warn(
"Couldn't parse 'uses:' declaration while checking for action pinning.",
path,
change.ln
);
}
}
}
}
}
}

async function checkAll() {
await checkDocs();
await checkChangelog();
await checkActionsArePinned();
}

schedule(checkAll);