78 lines
6.4 KiB
TypeScript
78 lines
6.4 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import { test } from "node:test"
|
|
import { DatabaseError } from "pg"
|
|
import { capturePollError, carryCapturedPollError, carryPollError, pollErrorLog, tagPollProbeGuard } from "./server-poll-error-provenance.js"
|
|
const id = "11111111-1111-4111-8111-111111111111"
|
|
|
|
test("genuine PG origin survives replacements without changing public error identity or properties", () => {
|
|
const original = new DatabaseError("PRIVATE SQL/password", 1, "error"); original.code = "57014"
|
|
const replacement = Object.assign(new Error("same public message"), { code: "STATE_UNAVAILABLE", statusCode: 503 })
|
|
const before = Object.getOwnPropertyDescriptors(replacement), json = JSON.stringify(replacement)
|
|
assert.equal(carryPollError(replacement, original, "probe.query"), replacement)
|
|
assert.deepEqual(Object.getOwnPropertyDescriptors(replacement), before); assert.equal(JSON.stringify(replacement), json)
|
|
const final = carryPollError(new Error("same final"), replacement, "poll.safe")
|
|
const record = pollErrorLog(final, id, "servers.poll")!
|
|
assert.equal(record.provenance.origin.sqlState, "57014"); assert.deepEqual(record.provenance.sites, ["probe.query", "poll.safe"])
|
|
assert(!JSON.stringify(record).includes("PRIVATE")); assert(!JSON.stringify(record).includes("password"))
|
|
})
|
|
test("unknown SQLSTATE and inherited/non-driver codes never become SQL provenance", () => {
|
|
const pg = new DatabaseError("private", 1, "error"); pg.code = "ZZ999"
|
|
assert.equal(capturePollError(pg).origin.sqlState, null)
|
|
assert.equal(capturePollError(Object.assign(new Error(), { code: "57014" })).origin.sqlState, null)
|
|
assert.equal(capturePollError(Object.assign(new Error(), { code: "ETIMEDOUT" })).origin.nodeCategory, "timeout")
|
|
})
|
|
test("malicious getters/proxies are unread and cannot replace a new error or leak raw fields", () => {
|
|
let calls = 0; const original = new Error()
|
|
for (const name of ["code", "message", "stack", "cause"]) Object.defineProperty(original, name, { get() { calls++; throw Error("secret") } })
|
|
const target = new Error("public")
|
|
assert.equal(carryPollError(target, original, "probe.query"), target); assert.equal(calls, 0)
|
|
const proxy = new Proxy({}, { getOwnPropertyDescriptor() { calls++; throw Error("secret") }, getPrototypeOf() { calls++; throw Error("secret") } })
|
|
assert.equal(carryPollError(new Error(), proxy, "poll.safe") instanceof Error, true); assert.equal(calls, 0)
|
|
assert(!JSON.stringify(pollErrorLog(target, id, "servers.poll")).includes("secret"))
|
|
})
|
|
test("only a trusted Poll operation type formats an event; shared Probe metadata alone is silent", () => {
|
|
const error = carryPollError(new Error(), Object.assign(new Error(), { code: "ECONNRESET" }), "probe.query")
|
|
assert.equal(pollErrorLog(error, id, "wireguard.export"), null); assert.equal(pollErrorLog(error, id, "ipsec.create"), null)
|
|
assert.equal(pollErrorLog(error, "invalid", "servers.poll"), null); assert.equal(pollErrorLog(new Error(), id, "servers.poll"), null)
|
|
assert.equal(pollErrorLog(error, id, "servers.poll")?.operationId, id)
|
|
})
|
|
test("closed captured native provenance has no raw error and chains stay <=8 and <=1KiB", () => {
|
|
const original = Object.assign(new Error("RAW native/URL"), { code: "EPIPE" })
|
|
let error = carryCapturedPollError(new Error(), capturePollError(original), "native.fence")
|
|
for (let i = 0; i < 20; i++) error = carryPollError(new Error(), error, "poll.safe")
|
|
const result = pollErrorLog(error, id, "servers.poll")!
|
|
assert.equal(result.provenance.sites.length, 8); assert.equal(result.provenance.truncated, true)
|
|
assert.equal(result.provenance.origin.nodeCategory, "pipe"); assert(Buffer.byteLength(JSON.stringify(result)) <= 1024)
|
|
assert(!JSON.stringify(result).includes("RAW")); assert(!Object.hasOwn(error, "cause")); assert(Object.isFrozen(result.provenance.origin))
|
|
})
|
|
test("forged captured extras are not spread into logs and projection failure leaves original throw untouched", () => {
|
|
const target = new Error("original")
|
|
const proxy = new Proxy({}, { getOwnPropertyDescriptor() { throw Error("private") } })
|
|
assert.equal(carryCapturedPollError(target, proxy as never, "poll.safe"), target)
|
|
assert.doesNotThrow(() => pollErrorLog(proxy, id, "servers.poll"))
|
|
const fake = { version: 1, origin: { kind: "pg", sqlState: "SECRET", nodeCategory: "secret", raw: "PRIVATE" }, sites: ["poll.safe"], truncated: false, message: "PRIVATE" }
|
|
const result = pollErrorLog(carryCapturedPollError(new Error(), fake as never, "poll.safe"), id, "servers.poll")!
|
|
assert.equal(result.provenance.origin.sqlState, null); assert(!JSON.stringify(result).includes("PRIVATE")); assert(!JSON.stringify(result).includes("SECRET"))
|
|
})
|
|
|
|
test("probe guard closed projection survives full chain; raw fields/getters/proxies cannot enter stderr",()=>{
|
|
let calls=0;const target=new Error("public"),before=Object.getOwnPropertyDescriptors(target)
|
|
const detail={phase:"query",queryKind:"principal",branch:"driver-reject",raw:"NEVER_PRIVATE",message:"NEVER_PRIVATE"}
|
|
tagPollProbeGuard(target,Error("NEVER_PRIVATE password query"),detail as never)
|
|
assert.deepEqual(Object.getOwnPropertyDescriptors(target),before)
|
|
const final=carryPollError(new Error(),target,"poll.safe"),log=pollErrorLog(final,id,"servers.poll")!
|
|
assert.deepEqual(log.provenance.probe,{phase:"query",queryKind:"principal",branch:"driver-reject"});assert(Object.isFrozen(log.provenance.probe))
|
|
assert(!JSON.stringify(log).includes("NEVER_PRIVATE"));assert(Buffer.byteLength(JSON.stringify(log))<=1024)
|
|
const hostile=Object.defineProperty({},"branch",{get(){calls++;throw Error("NEVER_PRIVATE")}})
|
|
assert.equal(tagPollProbeGuard(target,undefined,hostile as never),target)
|
|
const proxy=new Proxy({},{getOwnPropertyDescriptor(){calls++;throw Error("NEVER_PRIVATE")}})
|
|
assert.equal(tagPollProbeGuard(target,undefined,proxy as never),target);assert.equal(calls,0)
|
|
})
|
|
test("forged probe enum and unknown phase are omitted rather than interpreted",()=>{
|
|
for(const probe of [{phase:"query",queryKind:"SECRET",branch:"driver-reject"},{phase:"SECRET",queryKind:"meta",branch:"abort"},{phase:"query",queryKind:"commit",branch:"SECRET"}]){
|
|
const captured={version:1,origin:{kind:"other",sqlState:null,nodeCategory:null},sites:[],truncated:false,probe}
|
|
const final=carryCapturedPollError(new Error(),captured as never,"poll.safe"),log=pollErrorLog(final,id,"servers.poll")!
|
|
assert.equal(log.provenance.probe,undefined);assert(!JSON.stringify(log).includes("SECRET"))
|
|
}
|
|
})
|