mirror of
https://github.com/PR0M3TH3AN/bitgate.git
synced 2026-11-07 14:01:03 +00:00
nostr: resolveAuthorityRoster — moderator set as signed data
"Who is a moderator" should change without a redeploy, but apps had to hand-assemble the createAuthorityState actors map. Add resolveAuthorityRoster (@bitgate/nostr): turn signed kind-30000 "role set" events into the actor->roles map, ready to spread into createAuthorityState. It honors ONLY sets signed by an authorized key -- the root, or (with `signer: <role>`) an actor already granted that role, giving one-role- delegates-another chains in a single ordered pass. It keeps the latest set per publisher (kind 30000 is replaceable) and ignores anyone unauthorized, which is the security property: the roster is only as trustworthy as the key that signed it. Signature verification stays the caller's job (inject @bitgate/verify upstream). Covered by roster.test.js: root-only grants, unauthorized-ignored, delegation, replaceable-latest-wins, and that the output feeds createAuthorityState. README headless section shows the pattern. Addresses the "moderator-set as data" item of the Tessera feedback (docs/TODO.md) -- previously marked PARTIAL. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01BXQCvJPA6sVSQ5j8uBd9bB
This commit is contained in:
1 parent
1abba23df3
commit
cecd70c55f
5 files changed
+214
-7
No files matched your search
@@ -150,6 +150,23 @@ const decision = evaluateTarget(target, snapshot, { policy, surface: "registry"
|
||||
if (!decision.transaction || decision.transaction.effect === "allow") install(); // gate a non-visual action
|
||||
```
|
||||
|
||||
Don't hand-build `honoredModerators`. "Who is a moderator" is data that should
|
||||
change without a redeploy, so let the root publish it as a signed kind-30000 set
|
||||
and resolve it at runtime with `resolveAuthorityRoster` — it honors only
|
||||
root-signed sets (and, with `signer`, one-role-delegates-another chains), and
|
||||
its output spreads straight into `createAuthorityState`:
|
||||
|
||||
```js
|
||||
import { resolveAuthorityRoster } from "@bitgate/nostr";
|
||||
const authority = createAuthorityState(resolveAuthorityRoster(roleSetEvents, {
|
||||
root: ROOT,
|
||||
rosters: [
|
||||
{ identifier: "bitgate:moderators", role: "moderator" }, // root names moderators
|
||||
{ identifier: "bitgate:curators", role: "curator", signer: "moderator" }, // moderators name curators
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
A decision has four dimensions, so `transaction` can block an install or
|
||||
checkout while `visibility` still shows the listing with a warning — something a
|
||||
`hidden` boolean can't express. [`examples/headless-quickstart.mjs`](examples/headless-quickstart.mjs)
|
||||
|
||||
Reference in new issue
Block a user