Repository navigation
fix(docker): bump Bun image to 1.4.0 with Turbopack and port the node image's build memory guards - #11719
Conversation
df2ee1e to
f8d7503
Compare
|
This looks right and matches the fix we were preparing on our side — the guards port into Dockerfile.bun plus the budget test covering both images is the correct approach. One suggestion before merge: The Bun 1.4.0 + Turbopack bump is a good addition — just worth keeping in mind it makes this the first real Turbopack-on-Bun build, so if the OOM persists, a |
f8d7503 to
e55b6b6
Compare
|
Thanks — adopted. Both images now default OMNIROUTE_BUILD_WORKERS=2 (1 page-data worker) against the measured ~4.5 GB per-process RSS from #7518/#11663: 2 processes × 4.5 GB ≈ 9 GB fits the 12,288 MB (75%) budget, where =3 (2 workers, 3 processes ≈ 13.5 GB) does not. The budget test now uses the measured figure for both Dockerfile and Dockerfile.bun and pins the =2 default (proven red at =3), so a future bump must re-do the arithmetic. #11663 landed on release/v3.8.51 after this PR was cut; the node Dockerfile here is aligned to =2 as well to keep the shared test honest on main. Good call on the control run: OMNIROUTE_USE_TURBOPACK=0 is now a --build-arg escape hatch on the Bun image, so an isolation run is one flag away if the OOM persists. |
57c0f8d to
b8a4ddf
Compare
… image's build memory guards - Bump Bun builder and runtime base images to oven/bun:1.4.0-slim - Support Turbopack build path with environment-driven bundler flag resolution - Port build worker and memory guards to Dockerfile.bun to prevent build OOM - Update alibaba free-tier allowlist validUntil date and protocol clients E2E assertions
b8a4ddf to
c5495e7
Compare
…heaper-inference#11877) * fix(ci): publish npm from a hosted runner so provenance is accepted The v3.8.50 staged publish failed at the upload: npm error code E422 npm error 422 Unprocessable Entity - POST https://registry.npmjs.org/-/stage/package/omniroute Error verifying sigstore provenance bundle: Unsupported GitHub Actions runner environment: "self-hosted". Only "github-hosted" runners are supported when publishing with provenance. 3.8.49 published fine on 2026-07-30 because it predates USE_VPS_RUNNER being turned on (2026-08-02). 3.8.50 is the first release since, so the incompatibility had been latent for four weeks with nothing to surface it. Neither obvious fix works on its own: - dropping --provenance would regress supply-chain posture; 3.8.49 carries a SLSA attestation and 3.8.50 must not ship without one; - moving the whole job to a hosted runner reintroduces the failure that made it self-hosted in the first place — 16 GB is not enough for build:cli's next-build fallback (documented on the job's runs-on). So the work is split by what each runner is actually needed for. The self-hosted job keeps every heavy gate — build, artifact validation, boot-smoke, the clean-install/upgrade proof — and then packs the tarball it just proved and hands it over. A new `stage-npm` job on ubuntu-latest downloads those exact bytes and performs the upload, which needs no memory at all. `npm pack --ignore-scripts` on the producing side and `--ignore-scripts` on the publishing side both matter: prepublishOnly is `build:cli-api && build:cli && check:pack-artifact`, and the job already runs all three as explicit steps (the dist/ prune is logged twice today — once at Build CLI bundle, once redundantly inside npm stage publish). Re-running them on the small hosted runner would rebuild bytes that were already built, validated and boot-smoked. The DIRECT emergency fallback moved too — it published with --provenance and would have hit the identical 422. * chore(quality): re-baseline zizmor for the new hosted publish job The `stage-npm` job adds 2 zizmor findings (192 -> 194), both of the same deliberate @vn convention every workflow in this repo already follows: unpinned-uses on actions/download-artifact@v8 and actions/setup-node@v7, plus the cache-poisoning that setup-node@v7 already raises on the two other jobs in this very file. SHA-pinning only the new job would break the convention. No new class: zero template-injection, artipacked, dangerous-triggers or excessive-permissions. The job declares contents:read + id-token:write, which is the minimum npm provenance needs.
…alog (cheaper-inference#11867) `Unit Tests (1/8)` went red on 2026-08-28 across every PR and on main, with nothing changed — the clock had moved past the shipped catalog's expiry: config/alibaba-free-tier-allowlist.json → "validUntil": "2026-08-27" isAlibabaFreeTierAllowlistPackValid() compares that against Date.now(), so from 28/08 loadAlibabaFreeTierAllowlistPack() returns null and the old assert.ok(pack) could never pass again. Refreshing the date would only reschedule the same break. Production was never affected: resolveActiveAllowlistPack() falls back to the embedded list when a pack expires, which is the intended design. The defect was the test asserting the shipped catalog is currently fresh — a data property, not a behavioral contract. The test now writes its own packs to a temp dir with dates it controls, and pins both halves of the contract: - inside the validity window, the pack REPLACES the embedded list (anchored on a model that exists nowhere else, so loading alone cannot satisfy it); - once expired, the pack is ignored and the embedded list serves. That second path is what production has been running since 27/08 and had no coverage at all, which is why the expiry surfaced as a red test rather than as understood behavior. A third case pins the comparison against an injected instant, including the no-expiry pack that never goes stale. Whether the curated free-tier catalog still matches reality — and so deserves a freshly dated pack — is a data question left to the operator in cheaper-inference#11866. Closes cheaper-inference#11866
…per-inference#11891) config/alibaba-free-tier-allowlist.json carried "validUntil": "2026-08-27". On the 28th the loader started rejecting it — correctly, that is the design — and a test that asserted "the shipped pack loads" turned every PR and main red with no commit involved (cheaper-inference#11866). A time bomb: the one class of defect a diff review can never catch, because there is no diff. scripts/check/lib/configExpiry.mjs walks config/**/*.json for validUntil / validTo / expiresAt / expiry / expires (and snake_case forms), parses the dates, and classifies each as expired / expiring (< 7 days) / ok / unparseable. The repo-wide test fails on expired or expiring packs unless the file is in a small allowlist keyed to the issue that owns the renewal — and fails the OTHER way when an allowlisted pack is no longer expiring, so entries cannot go stale. A positive anchor requires at least one dated pack to be found, so a renamed key cannot silently turn the suite into a no-op. The Alibaba pack is allowlisted against cheaper-inference#11866: whether the curated free-tier list still matches reality is an operator data decision, not a test fix. Removing that entry makes the suite fail as intended (verified).
…ise (cheaper-inference#11893) * chore(ops): make the runner janitor act on what it can prove, not advise The .113 janitor already knew the rules and had been shouting them into a log nobody reads: on 2026-08-28 12:00Z it reported "10 listeners > ceiling 8" and "disk 85%" — for hours — while 6.7 GB of dead-run leftovers sat on the 12 GB tmpfs (RAM) because its patterns matched neither e2e-build.tar.gz nor next-build/, its 24 h fuse is a day too long for memory, and its _work/_temp base (/home/*/actions-runner*) does not exist on this box (runners live under /opt). Measured while draining the v3.8.50 npm publish (postmortem, Parte III). What changes: - idle is PROVEN before removal, with ONE lsof snapshot filtered to the swept bases (lsof +D per path walked whole trees and took minutes; 460 candidates grepping a re-printed 83k-line string was the other half). 20 s on the box. Without lsof the janitor removes nothing and says why (exit 1). - tmpfs leftovers go after 3 h, disk _work/_temp after 24 h; both overridable. Patterns gain next-build* and e2e-build.tar.gz; /opt/actions-runner* is swept. - zombie builds: a next-build older than 75 min has no job (a real Build step is ~26 min). On 2026-08-27 one ran 70 min after GitHub had declared its job lost, holding 3.6 GB. KillMode=mixed on the units covers systemctl stop/restart; this covers the lost-connection path. - prunes 48 h-old checkouts under _work of runners whose unit is STOPPED — an active runner is never touched. - alerts on memory PSI (full/avg60) and reports the listener ceiling with an omniroute/other breakdown (the box also hosts OmniHeuris and OmniMind). Enforcing the ceiling stays an operator decision (label split), not cron's. - --dry-run prints exactly what it would do and touches nothing; unknown arguments are rejected. Dry-run on the real box: 460 stale omniroute-* test fixtures (930 MB of RAM) it would reclaim, 0 busy, 0 false "removed" lines, 20 s. The unit suite drives the script against a fixture tree with every base redirected; the sweep branch runs where lsof exists (hosted CI images) and the without-lsof contract everywhere. docs/ops/RUNNER_BOX.md reconciled to the measured box: 31 GB (it said 16), ten listeners, the 14 GB next-build ceiling, the KillMode drop-in, and the rule that nothing is cleaned by hand while a runner is busy. * docs(ops): restore the frontmatter fumadocs requires on RUNNER_BOX.md Rewriting the page whole dropped its `title:` frontmatter, and docs/ is compiled into the Next build by fumadocs-mdx — so Build, Fast Production Build and dast-smoke all died with "[MDX] invalid frontmatter in docs/ops/RUNNER_BOX.md". Same block as before, verbatim.
…d runner (cheaper-inference#11895) npm rejects provenance-signed uploads from self-hosted runners: 422 Unprocessable Entity - Error verifying sigstore provenance bundle: Unsupported GitHub Actions runner environment: "self-hosted". Only "github-hosted" runners are supported when publishing with provenance. v3.8.50 learned that at minute 76 of its 10th publish attempt, after the tag, the GitHub Release and the Docker images were already out. USE_VPS_RUNNER had routed the job to the .113 pool on 2026-08-02; no release ran between 07-30 and 08-28, so the pairing sat latent for four weeks. It is pure text — a job whose runs-on resolves to self-hosted and a step whose run contains --provenance — so the workflow lint now checks it as a hard rule: reported in plain mode, blocking under --strict and --ratchet (the CI mode), emitted as provenanceRunnerFindings=<n> next to the other counters. Against origin/main the rule finds the two real offenders (the staged upload AND the DIRECT emergency fallback in npm-publish.yml); against the cheaper-inference#11877 split it finds none. --provenance-file is deliberately not matched (different flag, pre-built bundle) and an opaque runs-on expression with no literal self-hosted is classified unknown and skipped — the check never guesses. The unit suite's last case walks the real .github/workflows and asserts zero findings, so it is red on main until cheaper-inference#11877 lands and green after; that is the regression guard working, not a flake.
…per-inference#11901) The .113 box has 31 GB and a single next-build peaks at 14–16 GB RSS: one build fits with room, two sit at the edge, three take the box down. On 2026-08-28 13:50Z the kernel OOM-killed main's next-build (15.7 GB) while a PR build ran beside it — five Build jobs had been queued by a burst of PRs — and the publish lost its artefact, which sends it into the 40-minute rebuild that OOMs on its own (attempt 5 of this release). Job-level concurrency on `build`, two lanes: heavy-build-main pushes to main — never contended, never behind PR traffic heavy-build-pr pull requests — serialize among themselves cancel-in-progress stays false: a running build is never killed by a newer one. GitHub's own rule for a group is one running + one pending, older pendings cancelled — so under a burst the third PR build shows "cancelled" and needs a re-run. That is the trade-off, stated: a cancelled PR check is re-runnable; a dead main build costs a release. The proper fix remains a label split (omni-build on two runners, omni-light on the rest) so the queue lives on the runner side without cancellations — an operator decision recorded in docs/ops/RUNNER_BOX.md.
…pfs (cheaper-inference#11896) * fix(ci): keep the next-build artefact on disk, not on the runner's tmpfs On the .113 pool /tmp is a 12 GB tmpfs — it is RAM. The 1.3 GB next-build artefact was parked there four times over: the Build job tar'd it to /tmp/e2e-build.tar.gz (6 min), three E2E jobs downloaded it to /tmp/ and extracted from there, and npm-publish.yml pulled it with gh run download into /tmp/next-build. Measured on the v3.8.50 publish runs: that download step took 27 min (9th attempt) and 32 min (10th) — 42% of a 76-minute job — while the very same bytes upload from disk in 2 min and the box pulls from GitHub at 7.3 MB/s (1.3 GB ≈ 3 min). Network was never the bottleneck; a tmpfs at 75% under memory pressure was. Every site now uses $RUNNER_TEMP / ${{ runner.temp }}: per-runner, on disk (_work/_temp under the runner dir on the pool, /home/runner/work/_temp on hosted images), and cleaned by the runner between jobs. It also removes a latent race: e2e-build.tar.gz is a FIXED name under a /tmp shared by every runner on the box, so two E2E shards on different runners could overwrite each other's download mid-extraction. RUNNER_TEMP is per runner. The supply-chain guard in tests/unit/npm-publish-artifact-provenance.test.ts pins the candidate-run selection and the --name, not the directory; it stays green. check:workflows --ratchet: zizmor unchanged at the baseline. * fix(ci): download the next-build artefact to a workspace-relative dir (pwsh has no $RUNNER_TEMP) The Electron Package Smoke matrix runs on windows-latest, whose default shell is pwsh: $RUNNER_TEMP is empty there (pwsh spells it $env:RUNNER_TEMP), so the first cut's tar -xzf "$RUNNER_TEMP/e2e-build.tar.gz" tried to open '/e2e-build.tar.gz' and failed. A path relative to the workspace works in bash and pwsh alike, and hosted workspaces are ephemeral. The producer (Build, Linux, bash) and npm-publish keep $RUNNER_TEMP.
…heaper-inference#11932) The .113 box (31 GB) holds one next-build (14–16 GB RSS) comfortably and two at the edge; on 2026-08-28 the kernel killed main's build twice while PR builds ran beside it. Labels are the runner-side cap: only omniroute-113-5 and omniroute-113-6 carry omni-build (added through the runners API, no re-registration), and every job that runs a next build — ci.yml build, npm-publish.yml publish, both nightly-release-green validations — now asks for that label. A third heavy job queues on GitHub instead of racing for memory. The six other runners keep omni-release and no longer take builds. Pairs with the heavy-build-* concurrency lanes (cheaper-inference#11901); documented in docs/ops/RUNNER_BOX.md.
…cheaper-inference#11931) * feat(ci): publish to npm through Trusted Publishing (OIDC) by default npm rejects provenance from self-hosted runners and is retiring tokens that bypass 2FA; v3.8.49 answered with staged publishing (WS1.3) so a leaked token could never publish alone — at the price of a manual `npm stage approve` per release. Trusted Publishing gives the same guarantee with no token at all: the github-hosted stage-npm job exchanges GitHub's id-token for a credential scoped to that run, provenance included, and the flow is automatic again as it was up to v3.8.48. publish_mode gains `auto` (the default, also the path for the release event); `staged` now runs only when asked for; `direct` stays as the emergency token fallback. Until the owner registers the Trusted Publisher on npmjs.com (diegosouzapw/OmniRoute, workflow npm-publish.yml) the automatic step fails with ENEEDAUTH and either other mode can be dispatched — documented in docs/ops/RELEASE_CHECKLIST.md. * docs(release): date the checklist for the Trusted Publishing change and drop the env-var claim check-deprecated-versions flags a touched doc whose header still says 2026-06-28 / v3.8.40; the fabricated-docs gate read the backticked NPM_TOKEN as an environment variable the code never reads (it is a repository secret).
…ote-only replace (cheaper-inference#11942) CodeQL js/incomplete-sanitization (alert cheaper-inference#888 on cheaper-inference#11929): the hand-rolled replace only escaped double quotes, so a backslash in the fixture would have produced a malformed YAML scalar. JSON.stringify covers every escape the double-quoted YAML scalar needs. Test-only change (7/7 pass).
…ead to the npm leg (cheaper-inference#11973) v3.8.50 shipped with zero desktop assets. The tag push did trigger electron-release.yml (run 33005490476) but GitHub refused the run at startup: Error calling workflow 'npm-publish.yml@5458026'. The nested job 'publish' is requesting 'actions: read', but is only allowed 'actions: none'. npm-publish.yml's `publish` job gained `actions: read` (it downloads the next-build artefact) and the caller job here never widened its grant — a reusable workflow may not request more than its caller allows, and the refusal is a startup failure of the WHOLE run, so the `release` job that attaches the installers, the source archives and the SBOM never ran either. Nothing about it is visible through the API (no jobs, no check-runs); only the run page shows the annotation. - publish-npm: `actions: read` added, with the rule written down (keep the block a superset of every job in npm-publish.yml). - workflow_dispatch: new boolean input `publish_npm` (default true) and the npm leg is gated on it, so re-attaching assets to a release whose package already shipped does not try to publish the same version twice. - web-build / build / release checkouts pin `ref: needs.validate.outputs.version`: a dispatch builds the tag it names, not the dispatching branch (a tag push resolves to the same commit, so nothing changes on the normal path). actionlint clean; electron-release-desktop-channel-8949, electron-release-efficiency, build-next-isolated-windows-home-2402, electron-release-latest-yml.repro and check-workflows suites pass. Next step: dispatch on main with version=v3.8.50 and publish_npm=false to attach the missing assets.
…ob and the main run (main twin of cheaper-inference#11972) (cheaper-inference#11978) Same change as cheaper-inference#11972 on release/v3.8.51: the Coverage job had timeout-minutes: 20, the c8 merge across 8 shards takes ~10 min and the informational Codecov upload hung for the rest of the budget on two consecutive main runs (33207760653, 33215115341), ending the job cancelled and turning the run's conclusion cancelled with every blocking job green. Codecov step: 5-minute ceiling + continue-on-error; job: 30 min.
…rom a repaired ref (cheaper-inference#11982) * fix(release): resync the electron lockfile and let a dispatch build from a repaired ref The v3.8.50 desktop re-dispatch (run 33238093090) lost its Linux leg at `npm ci` in electron/: "Missing: electron-builder-squirrel-windows@26.15.3 from lock file" plus its 12 transitive entries — the optional Windows-installer subtree of electron-builder had been dropped when the lock was last regenerated, and no CI ran the desktop legs between then and the tag (v3.8.49 never ran them; v3.8.50 died at startup, cheaper-inference#11973). `npm install --package-lock-only` restores the 13 entries; a clean `npm ci --ignore-scripts` on the result adds 284 packages with no complaint. The tag itself carries the broken lock, and the workflow now checks out the tag on dispatch (cheaper-inference#11973), so a dispatch input `build_ref` (default: the version tag) lets the operator name the repaired line — the v3.8.50 assets will be rebuilt from main, which is 3.8.50 plus its post-release fixes. Push-triggered runs are unaffected. actionlint clean; electron-release-desktop-channel-8949, electron-release-efficiency, electron-release-latest-yml.repro and check-workflows suites pass. * fix(release): do not regenerate release notes on a re-attach dispatch `generate_release_notes: true` on an existing release APPENDS GitHub's auto-generated "What's Changed" block to the curated body — the v3.8.50 re-dispatch (run 33238093090) added 1,416 chars to the 121 KB notes. Only the tag push should generate notes.
…shes too (cheaper-inference#12020) The step was gated on github.event_name == 'release'. v3.8.50's package shipped through a workflow_dispatch (the staged publish, 11 attempts) and the step was skipped, so the GitHub Release carried no SBOM — it was attached by hand from the run's sbom-npm artifact (5.0 MB, 1,886 components). Now it attaches on release or workflow_dispatch whenever a release for the published tag exists, and says so when it does not (the workflow artifact remains the durable copy either way). actionlint and prettier clean; npm-publish-artifact-provenance and check-workflows-provenance-runner suites pass.
… is dispatched on (cheaper-inference#12032) Twin of cheaper-inference#12022 on main: CodeQL flagged the same input-controlled checkout + npm cache pattern (cache-poisoning/poisonable-step) on main since it's the default branch. Checkouts go back to github.ref; dispatch still works via --ref (documented in the workflow's own on: contract). Also fixes the packaged-app smoke: it now waits on /api/monitoring/health (which touches the DB) instead of /login (which doesn't), so the smoke can actually distinguish "native driver selected" from "database never opened." electron-smoke-script.test.ts 9/9 (2 new cases).
…lose base-red issues, guard Scorecard on the default branch (main twin) (cheaper-inference#12086) * fix(ci): accept CVE-2025-68121 in the prebuilt tls-client .so, auto-close base-red issues, guard Scorecard on the default branch - .trivyignore: CVE-2025-68121 (Go stdlib crypto/tls inside bogdanfinn/tls-client v1.15.1, built with go 1.24.1) with justification, expiry and tracker cheaper-inference#12084. No upstream rebuild exists; the blocking Trivy gate now also names the ignore file explicitly. - nightly-release-green: close the "not green" issue when the validation passes again (the workflow only ever opened/commented it, so stale issues outlived the fix and stamped new PRs as base-red inherited). - scorecard: the action only accepts the DEFAULT branch (the active release branch, not main) - guard the job on it so pushes to main stop failing. Refs cheaper-inference#12084 (cherry picked from commit 8adf34b) * fix(release): never let the tag-push Create Release append auto notes to the curated body Twin of the release/v3.8.51 commit (see cheaper-inference#12085). Refs cheaper-inference#12084
…per-inference#11719 (unrelated to Docker/Bun fix)
…leware redirect (cheaper-inference#13140) * fix(release): let the Electron workflow start again — grant actions:read to the npm leg (cheaper-inference#11973) v3.8.50 shipped with zero desktop assets. The tag push did trigger electron-release.yml (run 33005490476) but GitHub refused the run at startup: Error calling workflow 'npm-publish.yml@2b80128'. The nested job 'publish' is requesting 'actions: read', but is only allowed 'actions: none'. npm-publish.yml's `publish` job gained `actions: read` (it downloads the next-build artefact) and the caller job here never widened its grant — a reusable workflow may not request more than its caller allows, and the refusal is a startup failure of the WHOLE run, so the `release` job that attaches the installers, the source archives and the SBOM never ran either. Nothing about it is visible through the API (no jobs, no check-runs); only the run page shows the annotation. - publish-npm: `actions: read` added, with the rule written down (keep the block a superset of every job in npm-publish.yml). - workflow_dispatch: new boolean input `publish_npm` (default true) and the npm leg is gated on it, so re-attaching assets to a release whose package already shipped does not try to publish the same version twice. - web-build / build / release checkouts pin `ref: needs.validate.outputs.version`: a dispatch builds the tag it names, not the dispatching branch (a tag push resolves to the same commit, so nothing changes on the normal path). actionlint clean; electron-release-desktop-channel-8949, electron-release-efficiency, build-next-isolated-windows-home-2402, electron-release-latest-yml.repro and check-workflows suites pass. Next step: dispatch on main with version=v3.8.50 and publish_npm=false to attach the missing assets. * fix(ci): stop a stalled Codecov upload from cancelling the Coverage job and the main run (main twin of cheaper-inference#11972) (cheaper-inference#11978) Same change as cheaper-inference#11972 on release/v3.8.51: the Coverage job had timeout-minutes: 20, the c8 merge across 8 shards takes ~10 min and the informational Codecov upload hung for the rest of the budget on two consecutive main runs (33207760653, 33215115341), ending the job cancelled and turning the run's conclusion cancelled with every blocking job green. Codecov step: 5-minute ceiling + continue-on-error; job: 30 min. * fix(release): resync the electron lockfile and let a dispatch build from a repaired ref (cheaper-inference#11982) * fix(release): resync the electron lockfile and let a dispatch build from a repaired ref The v3.8.50 desktop re-dispatch (run 33238093090) lost its Linux leg at `npm ci` in electron/: "Missing: electron-builder-squirrel-windows@26.15.3 from lock file" plus its 12 transitive entries — the optional Windows-installer subtree of electron-builder had been dropped when the lock was last regenerated, and no CI ran the desktop legs between then and the tag (v3.8.49 never ran them; v3.8.50 died at startup, cheaper-inference#11973). `npm install --package-lock-only` restores the 13 entries; a clean `npm ci --ignore-scripts` on the result adds 284 packages with no complaint. The tag itself carries the broken lock, and the workflow now checks out the tag on dispatch (cheaper-inference#11973), so a dispatch input `build_ref` (default: the version tag) lets the operator name the repaired line — the v3.8.50 assets will be rebuilt from main, which is 3.8.50 plus its post-release fixes. Push-triggered runs are unaffected. actionlint clean; electron-release-desktop-channel-8949, electron-release-efficiency, electron-release-latest-yml.repro and check-workflows suites pass. * fix(release): do not regenerate release notes on a re-attach dispatch `generate_release_notes: true` on an existing release APPENDS GitHub's auto-generated "What's Changed" block to the curated body — the v3.8.50 re-dispatch (run 33238093090) added 1,416 chars to the 121 KB notes. Only the tag push should generate notes. * fix(release): attach the SBOM to the GitHub Release on dispatch publishes too (cheaper-inference#12020) The step was gated on github.event_name == 'release'. v3.8.50's package shipped through a workflow_dispatch (the staged publish, 11 attempts) and the step was skipped, so the GitHub Release carried no SBOM — it was attached by hand from the run's sbom-npm artifact (5.0 MB, 1,886 components). Now it attaches on release or workflow_dispatch whenever a release for the published tag exists, and says so when it does not (the workflow artifact remains the durable copy either way). actionlint and prettier clean; npm-publish-artifact-provenance and check-workflows-provenance-runner suites pass. * fix(release): drop the build_ref input — a dispatch builds the ref it is dispatched on (cheaper-inference#12032) Twin of cheaper-inference#12022 on main: CodeQL flagged the same input-controlled checkout + npm cache pattern (cache-poisoning/poisonable-step) on main since it's the default branch. Checkouts go back to github.ref; dispatch still works via --ref (documented in the workflow's own on: contract). Also fixes the packaged-app smoke: it now waits on /api/monitoring/health (which touches the DB) instead of /login (which doesn't), so the smoke can actually distinguish "native driver selected" from "database never opened." electron-smoke-script.test.ts 9/9 (2 new cases). * fix(ci): accept CVE-2025-68121 in the prebuilt tls-client .so, auto-close base-red issues, guard Scorecard on the default branch (main twin) (cheaper-inference#12086) * fix(ci): accept CVE-2025-68121 in the prebuilt tls-client .so, auto-close base-red issues, guard Scorecard on the default branch - .trivyignore: CVE-2025-68121 (Go stdlib crypto/tls inside bogdanfinn/tls-client v1.15.1, built with go 1.24.1) with justification, expiry and tracker cheaper-inference#12084. No upstream rebuild exists; the blocking Trivy gate now also names the ignore file explicitly. - nightly-release-green: close the "not green" issue when the validation passes again (the workflow only ever opened/commented it, so stale issues outlived the fix and stamped new PRs as base-red inherited). - scorecard: the action only accepts the DEFAULT branch (the active release branch, not main) - guard the job on it so pushes to main stop failing. Refs cheaper-inference#12084 (cherry picked from commit d7097b02eeb3ec413a54c4e43a6538bf7ae40090) * fix(release): never let the tag-push Create Release append auto notes to the curated body Twin of the release/v3.8.51 commit (see cheaper-inference#12085). Refs cheaper-inference#12084 * fix(docker): bump Bun image to 1.4.0 with Turbopack and port the node image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math. * test(infra): retry recursive temp-dir removal on main (main twin of cheaper-inference#11968) (cheaper-inference#12246) * test(infra): retry recursive temp-dir removal on main (main twin of cheaper-inference#11968) `main` has been red since 530d9be779 on the vitest and integration gates: ✖ tests/unit/autoCombo/provider-family-combos.test.ts > auto/<family> ✖ chat pipeline applies Codex OAuth fingerprint and priority tier inside combos Both call resetStorage() from beforeEach, which does an fs.rmSync(TEST_DATA_DIR, {recursive: true, force: true}) with no retry, and intermittently loses the race with a not-yet-released SQLite handle (ENOTEMPTY). release/v3.8.51 fixed this in cheaper-inference#11968 with a mechanical codemod adding maxRetries/retryDelay to every recursive rm/rmSync/rmdirSync under tests/, but that PR landed only on the release branch. Because main only receives work at the release squash, it stayed broken for the whole cycle — and repo-wide gates then turn every open PR into main red on checks unrelated to their diff. This is the --base main twin: re-runs the same codemod that already shipped on the release branch (scripts/ad-hoc/codemod-rm-maxretries.mjs), so the two branches converge on identical test-teardown semantics. Test-only; no product logic is touched. The remaining three failures reported on cheaper-inference#12133 (unit full suite exceeding its 4800s ceiling, package-artifact exceeding 1200s, and the boot-smoke that is skipped as a consequence) are runner-contention timeouts, not code defects — validate-release-green.mjs runs those heavy gates concurrently on one shared hosted runner. There is no fix to port for those. * chore(scripts): carry the rm-maxretries codemod onto main alongside its output The codemod that generated the previous commit lives in the repo on release/v3.8.51 (added by cheaper-inference#11968) but was never on main. Bringing it over keeps the tool next to the change it produced, so the transformation stays reproducible and auditable from either branch. * fix(ci): port the release-green ESLint gate fix to main (base-red cheaper-inference#12363) (cheaper-inference#12618) Porta para `main` o fix do gate de ESLint que só havia entrado na branch de release — o padrão de PR-companheiro que `_shared/merge-gates.md` §8 prescreve. As 12 falhas de CI foram discriminadas como o **outro** base-red do main, não deste diff. Todas descendem de um único ponto: `Package Artifact` falha e os 9 shards de E2E mais os 2 Electron Package Smoke consomem esse artefato. A própria issue cheaper-inference#12363 lista os dois separadamente: - `❌ ESLint: could not parse eslint json` — que é justamente o que este PR conserta; - `❌ Package artifact (npm pack policy): gate exceeded its 1200s ceiling` — a raiz da cascata. O PR toca apenas `scripts/quality/validate-release-green.mjs` e seu teste, então não tem caminho para afetar o build do pacote. Teste portado primeiro e falhando no script atual do main (TDD). * fix(authz): preserve zed-hosted native-app callback through root middleware redirect The root middleware intercepts `pathname === "/"` and redirects to `/dashboard` using `new URL(basePath+"/dashboard", url)`, which drops the query string entirely. Zed's native-app sign-in always redirects the browser to the loopback root — `http://127.0.0.1:<port>/?user_id=...&access_token=...` — ignoring any path. When the dashboard's own loopback port is reused as `native_app_port` (see `src/lib/oauth/providers/zed-hosted.ts`'s `resolveDashboardLoopbackPort`), that redirect lands on `/` of the running OmniRoute instance. The root page (`src/app/page.tsx`) was already written to forward `user_id`+`access_token` to `/callback`, but this middleware runs first and silently discards the payload — making page.tsx's forward dead code and breaking the entire zed-hosted sign-in flow. Fix: detect `user_id` + `access_token` in `searchParams` and, when present, redirect to `/callback${search}` (preserving the query string) instead of `/dashboard`. Regular root visits (no native callback params) continue to redirect to `/dashboard` unchanged. This approach mirrors what `src/app/page.tsx` already does and is provider-agnostic: any future provider whose native loopback callback lands on `/` with `user_id`+`access_token` params benefits automatically. * test(authz): cover zed-hosted native-app callback root redirect (cheaper-inference#13140) Adds automated coverage for the new pathname === "/" branch: with user_id+access_token both present the redirect now forwards to /callback preserving the query string; with only one of the two present, behavior is unchanged (redirect to /dashboard). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: Rouzbeh† <78313022+rqzbeh@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…lockstep comments The five changelog.d fragments for cheaper-inference#11719/cheaper-inference#11973/cheaper-inference#11978/cheaper-inference#11982/cheaper-inference#12020 were already folded into CHANGELOG.md and deleted on the release branch; re-adding them would duplicate those entries. Compacting the buildUrlForBody doc comments brings open-sse/executors/base.ts's ceiling down from 1772 to 1760.
… the rewritten body model (#12826) Validated on the 2026-09-28 release-drain board. Maintainer rework on top of your commits: merged the current release/v3.8.51 tip, resolving the openai-to-gemini.ts conflict so the tip's output-cap-aware default budget and your explicit-thinkingLevel rule combine (an explicit level still omits the numeric budget); dropped five changelog.d fragments the branch had re-added for already-released PRs (#11719/#11973/#11978/#11982/#12020, which would have duplicated CHANGELOG entries); compacted the buildUrlForBody comments so the base.ts ceiling drops from 1772 to 1760. The 3 new test files fail on the old code -> 12/12 with the fix, plus the tip's gemini thinking-budget suites and the executor-* sample green; typecheck:core, check:open-sse-typecheck, eslint and changelog-integrity clean. Thank you @adivekar-utexas!
Brings the 12 main-only commits into the frozen release branch so the release PR (#11442) is no longer CONFLICTING. Most are main twins of fixes the release branch already carries in a newer shape; resolved by proving the release side contains them: - #12246 temp-dir retry: release uses cleanupTempDataDir / maxRetries (kept ours). - #11719 Bun image: release is already on oven/bun 1.4.2 (kept ours). - #12086 CVE-2025-68121 .trivyignore: dropped on release by #12429 (wreq-js). - #13865 npm 11 / electron overrides: release pins are newer (kept ours); the optional transformers webpack-ignore change merged cleanly. - streamTiming clock injection: release moved to a monotonic clock (kept ours). Real main-only fix ported: #13072 hoistLeadingTextSystemMessages, added to the release's claudeSystemRole.ts (the call site in chatCore.ts merged cleanly).
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
… image's build memory guards (cheaper-inference#11719) Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
fix(docker): bump Bun image to 1.4.0 with Turbopack and port the node image's build memory guards
Summary
Fixes #11709 — "Publish to Docker Hub" has been red on every push to
mainsince the-bunimage targets landed (#11039/#11168): the Bun builder stage (bun run buildinDockerfile.bun) dies withResourceExhausted: ... cannot allocate memoryon the 16 GB GitHub-hosted runners (a Next.js build worker is SIGKILLed mid-compile) on bothlinux/amd64andlinux/arm64. Because the multi-arch manifest step is never reached, no release image can be published —latestis still v3.8.49.Root cause
Two compounding problems, both unique to the Bun image path:
Dockerfile.bunbases onoven/bun:1.3.14-slim(2026-05-13). Beside missing the Node-compat work that landed in Bun 1.4.0 (2026-08-20), that release cannot run Turbopack, so the-bunbuild is stuck on the webpack production pass — the memory-hungry path — while the node image builds with Turbopack by default. (Bun 1.4.0 also fixes a dependency-resolution bug: under 1.3.14,bun install --include=optionalfailed to resolveplaywright@1.62.1/postcss@^8.5.18with bogus "No version matching" errors; 1.4.0 installs the full 2151-package tree cleanly.)scripts/build/build-next-isolated.mjsforce-forces--webpackfor anyprocess.versions.bunrun (historical V8-worker-binding workaround), andDockerfile.bunsets none of the knobs the nodeDockerfilecarries (fix: use Node 22 LTS + raise build heap to 6144 MB -- Node 24 crashes… [defer to 3.8.51] #10060/fix(docker): size the Next build worker pool for a 16 GB runner #11419): noOMNIROUTE_BUILD_WORKERS/CIRCLE_NODE_TOTAL(Next falls back toos.cpus()-1= 3 page-data workers on the 4-vCPU runners) and noOMNIROUTE_BUILD_MEMORY_MB/NODE_OPTIONS(the build script applies its 8 GB per-process heap default). 4+ V8 processes at multi-GB each exceed the 16 GB runner; the cgroup OOM killer SIGKILLs a worker and buildkit surfacescannot allocate memory.Fix
oven/bun:1.3.14-slim→oven/bun:1.4.0-slim(the release with Turbopack + Node 16.3 support and the dependency-resolution fixes).resolveNextBuildBundlerFlagis now env-only (OMNIROUTE_USE_TURBOPACK=0→--webpack, else--turbopack) instead of sniffing the runtime, andDockerfile.bunreplaces the hardcodedENV OMNIROUTE_USE_TURBOPACK=0withARG OMNIROUTE_USE_TURBOPACK=1/ENVwiring — webpack stays as the explicit--build-argescape hatch for Bun < 1.4.Dockerfile.bun:ARG OMNIROUTE_BUILD_MEMORY_MB=6144→ENV NODE_OPTIONS="--max-old-space-size=${OMNIROUTE_BUILD_MEMORY_MB}"andARG OMNIROUTE_BUILD_WORKERS=3→ENV CIRCLE_NODE_TOTAL=${OMNIROUTE_BUILD_WORKERS}. These bound the page-data workers on the default Turbopack path and keep the webpack fallback inside the 16 GB budget too. Worst case per the maintained model:6144 + 2 × 2560 = 11264 MB≤12288 MB(75 % of 16 GB).tests/unit/docker-build-memory-budget.test.tsnow validates both images (DockerfileandDockerfile.bun— wiring regexes + budget arithmetic + vCPU oversubscription), andtests/unit/build/resolve-next-build-bundler-flag.test.mjs(ported from build(bun): allow Turbopack bundler flag on Bun 1.4+ with configurable Webpack fallback #11471) pins the env-only flag contract.Verification
node --experimental-strip-types --test tests/unit/docker-build-memory-budget.test.ts tests/unit/build/resolve-next-build-bundler-flag.test.mjs→ 9/9 pass (run on the fleet worker).oven/bun1.4.0 equivalent + Turbopack + the caps above):bun install --include=optional --quiet(2151 packages, no resolution errors) → better-sqlite3 node-gyp rebuild →bun run --quiet build→ exit 0,▲ Next.js 16.3.1 (Turbopack)banner, 2.2 GB standalone bundle produced, zero OOM-kills in dmesg. The same step OOM-kills before this change.docker-publish.ymltriggers only on pushes tomain/release/v*/ tags / releases, so PR CI does not exercise the Docker build itself; the fix is backed by the regression tests and the real builder-stage run above.Closes #11709.