fly_sdk/
secrets.rs

1use crate::API_BASE_URL;
2use reqwest::Client;
3use serde::{Deserialize, Serialize};
4use std::error::Error;
5use tracing::debug;
6
7#[derive(Debug, Deserialize, Serialize)]
8pub struct Secret {
9    pub label: String,
10    pub publickey: Vec<i32>,
11    #[serde(rename = "type")]
12    pub stype: String,
13}
14
15#[derive(Debug, Serialize)]
16pub struct SecretValue {
17    pub value: Vec<i32>,
18}
19
20impl SecretValue {
21    pub fn new(value: Vec<i32>) -> Self {
22        Self { value }
23    }
24}
25
26pub struct SecretsManager {
27    client: Client,
28    api_token: String,
29}
30
31impl SecretsManager {
32    pub fn new(client: Client, api_token: String) -> Self {
33        Self { client, api_token }
34    }
35
36    pub async fn list_secrets(&self, app_name: &str) -> Result<Vec<Secret>, Box<dyn Error>> {
37        let url = format!("{API_BASE_URL}/apps/{}/secrets", app_name);
38        let response = self
39            .client
40            .get(&url)
41            .bearer_auth(&self.api_token)
42            .send()
43            .await?;
44
45        if response.status().is_success() {
46            let secrets = response.json::<Vec<Secret>>().await?;
47            debug!("Successfully fetched secrets: {:?}", secrets);
48            Ok(secrets)
49        } else {
50            Err(format!("Failed to fetch secrets: {}", response.status()).into())
51        }
52    }
53
54    pub async fn create_secret(
55        &self,
56        app_name: &str,
57        secret_label: &str,
58        secret_type: &str,
59        value_request: SecretValue,
60    ) -> Result<Secret, Box<dyn Error>> {
61        debug!("Creating secret: {}", secret_label);
62        let url = format!(
63            "{API_BASE_URL}/apps/{}/secrets/{}/type/{}",
64            app_name, secret_label, secret_type
65        );
66        let response = self
67            .client
68            .post(&url)
69            .bearer_auth(&self.api_token)
70            .json(&value_request)
71            .send()
72            .await?;
73
74        let status = response.status();
75        if status.is_success() {
76            let secret = response.json::<Secret>().await?;
77            Ok(secret)
78        } else {
79            let error_text = response.text().await?;
80            Err(format!("Failed to create secret: {} - {}", status, error_text).into())
81        }
82    }
83
84    pub async fn generate_secret(
85        &self,
86        app_name: &str,
87        secret_label: &str,
88        secret_type: &str,
89    ) -> Result<(), Box<dyn Error>> {
90        debug!("Generating secret: {}", secret_label);
91        let url = format!(
92            "{API_BASE_URL}/apps/{}/secrets/{}/type/{}/generate",
93            app_name, secret_label, secret_type
94        );
95        let response = self
96            .client
97            .post(&url)
98            .bearer_auth(&self.api_token)
99            .send()
100            .await?;
101
102        if response.status().is_success() {
103            debug!("Successfully generated secret: {}", secret_label);
104            Ok(())
105        } else {
106            Err(format!("Failed to generate secret: {}", response.status()).into())
107        }
108    }
109
110    pub async fn destroy_secret(
111        &self,
112        app_name: &str,
113        secret_label: &str,
114    ) -> Result<(), Box<dyn Error>> {
115        debug!("Deleting secret: {}", secret_label);
116        let url = format!("{API_BASE_URL}/apps/{}/secrets/{}", app_name, secret_label);
117        let response = self
118            .client
119            .delete(&url)
120            .bearer_auth(&self.api_token)
121            .send()
122            .await?;
123
124        if response.status().is_success() {
125            debug!("Successfully deleted secret: {}", secret_label);
126            Ok(())
127        } else {
128            Err(format!("Failed to delete secret: {}", response.status()).into())
129        }
130    }
131}