Files
openrusrouter-mcp/test/redact.test.ts
T
vasyanskandClaude Opus 5.5 ade6eb82df Заведи каркас пакета и утилитный слой MCP-сервера
package.json, tsconfig, eslint, генерация типов из OpenAPI-спеки,
модули config/redact/errors/money/sanitize/cache с тестами и
обезличенные фикстуры живых ответов API openrusrouter.ru.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:48:00 +07:00

73 lines
2.8 KiB
TypeScript

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}`))));
});