zlayer_types/api/secrets.rs
1//! Secrets management API DTOs.
2//!
3//! Wire types for the secrets endpoints. Secret values are never exposed
4//! through the API except via an explicit admin-only `?reveal=true` request —
5//! only metadata is returned for listing and retrieval.
6
7use serde::{Deserialize, Serialize};
8use utoipa::ToSchema;
9
10/// Request to create or update a secret.
11///
12/// `scope` is optional and only honored on the legacy code path — when set
13/// alongside `?environment=`, the request is rejected.
14#[derive(Debug, Deserialize, ToSchema)]
15pub struct CreateSecretRequest {
16 /// The name of the secret.
17 pub name: String,
18 /// The secret value (will be encrypted at rest).
19 pub value: String,
20 /// Optional explicit scope (legacy form). Mutually exclusive with the
21 /// `?environment=` query parameter.
22 #[serde(default)]
23 pub scope: Option<String>,
24}
25
26/// Response containing secret metadata. Never includes the value unless
27/// the caller is on the explicit `?reveal=true` admin path, in which case
28/// `value` is populated.
29#[derive(Debug, Serialize, Deserialize, ToSchema)]
30pub struct SecretMetadataResponse {
31 /// The name/identifier of the secret.
32 pub name: String,
33 /// Unix timestamp when the secret was created.
34 pub created_at: i64,
35 /// Unix timestamp when the secret was last updated.
36 pub updated_at: i64,
37 /// Version number of the secret (incremented on each update).
38 pub version: u32,
39 /// Plaintext value — populated only on `?reveal=true` admin reads.
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub value: Option<String>,
42}
43
44/// Request body for secret rotation.
45#[derive(Debug, Deserialize, ToSchema)]
46pub struct RotateSecretRequest {
47 /// The new secret value (will be encrypted at rest).
48 pub value: String,
49}
50
51/// Response returned by the rotate endpoint.
52#[derive(Debug, Serialize, Deserialize, ToSchema)]
53pub struct RotateSecretResponse {
54 /// The secret name.
55 pub name: String,
56 /// Version prior to rotation. `None` if the secret did not exist (won't
57 /// happen today — rotate rejects missing secrets — but preserved for
58 /// forward compatibility).
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub previous_version: Option<u32>,
61 /// Version after rotation.
62 pub new_version: u32,
63}
64
65/// Response for the batch reveal endpoint — returns every secret in an env as plaintext.
66/// Admin-only for now (Phase 3 will gate this on per-env Read permission instead).
67#[derive(Debug, Serialize, Deserialize, ToSchema)]
68pub struct RevealAllSecretsResponse {
69 /// The environment id the secrets were revealed from.
70 pub environment: String,
71 /// Name → plaintext value map. Includes every secret in the scope.
72 pub secrets: std::collections::HashMap<String, String>,
73}
74
75/// Result body for `POST /api/v1/secrets/bulk-import`.
76#[derive(Debug, Serialize, Deserialize, ToSchema)]
77pub struct BulkImportResponse {
78 /// Number of new secrets created.
79 pub created: usize,
80 /// Number of existing secrets updated.
81 pub updated: usize,
82 /// Per-line errors. Empty when every line parsed and stored cleanly.
83 pub errors: Vec<String>,
84}
85
86/// Query for create / list / get / delete endpoints.
87#[derive(Debug, Default, Deserialize)]
88pub struct SecretsScopeQuery {
89 /// Environment id whose namespace to operate in. Mutually exclusive
90 /// with `scope`.
91 #[serde(default)]
92 pub environment: Option<String>,
93 /// Explicit scope string (legacy). Mutually exclusive with `environment`.
94 #[serde(default)]
95 pub scope: Option<String>,
96}
97
98/// Query for `GET /api/v1/secrets/{name}` — extends the scope query with a
99/// `reveal` flag for admin-only plaintext reads.
100#[derive(Debug, Default, Deserialize)]
101pub struct GetSecretQuery {
102 /// Environment id whose namespace to read from. Mutually exclusive with `scope`.
103 #[serde(default)]
104 pub environment: Option<String>,
105 /// Explicit scope string (legacy). Mutually exclusive with `environment`.
106 #[serde(default)]
107 pub scope: Option<String>,
108 /// When true, include the plaintext value. Admin only.
109 #[serde(default)]
110 pub reveal: bool,
111}
112
113/// Query for `POST /api/v1/secrets/bulk-import` — `environment` is required.
114#[derive(Debug, Deserialize)]
115pub struct BulkImportQuery {
116 /// Environment id to import the secrets into.
117 pub environment: String,
118}