Replace the audit record with chained audit events
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
+71
-17
@@ -4,34 +4,88 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{CallId, DataClass, DenyReason, Hash32, SessionId, Timestamp};
|
||||
|
||||
// JSON: {"outcome":"allowed","grant":"…"} ; the tag sits beside the fields; outcomes are snake_case
|
||||
// JSON: {"outcome":"denied","reason":"no_grant"} ; the tag sits beside the fields
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "outcome", rename_all = "snake_case", deny_unknown_fields)]
|
||||
pub enum DecisionRecord {
|
||||
Allowed {
|
||||
grant: String,
|
||||
},
|
||||
Approved {
|
||||
grant: String,
|
||||
approver: String,
|
||||
post: Option<String>,
|
||||
},
|
||||
Denied {
|
||||
reason: DenyReason,
|
||||
Allowed {},
|
||||
Ask {},
|
||||
Denied { reason: DenyReason },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ApprovalAnswer {
|
||||
Approved,
|
||||
Refused,
|
||||
Expired,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ResultStatus {
|
||||
Result,
|
||||
Failed,
|
||||
}
|
||||
|
||||
// JSON: {"type":"decision","session":"…",…} ; the tag sits beside the fields
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
|
||||
pub enum AuditEvent {
|
||||
Decision {
|
||||
session: SessionId,
|
||||
call: CallId,
|
||||
tool: String,
|
||||
arguments: String,
|
||||
outcome: DecisionRecord,
|
||||
grant: Option<String>,
|
||||
grant_sha256: Option<Hash32>,
|
||||
taint: DataClass,
|
||||
untrusted: bool,
|
||||
},
|
||||
Approval {
|
||||
session: SessionId,
|
||||
call: CallId,
|
||||
decision: u64,
|
||||
answer: ApprovalAnswer,
|
||||
by: Option<String>,
|
||||
post: Option<String>,
|
||||
reason: Option<String>,
|
||||
outcome: DecisionRecord,
|
||||
grant: Option<String>,
|
||||
grant_sha256: Option<Hash32>,
|
||||
taint: DataClass,
|
||||
untrusted: bool,
|
||||
},
|
||||
Result {
|
||||
session: SessionId,
|
||||
call: CallId,
|
||||
decision: u64,
|
||||
status: ResultStatus,
|
||||
class: DataClass,
|
||||
untrusted: bool,
|
||||
truncated: bool,
|
||||
bytes: u64,
|
||||
sha256: Hash32,
|
||||
taint_after: DataClass,
|
||||
},
|
||||
Recovery {
|
||||
torn_bytes: u64,
|
||||
torn_sha256: Hash32,
|
||||
},
|
||||
AcceptedBreak {
|
||||
file: String,
|
||||
line: u64,
|
||||
last_good: Hash32,
|
||||
},
|
||||
}
|
||||
|
||||
// JSON: {"seq":0,"time":"…","prev":"…","event":{"type":"decision",…}} ; `event` is a nested object.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct AuditRecord {
|
||||
pub seq: u64,
|
||||
pub time: Timestamp,
|
||||
pub prev: Hash32,
|
||||
pub session: SessionId,
|
||||
pub call: CallId,
|
||||
pub tool: String,
|
||||
pub arguments: String,
|
||||
pub session_taint: DataClass,
|
||||
pub decision: DecisionRecord,
|
||||
pub event: AuditEvent,
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub mod ids;
|
||||
pub mod log;
|
||||
pub mod wire;
|
||||
|
||||
pub use audit::{AuditRecord, DecisionRecord};
|
||||
pub use audit::{ApprovalAnswer, AuditEvent, AuditRecord, DecisionRecord, ResultStatus};
|
||||
pub use class::DataClass;
|
||||
pub use frame::{FrameError, MAX_FRAME, read_frame, write_frame};
|
||||
pub use grant::{Constraints, Grant, Mode};
|
||||
|
||||
Reference in New Issue
Block a user