Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/workflows/merge-bot-pull-request.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
name: Merge bot pull request action

# Auto-merges in-repo Dependabot pull requests: enable on opened or reopened, disable on a maintainer push.
# The merge method follows the base, since the two rulesets allow different forms.
# - develop takes squash.
# - main takes a merge commit.
# An App token is used rather than GITHUB_TOKEN, for two reasons.
# - It fires downstream workflows on merge, which GITHUB_TOKEN deliberately does not.
# - A Dependabot pull request's GITHUB_TOKEN is read-only regardless of who triggered the event.
# The trigger is pull_request_target rather than pull_request, because these jobs hold the App key.
# That resolves the workflow and action SHAs from the trusted base rather than from the pull request head.
# It is safe here because no job checks out pull request code, each one merging by URL alone.
# This repo carries no codegen workflow and no upstream-version tracker, so those jobs are not vendored.
on:
pull_request_target:
types: [ opened, reopened, synchronize ]

# Concurrency keys on the pull request number rather than github.ref.
# Under pull_request_target github.ref is the base branch, which would serialize every bot pull request.
# cancel-in-progress is false so a follow-up synchronize cannot cancel an in-flight opened run.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: false

jobs:

merge-dependabot:
name: Merge dependabot pull request job
runs-on: ubuntu-latest
# Dependabot pull requests raised in this repo, never from a fork.
# Restricted to opened and reopened so the disable job below stays sticky.
if: >-
(github.event.action == 'opened' || github.event.action == 'reopened') &&
github.event.pull_request.user.login == 'dependabot[bot]' &&
github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: write
pull-requests: write

steps:

- name: Generate GitHub App token step
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ secrets.CODEGEN_APP_CLIENT_ID }}
private-key: ${{ secrets.CODEGEN_APP_PRIVATE_KEY }}

# Every tier is auto-merged, semver-major included.
# The required checks are the gate, not the size of the bump.
# A major that breaks the build fails its checks and never merges.
- name: Merge pull request step
run: |
set -Eeuo pipefail
case "${{ github.event.pull_request.base.ref }}" in
develop) method=--squash ;;
main) method=--merge ;;
*)
echo "::error::Unsupported base branch: ${{ github.event.pull_request.base.ref }}"
exit 1
;;
esac
gh pr merge --auto "$method" "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}

disable-auto-merge-on-maintainer-push:
name: Disable auto-merge on maintainer push job
runs-on: ubuntu-latest
# Fires when a maintainer pushes to the bot's branch, which is a synchronize by a non-bot actor.
# Auto-merge is disabled so the maintainer's commits do not merge along with the bot's.
# Re-enabling it is then a deliberate manual act, and the disable call is idempotent.
if: >-
github.event.action == 'synchronize' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login == 'dependabot[bot]' &&
github.actor != github.event.pull_request.user.login
permissions:
pull-requests: write

steps:

- name: Generate GitHub App token step
# An App token is required because a Dependabot pull request's GITHUB_TOKEN is read-only.
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ secrets.CODEGEN_APP_CLIENT_ID }}
private-key: ${{ secrets.CODEGEN_APP_PRIVATE_KEY }}

- name: Disable auto-merge step
run: gh pr merge --disable-auto "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
2 changes: 0 additions & 2 deletions TODO.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,6 @@ The site is built and gated in CI. It is on GitHub, and it is not yet serving it
## Next, in dependency order

- Dispatch `publish-release.yml` once to prove the release path, which exists but has never run.
- Decide on `merge-bot-pull-request.yml`. Dependabot is configured and its pull requests will otherwise sit open, and the App secrets it needs are now in place.
- Provision the VPS: an unprivileged `blogdeploy` user, the deploy root, and `unattended-upgrades` with automatic reboot.
- Restrict the deploy key with `restrict,command=...`, no pty and no forwarding, so it can do nothing but rsync into `releases/` and swap the symlink. Generate per-environment keys so staging cannot reach production.
- Choose the staging FQDN, add its DNS record, and expose it through Pangolin as a public resource with **no auth**, since CI's live-URL check has to reach it. Authentication defaults to on for a public resource and has to be turned off deliberately.
Expand All@@ -38,7 +37,6 @@ The site is built and gated in CI. It is on GitHub, and it is not yet serving it
- The staging FQDN name.
- `/robots.txt/` and `/osd.xml/` currently sit in `slugs.map` pointing at `/`. The first would be better pointing at the real `/robots.txt`.
- Whether the 78 legacy date-archive redirects should point at `/all/` rather than `/`, so a visitor following a `/2015/` link lands somewhere they can find 2015 posts. It is a one-line change to rule R3.
- Whether to carry `merge-bot-pull-request.yml`. Dependabot is configured and its PRs will sit open without it, but it needs the App secrets, so it cannot be proven until those exist.

## Deliberate deviations from the fleet baseline

Expand Down
1 change: 0 additions & 1 deletion reports/Blog/audit.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -116,7 +116,6 @@ Carried forward rather than closed:
- The live redirect gate has not run against this build, so 917 of the 1,245 contracted URLs are asserted rather than proven.
- `publish-release.yml` has never been dispatched, so the release path is untested.
- No deploy exists, so the publish surface stays deferred and the registry entry stays `publish: []`.
- `merge-bot-pull-request.yml` is not carried. Dependabot is configured and its pull requests will sit open until either the merge bot is added or they are merged by hand. The App secrets it needs are now in place, so this is no longer blocked, only undone.
- `checks/README.md` carries a small prose backlog of `dash` and `semicolon` findings, left for the next edit of that file per the correct-as-you-next-edit rule.

<!-- Repo -->
Expand Down