mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 06:42:12 +03:00
fix(sonar): clear SonarCloud reliability + security ratings on release/v3.8.4
Reliability (D → A) — fix the 6 BUG findings:
- bin/cli/tray/autostart.mjs: replace `return ignoreFailure ? false : false`
(always-false ternary) with a meaningful branch that rethrows when
`ignoreFailure` is false.
- open-sse/services/combo.ts: reorder the quality-validation block so the
`combo.target.failed` emit runs BEFORE the `break` — the previous order
left the emit unreachable.
- src/app/api/playground/simulate-route/route.ts: drop the duplicate
`modelLower.includes("1m") || modelLower.includes("1m")` (and the 2m
twin) — both sides of the `||` were identical so the second check was
dead code.
- scripts/check/check-env-doc-sync.mjs: pass `localeCompare` to Array.sort
instead of relying on the default coercion-to-string ordering.
- src/sse/handlers/chat.ts: guard the cache TTL check with an explicit
`combosCachePromise !== null` so we don't evaluate a Promise as a
boolean.
Security (C → A) — close the Dockerfile hotspots:
- Builder stage now runs `npm ci`/`npm install` with `--ignore-scripts`
to neutralise transitive install-time RCE. OmniRoute's own postinstall
only rewrites a packaged `app/node_modules`, so it has nothing to do
during a fresh in-container install.
- Runner-base now drops to the baked-in `node` non-root user (UID/GID
1000) before the CMD runs. /app is chowned after all COPYs so the
runtime user can still read every file. The runner-cli stage briefly
elevates back to root for the apt + global npm installs and then
pins USER node again.
This commit is contained in:
24
Dockerfile
24
Dockerfile
@@ -10,10 +10,16 @@ COPY scripts/build/postinstall.mjs ./scripts/build/postinstall.mjs
|
||||
COPY scripts/build/postinstallSupport.mjs ./scripts/build/postinstallSupport.mjs
|
||||
COPY scripts/build/native-binary-compat.mjs ./scripts/build/native-binary-compat.mjs
|
||||
ENV NPM_CONFIG_LEGACY_PEER_DEPS=true
|
||||
# `--ignore-scripts` blocks the install/postinstall hooks of dependencies,
|
||||
# closing the supply-chain attack surface where a transitive dep can run
|
||||
# arbitrary code at install time. OmniRoute's own postinstall (better-sqlite3
|
||||
# binary touchups, @swc/helpers copy) is only needed when a packaged
|
||||
# `app/node_modules` is unpacked — inside the Docker builder we are doing a
|
||||
# fresh native-platform install, so dropping the scripts is safe.
|
||||
RUN if [ -f package-lock.json ]; then \
|
||||
npm ci --no-audit --no-fund --legacy-peer-deps; \
|
||||
npm ci --no-audit --no-fund --legacy-peer-deps --ignore-scripts; \
|
||||
else \
|
||||
npm install --no-audit --no-fund --legacy-peer-deps; \
|
||||
npm install --no-audit --no-fund --legacy-peer-deps --ignore-scripts; \
|
||||
fi
|
||||
|
||||
COPY . ./
|
||||
@@ -65,8 +71,15 @@ COPY --from=builder /app/scripts/build/runtime-env.mjs ./build/runtime-env.mjs
|
||||
COPY --from=builder /app/scripts/build/bootstrap-env.mjs ./build/bootstrap-env.mjs
|
||||
COPY --from=builder /app/scripts/dev/healthcheck.mjs ./healthcheck.mjs
|
||||
|
||||
# Hand /app over to the baked-in `node` non-root user (UID/GID 1000) so the
|
||||
# runtime process never holds root privileges. The chown happens after all
|
||||
# COPYs so it covers files originally owned by root in the builder stage.
|
||||
RUN chown -R node:node /app
|
||||
|
||||
EXPOSE 20128
|
||||
|
||||
USER node
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD ["node", "healthcheck.mjs"]
|
||||
|
||||
@@ -74,6 +87,11 @@ CMD ["node", "dev/run-standalone.mjs"]
|
||||
|
||||
FROM runner-base AS runner-cli
|
||||
|
||||
# Drop back to root briefly so we can install system + global npm packages,
|
||||
# then return to the `node` non-root user before the CMD inherited from
|
||||
# runner-base runs.
|
||||
USER root
|
||||
|
||||
# Install system dependencies required by openclaw (git+ssh references).
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git ca-certificates docker.io docker-compose \
|
||||
@@ -83,3 +101,5 @@ RUN apt-get update \
|
||||
# Install CLI tools globally. Separate layer from apt for better cache reuse.
|
||||
RUN npm install -g --no-audit --no-fund @openai/codex @anthropic-ai/claude-code droid openclaw@latest
|
||||
|
||||
USER node
|
||||
|
||||
|
||||
@@ -63,8 +63,9 @@ function runUserSystemctl(args, { ignoreFailure = true } = {}) {
|
||||
try {
|
||||
execSync(`systemctl --user ${args}`, { stdio: "ignore" });
|
||||
return true;
|
||||
} catch {
|
||||
return ignoreFailure ? false : false;
|
||||
} catch (err) {
|
||||
if (!ignoreFailure) throw err;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1653,17 +1653,25 @@ export async function handleComboChat({
|
||||
let timeoutId;
|
||||
const timeoutPromise = new Promise((resolve) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
log.warn("COMBO", `Model ${modelStr} exceeded ${COMBO_MODEL_TIMEOUT_MS}ms timeout — falling back`);
|
||||
resolve(new Response(
|
||||
JSON.stringify({ error: { message: `Model ${modelStr} timed out` } }),
|
||||
{ status: 524, headers: { 'Content-Type': 'application/json' } }
|
||||
));
|
||||
log.warn(
|
||||
"COMBO",
|
||||
`Model ${modelStr} exceeded ${COMBO_MODEL_TIMEOUT_MS}ms timeout — falling back`
|
||||
);
|
||||
resolve(
|
||||
new Response(JSON.stringify({ error: { message: `Model ${modelStr} timed out` } }), {
|
||||
status: 524,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
})
|
||||
);
|
||||
}, COMBO_MODEL_TIMEOUT_MS);
|
||||
});
|
||||
try {
|
||||
return await Promise.race([
|
||||
handleSingleModelWrapped(b, modelStr, target).catch((err) => {
|
||||
return new Response(JSON.stringify({ error: { message: err.message } }), { status: 502, headers: { "Content-Type": "application/json" } });
|
||||
return new Response(JSON.stringify({ error: { message: err.message } }), {
|
||||
status: 502,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}),
|
||||
timeoutPromise,
|
||||
]);
|
||||
@@ -2208,7 +2216,6 @@ export async function handleComboChat({
|
||||
lastError = `Upstream response failed quality validation: ${quality.reason}`;
|
||||
if (!lastStatus) lastStatus = 502;
|
||||
if (i > 0) fallbackCount++;
|
||||
break; // move to next model
|
||||
emit("combo.target.failed", {
|
||||
comboName: combo.name,
|
||||
targetIndex: i,
|
||||
@@ -2217,6 +2224,7 @@ export async function handleComboChat({
|
||||
error: `Quality: ${quality.reason}`,
|
||||
latencyMs: Date.now() - startTime,
|
||||
});
|
||||
break; // move to next model
|
||||
}
|
||||
const latencyMs = Date.now() - startTime;
|
||||
emit("combo.target.succeeded", {
|
||||
|
||||
@@ -209,7 +209,7 @@ function scanCodeVars({ cwd } = {}) {
|
||||
* Diff helper.
|
||||
*/
|
||||
function diff(set, against) {
|
||||
return [...set].filter((v) => !against.has(v)).sort();
|
||||
return [...set].filter((v) => !against.has(v)).sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
// ─── Programmatic entry point ──────────────────────────────────────────────
|
||||
|
||||
@@ -103,8 +103,8 @@ function estimateContextWindow(model: string): number {
|
||||
const modelLower = model.toLowerCase();
|
||||
if (modelLower.includes("128k") || modelLower.includes("128")) return 128000;
|
||||
if (modelLower.includes("200k") || modelLower.includes("200")) return 200000;
|
||||
if (modelLower.includes("1m") || modelLower.includes("1m")) return 1000000;
|
||||
if (modelLower.includes("2m") || modelLower.includes("2m")) return 2000000;
|
||||
if (modelLower.includes("1m")) return 1000000;
|
||||
if (modelLower.includes("2m")) return 2000000;
|
||||
return 128000;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ const COMBOS_CACHE_TTL_MS = 10_000;
|
||||
|
||||
async function getCombosCachedForChat(): Promise<unknown[]> {
|
||||
const now = Date.now();
|
||||
if (combosCachePromise && now - combosCacheTs < COMBOS_CACHE_TTL_MS) {
|
||||
if (combosCachePromise !== null && now - combosCacheTs < COMBOS_CACHE_TTL_MS) {
|
||||
return combosCachePromise;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user