Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
6cbcba7
feat(dashboard): show cache percentage in request logs
b3nw Aug 29, 2026
3d4f3e4
test(infra): retry recursive temp-dir removal instead of failing a sh…
diegosouzapw Aug 29, 2026
60bbf0f
fix(ci): stop a stalled Codecov upload from cancelling the Coverage j…
diegosouzapw Aug 29, 2026
757cc3b
fix(release): let the Electron workflow start again — grant actions:r…
diegosouzapw Aug 29, 2026
3b752f9
chore(quality): type the 55 no-explicit-any sites frozen under #11924…
diegosouzapw Aug 29, 2026
87b3bdf
fix(resilience): lock permanently retired models instead of short bac…
turbolego Aug 29, 2026
91f9a01
fix(resilience): stop hammering permanently-moved endpoints and billi…
turbolego Aug 29, 2026
d887937
fix(combo): lock GitHub models rejected as "not supported" for future…
turbolego Aug 29, 2026
c705147
docs(i18n): finish Freepik → Magnific rebrand in locale strings and R…
turbolego Aug 29, 2026
d2ad71c
fix(kie): route flux/kontext to its dedicated endpoint, not the Marke…
diegosouzapw Aug 29, 2026
674cc5f
fix(db): rate-limit Arena ELO fetch-failure warnings on repeated time…
diegosouzapw Aug 29, 2026
fb9cbe9
fix(ci): pass --pass-on-unpruned-suppressions in run-eslint-json.mjs …
diegosouzapw Aug 29, 2026
71093ed
fix(codex): keep parallel_tool_calls:false on translated Responses Li…
diegosouzapw Aug 29, 2026
322b218
fix(cli): drop the never-produced dist/index.cjs requirement from pre…
diegosouzapw Aug 29, 2026
bd04bb9
fix(sse): set X-OmniRoute-Selected-Connection-Id on successful combo …
diegosouzapw Aug 29, 2026
02ba573
fix(providers): scope Antigravity mitmAlias tier ids to the safe stat…
diegosouzapw Aug 29, 2026
e6de61f
fix(sse): stop the auto-combo candidates inspector from dropping bloc…
diegosouzapw Aug 29, 2026
c4bd8b8
fix(release): electron lockfile resync, build_ref, curated notes and …
diegosouzapw Aug 29, 2026
38e2616
fix(ci): stop hosted docker-publish OOM and unpaint Build (advisory) …
diegosouzapw Aug 29, 2026
47f7e5a
fix(release): the packaged-app smoke verifies the database opened, no…
diegosouzapw Aug 29, 2026
a9aee94
docs(ops): the .113 heavy-build ceiling is one runner, not two (#12048)
diegosouzapw Aug 29, 2026
9ec4d39
fix(ci): webpack for docker-publish even on omni-build (#12050)
diegosouzapw Aug 29, 2026
c8dc982
fix(ci): drop the stale ESLint cache restore-keys fallback from ci.ym…
diegosouzapw Aug 29, 2026
c9b1c12
fix(db): include local no-API-key providers in Qdrant embedding-model…
diegosouzapw Aug 29, 2026
d32c76f
fix(config): correct Hermes-4-405B display label from 7B to 405B (#11…
diegosouzapw Aug 29, 2026
065d998
fix(cli): update flow now says whether the running process needs a re…
diegosouzapw Aug 29, 2026
34e2f84
feat(api): explicit model exposure allow/deny list for /v1/models (#1…
diegosouzapw Aug 29, 2026
2b8d3a8
fix(radar): restore D12 public boundary (#12057)
diegosouzapw Aug 29, 2026
3b00535
feat(guardrails): enforce video transcript provenance, budgets and re…
diegosouzapw Aug 29, 2026
60dc242
feat(video): derive embedded subtitle provenance in the protected bro…
diegosouzapw Aug 29, 2026
ef66896
test(video): freeze FU-07/FU-09 promotion-evidence manifest, aggregat…
diegosouzapw Aug 29, 2026
f30e5b2
feat(video): connect tenant-bound drill-down lifecycle and multiresol…
diegosouzapw Aug 29, 2026
e8b2cd2
docs(video): clarify Video Bridge transcript provenance is caller-dec…
diegosouzapw Aug 29, 2026
5fcd39b
feat(video): orchestrate Audio Bridge STT with one-download budgets (…
diegosouzapw Aug 29, 2026
36b7920
refactor(video): extract a Video Bridge pipeline with explicit ports …
diegosouzapw Aug 29, 2026
55e33f3
fix(sse): default crash-guard logger to console.warn, not console (#1…
HouMinXi Aug 29, 2026
5698769
fix(cli): support --base-url alongside --endpoint in nodes subcommand…
HouMinXi Aug 29, 2026
d3420d2
fix(admission): exclude reclaimable page cache from the cgroup pressu…
HouMinXi Aug 29, 2026
38e2baa
fix(resilience): clear persisted LKGP pin on target exhaustion and sk…
HouMinXi Aug 29, 2026
aa861a8
fix(barrel): migrate src/app/ off the @/lib/localDb barrel import (#1…
jonlwheat2-gif Aug 30, 2026
2463781
fix(barrel): migrate src/lib/ off the localDb barrel to direct db imp…
jonlwheat2-gif Aug 30, 2026
38a2966
URGENT fix(build): route ChatGPT Web MCP bundle through runBuildTool …
jonlwheat2-gif Aug 30, 2026
4e11887
fix(barrel): migrate open-sse, src/shared, src/sse, src/models, src/d…
jonlwheat2-gif Aug 30, 2026
50bc8ab
fix(barrel): delete the @/lib/localDb barrel — every consumer migrate…
jonlwheat2-gif Aug 30, 2026
2ec24e7
fix(core): resolve DB init race condition and reasoning translation (…
raheemuddin786 Aug 30, 2026
da678bd
feat(config): add support for runtime system prompt configuration and…
raheemuddin786 Aug 30, 2026
92574de
fix(chat): preserve unstripped model string for passthrough provider …
raheemuddin786 Aug 30, 2026
d26fe03
feat(routing): add relayMode for schema-locked context handoffs (#11839)
raheemuddin786 Aug 30, 2026
47ea113
fix(ci): reconcile release test contract drift (#12082)
backryun Aug 30, 2026
49827c1
fix(dev): bound webpack and Tailwind scans (#12075)
backryun Aug 30, 2026
a1d6ff5
fix(api): preserve caller-provided X-Correlation-Id on chat completio…
aniruddhaadak80 Aug 30, 2026
55691e0
fix(usage): allow quota refresh for FREE lease-reserved connections (…
TheDemonTuan Aug 30, 2026
faebf6d
fix(shared): block cloud-metadata hosts under default remote-image gu…
santosraju99-hub Aug 30, 2026
c2c97af
ci: add API route TypeScript regression gate (#11705)
Sabeekhann Aug 30, 2026
1c37fff
fix(memory): honor category filter in GET /api/memory (#11699)
Sabeekhann Aug 30, 2026
ccee48d
fix(db): drop three consumer-less 1proxy exports — dead-code base-red…
diegosouzapw Aug 30, 2026
5684589
feat(dashboard): collapsible JSON tree viewer for request/response pa…
hartmark Aug 30, 2026
2e3cd59
feat(routing): add LiquidAI LFM2.5-2.6B free tier via OpenRouter (#11…
brick30llc-ctrl Aug 30, 2026
e620c50
fix(api): clear the six API-route TypeScript regressions the new gate…
diegosouzapw Aug 30, 2026
a3c19dd
fix(ci): accept CVE-2025-68121 in the prebuilt tls-client .so, auto-c…
diegosouzapw Aug 30, 2026
8180b32
fix(codex): restore imported account state (#11954)
Bl0ck154 Aug 30, 2026
70af41b
fix(db): invalidate connection cache after upsert (#11953)
Bl0ck154 Aug 30, 2026
097226b
fix(codex): normalize non-stream responses (#11951)
Bl0ck154 Aug 30, 2026
e96e40c
fix(images): forward Antigravity image size (#11952)
Bl0ck154 Aug 30, 2026
79b2e92
fix(codex): fail over image generation for imported free plans (#11948)
Bl0ck154 Aug 30, 2026
41f4f83
fix(release): never let the tag-push Create Release append auto notes…
diegosouzapw Aug 30, 2026
ff07430
fix(auth): downgrade expected transient states from warn to debug (#1…
patrykkopycinski Aug 30, 2026
8bed101
fix(guardrails): prevent duplicate prompt-injection-guard log output …
patrykkopycinski Aug 30, 2026
2201143
fix(providers): route OrcaRouter chat requests to /v1/chat/completion…
echel0nn Aug 30, 2026
41c6135
fix(ollama): preserve multi-byte UTF-8 content split across stream ch…
pacocartones Aug 30, 2026
81bf1ef
feat(leases): expose owner-authenticated connection display name (#11…
KaspaPulse Aug 30, 2026
2471a0d
feat(plugins): add OMNIROUTE_PLUGINS_DIR to override the plugin scan …
pacocartones Aug 30, 2026
15b1648
feat(providers): expose a usage-fetch capability in the provider plug…
pacocartones Aug 30, 2026
3852e05
fix(build): fail fast when an externalised optional native dep was si…
ujjawalkaushik1110 Aug 30, 2026
823dae0
fix(skills): expand shorthand property types in injected tool schemas…
alvinveroy Aug 30, 2026
66e02ec
fix(plugins): deliver onStreamComplete to disk-installed plugins (#11…
pacocartones Aug 30, 2026
4254b1f
chore(deps): bump github/codeql-action/analyze from 4.37.7 to 4.37.8 …
dependabot[bot] Aug 30, 2026
23144ad
chore(deps): bump github/codeql-action from 4.37.7 to 4.37.8 (#11926)
dependabot[bot] Aug 30, 2026
25aa95f
chore(deps): bump github/codeql-action/init from 4.37.7 to 4.37.8 (#1…
dependabot[bot] Aug 30, 2026
212fba7
docs: document native dependency check escape hatch (#12101)
RaviTharuma Aug 30, 2026
131e413
fix: mark Vercel AI Gateway as passthroughModels (#11771)
Rahulsharma0810 Aug 30, 2026
b07eaaf
fix(cli): probe both IPv4 and IPv6 loopback for server readiness (#11…
vermasomesh835 Aug 30, 2026
dfc84ba
fix: regenerate package-lock.json for packages/browser-pool workspace…
geekyNads Aug 30, 2026
e0029eb
feat(pricing): add GLM-5.3-Flash pricing, model specs, and catalog re…
AndrianBalanescu Aug 30, 2026
4c187de
fix(docs): resolve relative markdown and wiki links across Fumadocs a…
AndrianBalanescu Aug 30, 2026
8f38dcd
fix(dashboard): use opaque background and readable text color on cost…
ZaimMarzuki Aug 30, 2026
56dddfc
fix(antigravity): send complete loadCodeAssist metadata (ideType/plat…
rifqiawl Aug 30, 2026
4c8074b
fix(sse): give extended-thinking targets the reasoning readiness budg…
abhisheksharma2411 Aug 30, 2026
9903a6d
refactor(auto-combo): fix divergent scoring in combo health reporting…
jacobsparts Aug 30, 2026
0b19c5a
feat(nodejs): add 5dive as a configure target (#11852)
5dive-bot Aug 30, 2026
43dfb1d
board #11970
diegosouzapw Aug 30, 2026
6079e4a
test: move formatCachePercentage to shared formatting utils
diegosouzapw Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 16 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ INITIAL_PASSWORD=CHANGEME
# executor's on-disk thread-sticky session cache. Leave unset to rely on DATA_DIR.
# OMNIROUTE_DATA_DIR=/var/lib/omniroute

# Directory the runtime plugin scanner reads, overriding the home-derived default (#11827).
# Used by: src/lib/plugins/scanner.ts — getDefaultPluginDir(); it is also the root the
# plugin manager installs into. Set it in Docker/K8s to point straight at the bind-mounted
# plugin tree, instead of moving HOME (which changes every other HOME-relative behaviour)
# just to relocate the scan path. Unset = <HOME>/.omniroute/plugins, and
# /tmp/.omniroute/plugins when the process exports no home at all.
# Distinct from the CLI-only variable in section 9 that points the omniroute-cmd-* command
# loader (bin/cli/plugins.mjs) at a package tree — this one drives the server-side scanner.
# OMNIROUTE_PLUGINS_DIR=/opt/omniroute/plugins

# Escape hatch for the test-context DATA_DIR guard (#10428). A test run that never
# chose a DATA_DIR is redirected to a throwaway temp dir so it cannot open the
# operator's real database. Set to 1 only for a deliberate run against the real
Expand All @@ -71,6 +81,11 @@ INITIAL_PASSWORD=CHANGEME
# Never set this for the running server. Used by: src/lib/buildPhase.ts, src/lib/db/core.ts
# OMNIROUTE_BUILDING=1

# Skip the optional native-dependency prebuild check for exotic vendored trees.
# This does not make a missing dependency buildable. Used by: scripts/check/check-native-deps.mjs
# Default: 0 | Set to 1 only when native dependencies are supplied out of band.
# OMNIROUTE_SKIP_NATIVE_DEP_CHECK=0

# Encryption key for SQLite database encryption at rest.
# Used by: src/lib/db/encryption.ts — encrypts the entire SQLite database.
# Generate: openssl rand -hex 32 | Leave empty to disable DB encryption.
Expand Down Expand Up @@ -1749,6 +1764,7 @@ APP_LOG_TO_FILE=true

# Custom directory for CLI plugin discovery (omniroute-cmd-* packages).
# Default: ~/.omniroute/plugins/ Override in dev/CI to point at a local plugin tree.
# CLI-only: the server-side plugin scanner is pointed by OMNIROUTE_PLUGINS_DIR (section 2).
# OMNIROUTE_PLUGIN_PATH=

# ── Prompt cache (system prompt deduplication) ──
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/api-route-typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: API Route Typecheck

on:
pull_request:
branches:
- main
- "release/**"
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
api-typecheck:
name: API Route Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
cache: npm
- uses: ./.github/actions/npm-ci-retry
- name: Reject new API-route TypeScript diagnostics
run: node scripts/check/check-api-typecheck.mjs
- name: API typecheck gate unit tests
run: node --import tsx/esm --test tests/unit/build/check-api-typecheck.test.ts
30 changes: 22 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,11 @@ jobs:
.eslintcache
.eslintcache-complexity
key: eslint-${{ runner.os }}-${{ hashFiles('eslint.config.mjs', 'eslint.complexity-ratchets.config.mjs', 'config/quality/eslint-suppressions.json', 'package-lock.json') }}
restore-keys: |
eslint-${{ runner.os }}-
# No restore-keys fallback on purpose (#11600, P-II.1 of the v3.8.50 postmortem): a
# cache built under a different suppressions file / lint config / lockfile reports
# stale per-file verdicts, which is exactly how 215 pre-existing errors stayed
# invisible for a whole cycle. Exact key or a cold full lint (~13 min) — never a
# partial cache from another configuration.
# Single ESLint inventory (JSON) — quality-gate reuses the artifact instead of
# a second cold full-tree pass for eslintWarnings ratchet counts.
- name: ESLint (JSON report)
Expand Down Expand Up @@ -209,8 +212,11 @@ jobs:
.eslintcache
.eslintcache-complexity
key: eslint-${{ runner.os }}-${{ hashFiles('eslint.config.mjs', 'eslint.complexity-ratchets.config.mjs', 'config/quality/eslint-suppressions.json', 'package-lock.json') }}
restore-keys: |
eslint-${{ runner.os }}-
# No restore-keys fallback on purpose (#11600, P-II.1 of the v3.8.50 postmortem): a
# cache built under a different suppressions file / lint config / lockfile reports
# stale per-file verdicts, which is exactly how 215 pre-existing errors stayed
# invisible for a whole cycle. Exact key or a cold full lint (~13 min) — never a
# partial cache from another configuration.
# Coverage mergeada (coverage-summary.json) p/ o ratchet de cobertura.
# continue-on-error: o artifact pode não existir se a job test-coverage foi
# SKIPPED (shard flaky). Nesse caso collect-metrics pula coverage.* (ausente sem
Expand Down Expand Up @@ -621,9 +627,9 @@ jobs:
# 13:50Z the kernel OOM-killed main's build while a PR build ran beside it
# (five Build jobs had been queued by a burst of PRs). Two lanes: main keeps
# its own so a release is never queued behind PR traffic; PR builds serialize
# among themselves. GitHub keeps one running + one pending per group and
# CANCELS older pendings — a cancelled PR build is re-runnable; a dead main
# build costs the publish its artefact and a 40-minute rebuild that OOMs.
# among themselves. docker-publish.yml's amd64 leg joins `heavy-build-main`
# so a :next image build waits beside this artefact instead of becoming the
# third heavy (#11976). GitHub keeps one running + one pending per group.
concurrency:
group: heavy-build-${{ github.ref == 'refs/heads/main' && 'main' || 'pr' }}
cancel-in-progress: false
Expand Down Expand Up @@ -979,7 +985,11 @@ jobs:
# 10min was sized before #7114 added the lcov reporter (Codecov/Sonar need it);
# merging 8 shard JSONs + text+json+lcov now takes ~10-12min — three consecutive
# release-tip runs died at exactly 10m as job-timeout "cancelled" (2026-07-15/16).
timeout-minutes: 20
# 30, not 20 (2026-08-29): the informational Codecov upload below hung for the rest of
# the budget on two consecutive main runs (33207760653, 33215115341); the job ended
# `cancelled` and dragged the whole run's conclusion to `cancelled` although every
# blocking job was green. The upload step now has its own ceiling; this is headroom.
timeout-minutes: 30
needs: test-unit
if: ${{ !cancelled() && needs.test-unit.result == 'success' && !contains(github.event.pull_request.labels.*.name, 'hotfix') }}
env:
Expand Down Expand Up @@ -1058,6 +1068,10 @@ jobs:
# (if-no-files-found: warn) — Sonar consumes the same file.
- name: Upload coverage to Codecov (informational)
if: always()
# Informational means informational: its own ceiling and continue-on-error, so a
# stalled upload can neither eat the job's budget nor turn a green job cancelled.
timeout-minutes: 5
continue-on-error: true
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: coverage/lcov.info
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
- uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
languages: javascript-typescript
queries: security-extended
- uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
- uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
category: "/language:javascript-typescript"
44 changes: 40 additions & 4 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ on:
type: boolean
default: false

# One publish per ref. A merge storm used to fan out 8 concurrent hosted builds,
# every one OOM-killing `npm run build` inside BuildKit (#11976). The :next
# channel only needs the newest SHA; cancel-in-progress is the same pattern as
# quality.yml / nightly-release-green.
concurrency:
group: docker-publish-${{ github.ref }}
cancel-in-progress: true

# Least-privilege default: read-only at the top level; the build and merge jobs that
# push to GHCR grant packages: write themselves (Scorecard TokenPermissions).
permissions:
Expand Down Expand Up @@ -118,7 +126,23 @@ jobs:
name: Build Docker (${{ matrix.platform }})
needs: prepare
if: needs.prepare.outputs.skip != 'true'
runs-on: ${{ matrix.runner }}
# amd64: the .113 omni-build pool (31 GB / 32 cores, ONE listener since
# #12048). Hosted ubuntu-24.04 is ~7 GB and dies ResourceExhausted (#11976).
# Falls back to hosted when USE_VPS_RUNNER is off. arm64: no ARM box — stay
# on GitHub's ubuntu-24.04-arm.
# Webpack on BOTH arches: Turbopack on omniroute-113-6 hit
# TurbopackInternalError "there must be a path to a root" after 26 min
# (run 33253576569). The same tree's arm64 webpack build on hosted ARM
# succeeded (run 33264823398). Dockerfile already documents webpack as the
# Docker escape hatch (OMNIROUTE_USE_TURBOPACK=0).
runs-on: ${{ matrix.arch == 'amd64' && (vars.USE_VPS_RUNNER == 'true' && fromJSON('["self-hosted","omni-build"]') || 'ubuntu-24.04') || 'ubuntu-24.04-arm' }}
# Share the 1-slot omni-build ceiling (#12048) with ci.yml `Build` /
# npm-publish. Same group as main's Build so a :next publish waits beside
# the artefact instead of sitting next to it. arm64 is hosted — its own
# group, cancelled by the workflow-level concurrency.
concurrency:
group: ${{ matrix.arch == 'amd64' && 'heavy-build-main' || format('docker-publish-arm-{0}', github.ref) }}
cancel-in-progress: ${{ matrix.arch != 'amd64' }}
permissions:
contents: read
packages: write
Expand All @@ -127,10 +151,8 @@ jobs:
matrix:
include:
- platform: linux/amd64
runner: ubuntu-24.04
arch: amd64
- platform: linux/arm64
runner: ubuntu-24.04-arm
arch: arm64
env:
IMAGE_NAME: diegosouzapw/omniroute
Expand All @@ -143,6 +165,9 @@ jobs:
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/v{0}', inputs.version) || '' }}
fetch-depth: 0

- name: Assert Docker Engine
run: docker info

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

Expand All @@ -166,6 +191,8 @@ jobs:
context: .
target: runner-base
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
Expand All @@ -183,6 +210,8 @@ jobs:
context: .
target: runner-web
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
Expand All @@ -208,6 +237,8 @@ jobs:
file: Dockerfile.bun
target: runner-base
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
Expand All @@ -233,6 +264,8 @@ jobs:
file: Dockerfile.bun
target: runner-web
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
Expand Down Expand Up @@ -495,11 +528,14 @@ jobs:
severity: CRITICAL
ignore-unfixed: true
exit-code: "1"
# Explicit: the advisory scan above already points at it, and the blocking
# gate must honour the same accepted-risk list (#12084).
trivyignores: .trivyignore

- name: Upload Trivy SARIF to Security tab
if: needs.prepare.outputs.version != 'main'
continue-on-error: true
uses: github/codeql-action/upload-sarif@v4.37.7
uses: github/codeql-action/upload-sarif@v4.37.8
with:
sarif_file: trivy-results.sarif
category: trivy-image
Expand Down
27 changes: 26 additions & 1 deletion .github/workflows/electron-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ on:
push:
tags:
- "v*"
# A dispatch builds the ref it is dispatched ON (`gh workflow run … --ref v3.8.50` rebuilds
# that tag; `--ref main` builds the repaired line). The ref is deliberately NOT an input:
# CodeQL flags an input-controlled checkout next to the npm cache on the default branch as
# cache poisoning (actions/cache-poisoning/poisonable-step), and `github.ref` is trusted.
workflow_dispatch:
inputs:
version:
description: "Release version (e.g., v1.6.8)"
required: true
type: string
publish_npm:
description: "Also run the npm publish leg (turn off when re-attaching desktop assets to a release whose npm package already shipped)"
required: false
default: true
type: boolean

# Least-privilege default: read-only at the top level; each job grants the writes it
# needs (build/release upload assets, publish-npm forwards npm provenance / packages
Expand Down Expand Up @@ -404,7 +413,14 @@ jobs:
tag_name: ${{ needs.validate.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
# NEVER. Phase 3 of the release flow creates the GitHub Release with the curated
# notes seconds after pushing the tag, so by the time this step runs (1-2 h of
# builds later) the body already exists — and `true` APPENDS GitHub's
# auto-generated "What's Changed" block to it (v3.8.48 shipped that way; the
# v3.8.50 re-attach dispatch added +1,416 chars to a 121 KB body, run
# 33238093090). A curated body sits ~3 KB under the 125,000-char cap, so the
# append can also turn this step RED and leave the release with no assets.
generate_release_notes: false
fail_on_unmatched_files: false
files: |
release-assets/*.dmg
Expand Down Expand Up @@ -462,11 +478,20 @@ jobs:
publish-npm:
name: Publish to npm
needs: [validate, release]
# A re-dispatch that only re-attaches desktop assets must not publish the npm package again.
if: ${{ github.event_name != 'workflow_dispatch' || inputs.publish_npm }}
permissions:
# Must be `write`, not `read`: this job calls the reusable npm-publish.yml whose
# `publish` job needs `contents: write` (gh release upload — attach the SBOM, #3874).
# A reusable workflow's job cannot request more permission than the caller grants,
# so a `read` here makes GitHub reject the run at startup (startup_failure).
#
# `actions: read` for the same reason: the called `publish` job downloads the next-build
# artefact and requests it. v3.8.50 (run 33005490476) died at startup with "The nested
# job 'publish' is requesting 'actions: read', but is only allowed 'actions: none'" — and
# because `release` lives in this same workflow, the tag shipped with ZERO assets. Keep
# this block a superset of every job's permissions in npm-publish.yml.
actions: read
contents: write
id-token: write # npm provenance (forwarded to the reusable workflow)
packages: write # publish to npm.pkg.github.com
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/nightly-release-green.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,26 @@ jobs:
gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label base-red --body-file issue-body.md
fi

- name: Close tracking issue when the branch is green again
if: steps.validate.outputs.exit == '0'
env:
GH_TOKEN: ${{ github.token }}
TARGET: ${{ steps.branch.outputs.target }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# The open/update step above is the UPWARD half of the loop; without this
# step a stale "not green" issue outlives the fix and every base-green check
# (`AGENTS.md` → "Base-green check") keeps stamping new PRs as base-red inherited.
TITLE="🔴 Release branch not green: ${TARGET}"
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
if [ -n "$EXISTING" ]; then
gh issue close "$EXISTING" --repo "$GITHUB_REPOSITORY" --reason completed \
--comment "✅ \`${TARGET}\` is release-green again at \`${GITHUB_SHA:0:9}\` — ${RUN_URL}. Auto-closed by Release-Green (continuous)."
echo "Closed issue #$EXISTING"
fi

- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -294,6 +314,25 @@ jobs:
gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label base-red --body-file issue-body.md
fi

- name: Close tracking issue when the branch is green again
if: steps.validate.outputs.exit == '0'
env:
GH_TOKEN: ${{ github.token }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# The open/update step above is the UPWARD half of the loop; without this
# step a stale "not green" issue outlives the fix and every base-green check
# (`AGENTS.md` → "Base-green check") keeps stamping new PRs as base-red inherited.
TITLE="🔴 main branch not green"
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
if [ -n "$EXISTING" ]; then
gh issue close "$EXISTING" --repo "$GITHUB_REPOSITORY" --reason completed \
--comment "✅ \`main\` is main-green again at \`${GITHUB_SHA:0:9}\` — ${RUN_URL}. Auto-closed by Release-Green (continuous)."
echo "Closed issue #$EXISTING"
fi

- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v7
Expand Down
Loading