import { test } from "node:test"; import assert from "node:assert/strict"; import { redactError, redactString } from "../src/redact.js"; import { ApiError, toToolErrorResult } from "../src/errors.js"; const KEY = "orr_live_AbCdEf0123456789GhIjKlMnOpQrStUv"; function assertClean(serialized: string): void { assert.ok(!serialized.includes(KEY), serialized); assert.ok(!serialized.includes(`Bearer ${KEY}`), serialized); assert.ok(!serialized.includes(KEY.slice(9)), serialized); } test("redactString маскирует Bearer и ключи", () => { const out = redactString(`Authorization: Bearer ${KEY}; ключ=${KEY}; x${KEY}`); assertClean(out); assert.match(out, /Bearer \[REDACTED\]/); }); test("ключ в message", () => { const e = new Error(`request failed for ${KEY}`); assertClean(JSON.stringify(redactError(e))); }); test("ключ в cause.message не протекает", () => { const e = new Error("outer", { cause: new Error(`inner Bearer ${KEY}`) }); const r = redactError(e); assertClean(JSON.stringify(r)); assert.equal(r.message, "outer"); }); test("headers/config/request/stack не копируются", () => { const e = Object.assign(new Error("boom"), { status: 401, code: "invalid_key", path: "/api/balance", headers: { Authorization: `Bearer ${KEY}` }, config: { headers: { Authorization: `Bearer ${KEY}` } }, request: { auth: KEY }, }); e.stack = `Error: ${KEY}\n at x`; const r = redactError(e); assertClean(JSON.stringify(r)); assert.deepEqual(Object.keys(r).sort(), ["code", "message", "name", "path", "status"]); assert.equal(r.status, 401); }); test("произвольные значения", () => { assertClean(JSON.stringify(redactError(`string ${KEY}`))); assertClean(JSON.stringify(redactError({ message: `obj ${KEY}`, headers: { a: KEY } }))); assert.equal(redactError(null).message, "неизвестная ошибка"); assert.equal(redactError(42).message, "неизвестная ошибка"); }); test("toToolErrorResult маппит статусы и редактирует текст", () => { const cases: Array<[number, RegExp]> = [ [401, /недействителен или отозван/], [403, /запрещено/], [429, /лимит частоты/], [503, /временно недоступен/], ]; for (const [status, re] of cases) { const r = toToolErrorResult(new ApiError(status, "/api/balance", `oops ${KEY}`)); assert.equal(r.isError, true); assert.match(r.content[0].text, re); assertClean(JSON.stringify(r)); } const other = toToolErrorResult(new ApiError(400, "/api/usage", `bad Bearer ${KEY}`)); assert.match(other.content[0].text, /bad Bearer \[REDACTED\]/); assertClean(JSON.stringify(other)); assertClean(JSON.stringify(toToolErrorResult(new Error(`plain ${KEY}`)))); });