Refactor Rhai integration with context-based execution and type registry
Major Changes:
- Moved Rhai support from rhai_support/ to rhai/ module
- Implemented context-based execution with signatory access control
- Added TypeRegistry for dynamic type registration and object creation
- Refactored engine to use context (Vec<String>) instead of instance
- Removed old runner binary (moved to runner_rust crate)
Rhai Module:
- engine.rs: Core Rhai engine with context-based get_context()
- functions.rs: Rhai function bindings (create_note, create_event, etc.)
- mod.rs: Module exports and organization
Store Improvements:
- TypeRegistry for registering object types and creators
- Generic store uses type registry for dynamic object creation
- Improved error handling and type safety
Documentation:
- RHAI_REFACTOR_COMPLETE.md: Refactoring details
- SIGNATORY_ACCESS_CONTROL.md: Context-based access control
- TYPE_REGISTRY_DESIGN.md: Type registry architecture
- REFACTORING_COMPLETE.md: Overall refactoring summary
- TESTS_COMPLETE.md: Testing documentation
Build Status: ✅ Compiles successfully with minor warnings
This commit is contained in:
176
SIGNATORY_ACCESS_CONTROL.md
Normal file
176
SIGNATORY_ACCESS_CONTROL.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# 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<String>` - 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!** 🎉
|
||||
Reference in New Issue
Block a user