Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f69aba2dd8 | |||
| c3487ecd0e | |||
|
db75391fb6
|
|||
|
e3815af69b
|
|||
| 66a485f924 | |||
| 49d7204f89 | |||
|
bbcae1fc2b
|
@@ -1,7 +1,14 @@
|
|||||||
|
## v0.7.1 (2026-06-19)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- sbx mixins must be passed in directories, not as files and the files must be named spec.yaml per new sbx version
|
||||||
|
|
||||||
## v0.7.0 (2026-06-18)
|
## v0.7.0 (2026-06-18)
|
||||||
|
|
||||||
### Feat
|
### Feat
|
||||||
|
|
||||||
|
- added configurable cache path via the COYOTE_CACHE_PATH environment variable
|
||||||
- added a memory option to .set tab completions
|
- added a memory option to .set tab completions
|
||||||
- Added a diagnostic .info tools subcommand to make it easier to see what tools are enabled in all contexts
|
- Added a diagnostic .info tools subcommand to make it easier to see what tools are enabled in all contexts
|
||||||
- Added additional info outputs for enabled skills and sbx directories
|
- Added additional info outputs for enabled skills and sbx directories
|
||||||
|
|||||||
Generated
+5
-5
@@ -1060,9 +1060,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.64"
|
version = "1.2.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
|
checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -1402,7 +1402,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coyote-ai"
|
name = "coyote-ai"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_colours",
|
"ansi_colours",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -6712,9 +6712,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols"
|
name = "wayland-protocols"
|
||||||
version = "0.32.12"
|
version = "0.32.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f"
|
checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "coyote-ai"
|
name = "coyote-ai"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
description = "An all-in-one, batteries included LLM CLI Tool"
|
description = "An all-in-one, batteries included LLM CLI Tool"
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ const SBX_KIT_DIR_NAME: &str = "sbx-kit";
|
|||||||
const SBX_KIT_HASH_FILE: &str = "kit.sha256";
|
const SBX_KIT_HASH_FILE: &str = "kit.sha256";
|
||||||
const SBX_MIXIN_FILE_NAME: &str = "sbx-mixin.yaml";
|
const SBX_MIXIN_FILE_NAME: &str = "sbx-mixin.yaml";
|
||||||
const SBX_VAULT_MIXINS_DIR_NAME: &str = "sbx-vault-mixins";
|
const SBX_VAULT_MIXINS_DIR_NAME: &str = "sbx-vault-mixins";
|
||||||
|
const SBX_MIXIN_KITS_DIR_NAME: &str = "sbx-mixin-kits";
|
||||||
const GIT_DIR_NAME: &str = ".git";
|
const GIT_DIR_NAME: &str = ".git";
|
||||||
const GITIGNORE_FILE_NAME: &str = ".gitignore";
|
const GITIGNORE_FILE_NAME: &str = ".gitignore";
|
||||||
const DEFAULT_VISIBLE_TOOLS: [&str; 18] = [
|
const DEFAULT_VISIBLE_TOOLS: [&str; 18] = [
|
||||||
|
|||||||
+14
-4
@@ -4,8 +4,8 @@ use super::{
|
|||||||
ENV_FILE_NAME, FUNCTIONS_BIN_DIR_NAME, FUNCTIONS_DIR_NAME, GLOBAL_TOOLS_DIR_NAME,
|
ENV_FILE_NAME, FUNCTIONS_BIN_DIR_NAME, FUNCTIONS_DIR_NAME, GLOBAL_TOOLS_DIR_NAME,
|
||||||
GLOBAL_TOOLS_UTILS_DIR_NAME, MACROS_DIR_NAME, MCP_FILE_NAME, MEMORY_DIR_NAME,
|
GLOBAL_TOOLS_UTILS_DIR_NAME, MACROS_DIR_NAME, MCP_FILE_NAME, MEMORY_DIR_NAME,
|
||||||
MEMORY_INDEX_FILE_NAME, ModelsOverride, RAGS_DIR_NAME, ROLES_DIR_NAME, SBX_KIT_DIR_NAME,
|
MEMORY_INDEX_FILE_NAME, ModelsOverride, RAGS_DIR_NAME, ROLES_DIR_NAME, SBX_KIT_DIR_NAME,
|
||||||
SBX_KIT_HASH_FILE, SBX_MIXIN_FILE_NAME, SBX_VAULT_MIXINS_DIR_NAME, SKILLS_DIR_NAME,
|
SBX_KIT_HASH_FILE, SBX_MIXIN_FILE_NAME, SBX_MIXIN_KITS_DIR_NAME, SBX_VAULT_MIXINS_DIR_NAME,
|
||||||
WORKSPACE_MEMORY_DIR_NAME,
|
SKILLS_DIR_NAME, WORKSPACE_MEMORY_DIR_NAME,
|
||||||
};
|
};
|
||||||
use crate::client::ProviderModels;
|
use crate::client::ProviderModels;
|
||||||
use crate::utils::{get_env_name, list_file_names, normalize_env_name};
|
use crate::utils::{get_env_name, list_file_names, normalize_env_name};
|
||||||
@@ -33,8 +33,14 @@ pub fn local_path(name: &str) -> PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache_path() -> PathBuf {
|
pub fn cache_path() -> PathBuf {
|
||||||
let base_dir = dirs::cache_dir().unwrap_or_else(env::temp_dir);
|
if let Ok(v) = env::var(get_env_name("cache_dir")) {
|
||||||
base_dir.join(env!("CARGO_CRATE_NAME"))
|
PathBuf::from(v)
|
||||||
|
} else if let Ok(v) = env::var("XDG_CACHE_HOME") {
|
||||||
|
PathBuf::from(v).join(env!("CARGO_CRATE_NAME"))
|
||||||
|
} else {
|
||||||
|
let base_dir = dirs::cache_dir().unwrap_or_else(env::temp_dir);
|
||||||
|
base_dir.join(env!("CARGO_CRATE_NAME"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sandbox_kit_override() -> Option<PathBuf> {
|
pub fn sandbox_kit_override() -> Option<PathBuf> {
|
||||||
@@ -148,6 +154,10 @@ pub fn sbx_vault_mixins_hash_file() -> PathBuf {
|
|||||||
sbx_vault_mixins_dir().join(SBX_KIT_HASH_FILE)
|
sbx_vault_mixins_dir().join(SBX_KIT_HASH_FILE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sbx_mixin_kits_dir() -> PathBuf {
|
||||||
|
cache_path().join(SBX_MIXIN_KITS_DIR_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn config_file() -> PathBuf {
|
pub fn config_file() -> PathBuf {
|
||||||
match env::var(get_env_name("config_file")) {
|
match env::var(get_env_name("config_file")) {
|
||||||
Ok(value) => PathBuf::from(value),
|
Ok(value) => PathBuf::from(value),
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
use std::fs::{read_dir, read_to_string};
|
use std::fs::{read_dir, read_to_string};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use serde_yaml::Value;
|
use serde_yaml::Value;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
use crate::config::paths;
|
use crate::config::paths;
|
||||||
|
|
||||||
const SBX_MIXIN_FILE_NAME: &str = "sbx-mixin.yaml";
|
const SBX_MIXIN_FILE_NAME: &str = "sbx-mixin.yaml";
|
||||||
|
const KIT_SPEC_FILE_NAME: &str = "spec.yaml";
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DiscoveredMixin {
|
pub struct DiscoveredMixin {
|
||||||
@@ -17,6 +20,46 @@ pub struct DiscoveredMixin {
|
|||||||
pub domain_count: usize,
|
pub domain_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DiscoveredMixin {
|
||||||
|
pub fn kit_path(&self) -> Result<PathBuf> {
|
||||||
|
if self.path.is_dir() {
|
||||||
|
return Ok(self.path.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap_mixin_as_kit(&self.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap_mixin_as_kit(mixin_path: &Path) -> Result<PathBuf> {
|
||||||
|
let bytes = fs::read(mixin_path)
|
||||||
|
.with_context(|| format!("Failed to read sbx mixin {}", mixin_path.display()))?;
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(&bytes);
|
||||||
|
let hash = format!("{:x}", hasher.finalize());
|
||||||
|
|
||||||
|
let kit_dir = paths::sbx_mixin_kits_dir().join(&hash);
|
||||||
|
let spec_path = kit_dir.join(KIT_SPEC_FILE_NAME);
|
||||||
|
|
||||||
|
if let Ok(existing) = fs::read(&spec_path)
|
||||||
|
&& existing == bytes
|
||||||
|
{
|
||||||
|
return Ok(kit_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::create_dir_all(&kit_dir)
|
||||||
|
.with_context(|| format!("Failed to create mixin kit dir {}", kit_dir.display()))?;
|
||||||
|
fs::write(&spec_path, &bytes)
|
||||||
|
.with_context(|| format!("Failed to write {}", spec_path.display()))?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Wrapped mixin {} as kit at {}",
|
||||||
|
mixin_path.display(),
|
||||||
|
kit_dir.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(kit_dir)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn discover() -> Result<Vec<DiscoveredMixin>> {
|
pub fn discover() -> Result<Vec<DiscoveredMixin>> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
|
|
||||||
@@ -234,4 +277,166 @@ network:
|
|||||||
let found = collect_subdir_mixins(&absent);
|
let found = collect_subdir_mixins(&absent);
|
||||||
assert!(found.is_empty());
|
assert!(found.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod wrap_as_kit {
|
||||||
|
use super::*;
|
||||||
|
use serial_test::serial;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
|
||||||
|
struct TestCacheDirGuard {
|
||||||
|
key: String,
|
||||||
|
previous: Option<OsString>,
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCacheDirGuard {
|
||||||
|
fn new() -> Self {
|
||||||
|
let key = crate::utils::get_env_name("cache_dir");
|
||||||
|
let previous = env::var_os(&key);
|
||||||
|
let nanos = time::SystemTime::now()
|
||||||
|
.duration_since(time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos();
|
||||||
|
let path = env::temp_dir().join(format!("coyote-mixin-wrap-cache-{nanos}"));
|
||||||
|
fs::create_dir_all(&path).unwrap();
|
||||||
|
unsafe {
|
||||||
|
env::set_var(&key, &path);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
key,
|
||||||
|
previous,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestCacheDirGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
match &self.previous {
|
||||||
|
Some(v) => env::set_var(&self.key, v),
|
||||||
|
None => env::remove_var(&self.key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = fs::remove_dir_all(&self.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_mixin(name: &str, content: &str) -> PathBuf {
|
||||||
|
let root = unique_root(&format!("wrap-src-{name}"));
|
||||||
|
let path = root.join("sbx-mixin.yaml");
|
||||||
|
fs::write(&path, content).unwrap();
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn wrap_mixin_as_kit_creates_spec_yaml_with_original_content() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
|
let content = "schemaVersion: \"1\"\nkind: mixin\nname: probe\n";
|
||||||
|
let mixin = write_mixin("content", content);
|
||||||
|
|
||||||
|
let kit_dir = wrap_mixin_as_kit(&mixin).unwrap();
|
||||||
|
let spec = kit_dir.join("spec.yaml");
|
||||||
|
|
||||||
|
assert!(spec.exists(), "spec.yaml must exist in wrapped kit dir");
|
||||||
|
assert_eq!(fs::read_to_string(&spec).unwrap(), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn wrap_mixin_as_kit_is_deterministic_for_identical_content() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
|
let content = "schemaVersion: \"1\"\nkind: mixin\nname: probe\n";
|
||||||
|
let mixin_one = write_mixin("dedup-1", content);
|
||||||
|
let mixin_two = write_mixin("dedup-2", content);
|
||||||
|
|
||||||
|
let kit_a = wrap_mixin_as_kit(&mixin_one).unwrap();
|
||||||
|
let kit_b = wrap_mixin_as_kit(&mixin_two).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
kit_a, kit_b,
|
||||||
|
"same content should share the same content-addressed kit dir"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn wrap_mixin_as_kit_different_content_yields_different_dirs() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
|
let mixin_a = write_mixin("diff-a", "kind: mixin\nname: a\n");
|
||||||
|
let mixin_b = write_mixin("diff-b", "kind: mixin\nname: b\n");
|
||||||
|
|
||||||
|
let kit_a = wrap_mixin_as_kit(&mixin_a).unwrap();
|
||||||
|
let kit_b = wrap_mixin_as_kit(&mixin_b).unwrap();
|
||||||
|
|
||||||
|
assert_ne!(
|
||||||
|
kit_a, kit_b,
|
||||||
|
"different content must hash to different kit dirs"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn wrap_mixin_as_kit_is_idempotent_on_cache_hit() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
|
let mixin = write_mixin("idempotent", "kind: mixin\nname: probe\n");
|
||||||
|
|
||||||
|
let kit_first = wrap_mixin_as_kit(&mixin).unwrap();
|
||||||
|
let spec = kit_first.join("spec.yaml");
|
||||||
|
let mtime_first = fs::metadata(&spec).unwrap().modified().unwrap();
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
|
||||||
|
let kit_second = wrap_mixin_as_kit(&mixin).unwrap();
|
||||||
|
let mtime_second = fs::metadata(kit_second.join("spec.yaml"))
|
||||||
|
.unwrap()
|
||||||
|
.modified()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(kit_first, kit_second);
|
||||||
|
assert_eq!(
|
||||||
|
mtime_first, mtime_second,
|
||||||
|
"cache hit must not rewrite spec.yaml"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn kit_path_passes_through_existing_directory() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
|
let dir = unique_root("kit-path-dir-passthrough");
|
||||||
|
|
||||||
|
let m = DiscoveredMixin {
|
||||||
|
path: dir.clone(),
|
||||||
|
label: "vault".into(),
|
||||||
|
install_count: 1,
|
||||||
|
domain_count: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(m.kit_path().unwrap(), dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn kit_path_wraps_file_into_kit_dir() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
|
let mixin = write_mixin("kit-path-wrap", "kind: mixin\nname: probe\n");
|
||||||
|
|
||||||
|
let m = DiscoveredMixin {
|
||||||
|
path: mixin.clone(),
|
||||||
|
label: mixin.display().to_string(),
|
||||||
|
install_count: 0,
|
||||||
|
domain_count: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let wrapped = m.kit_path().unwrap();
|
||||||
|
assert!(wrapped.is_dir(), "kit_path of a file should be a directory");
|
||||||
|
assert!(wrapped.join("spec.yaml").exists());
|
||||||
|
assert_ne!(
|
||||||
|
wrapped, mixin,
|
||||||
|
"kit_path should not return the original file path"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-8
@@ -347,12 +347,13 @@ fn build_create_args(
|
|||||||
];
|
];
|
||||||
|
|
||||||
for mixin in mixins {
|
for mixin in mixins {
|
||||||
let mixin_str = mixin
|
let mixin_kit = mixin.kit_path()?;
|
||||||
.path
|
let mixin_str = mixin_kit
|
||||||
.to_str()
|
.to_str()
|
||||||
.ok_or_else(|| anyhow!("Mixin path is not valid UTF-8: {}", mixin.path.display()))?;
|
.ok_or_else(|| anyhow!("Mixin kit path is not valid UTF-8: {}", mixin_kit.display()))?
|
||||||
|
.to_string();
|
||||||
args.push("--kit".to_string());
|
args.push("--kit".to_string());
|
||||||
args.push(mixin_str.to_string());
|
args.push(mixin_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.push(SANDBOX_AGENT.to_string());
|
args.push(SANDBOX_AGENT.to_string());
|
||||||
@@ -590,15 +591,24 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn build_create_args_emits_base_kit_before_mixins() {
|
fn build_create_args_emits_base_kit_before_mixins() {
|
||||||
let kit = PathBuf::from("/cache/sbx-kit");
|
let kit = PathBuf::from("/cache/sbx-kit");
|
||||||
|
let unique = std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos();
|
||||||
|
let dir_a = env::temp_dir().join(format!("coyote-mixin-a-{unique}"));
|
||||||
|
let dir_b = env::temp_dir().join(format!("coyote-mixin-b-{unique}"));
|
||||||
|
fs::create_dir_all(&dir_a).unwrap();
|
||||||
|
fs::create_dir_all(&dir_b).unwrap();
|
||||||
|
|
||||||
let mixins = vec![
|
let mixins = vec![
|
||||||
DiscoveredMixin {
|
DiscoveredMixin {
|
||||||
path: PathBuf::from("/cfg/sbx-mixin.yaml"),
|
path: dir_a.clone(),
|
||||||
label: "user".into(),
|
label: "user".into(),
|
||||||
install_count: 0,
|
install_count: 0,
|
||||||
domain_count: 0,
|
domain_count: 0,
|
||||||
},
|
},
|
||||||
DiscoveredMixin {
|
DiscoveredMixin {
|
||||||
path: PathBuf::from("/cfg/agents/sql/sbx-mixin.yaml"),
|
path: dir_b.clone(),
|
||||||
label: "sql".into(),
|
label: "sql".into(),
|
||||||
install_count: 0,
|
install_count: 0,
|
||||||
domain_count: 0,
|
domain_count: 0,
|
||||||
@@ -614,15 +624,18 @@ mod tests {
|
|||||||
"--kit".to_string(),
|
"--kit".to_string(),
|
||||||
"/cache/sbx-kit".to_string(),
|
"/cache/sbx-kit".to_string(),
|
||||||
"--kit".to_string(),
|
"--kit".to_string(),
|
||||||
"/cfg/sbx-mixin.yaml".to_string(),
|
dir_a.display().to_string(),
|
||||||
"--kit".to_string(),
|
"--kit".to_string(),
|
||||||
"/cfg/agents/sql/sbx-mixin.yaml".to_string(),
|
dir_b.display().to_string(),
|
||||||
"coyote".to_string(),
|
"coyote".to_string(),
|
||||||
"--name".to_string(),
|
"--name".to_string(),
|
||||||
"my-box".to_string(),
|
"my-box".to_string(),
|
||||||
".".to_string(),
|
".".to_string(),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&dir_a);
|
||||||
|
let _ = fs::remove_dir_all(&dir_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -645,6 +658,7 @@ mod tests {
|
|||||||
|
|
||||||
mod vault_mixins {
|
mod vault_mixins {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::utils::get_env_name;
|
||||||
use gman::providers::aws_secrets_manager::AwsSecretsManagerProvider;
|
use gman::providers::aws_secrets_manager::AwsSecretsManagerProvider;
|
||||||
use gman::providers::azure_key_vault::AzureKeyVaultProvider;
|
use gman::providers::azure_key_vault::AzureKeyVaultProvider;
|
||||||
use gman::providers::gcp_secret_manager::GcpSecretManagerProvider;
|
use gman::providers::gcp_secret_manager::GcpSecretManagerProvider;
|
||||||
@@ -652,6 +666,46 @@ mod tests {
|
|||||||
use gman::providers::local::LocalProvider;
|
use gman::providers::local::LocalProvider;
|
||||||
use gman::providers::one_password::OnePasswordProvider;
|
use gman::providers::one_password::OnePasswordProvider;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
struct TestCacheDirGuard {
|
||||||
|
key: String,
|
||||||
|
previous: Option<std::ffi::OsString>,
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCacheDirGuard {
|
||||||
|
fn new() -> Self {
|
||||||
|
let key = get_env_name("cache_dir");
|
||||||
|
let previous = env::var_os(&key);
|
||||||
|
let unique = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos();
|
||||||
|
let path = env::temp_dir().join(format!("coyote-sandbox-vault-tests-{unique}"));
|
||||||
|
fs::create_dir_all(&path).unwrap();
|
||||||
|
unsafe {
|
||||||
|
env::set_var(&key, &path);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
key,
|
||||||
|
previous,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestCacheDirGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
match &self.previous {
|
||||||
|
Some(v) => env::set_var(&self.key, v),
|
||||||
|
None => env::remove_var(&self.key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = fs::remove_dir_all(&self.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_none_for_local() {
|
fn returns_none_for_local() {
|
||||||
@@ -664,6 +718,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn returns_some_for_aws() {
|
fn returns_some_for_aws() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
let p = SupportedProvider::AwsSecretsManager {
|
let p = SupportedProvider::AwsSecretsManager {
|
||||||
provider_def: AwsSecretsManagerProvider {
|
provider_def: AwsSecretsManagerProvider {
|
||||||
aws_profile: None,
|
aws_profile: None,
|
||||||
@@ -680,6 +735,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn returns_some_for_gcp() {
|
fn returns_some_for_gcp() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
let p = SupportedProvider::GcpSecretManager {
|
let p = SupportedProvider::GcpSecretManager {
|
||||||
provider_def: GcpSecretManagerProvider {
|
provider_def: GcpSecretManagerProvider {
|
||||||
gcp_project_id: None,
|
gcp_project_id: None,
|
||||||
@@ -695,6 +751,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn returns_some_for_one_password() {
|
fn returns_some_for_one_password() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
let p = SupportedProvider::OnePassword {
|
let p = SupportedProvider::OnePassword {
|
||||||
provider_def: OnePasswordProvider {
|
provider_def: OnePasswordProvider {
|
||||||
vault: None,
|
vault: None,
|
||||||
@@ -711,6 +768,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn returns_some_for_azure() {
|
fn returns_some_for_azure() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
let p = SupportedProvider::AzureKeyVault {
|
let p = SupportedProvider::AzureKeyVault {
|
||||||
provider_def: AzureKeyVaultProvider { vault_name: None },
|
provider_def: AzureKeyVaultProvider { vault_name: None },
|
||||||
};
|
};
|
||||||
@@ -724,6 +782,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn returns_some_for_gopass() {
|
fn returns_some_for_gopass() {
|
||||||
|
let _guard = TestCacheDirGuard::new();
|
||||||
let p = SupportedProvider::Gopass {
|
let p = SupportedProvider::Gopass {
|
||||||
provider_def: GopassProvider { store: None },
|
provider_def: GopassProvider { store: None },
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user