diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 00000000..6361a685 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,134 @@ +--- +name: CLA Assistant +on: + issue_comment: + types: + - created + pull_request_target: + types: + - opened + - closed + - synchronize + - labeled +jobs: + CLAAssistant: + runs-on: ubuntu-latest + permissions: + actions: write + contents: write + pull-requests: write + statuses: write + checks: write + issues: write + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + with: + egress-policy: audit + - name: Checkout Private Repo for Allowlist + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v6.0.2 + with: + repository: OpenZeppelin/cla-sigs + token: ${{ secrets.CLA_SIGS_ACCESS_PAT }} + sparse-checkout: | + allowlist.txt + sparse-checkout-cone-mode: false + - name: Read Allowlist File + id: read_allowlist + run: | + ALLOWLIST=$(cat allowlist.txt) + echo "allowlist=$ALLOWLIST" >> $GITHUB_OUTPUT + - name: Check if user is in allowlist + id: check_allowlist + run: | + PR_USER=${{ github.event.pull_request.user.login }} + if [[ "${{ steps.read_allowlist.outputs.allowlist }}" == *"$PR_USER"* ]]; then + echo "is_allowed=true" >> $GITHUB_OUTPUT + else + echo "is_allowed=false" >> $GITHUB_OUTPUT + fi + - name: CLA Assistant + continue-on-error: true + id: cla_assistant + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I confirm that I have read and hereby agree to the OpenZeppelin Contributor License Agreement') || github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_SIGS_ACCESS_PAT }} + with: + path-to-signatures: signatures/${{ github.event.repository.name }}/v1_cla.json + path-to-document: https://github.com/OpenZeppelin/cla-assistant/blob/main/openzeppelin_2025_cla.md + branch: main + allowlist: ${{ steps.read_allowlist.outputs.allowlist }} + remote-organization-name: OpenZeppelin + remote-repository-name: cla-sigs + custom-notsigned-prcomment: > + Thank you for your contribution to ${{ github.event.repository.name }}. Before being able to integrate those changes, we would like you to sign our [Contributor License Agreement](https://github.com/OpenZeppelin/cla-assistant/blob/main/openzeppelin_2025_cla.md). + You can sign the CLA by just posting a Pull Request Comment with the sentence below. Thanks. + custom-pr-sign-comment: I confirm that I have read and hereby agree to the OpenZeppelin Contributor License Agreement + - name: Label PR as CLA Unsigned + if: ${{ steps.cla_assistant.outcome != 'success' && steps.check_allowlist.outputs.is_allowed == 'false' }} + run: | + if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then + PR_NUMBER="${{ github.event.pull_request.number }}" + elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then + PR_NUMBER="${{ github.event.issue.number }}" + fi + ENDPOINT="https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels" + curl -L -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -d '{"labels":["cla: unsigned"]}' \ + $ENDPOINT + exit 1 + - name: Label PR as CLA Signed + if: ${{ steps.cla_assistant.outcome == 'success' && steps.check_allowlist.outputs.is_allowed == 'false' }} + run: |- + if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then + PR_NUMBER="${{ github.event.pull_request.number }}" + elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then + PR_NUMBER="${{ github.event.issue.number }}" + fi + ENDPOINT="https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels" + # Remove 'cla: unsigned' label if present + curl -L -X DELETE \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$ENDPOINT/cla:%20unsigned" || true + # Add 'cla: signed' label + curl -L -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -d '{"labels":["cla: signed"]}' \ + $ENDPOINT + - name: Label PR as CLA Allowlist + if: ${{ steps.check_allowlist.outputs.is_allowed == 'true' }} + run: |- + if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then + PR_NUMBER="${{ github.event.pull_request.number }}" + elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then + PR_NUMBER="${{ github.event.issue.number }}" + fi + ENDPOINT="https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels" + # Remove 'cla: unsigned' label if present + curl -L -X DELETE \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$ENDPOINT/cla:%20unsigned" || true + # Remove 'cla: signed' label if present + curl -L -X DELETE \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$ENDPOINT/cla:%20signed" || true + # Add allowlist label + curl -L -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -d '{"labels":["cla: allowlist"]}' \ + $ENDPOINT