Initial commit: Full Crawl API implementation
Some checks failed
CI / Test (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
CI / Build & Push (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled

This commit is contained in:
2026-04-29 07:03:48 +00:00
commit 62994d4f3d
92 changed files with 6176 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
use shared::error::AppError;
pub async fn get_secret(key: &str) -> Result<String, AppError> {
// Priority 1: Environment variable (for local dev)
if let Ok(val) = std::env::var(key) {
return Ok(val);
}
// Priority 2: Try Vault
if let Ok(val) = get_vault_secret(key).await {
return Ok(val);
}
// Priority 3: Try AWS Secrets Manager
if let Ok(val) = get_aws_secret(key).await {
return Ok(val);
}
Err(AppError::Internal(format!("Secret {} not found in any provider", key)))
}
async fn get_vault_secret(key: &str) -> Result<String, AppError> {
let vault_addr = match std::env::var("VAULT_ADDR") {
Ok(addr) => addr,
Err(_) => return Err(AppError::Internal("VAULT_ADDR not set".to_string())),
};
let vault_token = match std::env::var("VAULT_TOKEN") {
Ok(token) => token,
Err(_) => return Err(AppError::Internal("VAULT_TOKEN not set".to_string())),
};
let client = reqwest::Client::new();
let response = client
.get(format!("{}/v1/secret/data/{}", vault_addr, key))
.header("X-Vault-Token", vault_token)
.send()
.await
.map_err(|e| AppError::Internal(format!("Vault request failed: {}", e)))?;
let data: serde_json::Value = response
.json()
.await
.map_err(|e| AppError::Internal(format!("Vault response parse failed: {}", e)))?;
data["data"]["data"][key]
.as_str()
.map(|s| s.to_string())
.ok_or_else(|| AppError::Internal(format!("Secret {} not found in Vault", key)))
}
async fn get_aws_secret(key: &str) -> Result<String, AppError> {
let secret_name = format!("crawlapi/{}", key.to_lowercase().replace('_', "/"));
let config = aws_config::from_env().load().await;
let client = aws_sdk_secretsmanager::Client::new(&config);
let response = client
.get_secret_value()
.secret_id(&secret_name)
.send()
.await
.map_err(|e| AppError::Internal(format!("AWS Secrets Manager error: {}", e)))?;
response
.secret_string()
.map(|s| s.to_string())
.ok_or_else(|| AppError::Internal(format!("Secret {} not found in AWS", key)))
}