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
72 changes: 72 additions & 0 deletions .github/workflows/verifyPeerReview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# This workflow is intended to be triggered by Rulesets for all PRs in the Expensify org to enforce that all code against protected branches is peer-reviewed.
#
# Security model:
# - pull_request_target runs this workflow file from the base branch, not the PR head.
# - Only GitHub-Actions@main is checked out for scripts.
# - Never checkout the repo where the PR lives.
#
# Thus, all code we run for the check is itself peer-reviewed, and the check can't be hacked, bypassed, or used to leak secrets.
#
# Ruleset caveats (branch/path filters in `on:` are ignored; default activity types only - `opened`, `synchronize`, `reopened`):
# https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#supported-event-triggers
name: Verify peer review
run-name: Verify peer review for ${{ github.repository }}#${{ github.event.pull_request.number }}

on:
pull_request_target:

permissions:
contents: read
pull-requests: read

jobs:
verifyPeerReview:
name: Check independent approval
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
# v3.2.0
- name: Generate a GitHub App token
id: generateAppToken
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
with:
client-id: '3877737'
private-key: ${{ secrets.PEER_REVIEW_CHECKER_PRIVATE_KEY }}
owner: ${{ github.event.pull_request.base.repo.owner.login }}
repositories: |
${{ github.event.pull_request.base.repo.name }}
GitHub-Actions
permission-administration: read
permission-contents: read
permission-members: read
permission-metadata: read
permission-pull-requests: read

# v7.0.0
- name: Checkout GitHub-Actions
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
repository: Expensify/GitHub-Actions
path: GitHub-Actions
Comment on lines +45 to +49

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still safe if the PR is against the GH actions repo?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think so. Because it uses the pull_request_target trigger, the version of the workflow in the PR base will run. The default checkout will also use the ref from the PR base.


# v6.4.0
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version-file: GitHub-Actions/.nvmrc
cache: npm
cache-dependency-path: GitHub-Actions/package-lock.json

- name: Install npm packages
run: npm ci
working-directory: GitHub-Actions

- name: Verify peer review
run: >-
npm run verify-peer-review --
--owner '${{ github.event.pull_request.base.repo.owner.login }}'
--repo '${{ github.event.pull_request.base.repo.name }}'
--pull-request-number '${{ github.event.pull_request.number }}'
--base-ref '${{ github.event.pull_request.base.ref }}'
working-directory: GitHub-Actions
env:
GITHUB_TOKEN: ${{ steps.generateAppToken.outputs.token }}
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ jobs:
secrets: inherit
```

### `verifyPeerReview.yml`

Org-level ruleset workflow that verifies pull requests have an independent employee approval — e.g. blocking cases where an employee self-approves a pull request they asked Melvin to create.

Configure it to run via an org [ruleset](#rulesets) that requires this workflow on `pull_request_target` events. See the Rulesets section below for caveats.

**Disclaimer:** this workflow is currently a no-op that will always pass.

### `setup-composer-cache`

Restores Composer download caches and optionally runs `composer install`. See [setup-composer-cache/README.md](./setup-composer-cache/README.md) for details.
Expand Down
Loading