1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! # Hessra Context Token
//!
//! Context token implementation for information flow control (exposure tracking)
//! in the Hessra authorization system.
//!
//! Context tokens track what data an object (typically an AI agent) has been
//! exposed to during a session. Each data access adds exposure labels as
//! append-only biscuit blocks, which downstream systems use to restrict
//! available capabilities.
//!
//! ## Key Properties
//!
//! - **Append-only**: Exposure labels accumulate and cannot be removed within a session.
//! - **Reject-based enforcement**: Each label is recorded as a `reject if exposure({label})`
//! rule. A verifier asserts the labels it cares about as `exposure({label})` facts; a
//! matching reject rule fails authorization. Reject rules are monotonic and apply to the
//! whole token regardless of which key signed them -- any party (even an ephemeral key)
//! can tighten a token, and no `trusting` scope is needed on the authz path.
//! - **Enumerable**: Each label is also recorded as an `exposed_label({label})` metadata
//! fact (a separate predicate the reject rules never test), queried with
//! `trusting authority, {pubkey}` so only issuer-attested labels are reported.
//! - **Block-stacked**: All labels added in a single call land in the same block.
//! - **Inheritable**: Child contexts inherit parent exposure via `fork_context`.
//!
//! ## Authority Block
//!
//! ```datalog
//! context(subject);
//! check if time($time), $time < expiration;
//! // optional, only if mint-time exposures supplied:
//! reject if exposure(label_1);
//! exposed_label(label_1);
//! reject if exposure(label_2);
//! exposed_label(label_2);
//! exposure_source(source);
//! exposure_time(timestamp);
//! ```
//!
//! ## Third-party exposure blocks (one per `add_exposure` call)
//!
//! ```datalog
//! reject if exposure(label_a);
//! exposed_label(label_a);
//! reject if exposure(label_b);
//! exposed_label(label_b);
//! exposure_source(source);
//! exposure_time(timestamp);
//! ```
//!
//! ## Example
//!
//! ```rust
//! use hessra_context_token::{HessraContext, ContextVerifier, add_exposure};
//! use hessra_token_core::{KeyPair, TokenTimeConfig};
//!
//! let keypair = KeyPair::new();
//! let public_key = keypair.public();
//!
//! // Mint a fresh context token
//! let token = HessraContext::new("agent:openclaw".to_string(), TokenTimeConfig::default())
//! .issue(&keypair)
//! .expect("Failed to create context token");
//!
//! // Add exposure labels (stacked into one third-party block, signed by the issuer)
//! let exposed = add_exposure(
//! &token,
//! &keypair,
//! &["PII:SSN".to_string()],
//! "data:user-ssn".to_string(),
//! ).expect("Failed to add exposure");
//!
//! // Verify with chained exclusion checks
//! ContextVerifier::new(exposed.clone(), public_key)
//! .excludes("PII:email")
//! .verify()
//! .expect("PII:email is not attested");
//!
//! assert!(ContextVerifier::new(exposed, public_key)
//! .excludes("PII:SSN")
//! .verify()
//! .is_err());
//! ```
pub use ;
pub use ;
pub use HessraContext;
pub use ContextVerifier;
// Re-export commonly needed types from core
pub use ;