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)