diff options
Diffstat (limited to 'src/simtest')
| -rw-r--r-- | src/simtest/policy.rs | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/src/simtest/policy.rs b/src/simtest/policy.rs index 60a9f6b..b6be095 100644 --- a/src/simtest/policy.rs +++ b/src/simtest/policy.rs @@ -3,7 +3,8 @@ //! node registers, a write a node lets through for a user the registry doesn't have //! stays where it was made, and a remake carries the swarm over without refusing //! anything. A strict one (`"values": "signed"`) takes the values its users sign, and -//! nothing else there. +//! nothing else there; one declaring values sealed, only those sealed for their +//! readers. use std::time::Duration; @@ -315,3 +316,82 @@ async fn a_strict_swarm() { assert_eq!(plain(node, "config").await, Some(json!({"mode": "slow"}))); } } + +/// A swarm declaring values sealed (`access::sealed`), with the policy: a value sealed +/// for its declared readers goes everywhere; one a node writes plain there, or sealed +/// for a stranger too, gets nothing past the others. +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +async fn sealed_values() { + use crate::access::sealed::testing::sealed_for; + use crate::access::sshsig::PublicKey; + let alice_key = PublicKey([21; 32]); + let line = alice_key.line(); + let sim = Sim::with_identity(74); + let a = sim.start_with("a", &[], Start::Genesis, move |config| { + config.first_users = [( + "alice".to_owned(), + [("laptop".to_owned(), line.clone())].into(), + )] + .into(); + }); + let b = sim.start("b", &["a"], Start::Join); + let c = sim.start("c", &["a"], Start::Join); + sim.wait_ready(&[&a, &b, &c], SOON).await; + let nodes = [a.clone(), b.clone(), c.clone()]; + sim.wait_until("every node is registered", SOON, || { + let nodes = nodes.clone(); + async move { + for node in &nodes { + if crate::swarm::members::members(&node.doc.read().await.doc).len() < 3 { + return false; + } + } + true + } + }) + .await; + write_as( + &a, + "alice", + "_continuum/access/sealed", + json!([{"path": ["secrets", "*"], "readers": ["alice"]}]), + ) + .await; + write_as( + &a, + "alice", + "_continuum/access/policy", + json!({"version": 1}), + ) + .await; + sim.wait_converged(&[&a, &b, &c], SOON).await; + + // Sealed for alice, written on b: everywhere. + let sealed = sealed_for(&[alice_key]); + write_as(&b, "alice", "secrets/db", json!(sealed.clone())).await; + for node in [&a, &b, &c] { + let sealed = sealed.clone(); + sim.wait_until("the sealed value is everywhere", SOON, move || { + let sealed = sealed.clone(); + async move { plain(node, "secrets/db").await == Some(json!(sealed)) } + }) + .await; + assert_eq!(refused(node).await, 0, "an honest change was refused"); + } + + // c writes one sealed for a stranger too: refused by the others, and so is what it + // builds on it. + let stray = sealed_for(&[alice_key, PublicKey([22; 32])]); + write_as(&c, "alice", "secrets/web", json!(stray)).await; + write_as(&c, "alice", "secrets/api", json!("hunter2")).await; + for node in [&a, &b] { + sim.wait_until( + "the badly sealed writes are refused", + SOON, + move || async move { refused(node).await > 0 }, + ) + .await; + assert!(!holds(node, "secrets/web").await); + assert!(!holds(node, "secrets/api").await); + } +} |
