From bf702b653baed22087453842ad48bfc884022b5e Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Tue, 23 Apr 2024 23:33:06 +0200 Subject: [PATCH] Check write permissions --- .github/workflows/ci.yml | 10 +++++++ scripts/unprivileged-owners.sh | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100755 scripts/unprivileged-owners.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67ffe98..cb485d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,7 @@ jobs: name: GitHub CODEOWNERS Validator runs-on: ubuntu-latest steps: + - uses: cachix/install-nix-action@v26 - uses: actions/checkout@v4 with: @@ -57,3 +58,12 @@ jobs: # Specifies whether only teams are allowed as owners of files. owner_checker_owners_must_be_teams: "false" + + # The above validator doesn't currently ensure that people have write access: https://github.com/mszostok/codeowners-validator/issues/157 + # So we're doing it manually instead + - name: Check that codeowners have write access + # Important that we run the script from the base branch, + # because otherwise a PR from a fork could change it to extract the secret + run: trusted-base/scripts/unprivileged-owners.sh untrusted-pr ${{ github.repository }} + env: + GH_TOKEN: "${{ secrets.OWNERS_VALIDATOR_GITHUB_SECRET }}" diff --git a/scripts/unprivileged-owners.sh b/scripts/unprivileged-owners.sh new file mode 100755 index 0000000..1c88e61 --- /dev/null +++ b/scripts/unprivileged-owners.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash --pure -p codeowners github-cli + +set -euo pipefail + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' exit + +if (( $# != 2 )); then + echo "Usage: $0 PATH OWNER/REPO" + exit 1 +fi + +root=$1 +repo=$2 + +# Writes all code owners into $tmp/codeowners, one user per line (without @) +while read -r -a fields; do + # The first field is the filename + unset 'fields[0]' + if [[ "${fields[1]}" != "(unowned)" ]]; then + (IFS=$'\n'; echo "${fields[*]##@}") + fi +done < <(codeowners --file "$root/.github/CODEOWNERS") | + sort -u > "$tmp/codeowners" + +# Get all users with push access +gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + --method GET \ + -f permission=push \ + /repos/"$repo"/collaborators \ + -F per_page=100 \ + --paginate \ + --jq '.[].login' | + sort > "$tmp/collaborators" + +# Figure out all the owners that aren't collaborators +readarray -t unprivilegedOwners < <(comm -23 "$tmp/codeowners" "$tmp/collaborators") + +if (( "${#unprivilegedOwners[@]}" == 0 )); then + echo "All code owners have write permission" +else + echo "These code owners don't have write permission:" + for handle in "${unprivilegedOwners[@]}"; do + echo "- [ ] @$handle" + done + exit 1 +fi