aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/access.md3
-rw-r--r--src/remake/catchup.rs16
-rw-r--r--src/remake/switch.rs12
3 files changed, 30 insertions, 1 deletions
diff --git a/docs/access.md b/docs/access.md
index 46758b0..be91185 100644
--- a/docs/access.md
+++ b/docs/access.md
@@ -428,7 +428,8 @@ registry, the policy and the bans change only as a user who may change them sign
A running swarm turns strict through a remake of its own kind, `strict`, once (a swarm
strict already takes none: its registry, policy and bans change by their users'
-signatures, not by a majority of members): compaction
+signatures, not by a majority of members; its nodes neither vote for one nor follow one
+a majority commits anyway, switching or rejoining): compaction
that keeps, at the places values are signed (the registry, `_continuum/access`, the
bans, the paths listed in `userSigned`), only the values an operator looked over and
signed, and sets the strict policy. What was written after its base reaches the new
diff --git a/src/remake/catchup.rs b/src/remake/catchup.rs
index 4df5c90..6ef8121 100644
--- a/src/remake/catchup.rs
+++ b/src/remake/catchup.rs
@@ -528,6 +528,22 @@ fn prepare(
.filter(|next| next.previous == previous);
let gap = target.generation - previous.generation;
+ // A strict remake of a swarm strict already isn't followed: there its registry,
+ // policy and bans change by its users' signatures, not by a majority of members
+ // (`vote::strict_taken`). Strict as our document is, or once a remake since made it so.
+ let mut strict = crate::access::policy::of(old).strict();
+ for generation in previous.generation + 1..=target.generation {
+ if let Ok(epoch) = snapshot::read_epoch_metadata(copy, generation)
+ && epoch.kind == "strict"
+ {
+ if strict {
+ return Prepared::Failed(format!(
+ "epoch generation {generation} was made by a strict remake of a swarm strict already: not followed"
+ ));
+ }
+ strict = true;
+ }
+ }
// Writes made in our epoch go through every remake since, in order.
let translator = (previous.generation + 1..=target.generation).try_fold(
Translator::default(),
diff --git a/src/remake/switch.rs b/src/remake/switch.rs
index bd40d72..df3fcc8 100644
--- a/src/remake/switch.rs
+++ b/src/remake/switch.rs
@@ -192,6 +192,18 @@ async fn switch<H: Host>(
let translator = request
.translator()
.ok_or_else(|| format!("unknown remake kind {:?}", request.kind))?;
+ // A strict remake of a swarm strict already, committed by a majority of members
+ // anyway: not followed (`vote::strict_taken`, `catchup`).
+ if request.kind == "strict"
+ && host
+ .read_doc(|doc| crate::access::policy::of(doc).strict())
+ .await
+ {
+ return Err(
+ "a strict remake of a swarm strict already: its registry changes by its users' signatures; not followed"
+ .to_owned(),
+ );
+ }
let late_translator = translator.clone();
let superseded = host.superseded();
let previous = request.previous;