Files
osiris/SIGNATORY_ACCESS_CONTROL.md
Timur Gordon e04012c8c0 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
2025-10-28 03:33:39 +01:00

4.6 KiB

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):

let ctx = osiris("context_name", "owner_id", "redis://localhost:6379", 1);

New way:

// 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:

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

// 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):

OsirisContext::builder()
    .name("context_name")
    .owner("owner_id")  // Deprecated
    .herodb_url("redis://localhost:6379")
    .db_id(1)
    .build()?

New API:

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:

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:

cargo test --lib --features rhai-support

Migration Guide

If you have existing code using the old API:

  1. Replace owner() with participants():

    // Old
    .owner("user_id")
    
    // New
    .participants(vec!["user_id".to_string()])
    
  2. Update Rhai scripts:

    // 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! 🎉