From 829c899eaae498a7ba0af1a307d60260758bafa2 Mon Sep 17 00:00:00 2001 From: Brad Seiler Date: Fri, 6 Nov 2026 11:10:34 -0500 Subject: [PATCH] Cover required-state barriers and effective disable behavior Co-authored-by: Honor Signed-off-by: Brad Seiler --- crates/buzz-db/src/runtime/migration.rs | 12 +++++------ crates/buzz-db/src/store/community_auth.rs | 7 ++++--- .../store/community_auth/postgres_tests.rs | 11 ++++++++++ .../operator/postgres_tests/policy_tests.rs | 21 +++++++++++++++++++ scripts/run-tests.sh | 6 ++++++ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/crates/buzz-db/src/runtime/migration.rs b/crates/buzz-db/src/runtime/migration.rs index 2f0154ba9c..b3d7ccebda 100644 --- a/crates/buzz-db/src/runtime/migration.rs +++ b/crates/buzz-db/src/runtime/migration.rs @@ -3234,12 +3234,6 @@ mod postgres_tests { .expect("second post-apply reconciliation"); } - /// Migrations 0076 and 0078 refuse a populated table whose index was not - /// prebuilt concurrently. A relay that auto-migrated through earlier - /// releases and holds artifact data must still boot through every migration. When a - /// bounded inline build cannot take its lock it must fail closed without - /// recording that migration, keeping earlier migrations and each index - /// already built in its own transaction. #[tokio::test] #[ignore = "requires Postgres"] async fn policy_receipt_expand_preserves_populated_rows_and_legacy_inserts() { @@ -3279,6 +3273,12 @@ mod postgres_tests { } } + /// Migrations 0076 and 0078 refuse a populated table whose index was not + /// prebuilt concurrently. A relay that auto-migrated through earlier + /// releases and holds artifact data must still boot through every migration. When a + /// bounded inline build cannot take its lock it must fail closed without + /// recording that migration, keeping earlier migrations and each index + /// already built in its own transaction. #[tokio::test] #[ignore = "requires Postgres"] async fn populated_artifact_tables_auto_migrate_through_every_migration() { diff --git a/crates/buzz-db/src/store/community_auth.rs b/crates/buzz-db/src/store/community_auth.rs index 64ef7c2364..da65559ecc 100644 --- a/crates/buzz-db/src/store/community_auth.rs +++ b/crates/buzz-db/src/store/community_auth.rs @@ -102,15 +102,16 @@ pub struct UpgradeRecord { pub actor_pubkey: String, /// Owner precondition at acceptance. pub expected_owner_pubkey: String, - /// Issuer precondition at acceptance. + /// Issuer precondition at acceptance; omitted for disable. + #[serde(skip_serializing_if = "String::is_empty")] pub expected_issuer: String, /// Operator authorized to recover this receipt. pub operator_pubkey: String, - /// Accepted generation; concurrent enables converge on this value. + /// Immutable generation accepted for this operation. pub policy_generation: i64, /// Receipt proves acceptance; availability does not undo this fact. pub requires_nip_fi: bool, - /// Pending until BUZZ-512 supplies applied-and-drained evidence. + /// Current availability, with no certification of fleet-wide socket closure. pub state: String, /// Extensible activation obligations; unknown reasons must remain pending. pub pending_reasons: Vec, diff --git a/crates/buzz-db/src/store/community_auth/postgres_tests.rs b/crates/buzz-db/src/store/community_auth/postgres_tests.rs index 8f38806a1e..ee6354becd 100644 --- a/crates/buzz-db/src/store/community_auth/postgres_tests.rs +++ b/crates/buzz-db/src/store/community_auth/postgres_tests.rs @@ -659,6 +659,17 @@ async fn policy_enable_disable_reenable_history_and_identity() { ); } assert_eq!(policy(&db, &tuple).await.policy_generation, 3); + // Reasserting required policy fences an earlier uncommitted disable too. + let stale_disable = intent(&tuple, false, 3, true); + let reassert = intent(&tuple, true, 3, true); + assert_eq!(apply(&db, &reassert).await.acceptance.policy_generation, 4); + assert_eq!( + db.set_community_nip_fi_policy(&stale_disable, Ok(())) + .await + .unwrap(), + PolicyOutcome::Refused("policy_conflict") + ); + assert!(policy(&db, &tuple).await.requires_nip_fi); } #[tokio::test] diff --git a/crates/buzz-relay/src/api/operator/postgres_tests/policy_tests.rs b/crates/buzz-relay/src/api/operator/postgres_tests/policy_tests.rs index 163ad67ca4..b3f0163ec6 100644 --- a/crates/buzz-relay/src/api/operator/postgres_tests/policy_tests.rs +++ b/crates/buzz-relay/src/api/operator/postgres_tests/policy_tests.rs @@ -195,6 +195,27 @@ mod postgres_tests { .await; assert_eq!(current["effective_required"], mode.restricts()); } + // Enforce remains a global floor even after a stored disable. + Arc::make_mut(&mut Arc::get_mut(&mut state).unwrap().config).nip_fi_upgrades_enabled = true; + body["operation_id"] = Uuid::new_v4().to_string().into(); + body["requires_nip_fi"] = false.into(); + body["expected_policy_generation"] = 3.into(); + body["expected_requires_nip_fi"] = true.into(); + body.as_object_mut().unwrap().remove("expected_issuer"); + let response = read_json( + fresh_upgrade_request( + state.clone(), + &operator, + "POST", + path, + Some(body.to_string()), + ) + .await, + ) + .await; + assert_eq!(response["receipt"]["state"], "applied"); + assert_eq!(response["receipt"]["current_requires_nip_fi"], false); + assert_eq!(response["effective_required"], true); let invalid = fresh_upgrade_request( state.clone(), &operator, diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index b37790861e..384b0d2a5d 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -165,6 +165,12 @@ run_unit_tests() { run_test_step "buzz-admin NIP-FI binding command tests" \ cargo test -p buzz-admin nip_fi::tests -- --nocapture + run_test_step "buzz-admin NIP-FI upgrade command tests" \ + cargo test -p buzz-admin nip_fi_upgrade::tests -- --nocapture + + run_test_step "buzz-admin NIP-FI policy command tests" \ + cargo test -p buzz-admin nip_fi_policy::tests -- --nocapture + run_test_step "buzz-admin user-deletion intake command tests" \ cargo test -p buzz-admin user_deletions::tests -- --nocapture