mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-15 03:12:36 +03:00
Validado sobre o tip de `release/v3.8.51` depois de reconciliar com o #12620, que entrou primeiro nesta mesma sessão e ataca a mesma classe de problema por outra arquitetura. **A colisão e como foi resolvida.** O #12620 consertou o GHSA-qv45-56jc-4wmj adicionando `RAW_CREDENTIAL_PATTERNS` a `error.ts` e importando-os em `upstreamErrorPassthrough.ts`. Este PR resolve o mesmo problema quebrando `error.ts` em `errorSanitization.ts` + `errorPathRedaction.ts`. Mantive a divisão em módulos deste PR, porque ao comparar os dois vocabulários o dele já era mais amplo: o `STRONG_CREDENTIAL_TOKEN` daqui cobre `sk-`/`sk_` **com lookbehind e uma variante para a forma embutida** (que pega `sk-proj-…`), mais Slack `xox-`, AWS `AKIA`/`ASIA`, `github_pat_`/`ghp_`/`glpat-` e JWT de três segmentos. A única forma que o #12620 carregava e este conjunto não tinha era a chave do Google (`AIza…`) — adicionada aqui, com o mesmo quantificador limitado que os irmãos usam (AGENTS.md → PII §1, já que isso roda sobre corpos upstream não confiáveis). **A verificação não foi por inspeção.** Rodei as suítes do próprio #12620 contra esta estrutura: **48/48** em `error-sanitizer-sk-key-qv45`, `bifrost-relay-response-leak-9m72`, `search-baseurl-client-override-3f8g` e `search-baseurl-ssrf-guard` — incluindo a asserção anti-drift daquela suíte, que é o oráculo certo aqui: *para todo corpo que a camada de passthrough recusa como vazante, o sanitizador de fallback não pode devolvê-lo intacto*. Ela passa, então a propriedade de segurança dos três GHSAs sobrevive à troca de arquitetura. Os 21 arquivos de teste deste PR: **259/259**. `typecheck:core` limpo.
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { spawnSync } from "node:child_process";
|
|
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const REPO_ROOT = fileURLToPath(new URL("../../..", import.meta.url));
|
|
const CHILD_PATH = "/usr/local/bin:/usr/bin:/bin";
|
|
const CHILD_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
|
|
type IsolatedBoundaryFixtureOptions = {
|
|
fixtureUrl: URL;
|
|
expectedTests: number;
|
|
label: string;
|
|
timeoutMs?: number;
|
|
};
|
|
|
|
export function runIsolatedBoundaryFixture({
|
|
fixtureUrl,
|
|
expectedTests,
|
|
label,
|
|
timeoutMs = 180_000,
|
|
}: IsolatedBoundaryFixtureOptions): void {
|
|
const root = mkdtempSync(join(tmpdir(), "omniroute-public-error-child-"));
|
|
const dataDir = join(root, "data");
|
|
const pluginsDir = join(root, "plugins");
|
|
mkdirSync(dataDir, { recursive: true });
|
|
mkdirSync(pluginsDir, { recursive: true });
|
|
|
|
try {
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
["--import", "tsx/esm", "--test", "--test-reporter=tap", fileURLToPath(fixtureUrl)],
|
|
{
|
|
cwd: REPO_ROOT,
|
|
encoding: "utf8",
|
|
env: {
|
|
APP_LOG_TO_FILE: "false",
|
|
API_KEY_SECRET: "public-error-boundary-fixture-secret",
|
|
DATA_DIR: dataDir,
|
|
DISABLE_SQLITE_AUTO_BACKUP: "true",
|
|
LANG: "C.UTF-8",
|
|
LC_ALL: "C.UTF-8",
|
|
NODE_ENV: "test",
|
|
OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK: "true",
|
|
OMNIROUTE_PLUGINS_DIR: pluginsDir,
|
|
PATH: CHILD_PATH,
|
|
TZ: "UTC",
|
|
},
|
|
maxBuffer: CHILD_MAX_BUFFER_BYTES,
|
|
timeout: timeoutMs,
|
|
}
|
|
);
|
|
const diagnostics = [
|
|
`${label} child status=${String(result.status)} signal=${String(result.signal)}`,
|
|
result.error ? `error=${String(result.error)}` : "",
|
|
`stdout:\n${result.stdout}`,
|
|
`stderr:\n${result.stderr}`,
|
|
]
|
|
.filter(Boolean)
|
|
.join("\n");
|
|
|
|
assert.equal(result.error, undefined, diagnostics);
|
|
assert.equal(result.signal, null, diagnostics);
|
|
assert.equal(result.status, 0, diagnostics);
|
|
assert.match(result.stdout, new RegExp(`# tests ${expectedTests}(?:\\r?\\n|$)`), diagnostics);
|
|
assert.match(result.stdout, new RegExp(`# pass ${expectedTests}(?:\\r?\\n|$)`), diagnostics);
|
|
assert.match(result.stdout, /# fail 0(?:\r?\n|$)/, diagnostics);
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
}
|
|
}
|