From 5a8e651183ba57ca0dec3588c3103c2b3f01f56d Mon Sep 17 00:00:00 2001 From: codeshipsingh <58661393+codeshipsingh@users.noreply.github.com> Date: Fri, 11 Sep 2026 10:18:57 +0300 Subject: [PATCH] fix(identity): enforce 0600 on spawn ledger writes --- hermes_cli/process_identity.py | 6 +++--- tests/hermes_cli/test_process_identity.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/hermes_cli/process_identity.py b/hermes_cli/process_identity.py index 4247f74cd3..731ba061a6 100644 --- a/hermes_cli/process_identity.py +++ b/hermes_cli/process_identity.py @@ -20,6 +20,8 @@ from dataclasses import asdict, dataclass from pathlib import Path from typing import Optional +from utils import atomic_json_write + logger = logging.getLogger(__name__) SPAWN_ENV_VAR = "HERMES_SPAWN" @@ -265,9 +267,7 @@ def _append_entry(entry: LedgerEntry) -> bool: pruned.append(asdict(entry)) try: path.parent.mkdir(parents=True, exist_ok=True) - tmp = path.with_suffix(path.suffix + f".tmp{os.getpid()}") - tmp.write_text(json.dumps(pruned, indent=2), encoding="utf-8") - os.replace(tmp, path) + atomic_json_write(path, pruned, mode=0o600) return True except OSError: logger.debug("spawn ledger write failed", exc_info=True) diff --git a/tests/hermes_cli/test_process_identity.py b/tests/hermes_cli/test_process_identity.py index f250b394c7..9e4f98325c 100644 --- a/tests/hermes_cli/test_process_identity.py +++ b/tests/hermes_cli/test_process_identity.py @@ -15,6 +15,8 @@ Runs on any host: psutil interactions go through a fake module. from __future__ import annotations import json +import os +import stat import sys import types from pathlib import Path @@ -132,6 +134,18 @@ def test_register_self_writes_and_prunes_dead(tmp_path): assert me["create_time"] == pytest.approx(50.0, abs=0.01) +def test_register_self_writes_ledger_with_0600(tmp_path): + ledger = tmp_path / "spawn-ledger.json" + fake = _fake_psutil({999: 50.0}) + with patch.dict(sys.modules, {"psutil": fake}), \ + patch.object(pi, "_ledger_path", return_value=ledger), \ + patch.object(pi.os, "getpid", return_value=999): + assert pi.register_self("serve", project_root=Path("/x/install")) is True + + mode = stat.S_IMODE(os.stat(ledger).st_mode) + assert mode == 0o600 + + def test_register_self_inherits_spawn_tag_lineage(tmp_path): ledger = tmp_path / "spawn-ledger.json" fake = _fake_psutil({999: 50.0})