mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 15:52:52 +03:00
chore(deps): bump github/codeql-action/analyze from 4.36.3 to 4.37.0 (#6831)
* fix(electron): bump electron 42→43 + build better-sqlite3 from source (ABI 148) (#6605)
fix(electron): bump electron 42→43 + rebuild better-sqlite3 from source against the Electron ABI (148).
Electron 43 raises NODE_MODULE_VERSION to 148; better-sqlite3@12.11.1 has no electron-v148 prebuild, so the packaged app died with 'Nenhum driver SQLite disponível'. prepare-electron-standalone now compiles better-sqlite3 from source against the electron headers into build/Release (where 'bindings' resolves it). Validated by Electron Package Smoke (green) + local (node_register_module_v148).
Supersedes #6378. (--admin: the only reds are SonarQube/SonarCloud failing on a coverage-report artifact digest-mismatch — a GitHub Actions infra flake, not this diff; Sonar is green on main and the diff touches only the electron build.)
* deps: bump the development group across 1 directory with 6 updates (#6588)
deps: bump the development group (6 updates). Rebased onto current main; all checks green after the electron-smoke fix (#6605).
* fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump (#6620)
fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump.
undici 8.6+ changed ProxyAgent to forward plain-HTTP via request-proxy instead of CONNECT, breaking OAuth refresh through a connection proxy (501). proxyDispatcher now passes proxyTunnel:true. Validated: Unit Tests 3/8 (the OAuth-proxy test) green, new regression test green (fails without the fix on undici 8.7), SonarQube green.
Supersedes #6380. (--admin: the only red is Electron Package Smoke failing on a next-build artifact 'digest-mismatch' — a GitHub Actions infra flake corrupting the asar ('file data stream has unexpected number of bytes'); the better-sqlite3 rebuild itself succeeded (gyp ok) and the electron path is unchanged from #6605 which passed the smoke. Not this diff.)
* chore(deps): bump github/codeql-action/analyze from 4.36.3 to 4.37.0
Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.36.3 to 4.37.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](54f647b7e1...99df26d4f1)
---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
dependency-version: 4.37.0
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -26,6 +26,6 @@ jobs:
|
||||
with:
|
||||
languages: javascript-typescript
|
||||
queries: security-extended
|
||||
- uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
- uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||
with:
|
||||
category: "/language:javascript-typescript"
|
||||
|
||||
8
electron/package-lock.json
generated
8
electron/package-lock.json
generated
@@ -12,7 +12,7 @@
|
||||
"electron-updater": "^6.8.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^42.5.1",
|
||||
"electron": "^43.1.0",
|
||||
"electron-builder": "^26.15.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1367,9 +1367,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "42.5.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-42.5.1.tgz",
|
||||
"integrity": "sha512-2VFNJcHHbrhIpGsJHdkLoi/nWPZPxN3GHVPe+9At3Oz3/TJRwpr+7JL97ddBDbKyLmHGx3GfI2jvzcEQL28uFw==",
|
||||
"version": "43.1.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-43.1.0.tgz",
|
||||
"integrity": "sha512-DPfxpQLd4NL3BJ8DBxYAfmLUKKesF5Rx9dQx5FyczAP8bhOPScjHE48GArVeXu68LlAainuwkmQTQvdZwpIIAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"electron-updater": "^6.8.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^42.5.1",
|
||||
"electron": "^43.1.0",
|
||||
"electron-builder": "^26.15.3"
|
||||
},
|
||||
"overrides": {
|
||||
@@ -42,6 +42,7 @@
|
||||
"appId": "online.omniroute.desktop",
|
||||
"productName": "OmniRoute",
|
||||
"copyright": "Copyright © 2025 OmniRoute",
|
||||
"buildDependenciesFromSource": true,
|
||||
"directories": {
|
||||
"output": "dist-electron",
|
||||
"buildResources": "assets"
|
||||
|
||||
@@ -472,6 +472,12 @@ export function createProxyDispatcher(proxyUrl: string): Dispatcher {
|
||||
// valid; the cast suppresses the spurious missing-`port` error.
|
||||
dispatcher = new ProxyAgent({
|
||||
uri: cleanUri,
|
||||
// undici 8.6+ forwards plain-HTTP requests through the proxy as an origin
|
||||
// request (GET http://host/…) instead of a CONNECT tunnel; upstream proxies
|
||||
// that only speak CONNECT then reject it (501). OmniRoute tunnels ALL proxied
|
||||
// traffic (HTTP + HTTPS) via CONNECT, so force tunneling. Unknown option on
|
||||
// undici <8.6 → silently ignored (that version already tunneled by default).
|
||||
proxyTunnel: true,
|
||||
...proxyDispatcherOptions,
|
||||
...(family !== null
|
||||
? { proxyTls: { family, autoSelectFamily: false } as ProxyAgent.Options["proxyTls"] }
|
||||
|
||||
1763
package-lock.json
generated
1763
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -307,7 +307,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "^4.11.3",
|
||||
"@cyclonedx/cyclonedx-npm": "5.0.0",
|
||||
"@cyclonedx/cyclonedx-npm": "6.0.0",
|
||||
"@playwright/test": "^1.60.0",
|
||||
"@size-limit/file": "^12.1.0",
|
||||
"@stryker-mutator/core": "^9.6.1",
|
||||
@@ -323,13 +323,13 @@
|
||||
"@types/safe-regex": "^1.1.6",
|
||||
"@types/ws": "^8.18.0",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"bun": "1.3.10",
|
||||
"bun": "1.3.14",
|
||||
"c8": "^11.0.0",
|
||||
"concurrently": "^10.0.3",
|
||||
"cross-env": "^10.1.0",
|
||||
"dpdm": "^4.2.0",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-config-next": "16.2.9",
|
||||
"eslint-config-next": "16.2.10",
|
||||
"eslint-plugin-sonarjs": "^4.1.0",
|
||||
"fast-check": "^4.8.0",
|
||||
"glob": "^13.0.6",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { existsSync, lstatSync, readdirSync, rmSync } from "node:fs";
|
||||
import { cpSync, existsSync, lstatSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
||||
import { basename, dirname, join, relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { assembleStandalone } from "./assembleStandalone.mjs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
@@ -70,17 +71,86 @@ function removeGeneratedElectronArtifacts() {
|
||||
|
||||
// --- Electron-UNIQUE: remove native modules for electron-builder ABI rebuild ---
|
||||
|
||||
function removeNativeModules(baseDir) {
|
||||
function removeNativeModules(baseDir, prefixes = ["keytar"]) {
|
||||
if (!existsSync(baseDir)) return;
|
||||
const dirs = readdirSync(baseDir);
|
||||
for (const dir of dirs) {
|
||||
if (dir.startsWith("better-sqlite3") || dir.startsWith("keytar")) {
|
||||
if (prefixes.some((p) => dir.startsWith(p))) {
|
||||
const fullPath = join(baseDir, dir);
|
||||
rmSync(fullPath, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Electron-UNIQUE: rebuild better-sqlite3 against the Electron ABI --------
|
||||
//
|
||||
// The `npm ci` at the repo root compiles better-sqlite3 for the CI *Node* ABI
|
||||
// (e.g. 137 for Node 24). The packaged app runs its Next.js server via
|
||||
// ELECTRON_RUN_AS_NODE, so it needs the *Electron* ABI (146 for electron 42,
|
||||
// 148 for electron 43). We cannot rely on electron-builder's @electron/rebuild
|
||||
// here: it searches `electron/node_modules` (where better-sqlite3 does not live)
|
||||
// and, with the default prebuild path, tries to fetch a prebuilt binary — but
|
||||
// better-sqlite3@12.11.1 only ships prebuilds up to electron-v146, so electron
|
||||
// 43 (v148) silently gets no rebuild and the app dies with "Nenhum driver
|
||||
// SQLite disponível — better-sqlite3 (falhou)".
|
||||
//
|
||||
// Instead we copy the *full* module (source + binding.gyp) from the root into
|
||||
// the standalone and compile it from source against the Electron headers, so
|
||||
// `bindings` finds a correct build/Release/better_sqlite3.node regardless of
|
||||
// prebuild availability. Robust to any current/future electron version.
|
||||
|
||||
function readElectronVersion() {
|
||||
const pkg = JSON.parse(readFileSync(join(ROOT, "electron", "package.json"), "utf8"));
|
||||
const raw = pkg.devDependencies?.electron || pkg.dependencies?.electron || "";
|
||||
return String(raw).replace(/^[\^~]/, "");
|
||||
}
|
||||
|
||||
function rebuildBetterSqlite3ForElectron(standaloneNodeModules) {
|
||||
const srcMod = join(ROOT, "node_modules", "better-sqlite3");
|
||||
if (!existsSync(srcMod)) {
|
||||
console.warn("[electron] better-sqlite3 not found at repo root — skipping ABI rebuild.");
|
||||
return;
|
||||
}
|
||||
const electronVersion = readElectronVersion();
|
||||
if (!electronVersion) {
|
||||
throw new Error("[electron] could not resolve electron version for better-sqlite3 rebuild.");
|
||||
}
|
||||
const destMod = join(standaloneNodeModules, "better-sqlite3");
|
||||
// copyNatives only copies build/; we need the full module (src + binding.gyp)
|
||||
// to compile from source. Overwrite the copied Node-ABI build in the process.
|
||||
cpSync(srcMod, destMod, { recursive: true, force: true });
|
||||
rmSync(join(destMod, "build"), { recursive: true, force: true });
|
||||
|
||||
console.log(`[electron] rebuilding better-sqlite3 against electron ${electronVersion} ABI…`);
|
||||
const result = spawnSync(
|
||||
process.platform === "win32" ? "npx.cmd" : "npx",
|
||||
["--yes", "node-gyp", "rebuild"],
|
||||
{
|
||||
cwd: destMod,
|
||||
stdio: "inherit",
|
||||
// Compile against the Electron headers (not Node's) so the .node lands in
|
||||
// build/Release with the Electron NODE_MODULE_VERSION. No shell interpolation.
|
||||
env: {
|
||||
...process.env,
|
||||
npm_config_runtime: "electron",
|
||||
npm_config_target: electronVersion,
|
||||
npm_config_disturl: "https://electronjs.org/headers",
|
||||
npm_config_arch: process.arch,
|
||||
npm_config_build_from_source: "true",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (result.status !== 0) {
|
||||
throw new Error(
|
||||
`[electron] better-sqlite3 rebuild against electron ${electronVersion} failed (exit ${result.status}).`
|
||||
);
|
||||
}
|
||||
// Drop the now-unneeded compile inputs to keep the packaged app lean.
|
||||
for (const dir of ["deps", "src", "build/Debug", "build/obj.target"]) {
|
||||
rmSync(join(destMod, dir), { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function logContextualError(error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
console.error(`[electron] failed to prepare standalone bundle: ${message}`);
|
||||
@@ -108,9 +178,17 @@ assembleStandalone({
|
||||
// Electron-UNIQUE post-assembly steps
|
||||
removeGeneratedElectronArtifacts();
|
||||
|
||||
// Strip better-sqlite3 and keytar so electron-builder rebuilds them against Electron ABI
|
||||
removeNativeModules(join(ELECTRON_STANDALONE_DIR, "node_modules"));
|
||||
removeNativeModules(join(ELECTRON_STANDALONE_DIR, ".next", "node_modules"));
|
||||
// Rebuild better-sqlite3 from source against the Electron ABI in the primary
|
||||
// node_modules (where the standalone server resolves it). keytar is still
|
||||
// stripped so electron-builder's @electron/rebuild handles it (it has electron
|
||||
// prebuilds); also drop any stray Node-ABI better-sqlite3 under .next/node_modules
|
||||
// so it cannot shadow the rebuilt one.
|
||||
rebuildBetterSqlite3ForElectron(join(ELECTRON_STANDALONE_DIR, "node_modules"));
|
||||
removeNativeModules(join(ELECTRON_STANDALONE_DIR, "node_modules"), ["keytar"]);
|
||||
removeNativeModules(join(ELECTRON_STANDALONE_DIR, ".next", "node_modules"), [
|
||||
"better-sqlite3",
|
||||
"keytar",
|
||||
]);
|
||||
|
||||
console.log(
|
||||
`[electron] prepared standalone bundle: ${relative(ROOT, ELECTRON_STANDALONE_DIR) || "."}`
|
||||
|
||||
@@ -105,3 +105,66 @@ describe("proxyDispatcher connection pool", () => {
|
||||
assert.equal(closeCount, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("proxyDispatcher CONNECT tunneling (undici 8.6+ proxyTunnel)", () => {
|
||||
it("tunnels a plain-HTTP proxied request via CONNECT, not origin-forwarding", async () => {
|
||||
const http = await import("node:http");
|
||||
const net = await import("node:net");
|
||||
const { createProxyDispatcher } = await import("../../open-sse/utils/proxyDispatcher.ts");
|
||||
const { fetch: undiciFetch } = await import("undici");
|
||||
|
||||
// Upstream HTTP target.
|
||||
const target = http.createServer((_req, res) => {
|
||||
res.writeHead(200);
|
||||
res.end("ok");
|
||||
});
|
||||
await new Promise((r) => target.listen(0, r));
|
||||
const targetPort = (target.address() as { port: number }).port;
|
||||
|
||||
// Proxy that ONLY speaks CONNECT: 501 on a forwarded origin request, tunnels on CONNECT.
|
||||
let sawConnect = false;
|
||||
let sawForward = false;
|
||||
const proxy = http.createServer((_req, res) => {
|
||||
sawForward = true;
|
||||
res.writeHead(501);
|
||||
res.end("CONNECT only");
|
||||
});
|
||||
proxy.on("connect", (req, socket) => {
|
||||
sawConnect = true;
|
||||
const [host, port] = String(req.url).split(":");
|
||||
const upstream = net.connect(Number(port), host, () => {
|
||||
socket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
||||
upstream.pipe(socket);
|
||||
socket.pipe(upstream);
|
||||
});
|
||||
upstream.on("error", () => socket.destroy());
|
||||
});
|
||||
await new Promise((r) => proxy.listen(0, r));
|
||||
const proxyPort = (proxy.address() as { port: number }).port;
|
||||
|
||||
try {
|
||||
const dispatcher = createProxyDispatcher(`http://127.0.0.1:${proxyPort}`);
|
||||
const res = await undiciFetch(`http://127.0.0.1:${targetPort}/token`, {
|
||||
method: "POST",
|
||||
// @ts-expect-error undici dispatcher option
|
||||
dispatcher,
|
||||
signal: AbortSignal.timeout(3000),
|
||||
});
|
||||
assert.equal(res.status, 200, "request must succeed via CONNECT tunnel");
|
||||
assert.equal(
|
||||
sawConnect,
|
||||
true,
|
||||
"proxy must receive a CONNECT (tunnel), not a forwarded request"
|
||||
);
|
||||
assert.equal(
|
||||
sawForward,
|
||||
false,
|
||||
"proxy must NOT receive a forwarded origin request (undici 8.6+ regression)"
|
||||
);
|
||||
} finally {
|
||||
proxy.close();
|
||||
target.close();
|
||||
clearDispatcherCache();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user