fix(relay): confirm a stored create's resend before its members' policies

An exact resend of a kind:9007 writes nothing, so a member that closed
its channel adds after the create no longer refuses it.

Co-authored-by: claude00 <fb8b76a01257932b8ca35060862c29bd09b2137638573731c2d5074fc02c5385@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
This commit is contained in:
Bradley Axen
2026-10-17 22:17:04 -07:00
parent 95d4329a10
commit c2b22afc88
2 changed files with 37 additions and 3 deletions

View File

@@ -170,7 +170,8 @@ async fn create_respects_the_members_add_policy() {
/// Resending a create whose OK was lost is accepted; a different create for
/// the same UUID, even from its creator, is refused before its side effects,
/// so it can neither add nor announce anyone.
/// Mutations: refuse every existing UUID → resend not accepted → RED; let the
/// Mutations: refuse every existing UUID → resend not accepted → RED; check the
/// members' policies before recognizing a stored resend → RED; let the
/// creator's changed create through → stranger announced → RED.
#[tokio::test]
#[ignore = "requires Postgres"]
@@ -191,7 +192,7 @@ async fn resending_a_create_confirms_it() {
.expect("create");
assert!(first.accepted, "{}", first.message);
let before = roles(&state, &tenant, channel_id).await;
let resent = ingest(&state, &tenant, create, &creator)
let resent = ingest(&state, &tenant, create.clone(), &creator)
.await
.expect("resend");
assert!(resent.accepted, "{}", resent.message);
@@ -209,6 +210,27 @@ async fn resending_a_create_confirms_it() {
assert_eq!(changed.message, "duplicate: channel already exists");
}
// The agent closing its adds after the create doesn't refuse the resend.
let agent_bytes = agent.public_key().to_bytes().to_vec();
state
.db
.ensure_user(tenant.community(), &agent_bytes)
.await
.expect("agent user");
state
.db
.set_channel_add_policy(tenant.community(), &agent_bytes, "nobody")
.await
.expect("policy");
let resent_after_policy = ingest(&state, &tenant, create, &creator)
.await
.expect("resend after policy change");
assert!(
resent_after_policy.accepted,
"{}",
resent_after_policy.message
);
assert_eq!(roles(&state, &tenant, channel_id).await, before);
let notices = state
.db

View File

@@ -543,8 +543,20 @@ pub async fn validate_admin_event(
// CREATE_GROUP doesn't need an existing channel — skip h-tag extraction.
// Its initial members get the third-party add check a kind:9000 would.
if kind == 9007 {
let members = initial_members(event)?;
// Ingest confirms a resend of a stored create without writing anything,
// so a policy changed since then must not refuse it.
if members.is_empty()
|| state
.db
.get_event_by_id_for_event_write(tenant.community(), event.id.as_bytes())
.await?
.is_some()
{
return Ok(());
}
let actor_bytes = event.pubkey.to_bytes().to_vec();
for member in initial_members(event)? {
for member in members {
if let Some((policy, owner)) = state
.db
.get_agent_channel_policy(tenant.community(), &member)