Skip to content

ci: fix the publishing workflow after its first real runs - #2397

Merged
fengmk2 merged 3 commits into
mainfrom
fix/authorize-fork-pr-resolution
Aug 10, 2026
Merged

ci: fix the publishing workflow after its first real runs#2397
fengmk2 merged 3 commits into
mainfrom
fix/authorize-fork-pr-resolution

Conversation

@fengmk2

@fengmk2 fengmk2 commented Aug 10, 2026

Copy link
Copy Markdown
Member

Two fixes to main, both found by the first real runs of the publishing workflow. It could not be exercised before merge, because workflow_run only fires for workflow files already on the default branch.

First, the good news: the design works. PR #2328 published end to end through the new path with an OIDC token, no admin token involved. authorize, Pkg Preview, and the sticky comment all succeeded, and commit.a7180fa85c06fad48 is on the bridge:

commit.a7180fa85c06fad48 | pr: .../pull/2328 | at: 2026-08-10T07:35:31.617Z

1. Fork PRs could not be resolved at all

#2391 (from liangmiQwQ) failed in authorize with no open PR of voidzero-dev/vite-plus has head c7e51be… while that PR was open with exactly that head.

listPullRequestsAssociatedWithCommit returns empty for a fork PR's head commit. Confirmed against the live API:

commit result
#2387 head (same-repo) returns #2387
#2391 head (fork) empty

So it worked for every case reachable before merge and failed for the only case this feature exists for. workflow_run.pull_requests is empty for forks too, which is what sent me to the commit endpoint originally — I swapped one fork-blind source for another.

Now resolves via pulls?state=open&head=<head_owner>:<head_branch>, both GitHub-signed payload fields. The head-sha match is a separate step so the message distinguishes "no such PR" from "the PR moved on":

fork PR 2391 (real failure) -> OK: #2391 labeled=true fork=true
stale head                  -> FAIL: PR #2391 now at c7e51be, built 0000000
no such branch              -> FAIL: no open PR from liangmiQwQ:does-not-exist

I re-checked the rest of the publishing workflow for the same blind spot. Everything else keys off the PR number or the run id, which are base-repo objects and fork-safe: the post-approval pulls.get re-check returns correct state, head and labels for #2391, and the artifact download and the listWorkflowRunArtifacts precondition both see that run's 148MB bridge-packages.

2. The Docker gha cache broke the image push

#14 exporting to GitHub Actions Cache
#14 ERROR: error writing layer blob: failed to reserve cache
#13 exporting to image ... CANCELED

The cache export is fatal to the build, so it cancelled the push. I added this in the cleanup pass; it broke the job it was meant to speed up, and #2328's npm preview published while its Docker image did not.

Reverted rather than repaired. Making it work needs actions: write on the one job that installs and executes the preview package, which is the job SR-5 says to keep unprivileged, and this was the only type=gha usage in the repo so there was no working precedent. It was saving 60-90s of apt on a path that already waits on a human approval measured in minutes to days.

3. Terminology

"Trusted leg" and "build leg" were my own coinage and meant nothing to a reader who was not in the design conversation. The two workflows are now described as the build workflow and the publishing workflow, and where trust was the point the property is stated rather than encoded in a name.

This also surfaced something worth fixing later: publish-preview.yml is named "Publish preview build" and no longer publishes anything. Renaming it is the real fix, but the publishing workflow matches it by name:, so that has to be a coordinated change. The header says so outright for now.

The same terminology fix for the RFC and bridge docs is voidzero-dev/pkg-pr-registry-bridge#93, which also corrects SR-1 for the fork-blind endpoint above.

After merging

Re-label #2391 to get the first genuine fork preview.

