use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use crate::ids::{SecretId, UserId, WorkspaceId}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum SecretKind { Token, UsernamePassword, Header, Generic, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum SecretStatus { Active, Disabled, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Secret { pub id: SecretId, pub workspace_id: WorkspaceId, pub name: String, pub kind: SecretKind, pub status: SecretStatus, pub current_version: u32, #[serde(with = "time::serde::rfc3339")] pub created_at: OffsetDateTime, #[serde(with = "time::serde::rfc3339")] pub updated_at: OffsetDateTime, #[serde(with = "time::serde::rfc3339::option")] pub last_used_at: Option, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SecretVersion { pub secret_id: SecretId, pub version: u32, pub ciphertext: String, pub key_version: String, #[serde(with = "time::serde::rfc3339")] pub created_at: OffsetDateTime, pub created_by: Option, } #[cfg(test)] mod tests { use serde_json::json; use time::{OffsetDateTime, format_description::well_known::Rfc3339}; use super::{Secret, SecretKind, SecretStatus, SecretVersion}; use crate::ids::{SecretId, UserId, WorkspaceId}; #[test] fn secret_serializes_timestamps_as_rfc3339() { let secret = Secret { id: SecretId::new("secret_01"), workspace_id: WorkspaceId::new("ws_01"), name: "primary".to_owned(), kind: SecretKind::Token, status: SecretStatus::Active, current_version: 2, created_at: OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap(), updated_at: OffsetDateTime::parse("2026-03-25T12:05:00Z", &Rfc3339).unwrap(), last_used_at: Some(OffsetDateTime::parse("2026-03-25T12:07:00Z", &Rfc3339).unwrap()), }; let value = serde_json::to_value(&secret).unwrap(); assert_eq!(value["created_at"], json!("2026-03-25T12:00:00Z")); assert_eq!(value["updated_at"], json!("2026-03-25T12:05:00Z")); assert_eq!(value["last_used_at"], json!("2026-03-25T12:07:00Z")); } #[test] fn secret_version_deserializes_created_at_from_rfc3339() { let version: SecretVersion = serde_json::from_value(json!({ "secret_id": "secret_01", "version": 2, "ciphertext": "opaque", "key_version": "v2", "created_at": "2026-03-25T12:07:00Z", "created_by": "user_01" })) .unwrap(); assert_eq!( version.created_at, OffsetDateTime::parse("2026-03-25T12:07:00Z", &Rfc3339).unwrap() ); assert_eq!(version.created_by, Some(UserId::new("user_01"))); } }