Merge remote-tracking branch 'origin/release/v3.8.51' into fix/release-v3.8.51-basereds-agent-skills

# Conflicts:
#	.env.example
#	docs/reference/ENVIRONMENT.md
This commit is contained in:
diegosouzapw
2026-09-16 11:58:04 -03:00
6 changed files with 56 additions and 16 deletions

View File

@@ -2749,10 +2749,11 @@ APP_LOG_TO_FILE=true
# only non-credential metadata is synced. See docs/security/SOCKET_DEV_FINDINGS.md §5.
# OMNIROUTE_CLOUD_SYNC_SECRETS=false
#
# Set to "true" to reject an unsigned Cloud Sync payload even when no local
# secret is configured. Default OFF preserves v3.8.x back-compat for peers that
# have not rotated in a shared secret yet; the default flips to enforced in v3.9.
# Used by: src/lib/cloudSync.ts (#13679).
# Set to "true" to reject an UNSIGNED Cloud sync response when no local secret
# is configured (#13679). Default OFF keeps v3.8.x back-compat for peers that
# have not rotated in a shared secret yet; v3.9 flips the default to enforced.
# A signature that IS present is always verified, and always rejected when
# OMNIROUTE_CLOUD_SYNC_SECRET is unset, regardless of this flag.
# OMNIROUTE_CLOUD_SYNC_ENFORCE_SIGNATURE=false
# ─── Zed import legacy compat (v3.8.6) ──────────────────────────────────────

View File

