mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +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.
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
type JsonRecord = Record<string, unknown>;
|
|
|
|
export type ResponsesFailureOutputStringField = "id" | "text" | "refusal";
|
|
|
|
export type ResponsesFailureOutputStringProjector = (
|
|
field: ResponsesFailureOutputStringField,
|
|
value: string
|
|
) => string;
|
|
|
|
function asRecord(value: unknown): JsonRecord {
|
|
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
|
|
}
|
|
|
|
/**
|
|
* Retain only public assistant text/refusal output from a failed Responses payload.
|
|
* Failure envelopes may contain reasoning, tool arguments, annotations, commentary,
|
|
* or provider diagnostics, so every retained field is reconstructed explicitly.
|
|
*/
|
|
export function projectResponsesFailureOutput(
|
|
value: unknown,
|
|
projectString: ResponsesFailureOutputStringProjector
|
|
): JsonRecord[] {
|
|
if (!Array.isArray(value)) return [];
|
|
|
|
const output: JsonRecord[] = [];
|
|
for (const item of value) {
|
|
const record = asRecord(item);
|
|
if (record.type !== "message" || record.role !== "assistant" || record.phase === "commentary") {
|
|
continue;
|
|
}
|
|
|
|
const content: JsonRecord[] = [];
|
|
if (Array.isArray(record.content)) {
|
|
for (const part of record.content) {
|
|
const contentPart = asRecord(part);
|
|
if (contentPart.phase === "commentary") continue;
|
|
if (contentPart.type === "output_text" && typeof contentPart.text === "string") {
|
|
content.push({
|
|
type: "output_text",
|
|
text: projectString("text", contentPart.text),
|
|
// Preserve the required Responses schema without forwarding any
|
|
// untrusted citation/file metadata supplied by the provider.
|
|
annotations: [],
|
|
});
|
|
} else if (contentPart.type === "refusal" && typeof contentPart.refusal === "string") {
|
|
content.push({
|
|
type: "refusal",
|
|
refusal: projectString("refusal", contentPart.refusal),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
const projected: JsonRecord = {
|
|
type: "message",
|
|
role: "assistant",
|
|
content,
|
|
};
|
|
if (typeof record.id === "string") projected.id = projectString("id", record.id);
|
|
if (
|
|
record.status === "in_progress" ||
|
|
record.status === "completed" ||
|
|
record.status === "incomplete"
|
|
) {
|
|
projected.status = record.status;
|
|
}
|
|
output.push(projected);
|
|
}
|
|
return output;
|
|
}
|