# Signatory-Based Access Control for OSIRIS Contexts ## Overview OSIRIS contexts now use **signatory-based access control** instead of owner-based permissions. This means that access to a context is granted only if all participants are signatories of the Rhai script. ## Key Changes ### 1. **Removed Owner Field** - `OsirisContext` no longer has an `owner_id` field - Replaced with `participants: Vec` - a list of public keys ### 2. **Context Identification** - Context ID is now a **sorted, comma-separated list** of participant public keys - Example: `"pk1,pk2,pk3"` for a context with three participants - Sorting ensures consistent IDs regardless of input order ### 3. **Access Control via SIGNATORIES** - `get_context()` function checks the `SIGNATORIES` tag in the Rhai execution context - All requested participants must be present in the SIGNATORIES list - If any participant is not a signatory, access is denied ## API Changes ### Rhai Script Usage **Old way (deprecated):** ```rhai let ctx = osiris("context_name", "owner_id", "redis://localhost:6379", 1); ``` **New way:** ```rhai // Single participant let ctx = get_context(["pk1"]); // Multiple participants (shared context) let ctx = get_context(["pk1", "pk2", "pk3"]); ``` ### Setting Up SIGNATORIES When creating a Rhai engine, you must set up the SIGNATORIES tag: ```rust use rhai::{Engine, Dynamic, Map, Array}; let mut engine = create_osiris_engine("redis://localhost:6379", 1)?; // Create context tags let mut tag_map = Map::new(); // SIGNATORIES must be a Rhai array of strings let signatories: Array = vec![ Dynamic::from("pk1".to_string()), Dynamic::from("pk2".to_string()), Dynamic::from("pk3".to_string()), ]; tag_map.insert("SIGNATORIES".into(), Dynamic::from(signatories)); tag_map.insert("DB_PATH".into(), "/path/to/db".to_string().into()); tag_map.insert("CONTEXT_ID".into(), "script_context".to_string().into()); engine.set_default_tag(Dynamic::from(tag_map)); ``` ## Access Control Flow 1. **Script Execution**: Rhai script calls `get_context(["pk1", "pk2"])` 2. **Extract SIGNATORIES**: Function reads `SIGNATORIES` from context tag 3. **Verify Participants**: Checks that all participants (`pk1`, `pk2`) are in SIGNATORIES 4. **Grant/Deny Access**: - ✅ If all participants are signatories → create/return context - ❌ If any participant is missing → return error ## Example: Shared Context ```rhai // Three people want to collaborate // All three must have signed the script let shared_ctx = get_context(["alice_pk", "bob_pk", "charlie_pk"]); // Now all three can access the same data shared_ctx.save("notes", "note1", #{ title: "Meeting Notes", content: "Discussed project timeline" }); // Context ID will be: "alice_pk,bob_pk,charlie_pk" (sorted) print(shared_ctx.context_id()); ``` ## Builder API Changes ### Old API (deprecated): ```rust OsirisContext::builder() .name("context_name") .owner("owner_id") // Deprecated .herodb_url("redis://localhost:6379") .db_id(1) .build()? ``` ### New API: ```rust OsirisContext::builder() .participants(vec!["pk1".to_string(), "pk2".to_string()]) .herodb_url("redis://localhost:6379") .db_id(1) .build()? ``` ## Member Management All participants automatically get **admin privileges** in the context: - `Privilege::Admin` - `Privilege::Read` - `Privilege::Write` - `Privilege::ManageMembers` Additional members can still be added with custom privileges: ```rhai let ctx = get_context(["pk1", "pk2"]); ctx.add_member("pk3", ["read", "write"]); ``` ## Security Benefits 1. **Multi-signature Support**: Contexts can be shared between multiple parties 2. **Script-level Authorization**: Access control is enforced at script execution time 3. **No Hardcoded Owners**: Flexible participant model 4. **Transparent Access**: All participants have equal rights by default ## Testing Tests verify: - ✅ Valid signatories can create contexts - ✅ Invalid signatories are denied access - ✅ Context IDs are properly sorted - ✅ Multiple participants work correctly Run tests: ```bash cargo test --lib --features rhai-support ``` ## Migration Guide If you have existing code using the old API: 1. **Replace `owner()` with `participants()`**: ```rust // Old .owner("user_id") // New .participants(vec!["user_id".to_string()]) ``` 2. **Update Rhai scripts**: ```rhai // Old let ctx = osiris("name", "owner", "url", 1); // New let ctx = get_context(["owner"]); ``` 3. **Set up SIGNATORIES tag** in your engine configuration 4. **Update tests** to use the new API --- **All core functionality tested and verified!** 🎉