Files
ngit-grasp/tests/lifecycle
DanConwayDev a3bfd023b2 feat(private-repos): gate announcement admission on membership
In GRASP-08 private mode, accepted kind-30617 announcements expand
hosting and — via their referenced relays' NIP-11 owners — the
effective member set itself. Admission never checked the announcement
author, so a member could submit a third-party-signed announcement (or
sync could import one from an operator-configured source) and mint
membership for pubkeys no member ever chose.

AnnouncementPolicy now rejects a repository announcement whose author
is not a current effective member, using the shared PrivateAccess set
(configured members plus admitted relay owners) threaded from server
startup through create_relay and Nip34WritePolicy. The check runs at
the top of AnnouncementPolicy::validate, the single choke point every
announcement arrival path (direct publish, sync import, purgatory
entry) funnels through, and uses the existing AnnouncementResult
rejection machinery so operators observe these rejections like any
whitelist rejection. Public-mode behavior is unchanged (the gate is
None outside private mode) and no configuration was added: the gate is
implied by NGIT_PRIVATE_MODE.

Correctness assumptions: membership is evaluated against the live set
at admission time via PrivateAccess::contains, not re-derived; state
events (kind 30618) stay governed by GRASP-01 maintainer rules; and
removal is non-retroactive — repositories admitted while their author
was a member remain hosted until the operator curates them.

Deliberately excluded: outbound authentication when syncing from other
private services, which remains a follow-up in the design doc.

Validation: cargo clippy --all-targets -D warnings clean; lib tests
(783), private_mode (52, incl. new member/non-member admission
integration test), nip34_announcements (60), repository_creation (47),
and purgatory (55) suites all pass.
2026-08-15 09:40:21 +00:00
..