Skip to content
This repository was archived by the owner on Sep 2, 2026. It is now read-only.

Commit 962a9ce

Browse files
Type organization audit log responses
Co-authored-by: anode-agent[bot] <283895490+anode-agent[bot]@users.noreply.github.com>
1 parent 1fe5e4a commit 962a9ce

2 files changed

Lines changed: 272 additions & 2 deletions

File tree

‎src/resources/admin.rs‎

Lines changed: 212 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,22 @@ admin_string_literal_enum! {
545545
}
546546
}
547547

548+
admin_string_literal_enum! {
549+
/// Audit-log actor type.
550+
pub enum AdminAuditLogActorType {
551+
Session => "session",
552+
ApiKey => "api_key",
553+
}
554+
}
555+
556+
admin_string_literal_enum! {
557+
/// Audit-log API-key actor type.
558+
pub enum AdminAuditLogActorApiKeyType {
559+
User => "user",
560+
ServiceAccount => "service_account",
561+
}
562+
}
563+
548564
admin_string_literal_enum! {
549565
/// Bucket width accepted by most organization usage endpoints.
550566
pub enum AdminUsageBucketWidth {
@@ -871,6 +887,201 @@ pub type AdminUsageModerationsResponse = AdminUsagePage;
871887
pub type AdminUsageVectorStoresResponse = AdminUsagePage;
872888
pub type AdminUsageWebSearchCallsResponse = AdminUsagePage;
873889

890+
/// Event-specific audit-log details preserved under the upstream event alias.
891+
pub type AdminAuditLogEventDetails = BTreeMap<String, Value>;
892+
893+
/// Service account that performed an audit logged action through an API key.
894+
#[derive(Clone, Debug, Deserialize, PartialEq)]
895+
pub struct AdminAuditLogActorApiKeyServiceAccount {
896+
#[serde(default)]
897+
pub id: Option<String>,
898+
#[serde(flatten)]
899+
pub extra: BTreeMap<String, Value>,
900+
}
901+
902+
/// User that performed an audit logged action through an API key.
903+
#[derive(Clone, Debug, Deserialize, PartialEq)]
904+
pub struct AdminAuditLogActorApiKeyUser {
905+
#[serde(default)]
906+
pub id: Option<String>,
907+
#[serde(default)]
908+
pub email: Option<String>,
909+
#[serde(flatten)]
910+
pub extra: BTreeMap<String, Value>,
911+
}
912+
913+
/// API key actor for an audit log entry.
914+
#[derive(Clone, Debug, Deserialize, PartialEq)]
915+
pub struct AdminAuditLogActorApiKey {
916+
#[serde(default)]
917+
pub id: Option<String>,
918+
#[serde(default)]
919+
pub service_account: Option<AdminAuditLogActorApiKeyServiceAccount>,
920+
#[serde(default, rename = "type")]
921+
pub kind: Option<AdminAuditLogActorApiKeyType>,
922+
#[serde(default)]
923+
pub user: Option<AdminAuditLogActorApiKeyUser>,
924+
#[serde(flatten)]
925+
pub extra: BTreeMap<String, Value>,
926+
}
927+
928+
/// User in the session that performed an audit logged action.
929+
#[derive(Clone, Debug, Deserialize, PartialEq)]
930+
pub struct AdminAuditLogActorSessionUser {
931+
#[serde(default)]
932+
pub id: Option<String>,
933+
#[serde(default)]
934+
pub email: Option<String>,
935+
#[serde(flatten)]
936+
pub extra: BTreeMap<String, Value>,
937+
}
938+
939+
/// Session actor for an audit log entry.
940+
#[derive(Clone, Debug, Deserialize, PartialEq)]
941+
pub struct AdminAuditLogActorSession {
942+
#[serde(default)]
943+
pub ip_address: Option<String>,
944+
#[serde(default)]
945+
pub user: Option<AdminAuditLogActorSessionUser>,
946+
#[serde(flatten)]
947+
pub extra: BTreeMap<String, Value>,
948+
}
949+
950+
/// Actor that performed an audit logged action.
951+
#[derive(Clone, Debug, Deserialize, PartialEq)]
952+
pub struct AdminAuditLogActor {
953+
#[serde(default)]
954+
pub api_key: Option<AdminAuditLogActorApiKey>,
955+
#[serde(default)]
956+
pub session: Option<AdminAuditLogActorSession>,
957+
#[serde(default, rename = "type")]
958+
pub kind: Option<AdminAuditLogActorType>,
959+
#[serde(flatten)]
960+
pub extra: BTreeMap<String, Value>,
961+
}
962+
963+
/// Project scope for an audit log entry.
964+
#[derive(Clone, Debug, Deserialize, PartialEq)]
965+
pub struct AdminAuditLogProject {
966+
#[serde(default)]
967+
pub id: Option<String>,
968+
#[serde(default)]
969+
pub name: Option<String>,
970+
#[serde(flatten)]
971+
pub extra: BTreeMap<String, Value>,
972+
}
973+
974+
/// A log of a user action or configuration change within this organization.
975+
#[derive(Clone, Debug, Deserialize, PartialEq)]
976+
pub struct AdminAuditLog {
977+
pub id: String,
978+
pub effective_at: u64,
979+
#[serde(rename = "type")]
980+
pub event_type: AdminAuditLogEventType,
981+
#[serde(default)]
982+
pub actor: Option<AdminAuditLogActor>,
983+
#[serde(default, rename = "api_key.created")]
984+
pub api_key_created: Option<AdminAuditLogEventDetails>,
985+
#[serde(default, rename = "api_key.deleted")]
986+
pub api_key_deleted: Option<AdminAuditLogEventDetails>,
987+
#[serde(default, rename = "api_key.updated")]
988+
pub api_key_updated: Option<AdminAuditLogEventDetails>,
989+
#[serde(default, rename = "certificate.created")]
990+
pub certificate_created: Option<AdminAuditLogEventDetails>,
991+
#[serde(default, rename = "certificate.deleted")]
992+
pub certificate_deleted: Option<AdminAuditLogEventDetails>,
993+
#[serde(default, rename = "certificate.updated")]
994+
pub certificate_updated: Option<AdminAuditLogEventDetails>,
995+
#[serde(default, rename = "certificates.activated")]
996+
pub certificates_activated: Option<AdminAuditLogEventDetails>,
997+
#[serde(default, rename = "certificates.deactivated")]
998+
pub certificates_deactivated: Option<AdminAuditLogEventDetails>,
999+
#[serde(default, rename = "checkpoint.permission.created")]
1000+
pub checkpoint_permission_created: Option<AdminAuditLogEventDetails>,
1001+
#[serde(default, rename = "checkpoint.permission.deleted")]
1002+
pub checkpoint_permission_deleted: Option<AdminAuditLogEventDetails>,
1003+
#[serde(default, rename = "external_key.registered")]
1004+
pub external_key_registered: Option<AdminAuditLogEventDetails>,
1005+
#[serde(default, rename = "external_key.removed")]
1006+
pub external_key_removed: Option<AdminAuditLogEventDetails>,
1007+
#[serde(default, rename = "group.created")]
1008+
pub group_created: Option<AdminAuditLogEventDetails>,
1009+
#[serde(default, rename = "group.deleted")]
1010+
pub group_deleted: Option<AdminAuditLogEventDetails>,
1011+
#[serde(default, rename = "group.updated")]
1012+
pub group_updated: Option<AdminAuditLogEventDetails>,
1013+
#[serde(default, rename = "invite.accepted")]
1014+
pub invite_accepted: Option<AdminAuditLogEventDetails>,
1015+
#[serde(default, rename = "invite.deleted")]
1016+
pub invite_deleted: Option<AdminAuditLogEventDetails>,
1017+
#[serde(default, rename = "invite.sent")]
1018+
pub invite_sent: Option<AdminAuditLogEventDetails>,
1019+
#[serde(default, rename = "ip_allowlist.config.activated")]
1020+
pub ip_allowlist_config_activated: Option<AdminAuditLogEventDetails>,
1021+
#[serde(default, rename = "ip_allowlist.config.deactivated")]
1022+
pub ip_allowlist_config_deactivated: Option<AdminAuditLogEventDetails>,
1023+
#[serde(default, rename = "ip_allowlist.created")]
1024+
pub ip_allowlist_created: Option<AdminAuditLogEventDetails>,
1025+
#[serde(default, rename = "ip_allowlist.deleted")]
1026+
pub ip_allowlist_deleted: Option<AdminAuditLogEventDetails>,
1027+
#[serde(default, rename = "ip_allowlist.updated")]
1028+
pub ip_allowlist_updated: Option<AdminAuditLogEventDetails>,
1029+
#[serde(default, rename = "login.failed")]
1030+
pub login_failed: Option<AdminAuditLogEventDetails>,
1031+
#[serde(default, rename = "login.succeeded")]
1032+
pub login_succeeded: Option<Value>,
1033+
#[serde(default, rename = "logout.failed")]
1034+
pub logout_failed: Option<AdminAuditLogEventDetails>,
1035+
#[serde(default, rename = "logout.succeeded")]
1036+
pub logout_succeeded: Option<Value>,
1037+
#[serde(default, rename = "organization.updated")]
1038+
pub organization_updated: Option<AdminAuditLogEventDetails>,
1039+
#[serde(default)]
1040+
pub project: Option<AdminAuditLogProject>,
1041+
#[serde(default, rename = "project.archived")]
1042+
pub project_archived: Option<AdminAuditLogEventDetails>,
1043+
#[serde(default, rename = "project.created")]
1044+
pub project_created: Option<AdminAuditLogEventDetails>,
1045+
#[serde(default, rename = "project.deleted")]
1046+
pub project_deleted: Option<AdminAuditLogEventDetails>,
1047+
#[serde(default, rename = "project.updated")]
1048+
pub project_updated: Option<AdminAuditLogEventDetails>,
1049+
#[serde(default, rename = "rate_limit.deleted")]
1050+
pub rate_limit_deleted: Option<AdminAuditLogEventDetails>,
1051+
#[serde(default, rename = "rate_limit.updated")]
1052+
pub rate_limit_updated: Option<AdminAuditLogEventDetails>,
1053+
#[serde(default, rename = "role.assignment.created")]
1054+
pub role_assignment_created: Option<AdminAuditLogEventDetails>,
1055+
#[serde(default, rename = "role.assignment.deleted")]
1056+
pub role_assignment_deleted: Option<AdminAuditLogEventDetails>,
1057+
#[serde(default, rename = "role.created")]
1058+
pub role_created: Option<AdminAuditLogEventDetails>,
1059+
#[serde(default, rename = "role.deleted")]
1060+
pub role_deleted: Option<AdminAuditLogEventDetails>,
1061+
#[serde(default, rename = "role.updated")]
1062+
pub role_updated: Option<AdminAuditLogEventDetails>,
1063+
#[serde(default, rename = "scim.disabled")]
1064+
pub scim_disabled: Option<AdminAuditLogEventDetails>,
1065+
#[serde(default, rename = "scim.enabled")]
1066+
pub scim_enabled: Option<AdminAuditLogEventDetails>,
1067+
#[serde(default, rename = "service_account.created")]
1068+
pub service_account_created: Option<AdminAuditLogEventDetails>,
1069+
#[serde(default, rename = "service_account.deleted")]
1070+
pub service_account_deleted: Option<AdminAuditLogEventDetails>,
1071+
#[serde(default, rename = "service_account.updated")]
1072+
pub service_account_updated: Option<AdminAuditLogEventDetails>,
1073+
#[serde(default, rename = "user.added")]
1074+
pub user_added: Option<AdminAuditLogEventDetails>,
1075+
#[serde(default, rename = "user.deleted")]
1076+
pub user_deleted: Option<AdminAuditLogEventDetails>,
1077+
#[serde(default, rename = "user.updated")]
1078+
pub user_updated: Option<AdminAuditLogEventDetails>,
1079+
#[serde(flatten)]
1080+
pub extra: BTreeMap<String, Value>,
1081+
}
1082+
1083+
pub type AdminAuditLogListResponse = AdminConversationCursorPage<AdminAuditLog>;
1084+
8741085
/// Organization audit-log effective-time filter.
8751086
#[derive(Clone, Debug, Default, Eq, PartialEq)]
8761087
pub struct AdminAuditLogEffectiveAtParams {
@@ -2875,7 +3086,7 @@ impl AuditLogs {
28753086
pub fn list(
28763087
&self,
28773088
params: impl Into<AdminQueryParams>,
2878-
) -> Result<ApiResponse<AdminValue>, OpenAIError> {
3089+
) -> Result<ApiResponse<AdminAuditLogListResponse>, OpenAIError> {
28793090
get_query(&self.runtime, "/organization/audit_logs", params)
28803091
}
28813092
}

‎tests/admin_contract.rs‎

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,35 @@ fn usage_page_json(result_object: &str) -> Value {
356356
})
357357
}
358358

359+
fn audit_log_json(id: &str) -> Value {
360+
json!({
361+
"id": id,
362+
"effective_at": 1_717_172_600u64,
363+
"type": "project.created",
364+
"actor": {
365+
"type": "session",
366+
"session": {
367+
"ip_address": "203.0.113.10",
368+
"user": {
369+
"id": "user_admin",
370+
"email": "ops@example.com"
371+
}
372+
}
373+
},
374+
"project": {
375+
"id": "proj_research",
376+
"name": "Research"
377+
},
378+
"project.created": {
379+
"id": "proj_research",
380+
"data": {
381+
"name": "research",
382+
"title": "Research"
383+
}
384+
}
385+
})
386+
}
387+
359388
fn certificate_json(
360389
id: &str,
361390
object: &str,
@@ -910,6 +939,14 @@ fn admin_organization_typed_params_preserve_queries_and_bodies() {
910939
let mut responses = (0..24)
911940
.map(|index| json_response(json!({"id": format!("typed_admin_{index}")}).to_string()))
912941
.collect::<Vec<_>>();
942+
responses[0] = json_response(
943+
json!({
944+
"data": [audit_log_json("audit_1")],
945+
"has_more": true,
946+
"last_id": "audit_1"
947+
})
948+
.to_string(),
949+
);
913950
responses[1] = json_response(organization_invite_json("invite_new").to_string());
914951
responses[2] = json_response(
915952
json!({
@@ -1026,7 +1063,8 @@ fn admin_organization_typed_params_preserve_queries_and_bodies() {
10261063
let client = client(&server.url());
10271064
let org = client.admin().organization();
10281065

1029-
org.audit_logs()
1066+
let audit_logs = org
1067+
.audit_logs()
10301068
.list(AdminAuditLogListParams {
10311069
actor_emails: Some(vec![
10321070
String::from("ops@example.com"),
@@ -1046,6 +1084,27 @@ fn admin_organization_typed_params_preserve_queries_and_bodies() {
10461084
resource_ids: Some(vec![String::from("res_1")]),
10471085
})
10481086
.unwrap();
1087+
assert_eq!(audit_logs.output.data[0].id, "audit_1");
1088+
assert_eq!(
1089+
audit_logs.output.data[0].event_type,
1090+
AdminAuditLogEventType::ProjectCreated
1091+
);
1092+
assert_eq!(
1093+
audit_logs.output.data[0]
1094+
.actor
1095+
.as_ref()
1096+
.and_then(|actor| actor.kind.as_ref()),
1097+
Some(&AdminAuditLogActorType::Session)
1098+
);
1099+
assert_eq!(
1100+
audit_logs.output.data[0]
1101+
.project_created
1102+
.as_ref()
1103+
.and_then(|event| event.get("id"))
1104+
.and_then(Value::as_str),
1105+
Some("proj_research")
1106+
);
1107+
assert_eq!(audit_logs.output.next_after(), Some("audit_1"));
10491108

10501109
let invite = org
10511110
.invites()

0 commit comments

Comments
 (0)