Remove membership classes (spec, registry schema, enforcement); no roles or tiers

This commit is contained in:
George Coles
2026-09-15 12:59:35 -04:00
parent 276fe5e438
commit dfa1fb1143
16 changed files with 68 additions and 222 deletions
+2 -73
View File
@@ -4,7 +4,7 @@ use std::fs;
use std::path::Path;
use common::{ask, client, collection, config_for, spawn_relay};
use frxd::config::{CLASS_ENRICHMENT, CLASS_SOURCE, Member, save_members};
use frxd::config::{Member, save_members};
use frxd::index::LocalIndex;
use frxd::message::EXPOSURE_FULL;
use frxd::node::{self, Node, NodeHandle, current_period};
@@ -163,77 +163,7 @@ async fn aggregate_floor_rejects_finer_than_month() {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn enrichment_members_cannot_send_content() {
let root = tempfile::tempdir().unwrap();
let relay_url = spawn_relay().await;
let bob_full = start_node(
root.path(),
"bob",
&relay_url,
EXPOSURE_FULL,
&[("doc.txt", "enrichment test rust content")],
)
.await;
let carol_meta = start_node(
root.path(),
"carol",
&relay_url,
"metadata",
&[("doc.txt", "enrichment test rust metadata")],
)
.await;
let alice = start_node(
root.path(),
"alice",
&relay_url,
EXPOSURE_FULL,
&[("mine.txt", "alice local")],
)
.await;
save_members(
&alice.node.config.members_path(),
&[
Member {
name: "bob".to_string(),
pubkey: bob_full.pubkey.clone(),
class: CLASS_ENRICHMENT.to_string(),
previous: Vec::new(),
},
Member {
name: "carol".to_string(),
pubkey: carol_meta.pubkey.clone(),
class: CLASS_ENRICHMENT.to_string(),
previous: Vec::new(),
},
],
)
.unwrap();
let (_status, _raw, value) = ask(&client(), &alice.addr.to_string(), "rust", 5).await;
let responses = value.get("responses").and_then(Value::as_array).unwrap();
assert_eq!(
responses.len(),
1,
"full-exposure enrichment reply must be dropped"
);
assert_eq!(
responses[0].get("member").and_then(Value::as_str),
Some(carol_meta.pubkey.as_str())
);
assert!(
responses[0]
.get("results")
.and_then(Value::as_array)
.unwrap()[0]
.get("content")
.unwrap()
.is_null()
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn source_members_may_send_content() {
async fn full_exposure_responses_carry_content() {
let root = tempfile::tempdir().unwrap();
let relay_url = spawn_relay().await;
let bob = start_node(
@@ -257,7 +187,6 @@ async fn source_members_may_send_content() {
&[Member {
name: "bob".to_string(),
pubkey: bob.pubkey.clone(),
class: CLASS_SOURCE.to_string(),
previous: Vec::new(),
}],
)
+2 -4
View File
@@ -132,8 +132,6 @@ fn cli_init_add_search_status() {
"add".to_string(),
"carol".to_string(),
"ab".repeat(32),
"--class".to_string(),
"enrichment".to_string(),
]);
assert!(stdout.contains("carol"));
let stdout = run_ok(&[
@@ -142,7 +140,7 @@ fn cli_init_add_search_status() {
"member".to_string(),
"list".to_string(),
]);
assert!(stdout.contains("carol [enrichment]"));
assert!(stdout.contains("carol"));
let stdout = run_ok(&add_args(&config, &docs, "docs", true));
assert!(stdout.contains("indexed 1 file(s)"));
@@ -252,7 +250,7 @@ fn cli_registry_lifecycle() {
dir_arg.clone(),
"list".to_string(),
]);
assert!(stdout.contains("alice.frx.example [source] (2 key(s))"));
assert!(stdout.contains("alice.frx.example (2 key(s))"));
let stdout = run_ok(&[
"registry".to_string(),
-2
View File
@@ -367,7 +367,6 @@ async fn member_directory_filters_senders() {
&[frxd::config::Member {
name: "alice".to_string(),
pubkey: alice.public_hex(),
class: frxd::config::CLASS_SOURCE.to_string(),
previous: Vec::new(),
}],
)
@@ -409,7 +408,6 @@ async fn rotated_keys_are_accepted_through_previous_listing() {
vec![frxd::config::Member {
name: "carol".to_string(),
pubkey: new_key.public_hex(),
class: frxd::config::CLASS_SOURCE.to_string(),
previous,
}]
};
-1
View File
@@ -19,7 +19,6 @@ use serde_json::Value;
fn member_with_enc(id: &str, ed: &Keypair, enc_public: &str) -> RegistryMember {
RegistryMember {
id: id.to_string(),
class: "source".to_string(),
keys: vec![KeyEntry {
key: ed.public_hex(),
not_before: 0,
+4 -5
View File
@@ -106,10 +106,9 @@ fn registry_doc(
)
}
fn member(id: &str, key: &Keypair, class: &str) -> RegistryMember {
fn member(id: &str, key: &Keypair) -> RegistryMember {
RegistryMember {
id: id.to_string(),
class: class.to_string(),
keys: vec![KeyEntry {
key: key.public_hex(),
not_before: 0,
@@ -129,7 +128,7 @@ async fn relay_admission_gates_unlisted_keys() {
&registry_path,
&registry_doc(
&ma,
vec![member("alice.frx.example", &alice, "source")],
vec![member("alice.frx.example", &alice)],
vec![],
1,
),
@@ -187,8 +186,8 @@ async fn node_discovers_relays_from_registry() {
&registry_doc(
&ma,
vec![
member("alice.frx.example", &alice, "source"),
member("bob.frx.example", &bob_config.load_key().unwrap(), "source"),
member("alice.frx.example", &alice),
member("bob.frx.example", &bob_config.load_key().unwrap()),
],
vec![relay_url.clone()],
1,
+14 -22
View File
@@ -91,7 +91,7 @@ async fn application_pending_then_approve_then_enroll_binds_key() {
assert_eq!(dup.status(), reqwest::StatusCode::CONFLICT);
// MA approves: member stub; a member token then authorizes key enrollment
commands::registry_approve(&dir, id, None, None).unwrap();
commands::registry_approve(&dir, id, None).unwrap();
let signed = registry::load_registry(&dir.join("registry.json")).unwrap();
assert!(signed.doc.members.iter().any(|member| member.id == id));
let apps = registry::load_applications(&dir.join("applications.json")).unwrap();
@@ -137,7 +137,7 @@ async fn application_pending_then_approve_then_enroll_binds_key() {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn signup_stores_private_application_and_class() {
async fn signup_stores_private_application() {
let root = tempfile::tempdir().unwrap();
let dir = setup_ma(root.path());
let base = spawn_registry_server(&dir).await;
@@ -181,8 +181,7 @@ async fn signup_stores_private_application_and_class() {
Some("keswick-research.frx.invalid")
);
// private application record holds the contract details; applicants do not
// self-declare a class — the MA assigns it at approval
// private application record holds the contract details
let apps = registry::load_applications(&dir.join("applications.json")).unwrap();
assert_eq!(apps.len(), 1);
let app = &apps[0];
@@ -192,25 +191,18 @@ async fn signup_stores_private_application_and_class() {
assert_eq!(app.email, "ops@keswick.example");
assert_eq!(app.payment, "IBAN XX00 0000");
assert_eq!(app.privacy_link, "https://keswick.example/privacy");
assert_eq!(app.class, "source");
assert_eq!(app.status, "pending");
// approval with --class enrichment creates the member with that class
commands::registry_approve(
&dir,
"keswick-research.frx.invalid",
None,
Some(frxd::config::CLASS_ENRICHMENT),
)
.unwrap();
// approval creates the member entry
commands::registry_approve(&dir, "keswick-research.frx.invalid", None).unwrap();
let signed = registry::load_registry(&dir.join("registry.json")).unwrap();
let member = signed
.doc
.members
.iter()
.find(|m| m.id == "keswick-research.frx.invalid")
.unwrap();
assert_eq!(member.class, frxd::config::CLASS_ENRICHMENT);
assert!(
signed
.doc
.members
.iter()
.any(|m| m.id == "keswick-research.frx.invalid")
);
// public registry stays minimal: no org data in the signed snapshot
let raw = std::fs::read_to_string(dir.join("registry.json")).unwrap();
@@ -229,7 +221,7 @@ async fn invite_reissues_token_per_node() {
.unwrap();
submit_application(&http, &base, "Multi Node").await;
let id = "multi-node.frx.invalid";
commands::registry_approve(&dir, id, None, None).unwrap();
commands::registry_approve(&dir, id, None).unwrap();
let enroll = |token: String, pubkey: String| {
let http = http.clone();
@@ -282,7 +274,7 @@ async fn wizard_enrolls_and_writes_config() {
let http = reqwest::Client::new();
submit_application(&http, &base, "Wizard Test").await;
let id = "wizard-test.frx.invalid";
commands::registry_approve(&dir, id, None, None).unwrap();
commands::registry_approve(&dir, id, None).unwrap();
let token = commands::registry_token(&dir, id, None).unwrap();
let signed = registry::load_registry(&dir.join("registry.json")).unwrap();
let credentials = format!(
+5 -8
View File
@@ -19,13 +19,11 @@ use serde_json::Value;
fn member_entry(
id: &str,
key: &Keypair,
class: &str,
not_before: u64,
not_after: Option<u64>,
) -> RegistryMember {
RegistryMember {
id: id.to_string(),
class: class.to_string(),
keys: vec![KeyEntry {
key: key.public_hex(),
not_before,
@@ -122,7 +120,7 @@ async fn registry_gates_membership_and_revocation_propagates() {
&registry_path,
&ma_registry(
&ma,
vec![member_entry("alice.frx.example", &alice, "source", 0, None)],
vec![member_entry("alice.frx.example", &alice, 0, None)],
1,
),
)
@@ -162,7 +160,7 @@ async fn registry_gates_membership_and_revocation_propagates() {
&registry_path,
&ma_registry(
&ma,
vec![member_entry("alice.frx.example", &alice, "source", 0, None)],
vec![member_entry("alice.frx.example", &alice, 0, None)],
1,
),
)
@@ -187,7 +185,7 @@ async fn forged_or_wrong_key_snapshot_closes_the_registry() {
&registry_path,
&ma_registry(
&attacker,
vec![member_entry("alice.frx.example", &alice, "source", 0, None)],
vec![member_entry("alice.frx.example", &alice, 0, None)],
1,
),
)
@@ -222,7 +220,6 @@ async fn expired_key_is_not_authorized() {
vec![member_entry(
"alice.frx.example",
&alice,
"source",
0,
Some(now_ts().saturating_sub(1)),
)],
@@ -251,7 +248,7 @@ async fn fail_static_uses_last_validated_snapshot() {
let alice = Keypair::generate();
let snapshot = ma_registry(
&ma,
vec![member_entry("alice.frx.example", &alice, "source", 0, None)],
vec![member_entry("alice.frx.example", &alice, 0, None)],
1,
);
@@ -319,7 +316,7 @@ async fn registry_can_be_served_over_http() {
&registry_dir.join("registry.json"),
&ma_registry(
&ma,
vec![member_entry("alice.frx.example", &alice, "source", 0, None)],
vec![member_entry("alice.frx.example", &alice, 0, None)],
1,
),
)