diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..cab8367 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,40 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + schedule: + - cron: "0 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [actions, go] + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 + with: + build-mode: ${{ matrix.language == 'go' && 'autobuild' || 'none' }} + languages: ${{ matrix.language }} + queries: security-extended + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 7844a3b..07b060c 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -1,22 +1,69 @@ -name: Dependabot auto-merge +name: Dependabot strict gate on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] + push: + branches: [main] permissions: {} jobs: - dependabot: - name: Enable auto-merge - if: github.event.pull_request.user.login == 'dependabot[bot]' + strict-gate: + name: Strict Dependabot gate runs-on: ubuntu-24.04 - timeout-minutes: 5 + timeout-minutes: 30 permissions: - contents: write - pull-requests: write + checks: read + contents: read + pull-requests: read + env: + GH_TOKEN: ${{ github.token }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} steps: - - name: Enable auto-merge - env: - GH_TOKEN: ${{ github.token }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: gh pr merge --auto --squash "$PR_URL" + - name: Require successful checks on the exact Dependabot head + run: | + set -euo pipefail + if [[ "$GITHUB_EVENT_NAME" != pull_request || "$PR_AUTHOR" != 'dependabot[bot]' ]]; then + echo 'No Dependabot pull request to gate.' + exit 0 + fi + + for attempt in $(seq 1 50); do + current_head=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER" --jq .head.sha) + if [[ "$current_head" != "$PR_HEAD_SHA" ]]; then + echo 'Pull request head changed; the new run must establish its own gate.' >&2 + exit 1 + fi + + checks=$(gh api "repos/$GITHUB_REPOSITORY/commits/$PR_HEAD_SHA/check-runs?per_page=100") + if jq -e ' + .total_count <= 100 and + .check_runs as $runs + | ([ + ["CI", 15368], + ["CodeQL", 57789], + ["Analyze (actions)", 15368], + ["Analyze (go)", 15368] + ] | all(.[]; . as $required | + ($runs | map(select(.name == $required[0] and .app.id == $required[1]))) as $found + | ($found | length > 0 and all(.[]; .status == "completed" and .conclusion == "success")) + )) + and ($runs | all(.[]; + .name == "Strict Dependabot gate" or + .name == "Enable auto-merge" or + (.status == "completed" and .conclusion == "success") + )) + ' <<< "$checks" > /dev/null; then + echo "All exact-head checks passed on $PR_HEAD_SHA." + exit 0 + fi + + echo "Strict checks are not yet all successful (attempt $attempt/50)." + sleep 30 + done + + echo "Strict checks did not all pass on $PR_HEAD_SHA." >&2 + exit 1