Add Cloudflare Pages docs preview with /preview-docs slash command

Merged
LO
4mo ago
+275-0

Summary

Adds per-PR documentation previews on Cloudflare Pages so reviewers can see the rendered mkdocs site before merge.

  • Auto-preview: PRs from repo admins that touch docs/**, docs_src/**, mkdocs.yml or pyproject.toml build and deploy automatically on open and on every push.
  • Slash command: on any other PR, an admin or maintainer can comment /preview-docs to trigger a preview. Anyone else gets a polite rejection.
  • A sticky PR comment carries the preview URL (updated in place on each rebuild).
  • A companion workflow deletes the Cloudflare deployments when the PR closes.

Security

mkdocs executes Python from the PR (mkdocstrings imports src/mcp, !!python/name: directives in mkdocs.yml), so the design treats the build as untrusted code:

  • An authorize job checks the triggering actor's permission before any PR code is fetched. The auto-path keys on event.sender.login (the pusher), not the PR opener, so a non-admin pushing to an admin's branch does not get an auto-build.
  • The build job runs PR code with no secrets and uploads the static site/ as an artifact. The deploy job downloads the artifact and runs wrangler pages deploy — PR code never shares a runner with the Cloudflare token.
  • .github/zizmor.yml documents and suppresses the dangerous-triggers finding for these two workflows.

Setup required before this takes effect

  1. Create a Cloudflare Pages project (Direct Upload), e.g. mcp-python-sdk-docs.
  2. Repo secrets: CLOUDFLARE_API_TOKEN (scope: Account → Cloudflare Pages → Edit) and CLOUDFLARE_ACCOUNT_ID.
  3. Repo variable: CLOUDFLARE_PAGES_PROJECT = the project name from step 1.

pull_request_target runs the base branch's workflow, so this only takes effect once merged to main.

Test plan

  • actionlint clean on both new workflows
  • zizmor .github/workflows/ exits 0
  • uv sync --frozen --group docs && uv run --frozen --no-sync mkdocs build produces site/index.html + site/api/ locally
  • After merge + secrets configured: open a small docs PR as an admin → preview comment appears with a working pr-<n>.<project>.pages.dev link
  • Push to that PR → comment updates in place
  • Comment /preview-docs from a non-admin account on a fork PR → rejection reply
  • Comment /preview-docs from an admin → preview appears
  • Close the PR → Cloudflare deployments for pr-<n> are deleted