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
// Principal domain value types.
//
// Design Decision:
// - Principals are org-scoped durable owners/executors with structured metadata.
// - Ownership resolves through principal lineage to exactly one human user.
// - Execution provenance remains separate from ownership; principals only model
// who can own durable entities and who an unattended flow can act as.
//
// EVE-837: the `Principal` aggregate entity moved to the `everruns-platform`
// crate. The value types below stay in core because they are embedded by core
// domain models: `PrincipalSummary` is a field of `Session`/`SessionSchedule`/
// `AgentIdentity`, and `PrincipalKind` backs that summary. EVE-845: the
// `PrincipalStatus` lifecycle enum, which no core type embeds, moved to
// `everruns-platform` alongside the `Principal` aggregate it describes.
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::typed_id::PrincipalId;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
/// Class of principal that can hold permissions or own resources. `system`
/// is reserved for platform-internal callers and is never minted via the
/// public API.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "snake_case")]
pub enum PrincipalKind {
User,
AgentIdentity,
System,
}
impl std::fmt::Display for PrincipalKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::User => write!(f, "user"),
Self::AgentIdentity => write!(f, "agent_identity"),
Self::System => write!(f, "system"),
}
}
}
impl From<&str> for PrincipalKind {
fn from(value: &str) -> Self {
match value {
"agent_identity" => Self::AgentIdentity,
"system" => Self::System,
_ => Self::User,
}
}
}
/// Compact view of a principal — id + kind + the subject-id pointer back
/// into the user/agent-identity row. Used wherever a full `Principal`
/// would be redundant (e.g. as a sub-field of a session or audit record).
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct PrincipalSummary {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "principal_01933b5a000070008000000000000001"))]
pub id: PrincipalId,
pub kind: PrincipalKind,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
pub metadata: serde_json::Value,
}