From 7267341d495c0e3e1227199532821f88c757656d Mon Sep 17 00:00:00 2001 From: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com> Date: Sat, 3 Oct 2026 00:58:32 +0100 Subject: [PATCH] fix(effects): protect provenance control state efficiently A hardlink into the effect store was protected only by the log's own nlink refusal, which an agent could undo by removing the alias after writing through it. Adding the store to the recursive control-plane inventory would make every path check cost grow with accumulated runs. _aliases_effect_store instead uses the store's invariants: logs and launch indexes refuse st_nlink != 1 and the store is flat, so only a multiply linked regular file on the store's device is compared by inode against one non-recursive listing. Single-link files cost nothing and the store is never rglob-inventoried. The helper takes a stat result so it plugs into Wave 3's scan-local snapshot after the rebase. --- src/agent_runtime/resources.py | 49 ++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/agent_runtime/resources.py b/src/agent_runtime/resources.py index 66461744b..df3c9100b 100644 --- a/src/agent_runtime/resources.py +++ b/src/agent_runtime/resources.py @@ -28,6 +28,45 @@ def _absolute(value): raise ValueError("Resource path must be canonical and absolute") +def _effect_store_dirs(): + from src import constants + directories = {canonical_root(os.path.join(constants.DATA_DIR, "effects"))} + effect_log = sys.modules.get("src.agent_runtime.effect_log") + if effect_log is not None: + directories.add(canonical_root(effect_log.EFFECTS_DIR)) + return directories + + +def _aliases_effect_store(candidate, directories): + """Whether ``candidate`` (an ``os.stat`` result) is a hardlink into the effect store. + + The effect log and launch index refuse any file with more than one link, + and the store is flat. So only a multiply linked regular file on the + store's device can alias store state, and only then is the store listed, + one directory level, by inode. Ordinary single-link files cost nothing, + and the cost never depends on recursive store size. Uninspectable store + state fails closed. + """ + if not stat.S_ISREG(candidate.st_mode) or candidate.st_nlink < 2: + return False + for directory in directories: + try: + if os.stat(directory).st_dev != candidate.st_dev: + continue + with os.scandir(directory) as entries: + for entry in entries: + if entry.inode() != candidate.st_ino: + continue + observed = entry.stat(follow_symlinks=False) + if (observed.st_dev, observed.st_ino) == (candidate.st_dev, candidate.st_ino): + return True + except FileNotFoundError: + continue + except OSError: + return True + return False + + def _control_plane_path(path): # Execution snapshots/receipts are server state, even if a workspace root # contains the data directory. A writable user file cannot mint authority. @@ -46,11 +85,9 @@ def _control_plane_path(path): if processes is not None: job_dirs.add(canonical_root(processes._LAUNCH_DIR)) # Durable effect claims/outcomes/observations are server evidence state. - # The log refuses hardlinked files itself, so a prefix check suffices. - effect_dirs = {canonical_root(os.path.join(constants.DATA_DIR, "effects"))} - effect_log = sys.modules.get("src.agent_runtime.effect_log") - if effect_log is not None: - effect_dirs.add(canonical_root(effect_log.EFFECTS_DIR)) + # The store is not inventoried here: it grows with every run. Aliases are + # caught below by ``_aliases_effect_store`` instead. + effect_dirs = _effect_store_dirs() if any(Path(path).is_relative_to(directory) for directory in effect_dirs): return True # Producers may have configured paths different from the default constants. @@ -97,6 +134,8 @@ def _control_plane_path(path): candidate = os.stat(path) except FileNotFoundError: return False + if _aliases_effect_store(candidate, effect_dirs): + return True for control in protected: try: observed = os.stat(control)