mirror of
https://github.com/PR0M3TH3AN/bitgate.git
synced 2026-10-27 08:31:00 +00:00
The evaluator was a skeleton with invented thresholds (5/3/10/5) and two unimplemented branches. Rebuild it against the migration plan's spec and the behavior characterized from the pinned reference commit. Core: - four independent decision dimensions (ranking, visibility, interaction, transaction) with severity ladders and max-merge composition - stable reason identifiers replacing free-text strings - structured evidence, redacted unless a profile opts in - administrative-state reduction with capability filtering at merge time, so revoking a role drops that actor's entries immediately - protected actors stripped from every denial set - snapshot fingerprints for cache invalidation - generic policy engine: applications supply profiles and category thresholds; the core carries none of its own Characterization: - 34 generated fixtures covering every behavior the plan's Phase 0 requires - conformance suite that actually evaluates them, replacing a placeholder that asserted a list's length - reference thresholds (3/3/20/5, 60-day mute window) live in bitvid-compat as an application profile, not as engine defaults Fixes found while building: - reduceAdminState accepted malformed target identifiers, because getTargetKey formats anything it is given - community-user-deny fired for any contributor rather than only for community-curated sources 273 tests pass; typecheck and the reference-import guard are clean.
234 lines
7.8 KiB
JavaScript
234 lines
7.8 KiB
JavaScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { createAuthorityState } from "../src/authority.js";
|
|
import {
|
|
createEmptyAdminState,
|
|
isDenied,
|
|
mergeCommunitySource,
|
|
reduceAdminState,
|
|
serializeAdminState,
|
|
} from "../src/adminState.js";
|
|
|
|
const ROOT = "a1".repeat(32);
|
|
const MODERATOR = "b2".repeat(32);
|
|
const CURATOR = "c3".repeat(32);
|
|
const CREATOR = "d4".repeat(32);
|
|
const STRANGER = "e5".repeat(32);
|
|
const EVENT_ID = "1b".repeat(32);
|
|
|
|
const authority = () =>
|
|
createAuthorityState({
|
|
root: ROOT,
|
|
actors: {
|
|
[ROOT]: ["super_admin"],
|
|
[MODERATOR]: ["moderator"],
|
|
[CURATOR]: ["curator"],
|
|
},
|
|
});
|
|
|
|
/** @param {string} pubkey @returns {import("../src/identifiers.js").UserTarget} */
|
|
const user = (pubkey) => ({ type: "user", pubkey });
|
|
/** @param {string} id @returns {import("../src/identifiers.js").EventTarget} */
|
|
const event = (id) => ({ type: "event", id });
|
|
/**
|
|
* @param {string} kind
|
|
* @param {string} pubkey
|
|
* @param {string} identifier
|
|
* @returns {import("../src/identifiers.js").AddressTarget}
|
|
*/
|
|
const address = (kind, pubkey, identifier) => ({ type: "address", kind, pubkey, identifier });
|
|
|
|
describe("reduceAdminState", () => {
|
|
it("accepts a contribution the actor is authorized to make", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "user-deny", targets: [user(CREATOR)] }],
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.has(`user:${CREATOR}`)).toBe(true);
|
|
});
|
|
|
|
it("drops a contribution beyond the actor's capabilities", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: CURATOR, kind: "event-deny", targets: [event(EVENT_ID)] }],
|
|
authority(),
|
|
);
|
|
expect(state.eventDeny.size).toBe(0);
|
|
});
|
|
|
|
it("drops contributions from actors with no roles", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: STRANGER, kind: "user-deny", targets: [user(CREATOR)] }],
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.size).toBe(0);
|
|
});
|
|
|
|
it("drops an actor's entries as soon as the role is revoked", () => {
|
|
/** @type {import("../src/adminState.js").Contribution[]} */
|
|
const contributions = [{ actor: MODERATOR, kind: "user-deny", targets: [user(CREATOR)] }];
|
|
const withRole = reduceAdminState(contributions, authority());
|
|
expect(withRole.userDeny.size).toBe(1);
|
|
|
|
const revoked = createAuthorityState({ root: ROOT, actors: { [ROOT]: ["super_admin"] } });
|
|
expect(reduceAdminState(contributions, revoked).userDeny.size).toBe(0);
|
|
});
|
|
|
|
it("unions denials from several contributors", () => {
|
|
const state = reduceAdminState(
|
|
[
|
|
{ actor: MODERATOR, kind: "user-deny", targets: [user(CREATOR)] },
|
|
{ actor: CURATOR, kind: "user-deny", targets: [user(CREATOR)] },
|
|
],
|
|
authority(),
|
|
);
|
|
expect(state.contributors.get(`user:${CREATOR}`)).toEqual([MODERATOR, CURATOR]);
|
|
});
|
|
|
|
it("ignores targets of the wrong type for the contribution kind", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "event-deny", targets: [user(CREATOR)] }],
|
|
authority(),
|
|
);
|
|
expect(state.eventDeny.size).toBe(0);
|
|
});
|
|
|
|
it("ignores malformed contributions and targets", () => {
|
|
const state = reduceAdminState(
|
|
/** @type {any[]} */ ([
|
|
null,
|
|
{ actor: MODERATOR, kind: "not-a-kind", targets: [user(CREATOR)] },
|
|
{ actor: MODERATOR, kind: "user-deny", targets: [/** @type {any} */ ({ type: "user", pubkey: "short" })] },
|
|
{ actor: MODERATOR, kind: "user-deny" },
|
|
]),
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.size).toBe(0);
|
|
});
|
|
|
|
it("collects trust seeds as pubkeys", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "trust-seed", targets: [user(CREATOR)] }],
|
|
authority(),
|
|
);
|
|
expect(state.trustSeeds.has(CREATOR)).toBe(true);
|
|
expect(state.contributors.size).toBe(0);
|
|
});
|
|
|
|
it("records address denials by coordinate", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "address-deny", targets: [address("30023", CREATOR, "listing")] }],
|
|
authority(),
|
|
);
|
|
expect(state.addressDeny.has(`address:30023:${CREATOR}:listing`)).toBe(true);
|
|
});
|
|
|
|
it("returns empty state for non-array input", () => {
|
|
expect(reduceAdminState(/** @type {any} */ (null), authority()).userDeny.size).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("protected actors", () => {
|
|
it("cannot be denied through a contributor list", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "user-deny", targets: [user(ROOT)] }],
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.has(`user:${ROOT}`)).toBe(false);
|
|
});
|
|
|
|
it("cannot be denied even by many contributors", () => {
|
|
const state = reduceAdminState(
|
|
[
|
|
{ actor: MODERATOR, kind: "user-deny", targets: [user(ROOT)] },
|
|
{ actor: CURATOR, kind: "user-deny", targets: [user(ROOT)] },
|
|
],
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.has(`user:${ROOT}`)).toBe(false);
|
|
expect(state.contributors.has(`user:${ROOT}`)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("community sources", () => {
|
|
it("marks only contributions carrying a source", () => {
|
|
const state = reduceAdminState(
|
|
[
|
|
{ actor: MODERATOR, kind: "user-deny", targets: [user(CREATOR)] },
|
|
{ actor: CURATOR, kind: "user-deny", source: "list-a", targets: [user(STRANGER)] },
|
|
],
|
|
authority(),
|
|
);
|
|
expect(state.communitySources.has(`user:${CREATOR}`)).toBe(false);
|
|
expect(state.communitySources.get(`user:${STRANGER}`)).toEqual(["list-a"]);
|
|
});
|
|
|
|
it("merges a community list into existing state", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "user-deny", targets: [user(CREATOR)] }],
|
|
authority(),
|
|
);
|
|
mergeCommunitySource(
|
|
state,
|
|
{ actor: CURATOR, kind: "user-deny", source: "list-b", targets: [user(STRANGER)] },
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.has(`user:${CREATOR}`)).toBe(true);
|
|
expect(state.userDeny.has(`user:${STRANGER}`)).toBe(true);
|
|
expect(state.communitySources.get(`user:${STRANGER}`)).toEqual(["list-b"]);
|
|
});
|
|
|
|
it("still protects the root when merging a community list", () => {
|
|
const state = createEmptyAdminState();
|
|
mergeCommunitySource(
|
|
state,
|
|
{ actor: CURATOR, kind: "user-deny", source: "hostile", targets: [user(ROOT)] },
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.has(`user:${ROOT}`)).toBe(false);
|
|
});
|
|
|
|
it("ignores a community list from an unauthorized curator", () => {
|
|
const state = createEmptyAdminState();
|
|
mergeCommunitySource(
|
|
state,
|
|
{ actor: STRANGER, kind: "user-deny", source: "list-c", targets: [user(CREATOR)] },
|
|
authority(),
|
|
);
|
|
expect(state.userDeny.size).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("isDenied", () => {
|
|
const state = reduceAdminState(
|
|
[
|
|
{ actor: MODERATOR, kind: "user-deny", targets: [user(CREATOR)] },
|
|
{ actor: MODERATOR, kind: "event-deny", targets: [event(EVENT_ID)] },
|
|
{ actor: MODERATOR, kind: "address-deny", targets: [address("30023", CREATOR, "listing")] },
|
|
],
|
|
authority(),
|
|
);
|
|
|
|
it("detects denial per target type", () => {
|
|
expect(isDenied(user(CREATOR), state)).toBe(true);
|
|
expect(isDenied(event(EVENT_ID), state)).toBe(true);
|
|
expect(isDenied(address("30023", CREATOR, "listing"), state)).toBe(true);
|
|
});
|
|
|
|
it("does not leak denial across target types", () => {
|
|
expect(isDenied(user(STRANGER), state)).toBe(false);
|
|
expect(isDenied(address("30023", CREATOR, "other"), state)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("serializeAdminState", () => {
|
|
it("produces sorted, stable output", () => {
|
|
const state = reduceAdminState(
|
|
[{ actor: MODERATOR, kind: "user-deny", targets: [user(STRANGER), user(CREATOR)] }],
|
|
authority(),
|
|
);
|
|
const serialized = serializeAdminState(state);
|
|
expect(serialized.userDeny).toEqual([...serialized.userDeny].sort());
|
|
expect(serializeAdminState(state)).toEqual(serialized);
|
|
});
|
|
});
|