mirror of
https://github.com/PR0M3TH3AN/bitgate.git
synced 2026-10-27 08:31:00 +00:00
Tessera's #1 reason for not adopting BitGate: the on-ramp they found was the <bitgate-provider>/<bitgate-veil> widgets, so they never saw the "just the engine + events over Nostr" path, and — not finding a canonical decision event — invented their own kind-33604 shape. Both concerns were already solved, just not surfaced: - NIP-32 label events (kind 1985) ARE the canonical signed decision format; @bitgate/nostr already ships the codec and docs/labels.md documents interop. No 33604 needed. - The headless path is four pure functions, no runtime transport, no DOM. Add examples/headless-quickstart.mjs (runnable): moderators publish signed kind-1985 deny labels -> decodeLabels -> labelsToContributions -> reduce under an honored moderator set -> evaluateTarget against a plugin-registry policy. It shows exactly the transaction-dimension case the feedback names — a malware plugin stays visible (warn) but not installable (transaction deny), where a `hidden` boolean can't reach. Add a "Headless, straight from NIP-32 labels" README subsection stating labels are the canonical wire format and linking the example and docs/labels.md. Pin the behavior in tests/headless-quickstart.test.js (clean installable; malware visible-but-not-installable; an out-of-set labeller's deny ignored). Addresses the "no just-the-engine path", "decision format is ours", and "headless quickstart" items of the Tessera feedback (docs/TODO.md). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01BXQCvJPA6sVSQ5j8uBd9bB
90 lines
3.1 KiB
JavaScript
90 lines
3.1 KiB
JavaScript
// Pins examples/headless-quickstart.mjs: the NIP-32-labels -> decision round
|
|
// trip, and specifically that the `transaction` dimension gates a non-visual
|
|
// action (install) while the listing stays visible. If this drifts, the example
|
|
// in the docs is wrong.
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
createAuthorityState,
|
|
createEventTarget,
|
|
createPolicyDefinition,
|
|
createSnapshot,
|
|
evaluateTarget,
|
|
reduceAdminState,
|
|
} from "@bitgate/core";
|
|
import { decodeLabels, encodeLabel, labelsToContributions } from "@bitgate/nostr";
|
|
|
|
const ROOT = "a1".repeat(32);
|
|
const MOD_A = "b2".repeat(32);
|
|
const MOD_B = "c3".repeat(32);
|
|
const OUTSIDER = "f6".repeat(32); // not in the honored moderator set
|
|
const CLEAN = "d4".repeat(32);
|
|
const MALWARE = "e5".repeat(32);
|
|
const NOW = 1_750_000_000;
|
|
const NS = "org.bitblocks.plugins";
|
|
|
|
/** createEventTarget returns null on a bad id; every id here is valid 64-hex. */
|
|
const eventTarget = (id) => {
|
|
const target = createEventTarget(id);
|
|
if (!target) throw new Error(`bad event id: ${id}`);
|
|
return target;
|
|
};
|
|
|
|
const signed = (pubkey, template) => ({ ...template, pubkey, created_at: NOW, id: "0".repeat(64), sig: "" });
|
|
const denyLabel = (pubkey, eventId) =>
|
|
signed(pubkey, encodeLabel({ value: "deny", namespace: NS, targets: [eventTarget(eventId)] }));
|
|
|
|
const policy = createPolicyDefinition({
|
|
id: "plugin-registry",
|
|
name: "Plugin registry",
|
|
version: "1.0.0",
|
|
defaultProfile: "registry",
|
|
profiles: {
|
|
registry: {
|
|
name: "registry",
|
|
administrativeDeny: { visibility: "warn", interaction: "allow", transaction: "deny" },
|
|
viewerBlock: { visibility: "hide", interaction: "deny" },
|
|
allowViewerOverride: false,
|
|
reports: {},
|
|
mutes: {},
|
|
},
|
|
},
|
|
});
|
|
|
|
function decide(events, eventId) {
|
|
const authority = createAuthorityState({ root: ROOT, actors: { [MOD_A]: ["moderator"], [MOD_B]: ["moderator"] } });
|
|
const contributions = labelsToContributions(
|
|
events.flatMap((e) => decodeLabels(e)),
|
|
{ namespace: NS, denyValues: ["deny"], allowValues: ["allow"] },
|
|
);
|
|
const snapshot = createSnapshot({ authority, admin: reduceAdminState(contributions, authority) });
|
|
return evaluateTarget(eventTarget(eventId), snapshot, {
|
|
surface: "registry",
|
|
policyProfile: "registry",
|
|
policy,
|
|
now: NOW,
|
|
});
|
|
}
|
|
|
|
describe("headless quickstart: NIP-32 labels -> decision", () => {
|
|
const events = [denyLabel(MOD_A, MALWARE), denyLabel(MOD_B, MALWARE)];
|
|
|
|
it("leaves a clean plugin visible and installable", () => {
|
|
const d = decide(events, CLEAN);
|
|
expect(d.visibility.effect).toBe("allow");
|
|
expect(d.transaction?.effect ?? "allow").toBe("allow");
|
|
});
|
|
|
|
it("gates install on the malware plugin while keeping the listing visible", () => {
|
|
const d = decide(events, MALWARE);
|
|
// The four-dimension point: shown (warn) but not installable (transaction deny).
|
|
expect(d.visibility.effect).toBe("warn");
|
|
expect(d.transaction?.effect).toBe("deny");
|
|
});
|
|
|
|
it("ignores a deny label from a labeller outside the honored moderator set", () => {
|
|
const d = decide([denyLabel(OUTSIDER, MALWARE)], MALWARE);
|
|
expect(d.transaction?.effect ?? "allow").toBe("allow");
|
|
});
|
|
});
|