mirror of
https://github.com/block/buzz.git
synced 2026-11-02 23:41:08 +00:00
## Summary - discover shared managed agents from authenticated relay directory records instead of treating channel membership as sufficient proof - publish and refresh access-policy changes immediately so running clients converge across machines without a restart or five-minute poll - route profile edits through the exact managed instance and stop/restart runtimes around access changes so unrelated edits cannot silently widen access - keep mention send-time revalidation and Block owner-only build enforcement fail closed - explain invalid custom provider/model configuration instead of leaving Save silently disabled ### Related issue Fixes #3204 ### Known residuals - a brand-new remote agent's first policy record can wait for the bounded directory poll when no authenticated directory coordinate exists yet; send-time mention revalidation remains fail closed - a failed remote-provider policy redeploy is recorded but cannot undeploy the older provider instance until the provider protocol gains the destructor tracked by #5570 ### Testing - full Desktop unit suite: 4,961 tests passed - focused profile editor Playwright workflow passed, including Customize access edits and prompt-only edits after tightening an instance - Desktop TypeScript, Biome formatting, file-size ratchet, Tauri checks, and pre-push suites passed - independently reviewed for authenticated directory trust, live subscription teardown, runtime revocation ordering, fail-open edit paths, and per-agent provider deployment serialization --------- Signed-off-by: Wes <wesbillman@users.noreply.github.com> Signed-off-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@buzz.block.builderlab.xyz> Co-authored-by: diegorumo <diegorumo@gmail.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@buzz.block.builderlab.xyz>
102 lines
2.6 KiB
JavaScript
102 lines
2.6 KiB
JavaScript
import assert from "node:assert/strict";
|
||
import test, { mock } from "node:test";
|
||
|
||
import { relayClient } from "@/shared/api/relayClient";
|
||
import { KIND_MANAGED_AGENT } from "@/shared/constants/kinds";
|
||
import { startRelayAgentPolicyRefresh } from "./useAgentsDataRefresh.ts";
|
||
|
||
const coordinates = [
|
||
{ ownerPubkey: "owner-a", agentPubkey: "agent-a" },
|
||
{ ownerPubkey: "owner-b", agentPubkey: "agent-b" },
|
||
];
|
||
|
||
function event(pubkey, dTag) {
|
||
return {
|
||
id: "id",
|
||
pubkey,
|
||
created_at: 1,
|
||
kind: KIND_MANAGED_AGENT,
|
||
tags: dTag ? [["d", dTag]] : [],
|
||
content: "{}",
|
||
sig: "sig",
|
||
};
|
||
}
|
||
|
||
test("remote managed policy refresh accepts only exact authenticated coordinates", async () => {
|
||
let onEvent;
|
||
let filter;
|
||
let unsubscribeCalls = 0;
|
||
mock.method(relayClient, "subscribeLive", (nextFilter, listener) => {
|
||
filter = nextFilter;
|
||
onEvent = listener;
|
||
return Promise.resolve(() => {
|
||
unsubscribeCalls += 1;
|
||
return Promise.resolve();
|
||
});
|
||
});
|
||
|
||
let refreshes = 0;
|
||
const stop = startRelayAgentPolicyRefresh(coordinates, () => {
|
||
refreshes += 1;
|
||
});
|
||
await new Promise((resolve) => setImmediate(resolve));
|
||
|
||
assert.deepEqual(filter, {
|
||
kinds: [KIND_MANAGED_AGENT],
|
||
authors: ["owner-a", "owner-b"],
|
||
"#d": ["agent-a", "agent-b"],
|
||
limit: 0,
|
||
});
|
||
onEvent(event("owner-a", "agent-a"));
|
||
assert.equal(refreshes, 1);
|
||
|
||
for (const irrelevant of [
|
||
event("owner-x", "agent-a"),
|
||
event("owner-a", "agent-x"),
|
||
event("owner-a", "agent-b"), // authors×d cross-product
|
||
event("owner-a", null),
|
||
]) {
|
||
onEvent(irrelevant);
|
||
}
|
||
assert.equal(refreshes, 1, "irrelevant coordinates must not refresh");
|
||
|
||
stop();
|
||
assert.equal(unsubscribeCalls, 1);
|
||
mock.reset();
|
||
});
|
||
|
||
test("stopping before subscription readiness still closes the live query", async () => {
|
||
let resolveSubscription;
|
||
let unsubscribeCalls = 0;
|
||
mock.method(
|
||
relayClient,
|
||
"subscribeLive",
|
||
() =>
|
||
new Promise((resolve) => {
|
||
resolveSubscription = resolve;
|
||
}),
|
||
);
|
||
|
||
const stop = startRelayAgentPolicyRefresh(coordinates, () => {});
|
||
stop();
|
||
resolveSubscription(() => {
|
||
unsubscribeCalls += 1;
|
||
return Promise.resolve();
|
||
});
|
||
await new Promise((resolve) => setImmediate(resolve));
|
||
|
||
assert.equal(unsubscribeCalls, 1);
|
||
mock.reset();
|
||
});
|
||
|
||
test("no authenticated coordinates creates no global subscription", () => {
|
||
let subscriptions = 0;
|
||
mock.method(relayClient, "subscribeLive", () => {
|
||
subscriptions += 1;
|
||
return Promise.resolve(() => Promise.resolve());
|
||
});
|
||
startRelayAgentPolicyRefresh([], () => {})();
|
||
assert.equal(subscriptions, 0);
|
||
mock.reset();
|
||
});
|