ironflow_api/routes/secrets/
update.rs1use axum::Json;
4use axum::extract::{Path, State};
5use axum::response::IntoResponse;
6use serde::Deserialize;
7use validator::Validate;
8
9use ironflow_auth::extractor::Authenticated;
10
11use crate::entities::SecretResponse;
12use crate::error::ApiError;
13use crate::response::ok;
14use crate::state::AppState;
15
16#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
18#[derive(Debug, Deserialize, Validate)]
19pub struct UpdateSecretRequest {
20 #[validate(length(min = 1, max = 65536))]
22 pub value: String,
23}
24
25#[cfg_attr(
36 feature = "openapi",
37 utoipa::path(
38 put,
39 path = "/api/v1/secrets/{key}",
40 tags = ["secrets"],
41 params(("key" = String, Path, description = "Secret key")),
42 request_body(content = UpdateSecretRequest, description = "New secret value"),
43 responses(
44 (status = 200, description = "Secret updated", body = SecretResponse),
45 (status = 400, description = "Invalid input"),
46 (status = 401, description = "Unauthorized"),
47 (status = 403, description = "Forbidden"),
48 (status = 404, description = "Secret not found")
49 ),
50 security(("Bearer" = []))
51 )
52)]
53pub async fn update_secret(
54 auth: Authenticated,
55 State(state): State<AppState>,
56 Path(key): Path<String>,
57 Json(req): Json<UpdateSecretRequest>,
58) -> Result<impl IntoResponse, ApiError> {
59 if !auth.is_admin() {
60 return Err(ApiError::Forbidden);
61 }
62
63 req.validate()
64 .map_err(|e| ApiError::BadRequest(e.to_string()))?;
65
66 let existing = state.store.get_secret(&key).await?;
67 if existing.is_none() {
68 return Err(ApiError::SecretNotFound(key));
69 }
70
71 let secret = state.store.set_secret(&key, &req.value).await?;
72
73 Ok(ok(SecretResponse::from(secret)))
74}