Skip to main content

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}