use std::collections::HashMap;
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
use crate::{env, export, policy, types};
#[pyclass]
struct Vault {
inner: types::Vault,
decrypted: types::Murk,
pubkey: String,
}
#[pymethods]
impl Vault {
fn get(&self, key: &str) -> PyResult<Option<String>> {
let value = crate::get_secret(&self.decrypted, key, &self.pubkey).map(str::to_string);
if value.is_some() {
policy::enforce_agent_policy(
&self.inner,
&self.decrypted,
&self.pubkey,
&[key.to_string()],
)
.map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
}
Ok(value)
}
fn export(&self) -> PyResult<HashMap<String, String>> {
let resolved = export::resolve_secrets(&self.inner, &self.decrypted, &self.pubkey, &[]);
let keys: Vec<String> = resolved.keys().cloned().collect();
policy::enforce_agent_policy(&self.inner, &self.decrypted, &self.pubkey, &keys)
.map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
Ok(resolved
.into_iter()
.map(|(k, v)| (k, v.to_string()))
.collect())
}
fn keys(&self) -> Vec<String> {
self.inner.schema.keys().cloned().collect()
}
fn __len__(&self) -> usize {
self.inner.schema.len()
}
fn __getitem__(&self, key: &str) -> PyResult<String> {
self.get(key)?
.ok_or_else(|| PyRuntimeError::new_err(format!("key not found: {key}")))
}
fn __contains__(&self, key: &str) -> bool {
self.inner.schema.contains_key(key)
}
fn __repr__(&self) -> String {
format!(
"Vault({} secrets, {} recipients)",
self.inner.schema.len(),
self.inner.recipients.len()
)
}
}
#[pyfunction]
#[pyo3(signature = (vault_path=".murk"))]
fn load(vault_path: &str) -> PyResult<Vault> {
let (vault, murk, identity) =
crate::load_vault(vault_path).map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
let pubkey = identity
.pubkey_string()
.map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
Ok(Vault {
inner: vault,
decrypted: murk,
pubkey,
})
}
#[pyfunction]
#[pyo3(signature = (key, vault_path=".murk"))]
fn get(key: &str, vault_path: &str) -> PyResult<Option<String>> {
let v = load(vault_path)?;
v.get(key)
}
#[pyfunction]
#[pyo3(signature = (vault_path=".murk"))]
fn export_all(vault_path: &str) -> PyResult<HashMap<String, String>> {
let v = load(vault_path)?;
v.export()
}
#[pyfunction]
fn has_key() -> bool {
env::resolve_key().is_ok()
}
#[pymodule]
fn murk(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<Vault>()?;
m.add_function(wrap_pyfunction!(load, m)?)?;
m.add_function(wrap_pyfunction!(get, m)?)?;
m.add_function(wrap_pyfunction!(export_all, m)?)?;
m.add_function(wrap_pyfunction!(has_key, m)?)?;
Ok(())
}