Files
NetMesh/electron/plugins/extensionProviderService.test.cjs

1085 lines
38 KiB
JavaScript
Raw Normal View History

"use strict";
const assert = require("node:assert/strict");
const test = require("node:test");
const {
PluginExtensionProviderService,
STREAM_WINDOW_BYTES,
} = require("./extensionProviderService.cjs");
function fixture(options = {}) {
const identity = Object.freeze({
pluginId: "com.example.transport",
pluginVersion: "1.0.0",
runtimeId: "runtime-1",
runtimeKind: "browser",
securityPrincipal: "local:com.example.transport",
});
const providers = [
{
id: "com.example.transport.connection",
kind: "connection",
...(options.connectionConfigurationSchema === undefined
? {}
: { configurationSchema: options.connectionConfigurationSchema }),
},
{ id: "com.example.transport.auth", kind: "authentication" },
{ id: "com.example.transport.importer", kind: "importer" },
{
id: "com.example.transport.sync",
kind: "sync",
...(options.syncConfigurationSchema === undefined
? {}
: { configurationSchema: options.syncConfigurationSchema }),
},
];
const contributionService = {
listProviders({ kind }) {
return providers.filter((provider) => provider.kind === kind).map((provider) => ({
pluginId: provider.kind === "connection" && options.connectionOwnerPluginId
? options.connectionOwnerPluginId
: identity.pluginId,
pluginVersion: identity.pluginVersion,
provider,
}));
},
async activateProvider(providerId) {
const provider = providers.find((candidate) => candidate.id === providerId);
if (!provider) throw new Error("missing provider");
return {
plugin: {
id: identity.pluginId,
activeVersion: identity.pluginVersion,
manifest: { id: identity.pluginId },
},
provider,
identity,
};
},
};
const permissions = [];
const permissionEngine = {
async authorize(context, descriptor) {
if (typeof options.authorize === "function") {
return options.authorize(context, descriptor, permissions);
}
permissions.push({ context, descriptor });
return { scope: "application" };
},
};
const streamHandlers = [];
const rpcRegistry = {
registerIncomingStream(handler) { streamHandlers.push(handler); return { dispose() {} }; },
};
const runtimeListeners = [];
const writes = [];
const issuedLeases = [];
const revokedOperations = [];
const leaseStore = {
issue(params) {
issuedLeases.push(params);
return Object.freeze({
kind: "secret-lease",
id: "authentication-secret-lease-000000000001",
operationId: params.operationId,
expiresAt: Date.now() + (params.ttlMs ?? 30_000),
});
},
revokeOperation(pluginId, operationId) { revokedOperations.push({ pluginId, operationId }); },
};
const runtimeSupervisor = {
onDidChangeRuntime(listener) { runtimeListeners.push(listener); return { dispose() {} }; },
async request(pluginId, method, params, requestOptions) {
return options.request({ pluginId, method, params, requestOptions, identity, accept: streamHandlers[0] });
},
async openStream(_pluginId, streamId) {
return {
async write(bytes) { writes.push([streamId, Buffer.from(bytes)]); },
async end() { writes.push([streamId, "end"]); },
cancel() { writes.push([streamId, "cancel"]); },
};
},
};
const service = new PluginExtensionProviderService({
contributionService,
leaseStore,
permissionEngine,
rpcRegistry,
runtimeSupervisor,
...(options.maxImportRecordBytes === undefined
? {}
: { maxImportRecordBytes: options.maxImportRecordBytes }),
});
return { identity, issuedLeases, permissions, revokedOperations, runtimeListeners, service, writes };
}
function incoming(streamId, emit) {
return {
streamId,
signal: new AbortController().signal,
bind(handlers) { queueMicrotask(() => emit(handlers)); },
cancel() {},
};
}
test("connection providers bind bidirectional streams to an exact runtime and clean up on runtime exit", async () => {
let h;
const output = [];
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async (handlers) => {
await handlers.onChunk({ encoding: "binary", bytes: Uint8Array.from([65, 66]) }, () => {});
});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: "connection-1", status: "connected" },
};
},
});
const opened = await h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: "session-1",
configuration: { endpoint: "example" },
columns: 120,
rows: 40,
}, { onData: (bytes) => output.push(...bytes) });
assert.deepEqual(opened, {
sessionId: "session-1",
providerId: "com.example.transport.connection",
status: "connected",
diagnostics: [],
});
await new Promise((resolve) => setImmediate(resolve));
assert.deepEqual(output, [65, 66]);
await h.service.write("session-1", Uint8Array.from([1, 2]));
assert.deepEqual([...h.writes[0][1]], [1, 2]);
await h.service.write("session-1", "hello \u4e16\u754c");
assert.equal(h.writes[1][1].toString("utf8"), "hello \u4e16\u754c");
assert.equal(h.permissions[0].descriptor.permission, "provider.connection");
assert.equal(h.revokedOperations.length, 1);
assert.equal(h.revokedOperations[0].pluginId, h.identity.pluginId);
assert.match(h.revokedOperations[0].operationId, /^connection:/u);
h.runtimeListeners[0]({ pluginId: h.identity.pluginId, runtimeId: h.identity.runtimeId, status: "stopped" });
assert.throws(() => h.service.getSession("session-1"), /not found/i);
});
test("connection terminal input is chunked within the negotiated stream window", async () => {
let h;
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: "connection-large-input", status: "connected" },
};
},
});
await h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: "session-large-input",
configuration: {},
columns: 80,
rows: 24,
});
const input = Buffer.alloc((STREAM_WINDOW_BYTES * 2) + 3, 0x61);
await h.service.write("session-large-input", input);
assert.equal(h.writes.length, 3);
assert.equal(h.writes[0][0], h.writes[1][0]);
assert.equal(h.writes[1][0], h.writes[2][0]);
assert.equal(h.writes[0][1].byteLength, STREAM_WINDOW_BYTES);
assert.equal(h.writes[1][1].byteLength, STREAM_WINDOW_BYTES);
assert.equal(h.writes[2][1].byteLength, 3);
});
test("importer detection trims raw samples to the bounded JSON payload budget", async () => {
const maxProviderJsonBytes = 128 * 1024;
let seenPayload;
const h = fixture({
async request({ params }) {
seenPayload = params.payload;
return {
requestId: params.requestId,
status: "ok",
result: { confidence: 0.75, format: "json" },
};
},
});
const sample = Buffer.alloc(maxProviderJsonBytes, 0x61);
assert.deepEqual(await h.service.detectImporter({
providerId: "com.example.transport.importer",
fileName: "vault-export.json",
mediaType: "application/json",
sample,
}), { confidence: 0.75, format: "json" });
assert.ok(seenPayload);
assert.equal(seenPayload.fileName, "vault-export.json");
assert.equal(seenPayload.mediaType, "application/json");
assert.ok(Buffer.byteLength(JSON.stringify(seenPayload), "utf8") <= maxProviderJsonBytes);
const decoded = Buffer.from(seenPayload.sample.data, "base64");
assert.ok(decoded.byteLength > 0);
assert.ok(decoded.byteLength < sample.byteLength);
});
test("connection controls preserve host-owned connection and operation identities", async () => {
let h;
const controls = [];
h = fixture({
async request({ params, identity, accept }) {
if (params.operation === "open") {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: "provider-connection-1", status: "connected" },
};
}
controls.push(params);
return { requestId: params.requestId, status: "ok", result: null };
},
});
await h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: "session-control",
configuration: {},
columns: 80,
rows: 24,
});
await h.service.control("session-control", "resize", {
connectionId: "renderer-forged-connection",
operationId: "renderer-forged-operation",
columns: 100,
rows: 30,
});
assert.equal(controls.length, 1);
assert.equal(controls[0].payload.connectionId, "provider-connection-1");
assert.notEqual(controls[0].payload.operationId, "renderer-forged-operation");
assert.match(controls[0].payload.operationId, /^connection:resize:/u);
assert.deepEqual(h.revokedOperations.at(-1), {
pluginId: h.identity.pluginId,
operationId: controls[0].payload.operationId,
});
});
test("connection control operations must acknowledge with null", async () => {
for (const operation of ["resize", "signal", "reconnect", "close"]) {
let h;
h = fixture({
async request({ params, identity, accept }) {
if (params.operation === "open") {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: `provider-${operation}`, status: "connected" },
};
}
return {
requestId: params.requestId,
status: "ok",
result: { unexpected: true },
};
},
});
await h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: `session-${operation}`,
configuration: {},
columns: 80,
rows: 24,
});
await assert.rejects(
h.service.control(`session-${operation}`, operation, operation === "resize"
? { columns: 100, rows: 30 }
: operation === "signal"
? { signal: "interrupt" }
: {}),
/must be null|failed validation/i,
);
if (operation === "close") {
assert.throws(() => h.service.getSession(`session-${operation}`), /not found/i);
} else {
assert.ok(h.service.getSession(`session-${operation}`));
}
}
});
test("stale connection owners cannot close a same-ID replacement", () => {
const h = fixture({ async request() { throw new Error("not used"); } });
const oldOwner = Symbol("old-owner");
const newOwner = Symbol("new-owner");
const cancelled = [];
h.service.sessions.set("session-replaced", {
sessionOwner: newOwner,
input: { cancel() { cancelled.push("input"); } },
output: { cancel() { cancelled.push("output"); } },
});
assert.equal(h.service.closeSessionLocal("session-replaced", undefined, oldOwner), false);
assert.throws(() => h.service.getSession("session-replaced", oldOwner), /replaced/i);
assert.equal(h.service.getSession("session-replaced", newOwner).sessionOwner, newOwner);
assert.equal(h.service.closeSessionLocal("session-replaced", undefined, newOwner), true);
assert.deepEqual(cancelled, ["input", "output"]);
});
test("a same-ID replacement can open while the previous Provider close is pending", async () => {
let releaseClose;
const closeGate = new Promise((resolve) => { releaseClose = resolve; });
let openCount = 0;
let h;
h = fixture({
async request({ params, identity, accept }) {
if (params.operation === "open") {
openCount += 1;
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: `provider-replacement-${openCount}`, status: "connected" },
};
}
assert.equal(params.operation, "close");
await closeGate;
return { requestId: params.requestId, status: "ok", result: null };
},
});
const oldOwner = Symbol("old-owner");
const newOwner = Symbol("new-owner");
const params = {
providerId: "com.example.transport.connection",
sessionId: "session-fast-reconnect",
configuration: {},
columns: 80,
rows: 24,
};
await h.service.openConnection(params, { sessionOwner: oldOwner });
const closing = h.service.control(params.sessionId, "close", {}, { sessionOwner: oldOwner });
assert.throws(() => h.service.getSession(params.sessionId, oldOwner), /not found/i);
await h.service.openConnection(params, { sessionOwner: newOwner });
assert.equal(h.service.getSession(params.sessionId, newOwner).sessionOwner, newOwner);
releaseClose();
await closing;
assert.equal(h.service.getSession(params.sessionId, newOwner).sessionOwner, newOwner);
});
test("connection status results preserve structured diagnostics", async () => {
let h;
h = fixture({
async request({ params, identity, accept }) {
if (params.operation === "open") {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: "provider-status-diagnostics", status: "connected" },
};
}
return {
requestId: params.requestId,
status: "ok",
result: {
status: "error",
message: "Handshake rejected",
diagnostics: [{ severity: "error", message: "Remote rejected host key" }],
},
};
},
});
await h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: "session-status-diagnostics",
configuration: {},
columns: 80,
rows: 24,
});
assert.deepEqual(await h.service.control("session-status-diagnostics", "getStatus"), {
status: "error",
message: "Handshake rejected",
diagnostics: [{ severity: "error", message: "Remote rejected host key" }],
});
});
test("connection configuration is host-validated before invoking plugin code", async () => {
let requests = 0;
const h = fixture({
connectionConfigurationSchema: {
type: "object",
properties: {
endpoint: { type: "string", minLength: 1, maxLength: 64 },
},
required: ["endpoint"],
additionalProperties: false,
},
async request() {
requests += 1;
throw new Error("plugin code must not run for invalid configuration");
},
});
await assert.rejects(h.service.invoke({
kind: "connection",
providerId: "com.example.transport.connection",
operation: "validateConfiguration",
payload: { configuration: { endpoint: "", undeclared: true } },
}), /host schema validation/i);
assert.equal(requests, 0);
});
test("connection and authentication providers preserve explicit null configuration", async () => {
let h;
const seen = [];
h = fixture({
connectionConfigurationSchema: { type: "null" },
async request({ params, identity, accept }) {
seen.push({ kind: params.kind, operation: params.operation, configuration: params.payload.configuration });
if (params.kind === "connection") {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { connectionId: "connection-null", status: "connected" },
};
}
return {
requestId: params.requestId,
status: "ok",
result: {
status: "authenticated",
credential: { kind: "credential", id: "credential-null-reference-1234" },
},
};
},
});
await h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: "session-null",
configuration: null,
columns: 80,
rows: 24,
});
await h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: null,
}, () => {
throw new Error("challenge renderer must not run");
});
assert.deepEqual(seen.map((entry) => entry.configuration), [null, null]);
});
test("authentication secret challenges enter the runtime only as operation-bound one-use leases", async () => {
const responses = [];
const h = fixture({
async request({ params }) {
if (params.operation === "begin") {
return {
requestId: params.requestId,
status: "ok",
result: { status: "challenge", challenge: { id: "otp", kind: "otp", title: "One-time code" } },
};
}
responses.push(params.payload.response);
return {
requestId: params.requestId,
status: "ok",
result: { status: "authenticated", credential: { kind: "credential", id: "credential-reference-1234" } },
};
},
});
const result = await h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: {},
}, async (challenge) => {
assert.equal(challenge.kind, "otp");
return "123456";
});
assert.equal(result.status, "authenticated");
assert.equal(responses.length, 1);
assert.equal(responses[0].kind, "secret-lease");
assert.equal(typeof responses[0].id, "string");
assert.equal(h.issuedLeases.length, 1);
assert.equal(h.issuedLeases[0].pluginId, h.identity.pluginId);
assert.equal(h.issuedLeases[0].runtimeId, h.identity.runtimeId);
assert.equal(h.issuedLeases[0].operationId, responses[0].operationId);
assert.deepEqual(h.issuedLeases[0].credential, {
kind: "authentication-challenge",
challengeId: "otp",
});
assert.equal(h.issuedLeases[0].resolveSecret(), "123456");
assert.deepEqual(h.revokedOperations, [{
pluginId: h.identity.pluginId,
operationId: responses[0].operationId,
}]);
assert.equal(h.permissions[0].descriptor.permission, "provider.authentication");
});
test("authentication providers fail closed on malformed nested challenge contracts", async () => {
const h = fixture({
async request({ params }) {
return {
requestId: params.requestId,
status: "ok",
result: {
status: "challenge",
challenge: { id: "choice", kind: "choice", title: "Choose", choices: [{ label: "Missing value" }] },
},
};
},
});
await assert.rejects(h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: {},
}, async () => "unused"), /failed validation|challenge/i);
});
test("authentication cancellation reaches the provider with a fresh bounded signal", async () => {
const controller = new AbortController();
const operations = [];
const h = fixture({
async request({ params, requestOptions }) {
operations.push(params.operation);
if (params.operation === "begin") {
return {
requestId: params.requestId,
status: "ok",
result: {
status: "challenge",
challenge: { id: "password", kind: "password", title: "Password" },
},
};
}
assert.equal(params.operation, "cancel");
assert.equal(requestOptions.signal.aborted, false);
assert.equal(params.deadlineMs, 1_000);
return { requestId: params.requestId, status: "ok", result: { status: "cancelled" } };
},
});
await assert.rejects(h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: {},
}, async () => {
controller.abort(new DOMException("Cancelled", "AbortError"));
throw controller.signal.reason;
}, { signal: controller.signal }), (error) => error?.name === "AbortError");
assert.deepEqual(operations, ["begin", "cancel"]);
});
test("authentication text responses use the public Unicode code-point limit", async () => {
const response = "😀".repeat(8_192);
const h = fixture({
async request({ params }) {
if (params.operation === "begin") {
return {
requestId: params.requestId,
status: "ok",
result: {
status: "challenge",
challenge: { id: "text", kind: "text", title: "Input" },
},
};
}
assert.equal(params.operation, "respond");
assert.equal(params.payload.response, response);
return { requestId: params.requestId, status: "ok", result: { status: "authenticated" } };
},
});
const result = await h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: {},
}, async () => response);
assert.equal(result.status, "authenticated");
});
test("authentication responses are host-validated against the exact challenge before plugin delivery", async () => {
const operations = [];
const h = fixture({
async request({ params }) {
operations.push(params.operation);
if (params.operation === "begin") {
return {
requestId: params.requestId,
status: "ok",
result: {
status: "challenge",
challenge: {
id: "choice",
kind: "choice",
title: "Choose",
choices: [{ id: "allowed", label: "Allowed" }],
},
},
};
}
return {
requestId: params.requestId,
status: "ok",
result: { status: "cancelled" },
};
},
});
await assert.rejects(h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: {},
}, async () => "undeclared-choice"), /choice response is invalid/i);
await new Promise((resolve) => setImmediate(resolve));
assert.deepEqual(operations, ["begin", "cancel"]);
});
test("cross-plugin authentication cannot transfer a plugin-owned secret reference", async () => {
const h = fixture({
connectionOwnerPluginId: "org.example.connection",
async request({ params }) {
if (params.operation === "cancel") {
return { requestId: params.requestId, status: "ok", result: { status: "cancelled" } };
}
return {
requestId: params.requestId,
status: "ok",
result: {
status: "authenticated",
credential: { kind: "secret", id: "plugin-secret-reference-0001", key: "token" },
},
};
},
});
await assert.rejects(h.service.authenticate({
providerId: "com.example.transport.auth",
connectionProviderId: "com.example.transport.connection",
configuration: {},
}, async () => true), /host-owned CredentialRef/i);
});
test("importer providers produce a validated preview without mutating Vault state", async () => {
let h;
const jsonl = [
JSON.stringify({ type: "progress", completed: 1, total: 2, message: "Reading source" }),
JSON.stringify({
type: "draft",
draft: { kind: "host", value: { label: "Imported", hostname: "imported.example.com" } },
}),
JSON.stringify({ type: "warning", message: "Missing optional color" }),
"",
].join("\n");
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async (handlers) => {
await handlers.onChunk({ encoding: "binary", bytes: new TextEncoder().encode(jsonl) }, () => {});
await handlers.onClose("end");
});
assert.equal(await accept(stream, identity), true);
await new Promise((resolve) => setImmediate(resolve));
return {
requestId: params.requestId,
status: "ok",
result: { parsed: 1, warnings: 1, errors: 0 },
};
},
});
const progress = [];
const preview = await h.service.parseImporter({
providerId: "com.example.transport.importer",
fileName: "hosts.json",
sourceByteLength: 6,
source: (async function* source() {
yield new TextEncoder().encode("sou");
yield new TextEncoder().encode("rce");
}()),
}, { onProgress: (record) => progress.push(record) });
assert.equal(preview.records.length, 3);
assert.equal(preview.records[0].type, "progress");
assert.equal(preview.records[1].type, "draft");
assert.equal(preview.records[2].type, "warning");
assert.deepEqual(progress, [{ type: "progress", completed: 1, total: 2, message: "Reading source" }]);
assert.equal(preview.result.parsed, 1);
assert.equal(Buffer.concat(h.writes.filter(([, value]) => Buffer.isBuffer(value)).map(([, value]) => value)).toString(), "source");
assert.equal(h.writes.at(-1)[1], "end");
assert.equal(h.permissions[0].descriptor.permission, "provider.importer");
assert.equal(h.revokedOperations.length, 1);
assert.equal(h.revokedOperations[0].pluginId, h.identity.pluginId);
assert.match(h.revokedOperations[0].operationId, /^importer:/u);
});
test("import parsing rejects an unterminated JSONL record as soon as it exceeds the line cap", async () => {
let h;
h = fixture({
maxImportRecordBytes: 256 * 1024,
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async (handlers) => {
const first = new Uint8Array(192 * 1024).fill(0x61);
const second = new Uint8Array(65 * 1024).fill(0x62);
await handlers.onChunk({ encoding: "binary", bytes: first }, () => {});
assert.throws(
() => handlers.onChunk({ encoding: "binary", bytes: second }, () => {}),
/record limits/i,
);
});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { parsed: 0, warnings: 0, errors: 0 },
};
},
});
await assert.rejects(h.service.parseImporter({
providerId: "com.example.transport.importer",
fileName: "hosts.json",
data: new TextEncoder().encode("source"),
}), /record limits/i);
assert.equal(h.revokedOperations.length, 1);
assert.match(h.revokedOperations[0].operationId, /^importer:/u);
});
test("import parsing accepts public records larger than the old private line limit", async () => {
let h;
const jsonl = `${JSON.stringify({
type: "draft",
draft: {
kind: "snippet",
value: { label: "Large snippet", command: "x".repeat(300_000) },
},
})}\n`;
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async (handlers) => {
await handlers.onChunk({ encoding: "binary", bytes: new TextEncoder().encode(jsonl) }, () => {});
await handlers.onClose("end");
});
assert.equal(await accept(stream, identity), true);
await new Promise((resolve) => setImmediate(resolve));
return {
requestId: params.requestId,
status: "ok",
result: { parsed: 1, warnings: 0, errors: 0 },
};
},
});
const preview = await h.service.parseImporter({
providerId: "com.example.transport.importer",
data: new TextEncoder().encode("source"),
});
assert.equal(preview.records[0].type, "draft");
assert.equal(preview.records[0].draft.value.command.length, 300_000);
});
test("importer input streams fail closed if the selected file changes size", async () => {
let h;
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async (handlers) => {
await handlers.onClose("end");
});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { parsed: 0, warnings: 0, errors: 0 },
};
},
});
await assert.rejects(h.service.parseImporter({
providerId: "com.example.transport.importer",
sourceByteLength: 5,
source: (async function* source() { yield new TextEncoder().encode("changed"); }()),
}), /changed while it was being read|unexpected size/i);
assert.equal(h.revokedOperations.length, 1);
assert.match(h.revokedOperations[0].operationId, /^importer:/u);
});
test("importer providers cannot report completion counts that disagree with the bounded stream", async () => {
let h;
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async (handlers) => {
await handlers.onChunk({
encoding: "binary",
bytes: new TextEncoder().encode(`${JSON.stringify({ type: "warning", message: "one" })}\n`),
}, () => {});
await handlers.onClose("end");
});
assert.equal(await accept(stream, identity), true);
await new Promise((resolve) => setImmediate(resolve));
return {
requestId: params.requestId,
status: "ok",
result: { parsed: 1, warnings: 0, errors: 0 },
};
},
});
await assert.rejects(h.service.parseImporter({
providerId: "com.example.transport.importer",
fileName: "hosts.json",
data: new TextEncoder().encode("source"),
}), /counts do not match/i);
});
test("unsolicited plugin streams are not claimed by the extension Provider service", async () => {
const h = fixture({ request() { throw new Error("unused"); } });
const accepted = await h.service.acceptIncomingStream({ streamId: "unsolicited" }, h.identity);
assert.equal(accepted, false);
});
test("connection startup reports a provider rejection without waiting for the output-stream deadline", async () => {
const h = fixture({
async request() {
throw new Error("provider rejected open");
},
});
await assert.rejects(h.service.openConnection({
providerId: "com.example.transport.connection",
sessionId: "session-rejected",
configuration: {},
columns: 80,
rows: 24,
deadlineMs: 300_000,
}), /provider rejected open/);
assert.equal(h.service.expectations.size, 0);
});
test("import parsing reports a provider rejection without waiting for the output-stream deadline", async () => {
let sourceReturned = false;
const h = fixture({
async request() {
throw new Error("provider rejected parse");
},
});
const source = {
[Symbol.asyncIterator]() { return this; },
next() { return Promise.resolve({ value: new TextEncoder().encode("source"), done: false }); },
return() { sourceReturned = true; return Promise.resolve({ done: true }); },
};
await assert.rejects(h.service.parseImporter({
providerId: "com.example.transport.importer",
fileName: "hosts.json",
source,
sourceByteLength: 6,
deadlineMs: 300_000,
}), /provider rejected parse/);
await new Promise((resolve) => setImmediate(resolve));
assert.equal(sourceReturned, true);
assert.equal(h.service.expectations.size, 0);
});
test("import parsing enforces its deadline when a successful provider forgets to end output", async () => {
let h;
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return {
requestId: params.requestId,
status: "ok",
result: { parsed: 0, warnings: 0, errors: 0 },
};
},
});
await assert.rejects(h.service.parseImporter({
providerId: "com.example.transport.importer",
fileName: "hosts.json",
data: new TextEncoder().encode("source"),
deadlineMs: 25,
}), /output stream exceeded its deadline/i);
assert.equal(h.revokedOperations.length, 1);
assert.match(h.revokedOperations[0].operationId, /^importer:/u);
});
test("import parsing enforces its deadline while the selected input source stalls", async () => {
let h;
let sourceReturned = false;
h = fixture({
async request({ params, identity, accept }) {
const stream = incoming(params.payload.outputStreamId, async () => {});
assert.equal(await accept(stream, identity), true);
return new Promise(() => {});
},
});
const source = {
[Symbol.asyncIterator]() { return this; },
next() { return new Promise(() => {}); },
return() { sourceReturned = true; return Promise.resolve({ done: true }); },
};
await assert.rejects(h.service.parseImporter({
providerId: "com.example.transport.importer",
fileName: "hosts.json",
source,
sourceByteLength: 6,
deadlineMs: 25,
}), /input source exceeded its deadline/i);
await new Promise((resolve) => setImmediate(resolve));
assert.equal(sourceReturned, true);
assert.equal(h.revokedOperations.length, 1);
});
test("sync providers require provider.sync and only exchange encrypted object bytes", async () => {
const cipher = Buffer.from([0x9b, 0x01, 0x02, 0x03]);
let writePayload;
const h = fixture({
async request({ params }) {
assert.equal(params.kind, "sync");
if (params.operation === "connect") {
return {
requestId: params.requestId,
status: "ok",
result: { account: { id: "acct-1", name: "Plugin Sync" } },
};
}
if (params.operation === "getCapabilities") {
return {
requestId: params.requestId,
status: "ok",
result: {
revisions: true,
conditionalWrites: true,
atomicReplacement: true,
maxObjectBytes: 1024,
},
};
}
if (params.operation === "readObject") {
assert.equal(params.payload.key, "netcatty-vault.json");
assert.equal(typeof params.payload.outputStreamId, "string");
return {
requestId: params.requestId,
status: "ok",
result: {
found: true,
byteLength: cipher.byteLength,
encoding: "base64",
data: cipher.toString("base64"),
revision: "rev-1",
},
};
}
if (params.operation === "writeObject") {
writePayload = params.payload;
assert.equal(params.payload.key, "netcatty-vault.json");
assert.equal(params.payload.encoding, "base64");
assert.equal(Buffer.from(params.payload.data, "base64").equals(cipher), true);
return {
requestId: params.requestId,
status: "ok",
result: { created: true, revision: "rev-2" },
};
}
if (params.operation === "deleteObject") {
return {
requestId: params.requestId,
status: "ok",
result: { deleted: true },
};
}
if (params.operation === "disconnect") {
return { requestId: params.requestId, status: "ok", result: null };
}
throw new Error(`unexpected operation ${params.operation}`);
},
});
const connected = await h.service.connectSync({
providerId: "com.example.transport.sync",
configuration: { endpoint: "https://example.test" },
});
assert.equal(connected.account.id, "acct-1");
assert.equal(h.permissions[0].descriptor.permission, "provider.sync");
const caps = await h.service.getSyncCapabilities({
providerId: "com.example.transport.sync",
});
assert.equal(caps.conditionalWrites, true);
const read = await h.service.readSyncObject({
providerId: "com.example.transport.sync",
key: "netcatty-vault.json",
});
assert.equal(read.found, true);
assert.equal(Buffer.from(read.bytes).equals(cipher), true);
assert.equal(read.revision, "rev-1");
const written = await h.service.writeSyncObject({
providerId: "com.example.transport.sync",
key: "netcatty-vault.json",
bytes: cipher,
});
assert.equal(written.created, true);
assert.equal(written.revision, "rev-2");
assert.equal(writePayload.byteLength, cipher.byteLength);
const deleted = await h.service.deleteSyncObject({
providerId: "com.example.transport.sync",
key: "netcatty-vault.json",
});
assert.equal(deleted.deleted, true);
const disconnected = await h.service.disconnectSync({
providerId: "com.example.transport.sync",
});
assert.equal(disconnected, null);
});
test("sync providers fail closed without provider.sync permission", async () => {
const { PluginRpcError, RPC_ERRORS } = require("./rpcRouter.cjs");
const h = fixture({
async request() {
throw new Error("plugin should not be invoked");
},
async authorize() {
throw new PluginRpcError(RPC_ERRORS.permissionDenied, "missing provider.sync");
},
});
await assert.rejects(h.service.connectSync({
providerId: "com.example.transport.sync",
configuration: {},
}), /provider\.sync|permission/i);
});
test("sync writeObject streams large encrypted objects outside the JSON budget", async () => {
const { INLINE_SYNC_OBJECT_BYTES } = require("./extensionProviderService.cjs");
const large = Buffer.alloc(INLINE_SYNC_OBJECT_BYTES + 16, 0xab);
let sawStream = false;
const h = fixture({
async request({ params }) {
assert.equal(params.operation, "writeObject");
assert.equal(typeof params.payload.inputStreamId, "string");
assert.equal(params.payload.data, undefined);
sawStream = true;
return {
requestId: params.requestId,
status: "ok",
result: { created: false, revision: "stream-rev" },
};
},
});
const result = await h.service.writeSyncObject({
providerId: "com.example.transport.sync",
key: "netcatty-vault.json",
bytes: large,
});
assert.equal(sawStream, true);
assert.equal(result.revision, "stream-rev");
assert.ok(h.writes.some((entry) => entry[1] === "end"));
});