Files
Elydora-Python-SDK/tests/test_kiroide_plugin.py
T
雷电芽衣 aa4b8a8bdf chore(python): audit tests
Split the three oversized test files into support modules and topic
files, evaluate the rmdir dir_fd capability once at import, and drop
unused imports.

Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
2026-09-03 00:30:17 -04:00

348 lines
11 KiB
Python

from __future__ import annotations
import json
import os
from pathlib import Path
import time
from typing import Any
import pytest
from elydora import cli
from elydora.plugins import kiroide
from elydora.plugins.registry import SUPPORTED_AGENTS
from kiroide_support import (
AGENT_ID,
AuditHandler,
PRIVATE_KEY,
find_hook,
install_config,
legacy_document,
prepare_fixture,
run_command,
start_audit_server,
write_json,
)
def test_kiroide_uses_current_workspace_v1_hook_contract(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
home = tmp_path / "home with spaces"
workspace = tmp_path / "workspace with spaces"
home.mkdir()
workspace.mkdir()
config_path = workspace / ".kiro" / "hooks" / "elydora-audit.json"
existing_hook = {
"name": "workspace-context",
"trigger": "SessionStart",
"action": {"type": "agent", "prompt": "Read AGENTS.md"},
"enabled": True,
}
write_json(
config_path,
{"version": "v1", "owner": "workspace", "hooks": [existing_hook]},
)
monkeypatch.setenv("HOME", str(home))
monkeypatch.setenv("USERPROFILE", str(home))
monkeypatch.chdir(workspace)
plugin = kiroide.KiroIdePlugin()
plugin.install(install_config(home))
first_source = config_path.read_text(encoding="utf-8")
plugin.install(install_config(home))
assert SUPPORTED_AGENTS["kiroide"] == {
"name": "Kiro IDE",
"hook_event": "PreToolUse/PostToolUse",
"config_path": ".kiro/hooks/elydora-audit.json",
}
assert config_path.read_text(encoding="utf-8") == first_source
document = json.loads(first_source)
assert document["version"] == "v1"
assert document["owner"] == "workspace"
assert document["hooks"][0] == existing_hook
assert document["hooks"][1]["trigger"] == "PreToolUse"
assert document["hooks"][2]["trigger"] == "PostToolUse"
assert all(hook["matcher"] == ".*" for hook in document["hooks"][1:])
assert all(hook["timeout"] == 10 for hook in document["hooks"][1:])
assert all(hook["enabled"] is True for hook in document["hooks"][1:])
assert not (home / ".kiro" / "hooks" / "elydora-audit.json").exists()
private_key_path = home / ".elydora" / AGENT_ID / "private.key"
audit_path = home / ".elydora" / AGENT_ID / "hook.py"
assert private_key_path.read_text(encoding="utf-8") == PRIVATE_KEY
assert PRIVATE_KEY not in audit_path.read_text(encoding="utf-8")
if os.name != "nt":
assert private_key_path.stat().st_mode & 0o777 == 0o600
assert audit_path.stat().st_mode & 0o777 == 0o700
def test_kiroide_commands_block_frozen_agents_and_forward_native_events(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
api = start_audit_server()
try:
fixture = prepare_fixture(
monkeypatch, tmp_path, base_url=api.base_url
)
fixture.plugin.install(fixture.config)
document = json.loads(fixture.config_path.read_text(encoding="utf-8"))
payload = {
"hook_event_name": "preToolUse",
"cwd": str(fixture.workspace),
"session_id": "session-1",
"tool_name": "execute_bash",
"tool_input": {"command": "pytest -q"},
"future_field": {"retained": True},
}
status_cache_path = fixture.agent_directory / "status-cache.json"
write_json(
status_cache_path,
{"status": "frozen", "cached_at": time.time()},
)
if os.name != "nt":
status_cache_path.chmod(0o600)
blocked = run_command(
find_hook(document, "elydora-guard")["action"]["command"],
fixture,
payload,
)
assert blocked.returncode == 2
assert "Tool execution blocked" in blocked.stderr
payload["hook_event_name"] = "postToolUse"
payload["tool_response"] = {"success": True, "result": "12 passed"}
audited = run_command(
find_hook(document, "elydora-audit")["action"]["command"],
fixture,
payload,
)
assert audited.returncode == 0, audited.stderr
assert AuditHandler.operations[-1]["payload"] == payload
assert AuditHandler.operations[-1]["action"] == {
"tool": "execute_bash"
}
assert AuditHandler.operations[-1]["subject"] == {
"session_id": "session-1"
}
finally:
api.close()
def test_kiroide_status_requires_exact_enabled_hooks_and_runtime_sources(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path)
fixture.plugin.install(fixture.config)
assert fixture.plugin.status() == {
"installed": True,
"agent": "kiroide",
"details": f"Config: {fixture.config_path}",
}
document = json.loads(fixture.config_path.read_text(encoding="utf-8"))
find_hook(document, "elydora-guard")["enabled"] = False
write_json(fixture.config_path, document)
assert fixture.plugin.status() == {
"installed": False,
"agent": "kiroide",
"details": (
"Managed hooks are incomplete or invalid: "
f"{fixture.config_path}"
),
}
fixture.plugin.install(fixture.config)
fixture.guard_path.write_text("tampered\n", encoding="utf-8")
status = fixture.plugin.status()
assert status["installed"] is False
assert "runtime files are missing or invalid" in status["details"]
def test_kiroide_status_surfaces_malformed_runtime_metadata(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path)
fixture.plugin.install(fixture.config)
(fixture.agent_directory / "config.json").write_text(
"{ malformed", encoding="utf-8"
)
with pytest.raises(ValueError, match="parse Elydora runtime config"):
fixture.plugin.status()
@pytest.mark.parametrize(
("source", "message"),
[
("{ malformed", "parse Kiro IDE hooks"),
(
'{"version":"v1","version":"v1","hooks":[]}',
'duplicate field "version"',
),
({"version": "v0", "hooks": []}, 'version must be "v1"'),
({"version": "v1", "hooks": None}, 'field "hooks" must be an array'),
(
{
"version": "v1",
"hooks": [
{
"name": "bad",
"trigger": "FutureEvent",
"action": {"type": "command", "command": "echo bad"},
}
],
},
"unsupported trigger",
),
],
)
def test_kiroide_rejects_invalid_workspace_hooks_before_runtime_writes(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
source: Any,
message: str,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path, current=source)
original = fixture.config_path.read_text(encoding="utf-8")
with pytest.raises(ValueError, match=message):
fixture.plugin.install(fixture.config)
assert fixture.config_path.read_text(encoding="utf-8") == original
assert not fixture.agent_directory.exists()
def test_kiroide_cli_preflight_rejects_workspace_before_runtime_creation(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path, current="{ malformed")
private_key_file = tmp_path / "private.key"
token_file = tmp_path / "token"
private_key_file.write_text(PRIVATE_KEY, encoding="utf-8")
token_file.write_text("token-1", encoding="utf-8")
if os.name != "nt":
private_key_file.chmod(0o600)
token_file.chmod(0o600)
args = cli.build_parser().parse_args(
[
"install",
"--agent",
"kiroide",
"--org_id",
"org-1",
"--agent_id",
AGENT_ID,
"--private_key_file",
str(private_key_file),
"--token_file",
str(token_file),
"--kid",
"kid-1",
]
)
with pytest.raises(ValueError, match="parse Kiro IDE hooks"):
cli.cmd_install(args)
assert fixture.config_path.read_text(encoding="utf-8") == "{ malformed"
assert not fixture.agent_directory.exists()
def test_kiroide_rejects_noncanonical_private_keys_before_writes(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path)
fixture.config["private_key"] = PRIVATE_KEY + "="
with pytest.raises(ValueError, match="canonical 32-byte base64url"):
fixture.plugin.install(fixture.config)
assert not fixture.config_path.exists()
assert not fixture.agent_directory.exists()
def test_kiroide_rejects_managed_name_collisions(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
current = {
"version": "v1",
"hooks": [
{
"name": "elydora-guard",
"trigger": "PreToolUse",
"action": {"type": "command", "command": "user-command"},
}
],
}
fixture = prepare_fixture(monkeypatch, tmp_path, current=current)
with pytest.raises(ValueError, match="conflicts with the Elydora contract"):
fixture.plugin.install(fixture.config)
assert json.loads(fixture.config_path.read_text(encoding="utf-8")) == current
assert not fixture.agent_directory.exists()
def test_kiroide_rejects_linked_workspace_configuration_directory(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path)
external = tmp_path / "external-kiro"
external.mkdir()
try:
(fixture.workspace / ".kiro").symlink_to(external, target_is_directory=True)
except OSError as error:
pytest.skip(f"Directory symbolic links are unavailable: {error}")
with pytest.raises(OSError, match="not a physical directory"):
fixture.plugin.install(fixture.config)
assert not (external / "hooks" / "elydora-audit.json").exists()
assert not fixture.agent_directory.exists()
def test_kiroide_migrates_only_the_matching_legacy_python_hook(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
fixture = prepare_fixture(monkeypatch, tmp_path)
write_json(fixture.legacy_path, legacy_document(fixture))
fixture.plugin.install(fixture.config)
assert not fixture.legacy_path.exists()
write_json(fixture.legacy_path, legacy_document(fixture, "agent-2"))
fixture.plugin.install(fixture.config)
assert fixture.legacy_path.exists()
def test_kiroide_preserves_unrelated_legacy_hook_and_rejects_malformed_legacy(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
unrelated = {
"name": "User Hook",
"version": "1.0.0",
"hooks": {"post_tool_use": {"command": "user-command"}},
}
fixture = prepare_fixture(monkeypatch, tmp_path, legacy=unrelated)
fixture.plugin.install(fixture.config)
assert json.loads(fixture.legacy_path.read_text(encoding="utf-8")) == unrelated
fixture.plugin.uninstall(AGENT_ID)
fixture.legacy_path.write_text("{ malformed", encoding="utf-8")
with pytest.raises(ValueError, match="parse legacy Kiro IDE hook"):
fixture.plugin.install(fixture.config)
assert fixture.legacy_path.read_text(encoding="utf-8") == "{ malformed"