| name | handle-secrets |
| description | Guide for handling sensitive data (secrets) in this Rust project. NEVER use String for API tokens, passwords, private keys, or database credentials. Use ApiToken or Password wrapper types from src/shared/secrets/, and PlainApiToken/PlainPassword at DTO boundaries. Call .expose_secret() only when the actual value is needed. Prevents accidental exposure through Debug output and logs. Use when working with credentials, API keys, tokens, passwords, or any sensitive configuration. Triggers on "secret", "API token", "password", "credential", "sensitive data", "ApiToken", "secrecy", or "expose secret". |
| metadata | {"author":"torrust","version":"1.0"} |
Handling Sensitive Data (Secrets)
Core Rule
NEVER use String for sensitive data. Use wrapper types from src/shared/secrets/.
pub struct HetznerConfig {
pub api_token: String,
}
println!("{config:?}");
use crate::shared::secrets::ApiToken;
pub struct HetznerConfig {
pub api_token: ApiToken,
}
println!("{config:?}");
Type Reference
| Type | Use for | Where |
|---|
ApiToken | Cloud API tokens, admin tokens, API keys | Domain / Infra |
Password | DB passwords, SSH passwords, service creds | Domain / Infra |
PlainApiToken | DTO boundaries accepting raw string input | Config DTOs |
PlainPassword | DTO boundaries accepting raw string input | Config DTOs |
PlainApiToken and PlainPassword are type aliases for String — they signal "this will become a secret".
Using Secrets
use crate::shared::secrets::ApiToken;
use secrecy::ExposeSecret;
let token = ApiToken::from("my-api-token-123");
let token_str: &str = token.expose_secret();
DTO Boundary Pattern
use crate::shared::secrets::{PlainApiToken, ApiToken};
#[derive(Deserialize)]
pub struct HetznerSection {
pub api_token: PlainApiToken,
}
let config = HetznerConfig {
api_token: ApiToken::from(dto.api_token),
};
Checklist
Reference
Full guide: docs/contributing/secret-handling.md
ADR: docs/decisions/secrecy-crate-for-sensitive-data.md