mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
The frozen base for the multi-tenant rewrite. Consolidated 0001 schema makes community_id a first-class, server-resolved key on every scoped row, mapped table-by-table to docs/multi-tenant-conformance.md. Schema highlights: - channels PK is (community_id, id): the same channel UUID may legitimately co-exist in two communities; child FKs (channel_members, workflows, thread_metadata) are composite (community_id, channel_id) so a child can never reference a cross-community channel — DB-enforced, not by handler discipline. channels.community_id is immutable (BEFORE UPDATE trigger). - communities.host uniqueness is UNIQUE(lower(host)); normalize_host applies the same rule on the resolution side, so case/dot/default-port variants can never split one tenant into two. - every scoped unique/PK leads with community_id; cross-community dedup of the same signed event is allowed, within-community dup rejected. - new tables: communities (host map), scheduled_workflow_fires (the cron at-most-once claim), audit_log (per-community chain), and an explicit _operator_global_tables registry the migration lint reads. buzz-core: - normalize_host(host): the one shared host-canonicalization rule. - TenantContext fence doc corrected to say plainly it is a lint-and-review fence, not a compiler fence (resolved()/from_uuid are pub) — honest about the guarantee the API actually gives. Schema proven against Postgres with an adversarial fence suite (re-tenant rejected, cross-community FKs rejected, same-UUID/same-event cross-community allowed, host-case collision rejected). buzz-core: 189 tests + 2 doctests green. Folds in review round 1 from Mari (channel global-uniqueness leak, host normalization, fence-claim honesty) and Sami (NIP-98 localhost normalization to be dropped in the auth lane). Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co> Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
72 lines
2.5 KiB
Rust
72 lines
2.5 KiB
Rust
#![deny(unsafe_code)]
|
|
#![warn(missing_docs)]
|
|
//! `buzz-core` — zero-I/O foundation types for the Buzz relay.
|
|
//!
|
|
//! Provides [`StoredEvent`], filter matching, kind constants, and event
|
|
//! verification. All other Buzz crates depend on this one.
|
|
|
|
/// Channel and membership enums shared across crates.
|
|
pub mod channel;
|
|
/// NIP-AE Agent Engrams — slug grammar, conversation key, d-tag derivation,
|
|
/// body parse/serialize, envelope build/validate, head selection.
|
|
pub mod engram;
|
|
/// Relay-side error types.
|
|
pub mod error;
|
|
/// Relay-side event wrapper with verification tracking.
|
|
pub mod event;
|
|
/// NIP-01 subscription filter matching.
|
|
pub mod filter;
|
|
/// Git permission types — ref patterns, protection rules, policy evaluation.
|
|
pub mod git_perms;
|
|
/// Buzz kind number registry — custom event type constants.
|
|
pub mod kind;
|
|
/// Network utilities — SSRF-safe IP classification.
|
|
pub mod network;
|
|
/// Agent observer frame helpers.
|
|
pub mod observer;
|
|
/// NIP-AB device pairing — crypto primitives, message types, and errors.
|
|
pub mod pairing;
|
|
/// Presence status types shared across crates.
|
|
pub mod presence;
|
|
/// Tenant identity — the server-resolved community key carried on scoped paths.
|
|
pub mod tenant;
|
|
/// Schnorr signature and event ID verification.
|
|
pub mod verification;
|
|
|
|
pub use error::VerificationError;
|
|
pub use event::StoredEvent;
|
|
pub use nostr::{Event, EventId, Filter, Keys, Kind, PublicKey};
|
|
pub use presence::PresenceStatus;
|
|
pub use tenant::{normalize_host, CommunityId, TenantContext};
|
|
pub use verification::verify_event;
|
|
|
|
#[cfg(any(test, feature = "test-utils"))]
|
|
/// Test helper utilities for creating events and stored events.
|
|
pub mod test_helpers {
|
|
use crate::StoredEvent;
|
|
use chrono::Utc;
|
|
use nostr::{EventBuilder, Keys, Kind};
|
|
|
|
/// Create a signed test event with the given kind and random keys.
|
|
pub fn make_event(kind: Kind) -> nostr::Event {
|
|
let keys = Keys::generate();
|
|
EventBuilder::new(kind, "test")
|
|
.tags([])
|
|
.sign_with_keys(&keys)
|
|
.expect("sign")
|
|
}
|
|
|
|
/// Create a signed test event with the given keys and kind.
|
|
pub fn make_event_with_keys(keys: &Keys, kind: Kind) -> nostr::Event {
|
|
EventBuilder::new(kind, "test")
|
|
.tags([])
|
|
.sign_with_keys(keys)
|
|
.expect("sign")
|
|
}
|
|
|
|
/// Create a [`StoredEvent`] wrapper around a test event.
|
|
pub fn make_stored_event(kind: Kind, channel_id: Option<uuid::Uuid>) -> StoredEvent {
|
|
StoredEvent::with_received_at(make_event(kind), Utc::now(), channel_id, true)
|
|
}
|
|
}
|