"""Tests for myagents.secrets.""" import json import sys from pathlib import Path import pytest from myagents import secrets as secrets_mod @pytest.fixture() def fake_dirs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> dict[str, Path]: xiaohe_dir = tmp_path / ".xiaohe" / "agent" mytoolkit_dir = tmp_path / ".mytoolkit" monkeypatch.setattr(secrets_mod, "XIAOHE_CONFIG_DIR", xiaohe_dir) monkeypatch.setattr(secrets_mod, "XIAOHE_CONFIG_PATH", xiaohe_dir / "config.json") monkeypatch.setattr(secrets_mod, "MYTOOLKIT_CONFIG_PATH", mytoolkit_dir / "config.json") return {"xiaohe": xiaohe_dir, "mytoolkit": mytoolkit_dir} class TestGetKey: def test_returns_xiaohe_key_first(self, fake_dirs: dict[str, Path]) -> None: xiaohe_path = fake_dirs["xiaohe"] / "config.json" mytoolkit_path = fake_dirs["mytoolkit"] / "config.json" xiaohe_path.parent.mkdir(parents=True) xiaohe_path.write_text(json.dumps({"keys": {"kimi": "xiaohe-key"}})) mytoolkit_path.parent.mkdir(parents=True) mytoolkit_path.write_text(json.dumps({"keys": {"kimi": "mtk-key"}})) assert secrets_mod.get_key("kimi") == "xiaohe-key" def test_falls_back_to_mytoolkit_key(self, fake_dirs: dict[str, Path]) -> None: mytoolkit_path = fake_dirs["mytoolkit"] / "config.json" mytoolkit_path.parent.mkdir(parents=True) mytoolkit_path.write_text(json.dumps({"keys": {"kimi": "mtk-key"}})) assert secrets_mod.get_key("kimi") == "mtk-key" def test_returns_none_when_missing(self, fake_dirs: dict[str, Path]) -> None: assert secrets_mod.get_key("missing") is None def test_skips_empty_strings(self, fake_dirs: dict[str, Path]) -> None: xiaohe_path = fake_dirs["xiaohe"] / "config.json" xiaohe_path.parent.mkdir(parents=True) xiaohe_path.write_text(json.dumps({"keys": {"kimi": ""}})) assert secrets_mod.get_key("kimi") is None class TestSetKey: def test_stores_key_in_xiaohe_config(self, fake_dirs: dict[str, Path]) -> None: secrets_mod.set_key("deepseek", "sk-test") data = json.loads((fake_dirs["xiaohe"] / "config.json").read_text()) assert data["keys"]["deepseek"] == "sk-test" def test_rejects_empty_key(self, fake_dirs: dict[str, Path]) -> None: with pytest.raises(ValueError, match="cannot be empty"): secrets_mod.set_key("deepseek", "") def test_preserves_other_keys(self, fake_dirs: dict[str, Path]) -> None: xiaohe_path = fake_dirs["xiaohe"] / "config.json" xiaohe_path.parent.mkdir(parents=True) xiaohe_path.write_text(json.dumps({"keys": {"other": "keep"}})) secrets_mod.set_key("deepseek", "sk-test") data = json.loads(xiaohe_path.read_text()) assert data["keys"]["other"] == "keep" assert data["keys"]["deepseek"] == "sk-test" class TestRemoveKey: def test_removes_existing_key(self, fake_dirs: dict[str, Path]) -> None: xiaohe_path = fake_dirs["xiaohe"] / "config.json" xiaohe_path.parent.mkdir(parents=True) xiaohe_path.write_text(json.dumps({"keys": {"deepseek": "sk-test"}})) assert secrets_mod.remove_key("deepseek") is True data = json.loads(xiaohe_path.read_text()) assert "deepseek" not in data.get("keys", {}) def test_returns_false_when_missing(self, fake_dirs: dict[str, Path]) -> None: assert secrets_mod.remove_key("deepseek") is False class TestPermissions: @pytest.mark.skipif(sys.platform == "win32", reason="Unix permissions only") def test_config_file_is_user_readable_only(self, fake_dirs: dict[str, Path]) -> None: secrets_mod.set_key("kimi", "sk-test") path = fake_dirs["xiaohe"] / "config.json" mode = path.stat().st_mode assert mode & 0o777 == 0o600 class TestHasKey: def test_true_when_key_exists(self, fake_dirs: dict[str, Path]) -> None: secrets_mod.set_key("kimi", "sk-test") assert secrets_mod.has_key("kimi") is True def test_false_when_missing(self, fake_dirs: dict[str, Path]) -> None: assert secrets_mod.has_key("missing") is False