use blindplane_access::{
AccessGrant, AccessIssuer, AuditContext, AuditEvent, AuditEventKind, CapabilityKind,
CapabilityRule, Decision, Effect, GrantSpec, Permissions, PolicySpec, PrincipalKeypair,
PrincipalKind, RevocationSpec, RevocationState, RoleKeypair, TenantPolicy, open_audit_event,
seal_audit_event,
};
use blindplane_core::{Author, fastest_payload_suite};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let issuer = AccessIssuer::generate("acme-admin")?;
let alice = PrincipalKeypair::generate("acme", "alice", PrincipalKind::User, 1)?;
let admin = PrincipalKeypair::generate("acme", "admin", PrincipalKind::Administrator, 1)?;
let alice_audit = RoleKeypair::generate("acme", "audit", "alice-audit", 1)?;
let tenant_audit = RoleKeypair::generate("acme", "audit", "tenant-audit", 1)?;
let alice_grant = AccessGrant::issue(
&issuer,
alice.principal(),
&alice_audit,
GrantSpec {
grant_id: "alice-audit-v1".into(),
scope: "audit".into(),
permissions: Permissions::READ | Permissions::WRITE,
authorization_epoch: 1,
not_before: 1,
not_after: u64::MAX,
},
)?;
let admin_grant = AccessGrant::issue(
&issuer,
admin.principal(),
&tenant_audit,
GrantSpec {
grant_id: "admin-audit-v1".into(),
scope: "audit".into(),
permissions: Permissions::READ | Permissions::OBSERVE,
authorization_epoch: 1,
not_before: 1,
not_after: u64::MAX,
},
)?;
let alice_state = RevocationState::issue(
&issuer,
"acme",
"alice",
"audit",
RevocationSpec {
revision: 1,
minimum_authorization_epoch: 1,
minimum_role_key_epoch: 1,
issued_at: 1,
},
)?;
let admin_state = RevocationState::issue(
&issuer,
"acme",
"admin",
"audit",
RevocationSpec {
revision: 1,
minimum_authorization_epoch: 1,
minimum_role_key_epoch: 1,
issued_at: 1,
},
)?;
let trusted = issuer.trusted();
let alice_role = alice_grant.open_role(
&alice,
&trusted,
100,
&alice_state.verify(&trusted, "acme", "alice", "audit")?,
)?;
let admin_role = admin_grant.open_role(
&admin,
&trusted,
100,
&admin_state.verify(&trusted, "acme", "admin", "audit")?,
)?;
let policy = TenantPolicy::issue(
&issuer,
alice.principal(),
PolicySpec {
revision: 1,
previous_hash: [0; 32],
authorization_epoch: 1,
issued_at: 1,
not_before: 1,
not_after: u64::MAX,
rules: vec![CapabilityRule::new(
CapabilityKind::Mcp,
"github",
Effect::Allow,
)?],
},
)?;
let verified = policy.verify(&trusted, "acme", "alice", 100, 1, 1)?;
assert_eq!(
verified.decision(CapabilityKind::Mcp, "github"),
Decision::Allow
);
assert_eq!(
verified.decision(CapabilityKind::Skill, "deploy"),
Decision::Deny
);
let author = Author::generate()?;
let event = AuditEvent {
tenant_id: "acme".into(),
subject_id: "alice".into(),
session_id: "session-42".into(),
sequence: 1,
timestamp: 100,
kind: AuditEventKind::Request,
media_type: "application/json".into(),
body: br#"{"tool":"github.search","query":"private"}"#.to_vec(),
};
let record = seal_audit_event(
&author,
AuditContext {
tenant_id: "acme".into(),
subject_id: "alice".into(),
stream_id: "session-42".into(),
epoch: 1,
sequence: 1,
},
&event,
&alice_role,
&admin_role,
fastest_payload_suite(),
)?;
assert_eq!(
open_audit_event(&record, &alice_role, author.public_key())?,
event
);
assert_eq!(
open_audit_event(&record, &admin_role, author.public_key())?,
event
);
println!("user and tenant administrator opened the encrypted audit event");
Ok(())
}