@@ -0,0 +1 @@
- **fix(tests):** add `dist/httpClientAbortGuard.mjs` to the expected missing-paths list in `tests/unit/pack-artifact-policy.test.ts` — [#13636](https://github.com/diegosouzapw/OmniRoute/pull/13636) registered the file in `PACK_ARTIFACT_REQUIRED_PATHS` without updating the assertion, leaving the test red on the release tip for every PR that runs it ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))

View File

@@ -0,0 +1 @@
- **fix(ci):** the advisory `forgotten-sibling-tests` step no longer fails "Fast Quality Gates" when a PR touches a hub module — the cross-product of consumers × candidate tests reached millions of rows and rendering them exceeded V8's maximum string length, so the throw hit `main()`'s catch and exited 1. The report now lists at most 200 rows per section (and 5 000 per array in the JSON artifact) while the header keeps the exact totals

View File

@@ -323,7 +323,7 @@ OmniRoute provides a two-layer defense: request-side injection scanning and resp
| `OMNIROUTE_STANDALONE_DIR` | _.build/ standalone output_ | `scripts/build/colocate-standalone.mjs` | Build-time override for the standalone output directory consumed by the post-build colocation step. Not a runtime setting. |
| `OMNIROUTE_CLOUD_SYNC_SECRET` | _(empty)_ | `src/lib/cloudSync.ts` | Shared secret used to verify the HMAC-SHA256 signature of Cloud Sync responses. |
| `OMNIROUTE_CLOUD_SYNC_SECRETS` | `false` | `src/lib/cloudSync.ts` | Set to `true` to allow the Cloud Sync endpoint to overwrite local credentials. Default is `false`. |
| `OMNIROUTE_CLOUD_SYNC_ENFORCE_SIGNATURE` | `false` | `src/lib/cloudSync.ts` | Set to `true` to reject an unsigned Cloud Sync payload even when no local secret is configured. Default OFF keeps v3.8.x back-compat; the default flips to enforced in v3.9. |
| `OMNIROUTE_CLOUD_SYNC_ENFORCE_SIGNATURE` | `false` | `src/lib/cloudSync.ts` | Set to `true` to reject an unsigned Cloud Sync response when no local secret is configured (#13679). A signature that is present is always verified — and always rejected when `OMNIROUTE_CLOUD_SYNC_SECRET` is unset — regardless of this flag. The default flips to enforced in v3.9. |
| `OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP` | `false` | `src/app/api/providers/zed/import/route.ts` | Set to `true` to fall back to the v3.8.5 one-step "import everything" behavior without user confirmation. |
| `NEXT_PUBLIC_BASE_URL` | `http://localhost:20128` | OAuth, Dashboard, sync | Public-facing URL for OAuth redirect_uri, Dashboard links, and generated public URLs. Set this to the stable public URL when OAuth callbacks or generated browser links must use a canonical reverse-proxy host. |
| `NEXT_PUBLIC_CLOUD_URL` | _(empty)_ | Client-side | Client-side mirror of `CLOUD_URL`. |
@@ -1659,7 +1659,7 @@ Globale Defaults für den headless Browser und den ausgehenden Tool-Tunnel. Im D
| `CHATGPT_WEB_CODEX_CHROME_PATH` | _(auto-detect)_ | `open-sse/executors/chatgpt-web-codex.ts` | Expliziter Chrome-/Chromium-Pfad für npm-, systemd- und PM2-Betrieb. |
| `CHROME_PATH` | _(auto-detect)_ | `open-sse/executors/chatgpt-web-codex.ts` | Gemeinsamer Fallback für einen expliziten Chrome-/Chromium-Pfad. |
| `CHATGPT_WEB_CODEX_CDP_URL` | _(unset)_ | `open-sse/executors/chatgpt-web-codex.ts` | Interner CDP-Endpunkt; Docker verwendet den Sidecar auf Port `9223`. |
| `CDP_PROXY_TOKEN` | _(unset)_ | `docker/chatgpt-web-codex-browser/cdp-proxy.mjs` | Wenn gesetzt, muss jede Anfrage an den CDP-Proxy-Sidecar den Wert im Header `X-Omni-Cdp-Token` mitschicken; ohne den Wert leitet der Proxy unauthentifiziert weiter (#13679). |
| `CDP_PROXY_TOKEN` | _(unset)_ | `docker/chatgpt-web-codex-browser/cdp-proxy.mjs` | Wenn gesetzt, muss jede Anfrage an den CDP-Proxy-Sidecar diesen Wert im Header `X-Omni-Cdp-Token` mitschicken (#13679). Ohne Wert leitet der Proxy unauthentifiziert weiter — dann schützt nur die Netzisolierung des Compose-Netzes `chatgpt-web-codex-net`. Erzeugen mit `openssl rand -hex 32`. |
| `CHATGPT_WEB_CODEX_TUNNEL_ID` | _(unset)_ | `open-sse/executors/chatgpt-web-codex.ts` | Globale OpenAI-Tunnel-ID für lokale Codex-Tool-Runden. |
| `CHATGPT_WEB_CODEX_RUNTIME_KEY` | _(unset)_ | `open-sse/executors/chatgpt-web-codex.ts` | Globaler Tunnel Runtime-Key; niemals in Logs ausgeben. |
| `CHATGPT_WEB_CODEX_CONNECTOR_NAME` | `OmniRoute Codex v2` | `open-sse/executors/chatgpt-web-codex.ts` | Exakter Name des neu erstellten ChatGPT-Custom-Connectors für die MCP-Brücke. |

View File

@@ -205,7 +205,26 @@ function changedSymbols(root, base, entries) {
return result;
}
function markdown(result, base) {
// A changed hub module (providerRegistry.ts, providers.ts, …) is imported by thousands of
// consumers, and every consumer multiplies by its candidate tests, so the cross-product reaches
// millions of rows. Rendering all of them made `lines.join("\n")` exceed V8's maximum string
// length; the throw landed in main()'s catch, which exits 1 — so an ADVISORY step turned
// "Fast Quality Gates" red on every PR whose diff touched a hub (#13866 follow-up). The header
// keeps the exact totals; only the enumeration is bounded.
const RENDER_LIMIT = 200;
const JSON_ITEM_LIMIT = 5000;
/** First `limit` items plus a one-line note naming how many were withheld. */
function renderBounded(lines, items, format, limit = RENDER_LIMIT) {
for (const item of items.slice(0, limit)) lines.push(format(item));
if (items.length > limit) {
lines.push(
`- _… and ${items.length - limit} more not listed (report bounded at ${limit} rows per section; the counts above are exact)._`
);
}
}
export function markdown(result, base) {
const lines = [
"## Forgotten sibling tests (advisory)",
"",
@@ -218,12 +237,10 @@ function markdown(result, base) {
];
if (result.findings.length) {
lines.push("### Candidate tests absent from this diff", "");
for (const item of result.findings) {
renderBounded(lines, result.findings, (item) => {
const symbol = item.changedSymbols.length ? ` (${item.changedSymbols.join(", ")})` : "";
lines.push(
`- \`${item.changedModule}\`${symbol} -> \`${item.consumer}\` -> \`${item.candidateTest}\``
);
}
return `- \`${item.changedModule}\`${symbol} -> \`${item.consumer}\` -> \`${item.candidateTest}\``;
});
lines.push("", "> Report-only calibration: these findings do not fail the job.", "");
}
for (const [heading, items] of [
@@ -232,10 +249,12 @@ function markdown(result, base) {
]) {
if (!items.length) continue;
lines.push(`### ${heading}`, "");
for (const item of items)
lines.push(
renderBounded(
lines,
items,
(item) =>
`- \`${item.changedModule}\` -> \`${item.consumer}\`${item.candidateTest ? ` -> \`${item.candidateTest}\`` : ""}: ${item.reason || item.message}`
);
);
lines.push("");
}
return `${lines.join("\n")}\n`;
@@ -271,9 +290,26 @@ function main() {
});
const report = markdown(result, base);
process.stdout.write(report);
// The JSON artifact is bounded for the same reason the markdown is: a hub-module diff
// produces millions of rows and `JSON.stringify` would throw the same "Invalid string
// length". `totals` keeps every count exact, so tooling can still see the real numbers.
const jsonResult = {
...result,
totals: {
findings: result.findings.length,
diagnostics: result.diagnostics.length,
suppressed: result.suppressed.length,
maskingRisks: result.maskingRisks.length,
},
itemLimit: JSON_ITEM_LIMIT,
findings: result.findings.slice(0, JSON_ITEM_LIMIT),
diagnostics: result.diagnostics.slice(0, JSON_ITEM_LIMIT),
suppressed: result.suppressed.slice(0, JSON_ITEM_LIMIT),
maskingRisks: result.maskingRisks.slice(0, JSON_ITEM_LIMIT),
};
for (const [target, contents] of [
[summaryPath, report],
[jsonPath, `${JSON.stringify(result, null, 2)}\n`],
[jsonPath, `${JSON.stringify(jsonResult, null, 2)}\n`],
]) {
if (!target) continue;
fs.mkdirSync(path.dirname(target), { recursive: true });

View File

@@ -299,6 +299,7 @@ test("findMissingArtifactPaths flags missing root runtime files in the tarball",
"config/release/wreq-js-rust-notices.md",
"dist/head-response-guard.cjs",
"dist/http-method-guard.cjs",
"dist/httpClientAbortGuard.mjs",
"dist/main-server-timeouts.mjs",
"dist/open-sse/services/compression/engines/rtk/filters/generic-output.json",
"dist/open-sse/services/compression/rules/en/filler.json",