Preview publishing is broken on main for fork PRs, which is the case the
whole split exists for. First real fork PR (#2391 from liangmiQwQ) failed
with "no open PR of voidzero-dev/vite-plus has head c7e51be" while that PR
was open with exactly that head.

Cause: listPullRequestsAssociatedWithCommit returns EMPTY for a fork PR's
head commit. Verified against the live API — it returns #2387 for a
same-repo head and nothing for #2391's. So the lookup worked for every case
I could test and failed for the only case that matters.

`workflow_run.pull_requests` is empty for forks too, which is what sent me to
the commit endpoint in the first place. I swapped one fork-blind source for
another and could not have caught it before merge, since workflow_run cannot
fire until the file is on the default branch.

Now resolves via `pulls?state=open&head=<head_owner>:<head_branch>`, both
GitHub-signed payload fields, so this is as trustworthy as the sha was. The
head-sha match is a separate step so the failure says which of the two
happened: no such PR, or the PR moved on since the build.

Checked against the live API: #2391 resolves and is labeled, a stale head
reports the PR and both shas, and an unknown branch reports no PR.
@netlify

netlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit 5125bbb
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a79860456d7aa0008e344dc

@fengmk2 fengmk2 self-assigned this Aug 10, 2026
@fengmk2

fengmk2 commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 96ff4c8921

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@liangmiQwQ

Copy link
Copy Markdown
Collaborator

Thx ❤️

The Docker preview job now fails outright:

  #14 exporting to GitHub Actions Cache
  #14 ERROR: error writing layer blob: failed to reserve cache
  #13 exporting to image ... CANCELED
  ERROR: failed to build: failed to solve: error writing layer blob

The cache export is fatal to the build, so it cancelled the image push. My
optimization broke the job it was meant to speed up, and the npm preview for
PR #2328 published fine while its Docker image did not.

Reverting rather than fixing it. Making it work would need `actions: write`
on the one job that installs and executes the preview package, which is the
job SR-5 says to keep as unprivileged as possible, and this was the only
`type=gha` usage in the repo so there was no working precedent to copy. The
benefit was 60-90s of apt on a path that already waits on a human approval
measured in minutes to days, so it was buying almost nothing.

`ignore-error=true` would keep the build green but the export would keep
failing, leaving a dead directive and a stack trace in every log.
@fengmk2 fengmk2 changed the title ci: resolve the preview PR by head branch, not commit association ci: fix the trusted leg after its first real runs Aug 10, 2026
@fengmk2
fengmk2 requested a review from wan9chi August 10, 2026 07:48
"Trusted leg" and "build leg" were my own coinage and mean nothing to a
reader who was not in the design conversation. Replaced throughout with
plain descriptions of what each file does: the build workflow and the
publishing workflow.

Where trust mattered I now state the property instead of encoding it in a
name, so "TRUSTED LEG" became "It is the only place a bridge credential
exists" and "BUILD LEG (untrusted)" became "It holds no secrets and no OIDC
permission, so it is safe to run for a pull request from a fork".

Also added a line the naming badly needed: publish-preview.yml is called
"Publish preview build" and no longer publishes anything, so it now says so
outright. Renaming it would be better but the publishing workflow matches it
by NAME, so that has to be a coordinated change.

Left the one pre-existing "arm64 QEMU leg", where leg means a matrix leg and
is the normal term.
@fengmk2 fengmk2 changed the title ci: fix the trusted leg after its first real runs ci: fix the publishing workflow after its first real runs Aug 10, 2026
@fengmk2
fengmk2 merged commit 3b95765 into main Aug 10, 2026
45 checks passed
@fengmk2
fengmk2 deleted the fix/authorize-fork-pr-resolution branch August 10, 2026 08:28
fengmk2 added a commit to voidzero-dev/pkg-pr-registry-bridge that referenced this pull request Aug 10, 2026
Two related cleanups, both prompted by voidzero-dev/vite-plus#2397.

## "leg" was jargon I invented

"Trusted leg" and "build leg" carry no meaning for a reader who was not
in the design conversation. Replaced throughout the RFC, docs, action
and worker comments with plain descriptions: **the build workflow** and
**the publishing workflow**. Where trust was the point, the property is
now stated rather than encoded in a name.

Left one untouched: a pre-existing "arm64 QEMU leg", where leg means a
matrix leg and is the normal term.

## SR-1 named an endpoint that does not work for forks

This is the more important half. SR-1 said:

> resolve the PR number from `head_sha` via `GET
/repos/{repo}/commits/{head_sha}/pulls`

Following that cost a production outage.
`listPullRequestsAssociatedWithCommit` returns **empty** for a fork PR's
head commit while working correctly for a same-repo one:

| commit | result |
| --- | --- |
| same-repo PR head | returns the PR |
| fork PR head | **empty** |

So it passes every test reachable before the workflow is on the default
branch, and fails for the only case this whole design exists for.
`workflow_run.pull_requests` is fork-blind in the same way, which is
precisely what makes the commit endpoint look like the alternative.

SR-1 now says to resolve by **head repository and branch**, to check the
head sha separately so the failure distinguishes "no such PR" from "the
PR moved on", and records the general rule:

> Anything keyed on a fork's commit is suspect; the PR number, the run
id, and the head branch are all base-repo facts and are not.

I kept the wrong version described rather than silently deleting it,
because the next implementer will otherwise reach for the same endpoint
for the same reason I did. `docs/ci-setup.md` gets the short form.

The SR-1 anchor is renamed to match; all cross-references updated and
verified to resolve.

206 tests pass, typecheck clean, no action-bundle drift (comments are
stripped).
@fengmk2 fengmk2 mentioned this pull request Aug 11, 2026
fengmk2 added a commit that referenced this pull request Aug 12, 2026
Release vite-plus v0.2.9: two new commands, and `vp run` now works in AI
agent sandboxes.

`vp toolchain` prints the tools, versions, and bundling relationships in
the active release. `vp hooks` manages the Vite+ dispatcher for Git
hooks, and removes the manual setup steps. `vp run` no longer fails in
the default Codex CLI and Claude Code sandboxes. Those sandboxes deny
Unix sockets and shared memory, which task IPC and file-access tracking
used. The rest of the release makes the install path more reliable. It
fixes npm 12 blocked install scripts, Yarn 2+ integrity pins, and
baseline Bun builds for older CPUs. It also fixes downloads that stopped
on slow connections.

### Highlights

- New `vp toolchain` command. It prints the tools, versions, and
bundling relationships in the active Vite+ release as a tree. The tree
shows vite-plus, core, vite, rolldown, oxc, oxc-resolver, and the
compiled Vite Task with its build time and revision. Give a tool name to
select part of the tree. Use `--json` for machine-readable output. Use
`--global` for the global release
([#2111](#2111)), by
@fengmk2
- New `vp hooks` command. It manages the Vite+ dispatcher for Git hooks.
`enable` installs or refreshes the dispatcher and sets `core.hooksPath`.
`disable` removes the dispatcher and keeps that preference, so `prepare`
and `vp config` do not install it again. `status` shows the current
state. Use `--hooks-dir` to set a custom directory. Vite+ keeps that
directory for later commands. Vite+ does not change project-owned hooks,
`staged` config, or `package.json` lifecycle scripts
([#2341](#2341)), by
@dennybiasiolli
- `vp run` now works in the default Codex CLI and Claude Code sandboxes.
Before this release, a cached task failed with `Failed to set up task
communication: Operation not permitted`. The task code never started.
Automatic file-access tracking also failed. Task caching and input
tracking now work in both default profiles. You do not need extra
sandbox permissions
([vite-task#569](voidzero-dev/vite-task#569),
[vite-task#576](voidzero-dev/vite-task#576)), by
@wan9chi

### Features

- `vp create` now shows the dependencies whose install scripts npm 12
blocked. Before this release, Vite+ left those dependencies unbuilt and
gave no message. To approve them, `vp create` runs `vp pm
approve-builds` and then `vp pm rebuild`
([#2336](#2336)), by
@fengmk2
- Large downloads no longer stop on slow connections. Node.js tarballs
and package-manager tarballs now use a 10 minute timeout. Before this
release, they used the shared 2 minute per-request limit. That limit
stopped healthy downloads below approximately 250 KB/s. It also made `vp
env install` and `vp migrate` impossible to complete. Set
`VP_DOWNLOAD_TIMEOUT` to a different number of seconds
([#2386](#2386)), by
@tarikermis
- Package-manager downloads now show a byte progress bar. The managed
Node.js runtime already showed one. A slow download no longer looks
stopped ([#2369](#2369)),
by @semimikoh
- You can now select JetBrains editors (IntelliJ, WebStorm, and similar)
in the editor setup question. Vite+ writes the Oxc plugin ID to
`.idea/externalDependencies.xml`. The docs now describe the gitignore
strategy for `.idea`
([#2204](#2204),
[#2378](#2378)), by
@KTrain5169
- `vp` now shows a warning when it falls back to the global CLI in a
project that has no project-local `vite-plus`. If the project declares
the dependency, `vp` tells you to run `vp install`. If the project does
not declare it, `vp` points to the migration guide. `vp migrate` and
commands outside a project stay silent
([#2362](#2362)), by
@liangmiQwQ
- Generated editor settings now disable nested Oxlint config resolution.
The Vite+ config stays authoritative
([#2331](#2331)), by
@liangmiQwQ

> [!NOTE]
> Upstream toolchain upgrade: vite `8.2.0` -> `8.2.1`, rolldown `1.2.2`
-> `1.2.3`, oxlint `1.76.0` -> `1.77.0`, oxfmt `0.61.0` -> `0.62.0`, and
the oxc npm packages and Rust crates `0.142.0` -> `0.143.0`. oxfmt and
oxlint both changed. The new versions can report problems in code that
passed before. If your CI runs `vp check`, run `vp fmt` after you
upgrade ([#2373](#2373)),
by @voidzero-guard[bot]

### Fixes & Enhancements

- Yarn 2+ pins from `corepack use` now verify against the extracted CLI
(`bin/yarn.js`), not the npm tarball. `vp install` no longer fails on a
cold cache. `vp run` no longer downloads Yarn again on every run
([#2227](#2227)), by
@leslieeilsel
- `vp dev` no longer crashes at startup with `ENOENT` when
`experimental.bundledDev` is enabled. The bundled dev client path now
points to the packaged layout
([#2384](#2384)), by
@lofcz
- `vp migrate` now rejects a workspace member as its target. Before this
release, it migrated the enclosing workspace instead. It now tells you
to run the command from the workspace root
([#2229](#2229)), by
@leslieeilsel
- `VP_NODE_VERSION=22` and other partial versions now resolve to an
exact Node.js release. This applies to shim-dispatched commands such as
`vp env exec node -v`
([#2411](#2411)), by
@jong-kyung
- Managed `bunx` shims now dispatch through `bun x`. `bunx <package>` no
longer starts a matching package script recursively. This applies to new
Bun installations
([#2151](#2151)), by
@liangmiQwQ
- Managed Bun now selects the baseline build on x64 CPUs that do not
have AVX2. Bun's standard builds require AVX2. Cached installations keep
their current files
([#2179](#2179)), by
@liangmiQwQ
- Generated Nushell env files now escape and normalize paths correctly.
A `VP_HOME` path that contains spaces or quotes now loads without an
error ([#2191](#2191)), by
@naokihaba
- `vite-plus/test/browser-*` type exports now add `.js` extensions to
relative shim specifiers. Those specifiers now resolve with `NodeNext`
module resolution
([#2360](#2360)), by
@eai04191
- Tool-backed help is now consistent with upstream. An exact `vp
<command> --help` shows the local themed help. A command with more
arguments (`vp test --help --coverage`, `vp test list --help`) goes to
the bundled tool. Deep help and subcommand help stay complete
([#2345](#2345)), by
@liangmiQwQ
- Vite Task diagnostics now print paths and working directories without
Rust debug formatting. Vite+ no longer prints quoted paths or escaped
Windows backslashes
([vite-task#534](voidzero-dev/vite-task#534)),
by @liangmiQwQ
- Broad workspace globs no longer find and run package scripts inside
`node_modules`
([vite-task#539](voidzero-dev/vite-task#539)),
by @jong-kyung

### Refactor

- Rename the internal Rust crates from `vite_*` to `vp_*`
([#2335](#2335)), by
@fengmk2
- Move the shared CLI helpers into `utils`
([#2347](#2347)), by
@jong-kyung
- Remove a redundant Vite reporter patch from core
([#2355](#2355)), by
@jong-kyung
- Remove the duplicate export transformers in tools
([#2358](#2358)), by
@jong-kyung
- Move the accent helpers into `crate::help`
([#2363](#2363)), by
@jong-kyung
- Sort installed Node.js versions with node-semver
([#2366](#2366)), by
@jong-kyung
- Remove the duplicate package-manager command resolution tests
([#2393](#2393)), by
@jong-kyung
- Share the Vite config file order between the CLI code paths
([#2409](#2409)), by
@jong-kyung
- Use the silent spinner again in the migrators
([#2408](#2408)), by
@jong-kyung

### Docs

- Document how to write custom Oxlint plugins in the lint guide
([#2381](#2381)), by
@connorshea
- Document manual installation in the migrate guide
([#2365](#2365)), by
@liangmiQwQ
- Add a View Prompt dialog for the setup prompt
([#2400](#2400)), by
@dennybiasiolli
- Correct the documented `overrides` behavior to match Vite+
([#1942](#1942)), by
@liangmiQwQ
- Explain `setup-vite-plus-action` version pinning in the CI guide
([#2359](#2359)), by
@fengmk2
- Correct the config and staged paths in the CLI `BUNDLING.md`
([#2334](#2334)), by
@dennybiasiolli
- Remove unused performance data from the docs
([#2392](#2392)), by
@jong-kyung
- Add the v0.2.8 release learnings to the release-manager skill
([#2333](#2333)), by
@fengmk2

### Chore

- Update the compiled Vite Task to `d05b1dc`
([#2339](#2339),
[#2403](#2403)), by
@wan9chi
- Update the Rust nightly toolchain to `2026-08-02`
([#2342](#2342)), by
@wan9chi
- Update the repository pnpm to v11
([#1997](#1997)), by
@renovate[bot]
- Remove the unused VitePress bundling from core
([#2332](#2332)), by
@jong-kyung
- Remove the unused tool subcommands
([#2324](#2324)), by
@jong-kyung
- Remove the unused `build:src` task
([#2396](#2396)), by
@jong-kyung
- Handle upstream help differences in the dependency upgrade workflow
([#2330](#2330)), by
@liangmiQwQ
- Publish preview builds from fork PRs with GitHub OIDC
([#2387](#2387)), by
@fengmk2
- Require the preview publish approval only for fork PRs
([#2404](#2404)), by
@fengmk2
- Correct the publishing workflow after its first real runs
([#2397](#2397)), by
@fengmk2
- Deploy the production docs on release, and deploy a main preview on
push ([#2389](#2389)), by
@fengmk2
- Check the format of docs PRs with the `vp` built from the checkout
([#2388](#2388)), by
@fengmk2
- Run the e2e migrate test at the clone root
([#2410](#2410)), by
@fengmk2
- Pin the `dev_engines_runtime_pnpm11` snapshot to the seeded default
Node version
([#2390](#2390)), by
@fengmk2
- Use `pnpm test` again as the full gate
([#2376](#2376)), by
@jong-kyung
- Remove the global compile checks that did nothing
([#2394](#2394)), by
@jong-kyung

### Bundled Versions

| Tool | Version | Source |
| --------------- | ---------- |
----------------------------------------------------------------------------
|
| vite | `8.2.1` |
[`4216158`](vitejs/vite@4216158)
|
| rolldown | `1.2.3` |
[`52dbd19`](rolldown/rolldown@52dbd19)
|
| tsdown | `0.22.14` | [npm](https://npmx.dev/package/tsdown/v/0.22.14)
|
| vitest | `4.1.10` | [npm](https://npmx.dev/package/vitest/v/4.1.10) |
| oxlint | `1.77.0` | [npm](https://npmx.dev/package/oxlint/v/1.77.0) |
| oxlint-tsgolint | `7.0.2001` |
[npm](https://npmx.dev/package/oxlint-tsgolint/v/7.0.2001) |
| oxfmt | `0.62.0` | [npm](https://npmx.dev/package/oxfmt/v/0.62.0) |

### Upgrade

```bash
vp upgrade
```

### New Contributors

@eai04191, @KTrain5169, @lofcz, @tarikermis, @leslieeilsel

**Full Changelog**:
v0.2.8...v0.2.9

---

Merging this PR will trigger the release workflow.

---------

Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com>
Co-authored-by: MK <fengmk2@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants