harden(authority): add pre-scale diagnostics and request safety

This commit is contained in:
Youzini-afk
2026-04-28 22:28:21 +08:00
parent aa62efe5b9
commit 2dee3cd8ff
9 changed files with 644 additions and 49 deletions

View File

@@ -260,6 +260,18 @@ async function testAdapterBasics() {
assert.deepEqual(readResult.payload, { hello: "world" });
const deleteResult = await adapter.delete("user/files/demo.json");
assert.equal(deleteResult.deleted, true);
await assert.rejects(
() => adapter.writeJson("../secret.json", {}),
/Unsafe Authority Blob path/,
);
await assert.rejects(
() => adapter.readJson("user/files/%2e%2e/secret.json"),
/Unsafe Authority Blob path/,
);
await assert.rejects(
() => adapter.stat("C:/Users/demo.json"),
/Unsafe Authority Blob path/,
);
}
async function testAuthorityBlobFailOpenFallsBackToUserFiles() {

View File

@@ -0,0 +1,103 @@
import assert from "node:assert/strict";
import {
AUTHORITY_SESSION_HEADER,
AuthorityHttpClient,
AuthorityHttpError,
} from "../runtime/authority-http-client.js";
function jsonResponse(status, payload) {
return {
ok: status >= 200 && status < 300,
status,
headers: {
get(name) {
return String(name || "").toLowerCase() === "content-type" ? "application/json" : "";
},
},
async json() {
return payload;
},
};
}
{
const calls = [];
const client = new AuthorityHttpClient({
baseUrl: "https://authority.example.test/root",
fetchImpl: async (url, options = {}) => {
calls.push({ url, options });
if (url.endsWith("/session/init") && calls.filter((call) => call.url.endsWith("/session/init")).length === 1) {
return jsonResponse(200, { sessionToken: "old-session" });
}
if (url.endsWith("/session/init")) {
return jsonResponse(200, { sessionToken: "new-session" });
}
if (url.endsWith("/data") && options.headers?.[AUTHORITY_SESSION_HEADER] === "old-session") {
return jsonResponse(401, { code: "session-expired", message: "session expired" });
}
if (url.endsWith("/data") && options.headers?.[AUTHORITY_SESSION_HEADER] === "new-session") {
return jsonResponse(200, { ok: true, value: 42 });
}
return jsonResponse(500, { error: "unexpected" });
},
});
const result = await client.requestJson("/data", { session: true, body: { q: 1 } });
assert.deepEqual(result, { ok: true, value: 42 });
assert.deepEqual(
calls.map((call) => [call.url, call.options.headers?.[AUTHORITY_SESSION_HEADER] || ""]),
[
["https://authority.example.test/root/session/init", ""],
["https://authority.example.test/root/data", "old-session"],
["https://authority.example.test/root/session/init", ""],
["https://authority.example.test/root/data", "new-session"],
],
);
}
{
const calls = [];
const client = new AuthorityHttpClient({
baseUrl: "https://authority.example.test/root",
fetchImpl: async (url, options = {}) => {
calls.push({ url, options });
if (url.endsWith("/session/init")) {
return jsonResponse(200, { sessionToken: "permission-session" });
}
return jsonResponse(403, { code: "permission-denied", message: "permission denied" });
},
});
await assert.rejects(
() => client.requestJson("/private", { session: true, body: {} }),
(error) => {
assert.equal(error instanceof AuthorityHttpError, true);
assert.equal(error.status, 403);
assert.equal(error.category, "permission");
return true;
},
);
assert.equal(calls.filter((call) => call.url.endsWith("/session/init")).length, 1);
}
{
const client = new AuthorityHttpClient({
baseUrl: "https://authority.example.test/root",
timeoutMs: 5,
fetchImpl: async (_url, options = {}) => await new Promise((_resolve, reject) => {
options.signal?.addEventListener("abort", () => {
reject(Object.assign(new Error("aborted"), { name: "AbortError" }));
}, { once: true });
}),
});
await assert.rejects(
() => client.requestJson("/slow", { session: false }),
(error) => {
assert.equal(error instanceof AuthorityHttpError, true);
assert.equal(error.category, "timeout");
assert.equal(error.code, "timeout");
return true;
},
);
}
console.log("authority-http-client tests passed");

View File

@@ -135,6 +135,9 @@ assert.equal(submitted.idempotencyKey, idempotencyKey);
const completed = await adapter.waitForCompletion(submitted.id, { timeoutMs: 1000 });
assert.equal(completed.status, "completed");
assert.equal(completed.success, true);
assert.equal(completed.waitDiagnostics.mode, "poll");
assert.equal(completed.waitDiagnostics.pollCount, 1);
assert.equal(completed.waitDiagnostics.terminal, true);
const page = await adapter.listPage({ limit: 10 });
assert.equal(page.jobs.length, 1);
@@ -310,6 +313,36 @@ assert.equal(timedOutJob.status, "timeout");
assert.equal(timedOutJob.terminal, true);
assert.equal(timedOutJob.success, false);
let adapterTimeoutPolls = 0;
const timeoutAdapter = createAuthorityJobAdapter(
{
authorityBaseUrl: "/api/plugins/authority",
authorityJobPollIntervalMs: 1,
authorityJobPollMaxIntervalMs: 2,
authorityJobPollBackoffFactor: 2,
},
{
jobClient: {
async get(payload = {}) {
adapterTimeoutPolls += 1;
return {
job: {
id: payload.jobId,
status: "running",
progress: 0.4,
},
};
},
},
},
);
const adapterTimedOutJob = await timeoutAdapter.waitForCompletion("job-wait-timeout", { timeoutMs: 1 });
assert.equal(adapterTimedOutJob.status, "timeout");
assert.equal(adapterTimedOutJob.waitDiagnostics.mode, "poll");
assert.equal(adapterTimedOutJob.waitDiagnostics.pollCount >= 1, true);
assert.equal(adapterTimedOutJob.waitDiagnostics.lastStatus, "running");
assert.equal(adapterTimeoutPolls >= 1, true);
const streamingClient = {
async streamJob(payload) {
return (async function* () {

View File

@@ -72,7 +72,18 @@ function createMockTriviumClient({ failBulkUpsert = false } = {}) {
calls,
async purge(payload) {
calls.push(["purge", payload]);
return { ok: true };
return {
ok: true,
diagnostics: {
operation: "purge",
pageSize: payload.purgePageSize || 200,
maxPages: payload.purgeMaxPages || 1000,
pages: 1,
scanned: 0,
deleted: 0,
truncated: false,
},
};
},
async bulkUpsert(payload) {
calls.push(["bulkUpsert", payload]);
@@ -174,6 +185,13 @@ assert.equal(isAuthorityVectorConfig(config), true);
const linkCall = triviumClient.calls.find(([name]) => name === "linkMany");
assert.equal(linkCall?.[1]?.links?.[0]?.fromId, "node-a");
assert.equal(linkCall?.[1]?.links?.[0]?.toId, "node-b");
assert.equal(result.timings.authorityDiagnostics.purge.operation, "purge");
assert.equal(result.timings.authorityDiagnostics.upsert.operation, "bulkUpsert");
assert.equal(result.timings.authorityDiagnostics.upsert.chunks.length, 2);
assert.equal(result.timings.authorityDiagnostics.upsert.chunks.every((chunk) => chunk.ok), true);
assert.ok(result.timings.authorityDiagnostics.upsert.totalBytes > 0);
assert.equal(result.timings.authorityDiagnostics.link.operation, "linkMany");
assert.equal(result.timings.authorityDiagnostics.link.totalItems, 1);
}
{
@@ -230,11 +248,15 @@ assert.equal(isAuthorityVectorConfig(config), true);
archived: false,
ownerKeys: ["character:Alice"],
},
candidateIds: ["node-a"],
searchText: "Alice archive",
});
assert.deepEqual(filteredIds, ["node-a", "node-b"]);
const filterCall = triviumClient.calls.find(([name]) => name === "filterWhere");
assert.equal(filterCall?.[1]?.collectionId, "authority-filter");
assert.equal(filterCall?.[1]?.filters?.ownerKeys?.[0], "character:Alice");
assert.deepEqual(filterCall?.[1]?.candidateIds, ["node-a"]);
assert.equal(filterCall?.[1]?.searchText, "Alice archive");
}
{