Files
ZacharyZhang-NY e37418c489 feat(python): durable transaction subsystem and Kiro IDE 1.0 adapter
Land the crash-recoverable managed-file transaction engine (journal,
staging, commit, restart recovery, opaque snapshots, private artifacts,
Windows DACL hardening) and the Kiro IDE 1.0 workspace hook plugin with
legacy migration.

Repair five defects that kept the suite red (426 failures to zero):

- Anchor the transaction state directory at ~/.elydora/transactions
  instead of the shared system temp directory. The recovery journal now
  shares fate with the runtimes it repairs, survives temp cleaners, and
  isolates naturally under per-test fake homes.
- Skip pending-transaction recovery when no state directory exists so
  rejected installs never create runtime directories.
- Create the runtime root's parent before hardening it, matching the Go
  SDK's expand behavior for fresh homes.
- Stop using file timestamps as identity evidence: Windows exposes
  mtime/ctime with delayed cross-handle visibility. Reads now prove
  stability through a verification re-read; snapshots compare device,
  inode, size, and SHA-256.
- Stop comparing synthetic Windows permission bits across stat
  boundaries: path stats derive execute bits from file extensions while
  handle stats do not, which falsely flagged every managed .cmd wrapper.
  Snapshots store raw modes for restoration and compare portable bits.

Reservation cleanup now verifies content before discarding so a
concurrent writer's file at a rollback path is preserved, and the
install-failure tests assert the precise contract: no agent runtime
residue, with the durable state directory allowed to remain.

Gates: pytest 807 passed, mypy clean, pip check clean, wheel builds.
2026-07-21 18:53:06 -04:00

430 lines
13 KiB
Python

