You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@magpie.apache.org by "potiuk (via GitHub)" <gi...@apache.org> on 2026/09/16 15:15:02 UTC

[PR] feat: per-PR preview deployments at magpie-pr.staged.apache.org [magpie-site]

potiuk opened a new pull request, #178:
URL: https://github.com/apache/magpie-site/pull/178

   Implements the design in #176. A maintainer comments `/show-preview` on a pull
   request; a scheduled workflow publishes that PR's built site at
   `https://magpie-pr<N>.staged.apache.org/`, keeps it tracking the PR's head
   commit, and retires it when the PR closes.
   
   **Please read #176 first** — it records what was probed against real ASF
   infrastructure before any of this was written, and several decisions here only
   make sense against those findings.
   
   ## How it works
   
   **`build.yml`** (unprivileged, runs on `pull_request`, executes the PR's own
   code) builds the site and uploads it as an artifact with metadata naming the PR
   and its head SHA.
   
   **`preview-publish.yml`** (privileged, `schedule` every 15 min +
   `workflow_dispatch`, holds a token that can push branches and comment) never
   checks out, builds or executes pull-request code. It consumes that artifact,
   validates it, and force-pushes static files to `preview/pr<N>-staging`, whose
   generated `.asf.yaml` makes infra serve it.
   
   **`pull_request_target` appears nowhere.** That is the constraint the whole
   shape follows from.
   
   ## Three findings that shaped the implementation
   
   - **Deleting a preview branch does not unstage the site.** Verified directly:
     the host still served HTTP 200 ten minutes after the branch was deleted. So
     teardown force-pushes a tombstone *first* and deletes the branch on a later
     run. "Delete the preview" is not implementable as a branch deletion.
   - **A pull request can ship a `.git/` directory inside its own build artifact.**
     `git init` reinitialises an existing one, preserving its hooks, and the commit
     would then execute them in the job holding the ASF push token. Neither the
     entry-name screen nor the symlink walk catches it — the name is clean and it
     is not a symlink. Closed with three independent layers.
   - **An archive entry that escapes the extraction root lands outside the tree**,
     where no walk of that tree can ever see it. Screening entry names *before*
     extraction is the only place that defence can live.
   
   ## Security model
   
   - The privileged job consumes artifacts only; it never runs PR code.
   - Artifact metadata is attacker-controlled, so publishing requires its
     `headSha` to equal the head SHA the API reports for that PR — without it a
     fork could claim another PR's number.
   - `.asf.yaml` and `robots.txt` are generated by the publisher and overwrite
     anything of the same name in the artifact.
   - Archives containing symlink members, absolute or traversing entry names, or
     an unreadable expanded size are refused outright.
   - `.git`, `.gitignore` and `.gitmodules` are stripped at any depth; every git
     call pins `core.hooksPath` and `core.excludesFile` to `/dev/null`; the commit
     uses `--no-verify`.
   - The token is redacted from every field of a child-process rejection that can
     reach a log, including `spawnargs`.
   - Unknown armed state never triggers a destructive action — missing data must
     not be more dangerous than an explicit "no".
   
   This PR also splits `build.yml` so the job running `npm ci` and `npm run build`
   on pull-request code no longer holds `contents: write`; the publish step moves
   to a separate `main`-only `deploy` job.
   
   ## Testing
   
   83 unit tests (`npm test`, Node's built-in runner, no new dependency), now run
   in CI — they weren't before. The security-carrying logic was deliberately
   extracted into pure functions so it is testable: metadata validation, entry-name
   screening, symlink-member detection, tree preparation, token redaction, and the
   publish/tombstone/delete decision.
   
   `git.mjs`'s push path and `artifact.mjs`'s fetch path have no integration
   coverage. Both are thin shells over `git` and `fetch`, and they cannot be
   exercised without a real repository and a real token — which is what the
   post-merge checklist below is for.
   
   ## This cannot be tested before it merges
   
   `schedule` and `workflow_dispatch` only ever run the default branch's copy of a
   workflow, so nothing here runs from a PR branch. Post-merge acceptance:
   
   1. Comment `/show-preview` on a throwaway PR (or dispatch **Publish PR
      previews** with its number to skip the wait).
   2. Confirm `preview/pr<N>-staging` appears and the URL serves within ~3 minutes.
   3. Push a commit; confirm the preview follows the new SHA.
   4. Close the PR; confirm the URL serves the tombstone — not a 404 — and that
      the branch is deleted on the following run.
   5. Confirm `https://magpie.apache.org/` is unchanged.
   
   Heads-up: the first scheduled run after merge posts the explainer comment on
   every currently-open PR at once. That is expected, and it will be visible on
   `commits@`.
   
   ## Open question for the list
   
   Tombstoning stops a PR's content being served, but the hostname keeps resolving
   and keeps serving the tombstone. Whether INFRA can purge a staging profile — and
   whether an accumulating set of tombstoned preview hostnames is acceptable to
   them — is worth asking on `users@infra.apache.org` before this is relied on.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@magpie.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] feat: per-PR preview deployments at magpie-pr.staged.apache.org [magpie-site]

Posted by "potiuk (via GitHub)" <gi...@apache.org>.
potiuk merged PR #178:
URL: https://github.com/apache/magpie-site/pull/178


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@magpie.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org