Skip to main content

confium_operator/
crd.rs

1//! CRD definitions for Confium Kubernetes resources.
2
3use serde::{Deserialize, Serialize};
4
5/// `ConfiumSigningCeremony` custom resource spec.
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct SigningCeremonySpec {
8    /// Threshold scheme: `cmp20` or `gg18`.
9    pub scheme: String,
10    /// Threshold T.
11    pub threshold: u32,
12    /// Total party count N.
13    #[serde(rename = "partyCount")]
14    pub party_count: u32,
15    /// Reference to the message to sign.
16    #[serde(rename = "messageRef")]
17    pub message_ref: ConfigMapRef,
18    /// Reference to where the output signature should be stored.
19    #[serde(rename = "outputRef")]
20    pub output_ref: SecretRef,
21}
22
23/// Reference to a ConfigMap containing the message to sign.
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ConfigMapRef {
26    pub config_map: String,
27    pub key: String,
28}
29
30/// Reference to a Secret where the signature will be stored.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct SecretRef {
33    pub secret: String,
34}
35
36/// Status of a signing ceremony.
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct SigningCeremonyStatus {
39    pub phase: CeremonyPhase,
40    pub started_at: Option<String>,
41    pub completed_at: Option<String>,
42    pub signature_secret: Option<String>,
43    pub error: Option<String>,
44}
45
46/// Phases of a signing ceremony lifecycle.
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
48#[serde(rename_all = "lowercase")]
49pub enum CeremonyPhase {
50    /// Ceremony has been created but not started.
51    Pending,
52    /// DKG is in progress.
53    KeygenRunning,
54    /// DKG complete; signing in progress.
55    Signing,
56    /// Ceremony completed; signature stored.
57    Completed,
58    /// Ceremony failed.
59    Failed,
60}
61
62/// The full CRD object.
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct SigningCeremony {
65    #[serde(rename = "apiVersion")]
66    pub api_version: String,
67    pub kind: String,
68    pub metadata: ObjectMeta,
69    pub spec: SigningCeremonySpec,
70    pub status: Option<SigningCeremonyStatus>,
71}
72
73/// Kubernetes object metadata (simplified).
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct ObjectMeta {
76    pub name: String,
77    pub namespace: Option<String>,
78    #[serde(default)]
79    pub labels: std::collections::BTreeMap<String, String>,
80}
81
82/// Generate the CRD YAML for `kubectl apply`.
83pub fn crd_yaml() -> String {
84    r#"apiVersion: apiextensions.k8s.io/v1
85kind: CustomResourceDefinition
86metadata:
87  name: confiumsigningceremonies.confium.org
88spec:
89  group: confium.org
90  names:
91    kind: ConfiumSigningCeremony
92    listKind: ConfiumSigningCeremonyList
93    plural: confiumsigningceremonies
94    singular: confiumsigningceremony
95  scope: Namespaced
96  versions:
97    - name: v1alpha1
98      served: true
99      storage: true
100      schema:
101        openAPIV3Schema:
102          type: object
103          properties:
104            spec:
105              type: object
106              required: [scheme, threshold, partyCount]
107              properties:
108                scheme:
109                  type: string
110                  enum: [cmp20, gg18]
111                threshold:
112                  type: integer
113                  minimum: 1
114                partyCount:
115                  type: integer
116                  minimum: 1
117                messageRef:
118                  type: object
119                  properties:
120                    configMap: { type: string }
121                    key: { type: string }
122                outputRef:
123                  type: object
124                  properties:
125                    secret: { type: string }
126            status:
127              type: object
128              properties:
129                phase:
130                  type: string
131                  enum: [pending, keygenrunning, signing, completed, failed]
132                startedAt: { type: string }
133                completedAt: { type: string }
134                signatureSecret: { type: string }
135                error: { type: string }
136"#
137    .to_string()
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn crd_yaml_is_valid_yaml() {
146        let yaml = crd_yaml();
147        let parsed: serde_yaml::Value = serde_yaml::from_str(&yaml).expect("CRD YAML must parse");
148        assert_eq!(parsed["kind"], "CustomResourceDefinition");
149    }
150
151    #[test]
152    fn ceremony_spec_round_trips() {
153        let spec = SigningCeremonySpec {
154            scheme: "cmp20".to_string(),
155            threshold: 3,
156            party_count: 5,
157            message_ref: ConfigMapRef {
158                config_map: "release-artifact".to_string(),
159                key: "release.tar.gz".to_string(),
160            },
161            output_ref: SecretRef {
162                secret: "release-signature".to_string(),
163            },
164        };
165        let json = serde_json::to_string(&spec).unwrap();
166        let parsed: SigningCeremonySpec = serde_json::from_str(&json).unwrap();
167        assert_eq!(parsed.scheme, "cmp20");
168        assert_eq!(parsed.threshold, 3);
169    }
170}