from __future__ import annotations
import base64
import os
from pathlib import Path
from typing import List
import pytest
from elydora import _cli_secrets, cli
from elydora._cli_secrets import (
MAX_SECRET_FILE_BYTES,
InstallSecrets,
resolve_install_secrets,
)
from elydora.plugins._file_io import write_text_atomic
from elydora.plugins import (
copilot,
cursor,
opencode,
)
from elydora.plugins.hook_template import generate_hook_script
from elydora.utils import base64url_decode
PRIVATE_KEY = base64.urlsafe_b64encode(bytes([7]) * 32).rstrip(b"=").decode()
API_TOKEN = "ely_test_token"
class FakeTerminal:
def __init__(self, *, interactive: bool, answers: List[str]) -> None:
self.interactive = interactive
self.answers = answers
self.prompts: List[str] = []
def read_hidden(self, prompt: str) -> str:
self.prompts.append(prompt)
if not self.answers:
raise AssertionError("unexpected hidden prompt")
return self.answers.pop(0)
def write_secret(path: Path, value: str) -> None:
path.write_bytes(value.encode("utf-8"))
if os.name != "nt":
path.chmod(0o600)
def test_install_secrets_resolve_from_hidden_prompts() -> None:
terminal = FakeTerminal(
interactive=True,
answers=[PRIVATE_KEY, API_TOKEN],
)
secrets = resolve_install_secrets(
private_key_file=None,
token_file=None,
terminal=terminal,
)
assert secrets == InstallSecrets(PRIVATE_KEY, API_TOKEN)
assert terminal.prompts == ["Private key: ", "API token (optional): "]
def test_noninteractive_install_requires_private_key_file() -> None:
terminal = FakeTerminal(interactive=False, answers=[])
with pytest.raises(RuntimeError, match="--private_key_file <path>"):
resolve_install_secrets(
private_key_file=None,
token_file=None,
terminal=terminal,
)
assert terminal.prompts == []
def test_hidden_prompt_rejects_getpass_echo_fallback(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def fallback_getpass(prompt: str, stream: object) -> str:
_cli_secrets.warnings.warn(
"terminal echo is active",
_cli_secrets.getpass.GetPassWarning,
)
return PRIVATE_KEY
monkeypatch.setattr(_cli_secrets.getpass, "getpass", fallback_getpass)
with pytest.raises(RuntimeError, match="interactive terminal"):
_cli_secrets._DefaultTerminal().read_hidden("Private key: ")
def test_secret_files_allow_one_trailing_line_ending(tmp_path: Path) -> None:
private_key_file = tmp_path / "private.key"
token_file = tmp_path / "token"
write_secret(private_key_file, PRIVATE_KEY + "\r\n")
write_secret(token_file, API_TOKEN + "\n")
secrets = resolve_install_secrets(
private_key_file=str(private_key_file),
token_file=str(token_file),
terminal=FakeTerminal(interactive=False, answers=[]),
)
assert secrets == InstallSecrets(PRIVATE_KEY, API_TOKEN)
@pytest.mark.parametrize(
"content, message",
[
(PRIVATE_KEY + "\nsecond-line\n", "exactly one line"),
("", "private key is empty"),
("key\0value", "exactly one line"),
],
)
def test_private_key_file_rejects_invalid_content(
tmp_path: Path,
content: str,
message: str,
) -> None:
private_key_file = tmp_path / "private.key"
write_secret(private_key_file, content)
with pytest.raises(ValueError, match=message):
resolve_install_secrets(
private_key_file=str(private_key_file),
token_file=None,
terminal=FakeTerminal(interactive=False, answers=[]),
)
def test_private_key_file_rejects_oversized_content(tmp_path: Path) -> None:
private_key_file = tmp_path / "private.key"
write_secret(private_key_file, "a" * (MAX_SECRET_FILE_BYTES + 1))
with pytest.raises(ValueError, match="exceeds"):
resolve_install_secrets(
private_key_file=str(private_key_file),
token_file=None,
terminal=FakeTerminal(interactive=False, answers=[]),
)
def test_private_key_file_rejects_symbolic_links(tmp_path: Path) -> None:
target = tmp_path / "target.key"
write_secret(target, PRIVATE_KEY)
link = tmp_path / "linked.key"
try:
link.symlink_to(target)
except OSError as error:
pytest.skip(f"File symbolic links are unavailable: {error}")
with pytest.raises(ValueError, match="regular file"):
resolve_install_secrets(
private_key_file=str(link),
token_file=None,
terminal=FakeTerminal(interactive=False, answers=[]),
)
@pytest.mark.skipif(os.name == "nt", reason="POSIX permission contract")
def test_private_key_file_requires_owner_only_permissions(tmp_path: Path) -> None:
private_key_file = tmp_path / "private.key"
write_secret(private_key_file, PRIVATE_KEY)
private_key_file.chmod(0o640)
with pytest.raises(ValueError, match="accessible only by its owner"):
resolve_install_secrets(
private_key_file=str(private_key_file),
token_file=None,
terminal=FakeTerminal(interactive=False, answers=[]),
)
def test_secret_file_identity_is_stable_while_opening(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
private_key_file = tmp_path / "private.key"
replacement = tmp_path / "replacement.key"
write_secret(private_key_file, PRIVATE_KEY)
write_secret(replacement, PRIVATE_KEY)
original_open = os.open
swapped = False
def replace_then_open(path: str, flags: int) -> int:
nonlocal swapped
if path == str(private_key_file) and not swapped:
os.replace(replacement, private_key_file)
swapped = True
return original_open(path, flags)
monkeypatch.setattr(os, "open", replace_then_open)
with pytest.raises(OSError, match="changed while opening"):
resolve_install_secrets(
private_key_file=str(private_key_file),
token_file=None,
terminal=FakeTerminal(interactive=False, answers=[]),
)
@pytest.mark.parametrize(
"option, replacement",
[
("--private_key", "--private_key_file"),
("--token", "--token_file"),
],
)
def test_cli_rejects_legacy_secret_arguments_without_echoing_values(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
option: str,
replacement: str,
) -> None:
secret = "must-not-appear"
monkeypatch.setenv("HOME", str(tmp_path))
monkeypatch.setenv("USERPROFILE", str(tmp_path))
monkeypatch.setattr(
"sys.argv",
["elydora", "install", option, secret],
)
with pytest.raises(SystemExit) as exc_info:
cli.main()
assert exc_info.value.code == 1
error = capsys.readouterr().err
assert replacement in error
assert secret not in error
assert not (tmp_path / ".elydora").exists()
def test_cli_reads_credentials_from_files_before_installing(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
private_key_file = tmp_path / "private.key"
token_file = tmp_path / "token"
write_secret(private_key_file, PRIVATE_KEY)
write_secret(token_file, API_TOKEN)
monkeypatch.setenv("HOME", str(tmp_path))
monkeypatch.setenv("USERPROFILE", str(tmp_path))
installed: list[dict[str, str]] = []
class Plugin:
manages_guard_runtime = False
def preflight_install(self, config: dict[str, str]) -> None:
assert Path(config["guard_script_path"]).exists() is False
def install(self, config: dict[str, str]) -> None:
assert Path(config["guard_script_path"]).is_file()
installed.append(config)
monkeypatch.setattr(cli, "_get_plugin", lambda _name: Plugin())
args = cli.build_parser().parse_args(
[
"install",
"--agent",
"opencode",
"--org_id",
"org-1",
"--agent_id",
"agent-1",
"--private_key_file",
str(private_key_file),
"--token_file",
str(token_file),
"--kid",
"key-1",
]
)
cli.cmd_install(args)
assert installed[0]["private_key"] == PRIVATE_KEY
assert installed[0]["token"] == API_TOKEN
guard_path = tmp_path / ".elydora" / "agent-1" / "guard.py"
assert guard_path.is_file()
if os.name != "nt":
assert guard_path.stat().st_mode & 0o777 == 0o700
def test_cursor_cli_preflight_rejects_config_before_runtime_writes(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
private_key_file = tmp_path / "private.key"
write_secret(private_key_file, PRIVATE_KEY)
home_dir = tmp_path / "home"
config_path = home_dir / ".cursor" / "hooks.json"
config_path.parent.mkdir(parents=True)
config_path.write_text("{ malformed", encoding="utf-8")
monkeypatch.setenv("HOME", str(home_dir))
monkeypatch.setenv("USERPROFILE", str(home_dir))
args = cli.build_parser().parse_args(
[
"install",
"--agent",
"cursor",
"--org_id",
"org-1",
"--agent_id",
"agent-1",
"--private_key_file",
str(private_key_file),
"--kid",
"key-1",
]
)
with pytest.raises(ValueError, match="parse Cursor user hooks"):
cli.cmd_install(args)
assert config_path.read_text(encoding="utf-8") == "{ malformed"
assert (home_dir / ".elydora").exists() is False
def test_generated_hook_reads_private_key_from_private_file(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setenv("HOME", str(tmp_path))
monkeypatch.setenv("USERPROFILE", str(tmp_path))
key_path = tmp_path / ".elydora" / "agent-1" / "private.key"
key_path.parent.mkdir(parents=True)
write_secret(key_path, PRIVATE_KEY)
script = generate_hook_script(
org_id="org-1",
agent_id="agent-1",
kid="key-1",
base_url="https://api.elydora.com",
)
namespace = {"__name__": "test_hook"}
exec(compile(script, "hook.py", "exec"), namespace)
assert namespace["read_private_key"]() == base64url_decode(PRIVATE_KEY)
assert PRIVATE_KEY not in script
assert "PRIVATE_KEY_PATH" in script
def test_atomic_secret_write_preserves_existing_file_on_replace_failure(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
destination = tmp_path / "private.key"
destination.write_text("original", encoding="utf-8")
def fail_replace(_source: str, _destination: str) -> None:
raise OSError("replace failed")
monkeypatch.setattr(os, "replace", fail_replace)
with pytest.raises(OSError, match="replace failed"):
write_text_atomic(
str(destination),
"replacement",
0o600,
"Elydora private key",
)
assert destination.read_text(encoding="utf-8") == "original"
assert list(tmp_path.glob(".private.key.*.tmp")) == []
@pytest.mark.parametrize(
"module, plugin_type, agent_name",
[
(copilot, copilot.CopilotPlugin, "copilot"),
(cursor, cursor.CursorPlugin, "cursor"),
(opencode, opencode.OpenCodePlugin, "opencode"),
],
)
def test_legacy_plugins_persist_one_owner_only_private_key(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
module: object,
plugin_type: type,
agent_name: str,
) -> None:
case_root = tmp_path / agent_name
runtime_root = case_root / ".elydora"
guard_path = runtime_root / "agent-1" / "guard.py"
guard_path.parent.mkdir(parents=True)
if module not in (cursor, copilot):
guard_path.write_text("pass\n", encoding="utf-8")
if module in (cursor, copilot):
monkeypatch.setenv("HOME", str(case_root))
monkeypatch.setenv("USERPROFILE", str(case_root))
else:
monkeypatch.setattr(module, "ELYDORA_DIR", str(runtime_root))
if hasattr(module, "SETTINGS_PATH"):
monkeypatch.setattr(
module,
"SETTINGS_PATH",
str(case_root / "provider" / "settings.json"),
)
elif module is opencode:
monkeypatch.setattr(module, "PLUGIN_DIR", str(case_root / "plugins"))
elif module is copilot:
case_root.mkdir(parents=True, exist_ok=True)
monkeypatch.setenv("COPILOT_HOME", str(case_root / ".copilot"))
monkeypatch.chdir(case_root)
plugin_type().install(
{
"org_id": "org-1",
"agent_id": "agent-1",
"agent_name": agent_name,
"private_key": PRIVATE_KEY,
"kid": "key-1",
"token": API_TOKEN,
"base_url": "https://api.elydora.com",
"guard_script_path": str(guard_path),
}
)
private_key_path = runtime_root / "agent-1" / "private.key"
hook_path = runtime_root / "agent-1" / "hook.py"
assert private_key_path.read_text(encoding="utf-8") == PRIVATE_KEY
assert PRIVATE_KEY not in hook_path.read_text(encoding="utf-8")
if os.name != "nt":
assert private_key_path.stat().st_mode & 0o777 == 0o600
assert hook_path.stat().st_mode & 0o777 == 0o700