fix: make Codex hooks transactional

This commit is contained in:
ZacharyZhang-NY committed 2026-07-20 02:41:42 -04:00
1 parent c3602da5f3
commit cb6173e6ee
17 files changed
+2308 -870

No files matched your search

+193
View File
@@ -0,0 +1,193 @@
"""Codex hook source and managed runtime I/O."""
from __future__ import annotations
import os
import stat
from typing import Any, List, Optional
from ._managed_files import (
MAX_CONFIG_BYTES,
MAX_SOURCE_BYTES,
physical_directory_exists,
physical_file_exists,
read_physical_file,
)
from ._strict_json import JsonObject, parse_json_object
from ._transaction import FileChange, source_change, write_changes
from .codex_contract import (
AGENT_KEY,
CONFIG_FILE,
CodexDocument,
RenderedDocument,
RuntimeContract,
create_document,
parse_document,
)
def _same_agent_id(value: Any, expected: str) -> bool:
return isinstance(value, str) and os.path.normcase(value) == os.path.normcase(
expected
)
def codex_home_path() -> str:
configured = os.environ.get("CODEX_HOME")
if configured is None or configured == "":
return os.path.join(os.path.expanduser("~"), ".codex")
try:
metadata = os.stat(configured)
except OSError as error:
raise OSError(f"Resolve CODEX_HOME at {configured}: {error}") from error
if not stat.S_ISDIR(metadata.st_mode):
raise OSError(f"CODEX_HOME is not a directory: {configured}")
try:
canonical = os.path.realpath(configured, strict=True)
except OSError as error:
raise OSError(f"Canonicalize CODEX_HOME at {configured}: {error}") from error
if not physical_directory_exists(canonical, "CODEX_HOME"):
raise OSError(f"CODEX_HOME is missing: {canonical}")
return canonical
def config_path() -> str:
return os.path.join(codex_home_path(), CONFIG_FILE)
def read_document() -> CodexDocument:
file_path = config_path()
snapshot = read_physical_file(file_path, "Codex user hooks", MAX_SOURCE_BYTES)
if snapshot is None:
return create_document(file_path)
return parse_document(file_path, snapshot.contents)
def validate_hooks_directory(file_path: str) -> None:
directory = os.path.dirname(file_path)
physical_directory_exists(directory, "Codex hooks directory")
def rendered_change(rendered: RenderedDocument) -> Optional[FileChange]:
if not rendered.changed:
return None
return source_change(
rendered.document.file_path,
"Codex user hooks",
rendered.document.raw,
rendered.next_source,
0o600,
MAX_SOURCE_BYTES,
)
def runtime_change(
file_path: str,
label: str,
next_source: str,
mode: int,
maximum_bytes: int = MAX_SOURCE_BYTES,
) -> Optional[FileChange]:
snapshot = read_physical_file(file_path, label, maximum_bytes)
return source_change(
file_path,
label,
None if snapshot is None else snapshot.contents,
next_source,
mode,
maximum_bytes,
)
def _read_runtime_config(file_path: str) -> Optional[JsonObject]:
snapshot = read_physical_file(
file_path,
"Elydora runtime config",
MAX_CONFIG_BYTES,
)
if snapshot is None:
return None
return parse_json_object(
snapshot.contents,
f"Elydora runtime config at {file_path}",
)
def validate_runtime_identity(agent_directory: str, agent_id: str) -> bool:
config_path_value = os.path.join(agent_directory, "config.json")
config = _read_runtime_config(config_path_value)
artifacts = [
("private.key", "Elydora private key"),
("guard.py", "Elydora guard runtime"),
("hook.py", "Elydora audit runtime"),
("chain-state.json", "Elydora chain state"),
("status-cache.json", "Elydora status cache"),
("error.log", "Elydora error log"),
]
artifact_states = [
physical_file_exists(os.path.join(agent_directory, name), label)
for name, label in artifacts
]
artifact_exists = any(artifact_states)
if config is None:
if artifact_exists:
raise ValueError(
"Elydora runtime identity cannot be verified without config.json: "
f"{agent_directory}"
)
return False
if config.get("agent_name") != AGENT_KEY or not _same_agent_id(
config.get("agent_id"),
agent_id,
):
raise ValueError(
f"Elydora runtime config identity does not match Codex agent {agent_id}: "
f"{config_path_value}"
)
return True
def validate_runtime_tree(
runtime_root: str, agent_directory: str, agent_id: str
) -> None:
if not physical_directory_exists(runtime_root, "Elydora runtime directory"):
return
if not physical_directory_exists(
agent_directory,
"Elydora agent runtime directory",
):
return
validate_runtime_identity(agent_directory, agent_id)
def runtime_files_exist(contracts: List[RuntimeContract]) -> bool:
for contract in contracts:
agent_directory = os.path.dirname(contract.guard_path)
if not physical_directory_exists(
agent_directory,
"Elydora agent runtime directory",
):
continue
config = _read_runtime_config(os.path.join(agent_directory, "config.json"))
if (
config is None
or config.get("agent_name") != AGENT_KEY
or not _same_agent_id(config.get("agent_id"), contract.agent_id)
):
continue
if all(
(
physical_file_exists(contract.guard_path, "Elydora guard runtime"),
physical_file_exists(contract.audit_path, "Elydora audit runtime"),
physical_file_exists(
os.path.join(agent_directory, "private.key"),
"Elydora private key",
),
)
):
return True
return False
def write_codex_changes(changes: List[FileChange], label: str) -> None:
write_changes(changes, label)