nixfleet_proto/
bootstrap_nonces.rs1use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11
12use crate::fleet_resolved::Meta;
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15#[serde(rename_all = "camelCase")]
16pub struct BootstrapNonces {
17 pub schema_version: u32,
18 pub bootstrap_nonces: Vec<BootstrapNonceEntry>,
21 pub meta: Meta,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25#[serde(rename_all = "camelCase")]
26pub struct BootstrapNonceEntry {
27 pub nonce: String,
29 pub hostname: String,
32 pub expires_at: DateTime<Utc>,
36 #[serde(default)]
38 pub minted_at: Option<DateTime<Utc>>,
39 #[serde(default)]
41 pub minted_by: Option<String>,
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 fn meta_v1() -> Meta {
49 Meta {
50 schema_version: 1,
51 signed_at: Some("2026-05-13T10:00:00Z".parse().unwrap()),
52 ci_commit: Some("abc12345".into()),
53 signature_algorithm: Some("ecdsa-p256".into()),
54 }
55 }
56
57 #[test]
58 fn optional_audit_fields_default_to_none() {
59 let json = r#"{
60 "nonce": "1ed727e1f9c24e6ab87eb9693ba35e26",
61 "hostname": "agent-01",
62 "expiresAt": "2026-05-13T22:57:45Z"
63 }"#;
64 let entry: BootstrapNonceEntry = serde_json::from_str(json).unwrap();
65 assert_eq!(entry.nonce, "1ed727e1f9c24e6ab87eb9693ba35e26");
66 assert_eq!(entry.hostname, "agent-01");
67 assert_eq!(entry.minted_at, None);
68 assert_eq!(entry.minted_by, None);
69 }
70
71 #[test]
72 fn camelcase_on_wire() {
73 let r = BootstrapNonces {
74 schema_version: 1,
75 bootstrap_nonces: vec![],
76 meta: meta_v1(),
77 };
78 let s = serde_json::to_string(&r).unwrap();
79 assert!(s.contains("\"schemaVersion\""));
80 assert!(s.contains("\"bootstrapNonces\""));
81 }
82}