From 9fb9269d0d54af27c0c9be50d54839b2a07997cc Mon Sep 17 00:00:00 2001 From: Assem Hasna Date: Tue, 1 Sep 2026 08:23:55 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=20=20feat(verifier):=20scope=20bot=20exemp?= =?UTF-8?q?tions=20to=20approved=20repositories=20=F0=9F=94=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - replace global bot arrays with a repo-keyed ALLOWED_BOTS json map - gate both exemption paths on the calling repository's bot list - fail closed on repositories with no entry, logging the reason - document the per-repository allowlist in the readme Closes: DEV-339 --- README.md | 4 ++++ verify_commits.sh | 24 ++++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 439b59f..4ffec5c 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,7 @@ Verifies that pull request commits are SSH-signed with enrolled, hardware-backed (`sk-`, FIDO2) keys. Runs on pull requests and in merge queues as an organization required workflow; the enrollment registry is [`allowed_signers`](allowed_signers). + +Bot exemptions are per repository: `ALLOWED_BOTS` in +[`verify_commits.sh`](verify_commits.sh) maps `owner/repo` to the bot logins +allowed there, and a repository with no entry gets none. diff --git a/verify_commits.sh b/verify_commits.sh index 1ee32ed..90f341a 100755 --- a/verify_commits.sh +++ b/verify_commits.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # See README.md for what this checks, how it works, and its limits. # Usage: GH_TOKEN=... GITHUB_REPOSITORY=owner/repo verify_commits.sh +# Requires: gh, jq, ssh-keygen set -euo pipefail : "${GH_TOKEN:?GH_TOKEN required}" @@ -26,24 +27,39 @@ WORKDIR="$(mktemp -d)" trap 'rm -rf "$WORKDIR"' EXIT WEBFLOW_EMAIL="noreply@github.com" -WEBFLOW_BOT_LOGINS=("renovate[bot]" "github-actions[bot]" "cow-github-bot[bot]") -ALLOWED_AUTOMATED_LOGINS=("cow-protocol") + +# A repository with no entry gets no exemptions: its bot commits fail like anyone else's. +ALLOWED_BOTS='{ + "cowprotocol/commit-verifier": ["renovate[bot]"], + "cowprotocol/infrastructure": ["renovate[bot]", "cow-github-bot[bot]"], + "cowprotocol/services": ["renovate[bot]"] +}' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ALLOWED_SIGNERS_FILE="${ALLOWED_SIGNERS_FILE:-$SCRIPT_DIR/allowed_signers}" log() { printf '[verify-commits] %s\n' "$*" >&2; } +if ! REPO_BOTS="$(jq -r --arg repo "$GITHUB_REPOSITORY" '.[$repo] // [] | .[]' <<<"$ALLOWED_BOTS")"; then + echo "::error::ALLOWED_BOTS is not valid JSON" + exit 1 +fi +[[ -n "$REPO_BOTS" ]] || log "no bots allowed on $GITHUB_REPOSITORY" + +is_allowed_bot() { + [[ -n "$1" && -n "$REPO_BOTS" ]] && grep -qxF "$1" <<<"$REPO_BOTS" +} + is_allowed_automated_account() { local author_login="$1" author_email="$2" signature_file="$3" payload_file="$4" - printf '%s\n' "${ALLOWED_AUTOMATED_LOGINS[@]}" | grep -qxF "$author_login" || return 1 + is_allowed_bot "$author_login" || return 1 in_allowed_signers_registry "$author_email" "$signature_file" "$payload_file" } is_verified_webflow() { local author_login="$1" committer_email="$2" verified="$3" [[ "$committer_email" == "$WEBFLOW_EMAIL" && "$verified" == "true" ]] || return 1 - printf '%s\n' "${WEBFLOW_BOT_LOGINS[@]}" | grep -qxF "$author_login" + is_allowed_bot "$author_login" } fingerprint_of_key() { From ae683f06a6574ea88e7be3375f086666bd11b6f9 Mon Sep 17 00:00:00 2001 From: Assem Hasna Date: Tue, 1 Sep 2026 08:30:22 +0200 Subject: [PATCH 2/2] chore: allow Renovate on all repos --- README.md | 3 ++- verify_commits.sh | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4ffec5c..95db85e 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,5 @@ an organization required workflow; the enrollment registry is Bot exemptions are per repository: `ALLOWED_BOTS` in [`verify_commits.sh`](verify_commits.sh) maps `owner/repo` to the bot logins -allowed there, and a repository with no entry gets none. +allowed there, plus a `"*"` list that applies everywhere. A bot listed nowhere +gets no exemption. diff --git a/verify_commits.sh b/verify_commits.sh index 90f341a..885ef38 100755 --- a/verify_commits.sh +++ b/verify_commits.sh @@ -28,11 +28,12 @@ trap 'rm -rf "$WORKDIR"' EXIT WEBFLOW_EMAIL="noreply@github.com" -# A repository with no entry gets no exemptions: its bot commits fail like anyone else's. +# "*" applies to every repository, the rest add to it. A bot listed nowhere +# gets no exemption and fails like anyone else. ALLOWED_BOTS='{ - "cowprotocol/commit-verifier": ["renovate[bot]"], - "cowprotocol/infrastructure": ["renovate[bot]", "cow-github-bot[bot]"], - "cowprotocol/services": ["renovate[bot]"] + "*": ["renovate[bot]"], + "cowprotocol/infrastructure": ["cow-github-bot[bot]"], + "cowprotocol/services": ["cow-github-bot[bot]"] }' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -40,11 +41,15 @@ ALLOWED_SIGNERS_FILE="${ALLOWED_SIGNERS_FILE:-$SCRIPT_DIR/allowed_signers}" log() { printf '[verify-commits] %s\n' "$*" >&2; } -if ! REPO_BOTS="$(jq -r --arg repo "$GITHUB_REPOSITORY" '.[$repo] // [] | .[]' <<<"$ALLOWED_BOTS")"; then +if ! REPO_BOTS="$(jq -r --arg repo "$GITHUB_REPOSITORY" '(.["*"] // []) + (.[$repo] // []) | .[]' <<<"$ALLOWED_BOTS")"; then echo "::error::ALLOWED_BOTS is not valid JSON" exit 1 fi -[[ -n "$REPO_BOTS" ]] || log "no bots allowed on $GITHUB_REPOSITORY" +if [[ -n "$REPO_BOTS" ]]; then + log "bots allowed on $GITHUB_REPOSITORY: ${REPO_BOTS//$'\n'/ }" +else + log "no bots allowed on $GITHUB_REPOSITORY" +fi is_allowed_bot() { [[ -n "$1" && -n "$REPO_BOTS" ]] && grep -qxF "$1" <<<"$REPO_BOTS"