diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml index c6405e3..dc93538 100644 --- a/.github/workflows/dco.yml +++ b/.github/workflows/dco.yml @@ -6,6 +6,11 @@ on: schedule: - cron: '43 11 * * 0' workflow_dispatch: + inputs: + base_sha: + description: Queue commit parent; omit to run the DCO fixture. + type: string + required: false permissions: {} concurrency: group: dco-${{ github.event.pull_request.number || github.ref }} @@ -26,11 +31,12 @@ jobs: - name: Check every proposed commit env: EVENT_NAME: ${{ github.event_name }} - BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.merge_group.base_sha - }} + BASE_SHA: ${{ inputs.base_sha || github.event_name == 'pull_request' && github.event.pull_request.base.sha + || github.event.merge_group.base_sha }} HEAD_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} PR_NUMBER: ${{ github.event.pull_request.number || '' }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} shell: bash run: | set -euo pipefail @@ -80,7 +86,21 @@ jobs: fi } - if [ "$EVENT_NAME" = schedule ] || [ "$EVENT_NAME" = workflow_dispatch ]; then + check_queue_dispatch() { + # A dispatched queue run validates the exact synthetic commit + # built from the parent selected by the trusted reconciler. + [[ "$GITHUB_REF" == refs/heads/gh-readonly-queue/"$DEFAULT_BRANCH"/* ]] || return 1 + [[ "$BASE_SHA" =~ ^[0-9a-f]{40}$ ]] || return 1 + test "$(git rev-parse "${HEAD_SHA}^")" = "$BASE_SHA" || return 1 + local original_event=$EVENT_NAME + EVENT_NAME=merge_group + check_signoffs + EVENT_NAME=$original_event + } + + if [ "$EVENT_NAME" = workflow_dispatch ] && [ -n "$BASE_SHA" ]; then + check_queue_dispatch + elif [ "$EVENT_NAME" = schedule ] || [ "$EVENT_NAME" = workflow_dispatch ]; then fixture=$(mktemp -d) trap 'rm -rf "$fixture"' EXIT cd "$fixture" @@ -95,6 +115,17 @@ jobs: HEAD_SHA=$(git rev-parse HEAD) check_signoffs BASE_SHA=$HEAD_SHA + git -c user.name=Fixture -c user.email=fixture@example.invalid \ + commit --allow-empty -qm 'unsigned synthetic queue tip' + HEAD_SHA=$(git rev-parse HEAD) + GITHUB_REF="refs/heads/gh-readonly-queue/$DEFAULT_BRANCH/fixture" + check_queue_dispatch + BASE_SHA=$(git rev-parse "${HEAD_SHA}^^") + if check_queue_dispatch; then + echo 'DCO queue fixture accepted a wrong parent' >&2 + exit 1 + fi + BASE_SHA=$HEAD_SHA git -c user.name='dependabot[bot]' -c user.email='49699333+dependabot[bot]@users.noreply.github.com' \ commit --allow-empty -qm $'bad trailer\n\nSigned-off-by: dependabot[bot] ' HEAD_SHA=$(git rev-parse HEAD) @@ -106,3 +137,16 @@ jobs: else check_signoffs fi + queue-completion: + continue-on-error: true + name: Queue completion callback + if: always() && github.event_name == 'workflow_dispatch' && startsWith(github.ref, format('refs/heads/gh-readonly-queue/{0}/', + github.event.repository.default_branch)) + needs: [sign-off] + runs-on: ubuntu-24.04 + timeout-minutes: 2 + permissions: + actions: write # Notify the trusted default-branch reconciler. + steps: + - name: Notify trusted queue reconciler + uses: nix-forge/ci/actions/queue-completion@bb1b39a9082f72dc6c7ce596103ce7a5e4d29b01 # v2.8.0-compatible diff --git a/.github/workflows/reconcile-merge-queue.yml b/.github/workflows/reconcile-merge-queue.yml index 0ca86f2..f15c3bd 100644 --- a/.github/workflows/reconcile-merge-queue.yml +++ b/.github/workflows/reconcile-merge-queue.yml @@ -1,7 +1,7 @@ name: Reconcile merge queue on: # zizmor: ignore[dangerous-triggers] Reads API metadata and runs only the default branch's script. workflow_run: - workflows: ["CI", "CodeQL"] + workflows: ["CI", "CodeQL", "DCO"] types: [completed] schedule: - cron: 17 * * * * @@ -34,5 +34,6 @@ jobs: - name: Reconcile verified automation uses: nix-forge/ci/actions/reconcile-queue@bb1b39a9082f72dc6c7ce596103ce7a5e4d29b01 # v2.8.0 with: - workflows: '["ci.yml", "codeql.yml"]' + workflows: '["ci.yml", "codeql.yml", "dco.yml"]' + base-sha-workflows: '["dco.yml"]' source-run-id: ${{ inputs.source_run_id }}