Signup without a code queues a pending application; registry approve issues credentials
This commit is contained in:
+79
-2
@@ -50,7 +50,7 @@ async fn signup_issues_invite_and_enroll_binds_key() {
|
||||
|
||||
let response = http
|
||||
.post(format!("{base}/v1/signup"))
|
||||
.json(&serde_json::json!({"label": "Alice Dev", "code": "sesame", "attestation": true, "privacy_ack": true}))
|
||||
.json(&serde_json::json!({"label": "Alice Dev", "code": "sesame", "org": "Alice Dev Org", "representative": "Alice", "email": "alice@example.org", "attestation": true, "privacy_ack": true}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -169,6 +169,83 @@ async fn signup_stores_private_application_and_class() {
|
||||
assert_eq!(app.class, "enrichment");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn signup_without_code_queues_application_for_approval() {
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let dir = setup_ma(root.path());
|
||||
let base = spawn_registry_server(&dir, Some("sesame")).await;
|
||||
let http = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(5))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// no code: application queues as pending; no credentials, no member entry
|
||||
let response = http
|
||||
.post(format!("{base}/v1/signup"))
|
||||
.json(&serde_json::json!({
|
||||
"label": "Pending Co",
|
||||
"org": "Pending Co Ltd",
|
||||
"representative": "P. Pending",
|
||||
"email": "ops@pending.example",
|
||||
"attestation": true,
|
||||
"privacy_ack": true
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), reqwest::StatusCode::ACCEPTED);
|
||||
let body: Value = response.json().await.unwrap();
|
||||
assert_eq!(body.get("status").and_then(Value::as_str), Some("pending"));
|
||||
assert!(body.get("credentials").is_none());
|
||||
let id = "pending-co.frx.invalid";
|
||||
|
||||
let signed = registry::load_registry(&dir.join("registry.json")).unwrap();
|
||||
assert!(
|
||||
signed.doc.members.iter().all(|member| member.id != id),
|
||||
"a pending application must not create a member entry"
|
||||
);
|
||||
let apps = registry::load_applications(&dir.join("applications.json")).unwrap();
|
||||
assert_eq!(apps.len(), 1);
|
||||
assert_eq!(apps[0].id, id);
|
||||
assert_eq!(apps[0].status, "pending");
|
||||
|
||||
// a wrong code is still rejected, not queued
|
||||
let rejected = http
|
||||
.post(format!("{base}/v1/signup"))
|
||||
.json(&serde_json::json!({
|
||||
"label": "other", "code": "wrong", "org": "O", "representative": "R",
|
||||
"email": "r@o.example", "attestation": true, "privacy_ack": true
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(rejected.status(), reqwest::StatusCode::FORBIDDEN);
|
||||
|
||||
// MA approves: member stub + invite; enrollment binds the key
|
||||
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();
|
||||
assert_eq!(apps[0].status, "approved");
|
||||
|
||||
let invites = registry::load_invites(&dir.join("invites.json")).unwrap();
|
||||
let invite = invites.iter().find(|invite| invite.id == id).unwrap();
|
||||
let key = Keypair::generate();
|
||||
let enrolled = http
|
||||
.post(format!("{base}/v1/enroll"))
|
||||
.json(&serde_json::json!({
|
||||
"id": id,
|
||||
"token": invite.token,
|
||||
"pubkey": key.public_hex(),
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(enrolled.status().is_success());
|
||||
let signed = registry::load_registry(&dir.join("registry.json")).unwrap();
|
||||
assert!(registry::authorized_keys(&signed, now_ts()).contains_key(&key.public_hex()));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn wizard_enrolls_and_writes_config() {
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
@@ -177,7 +254,7 @@ async fn wizard_enrolls_and_writes_config() {
|
||||
let http = reqwest::Client::new();
|
||||
let body: Value = http
|
||||
.post(format!("{base}/v1/signup"))
|
||||
.json(&serde_json::json!({"label": "Wizard Test", "code": "sesame", "attestation": true, "privacy_ack": true}))
|
||||
.json(&serde_json::json!({"label": "Wizard Test", "code": "sesame", "org": "Wizard Test Org", "representative": "Wiz", "email": "wiz@example.org", "attestation": true, "privacy_ack": true}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
|
||||
Reference in New Issue
Block a user