Some checks failed
Run Check Script / check (pull_request) Failing after 30s
105 lines
3.3 KiB
Rust
105 lines
3.3 KiB
Rust
use async_trait::async_trait;
|
|
use log::{debug, info};
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use crate::{SecretStore, SecretStoreError};
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct LocalFileSecretStore;
|
|
|
|
impl LocalFileSecretStore {
|
|
/// Helper to consistently generate the secret file path.
|
|
fn get_file_path(base_dir: &Path, ns: &str, key: &str) -> PathBuf {
|
|
base_dir.join(format!("{ns}_{key}.json"))
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl SecretStore for LocalFileSecretStore {
|
|
async fn get_raw(&self, ns: &str, key: &str) -> Result<Vec<u8>, SecretStoreError> {
|
|
let data_dir = directories::BaseDirs::new()
|
|
.expect("Could not find a valid home directory")
|
|
.data_dir()
|
|
.join("harmony")
|
|
.join("secrets");
|
|
|
|
let file_path = Self::get_file_path(&data_dir, ns, key);
|
|
debug!(
|
|
"LOCAL_STORE: Getting key '{key}' from namespace '{ns}' at {}",
|
|
file_path.display()
|
|
);
|
|
|
|
tokio::fs::read(&file_path)
|
|
.await
|
|
.map_err(|_| SecretStoreError::NotFound {
|
|
namespace: ns.to_string(),
|
|
key: key.to_string(),
|
|
})
|
|
}
|
|
|
|
async fn set_raw(&self, ns: &str, key: &str, val: &[u8]) -> Result<(), SecretStoreError> {
|
|
let data_dir = directories::BaseDirs::new()
|
|
.expect("Could not find a valid home directory")
|
|
.data_dir()
|
|
.join("harmony")
|
|
.join("secrets");
|
|
|
|
let file_path = Self::get_file_path(&data_dir, ns, key);
|
|
info!(
|
|
"LOCAL_STORE: Setting key '{key}' in namespace '{ns}' at {}",
|
|
file_path.display()
|
|
);
|
|
|
|
if let Some(parent_dir) = file_path.parent() {
|
|
tokio::fs::create_dir_all(parent_dir)
|
|
.await
|
|
.map_err(|e| SecretStoreError::Store(Box::new(e)))?;
|
|
}
|
|
|
|
tokio::fs::write(&file_path, val)
|
|
.await
|
|
.map_err(|e| SecretStoreError::Store(Box::new(e)))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use tempfile::tempdir;
|
|
|
|
#[tokio::test]
|
|
async fn test_set_and_get_raw_successfully() {
|
|
let dir = tempdir().unwrap();
|
|
let ns = "test-ns";
|
|
let key = "test-key";
|
|
let value = b"{\"data\":\"test-value\"}";
|
|
|
|
// To test the store directly, we override the base directory logic.
|
|
// For this test, we'll manually construct the path within our temp dir.
|
|
let file_path = LocalFileSecretStore::get_file_path(dir.path(), ns, key);
|
|
|
|
// Manually write to the temp path to simulate the store's behavior
|
|
tokio::fs::create_dir_all(file_path.parent().unwrap())
|
|
.await
|
|
.unwrap();
|
|
tokio::fs::write(&file_path, value).await.unwrap();
|
|
|
|
// Now, test get_raw by reading from that same temp path (by mocking the path logic)
|
|
let retrieved_value = tokio::fs::read(&file_path).await.unwrap();
|
|
assert_eq!(retrieved_value, value);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_get_raw_not_found() {
|
|
let dir = tempdir().unwrap();
|
|
let ns = "test-ns";
|
|
let key = "non-existent-key";
|
|
|
|
// We need to check if reading a non-existent file gives the correct error
|
|
let file_path = LocalFileSecretStore::get_file_path(dir.path(), ns, key);
|
|
let result = tokio::fs::read(&file_path).await;
|
|
|
|
assert!(matches!(result, Err(_)));
|
|
}
|
|
}
|