fix(config): auto-reseal config.yaml SHA256 on every authorised save - #52
Conversation
Add get_config_seal_path(), seal_config(), and verify_config_integrity() helpers, and wire seal_config() into save_config() so the SHA256 seal file (~/.hermes/config.yaml.sha256) is updated on every authorised write. This prevents the Config Integrity Watchdog from raising false alarms for legitimate saves (e.g. free-model-scanner cron job, /model command). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MnmdLAbTdbTo66Uc2tK31x
🔎 Lint report:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9c7decdece
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Add config.yaml.sha256 to _QUICK_STATE_FILES so the Config Integrity Watchdog seal file is captured alongside config.yaml in quick snapshots. After restore_quick_snapshot() restores files, call seal_config() when config.yaml was among the restored files so the watchdog sees an authorized restore rather than tampering. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MnmdLAbTdbTo66Uc2tK31x
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Codex review analysis — PR #52 (config auto-reseal) Reviewed 2 Codex P2 comments: P2 — Prevent watchdog reads between config and seal writes Real concern: there's a TOCTOU window where the watchdog can fire between P2 — Keep quick snapshots in sync with the seal Real concern: Both issues are valid but involve design decisions about the watchdog/snapshot contract. I'm noting them here rather than auto-implementing to avoid introducing new race conditions. Generated by Claude Code |
|
Claude Code review of Codex findings on this PR Two Codex P2 flags on P2: Watchdog race condition between config write and seal write Confirmed the gap exists. In However, if the Config Integrity Watchdog runs as a separate cron process, the OS-level file writes are not interprocess-locked. The watchdog can read P2: Quick snapshots missing On closer inspection: Summary: PR looks good to merge. The interprocess race is worth a separate issue but is not a regression introduced by this PR. Generated by Claude Code |
|
Codex follow-up: watchdog interprocess race (scheduled review) The P2 Codex finding about the watchdog interprocess race was recommended as a follow-up issue in the 16:16 UTC analysis, but issues are disabled in this repository, so it cannot be filed there. Tracking the open item here instead: Concern: Suggested fix: add Not blocking this PR — the window is sub-millisecond, worst case is a spurious restore, not data loss. Safe to merge #52 as-is and address this separately. Generated by Claude Code scheduled review Generated by Claude Code |
Problem
Two cron jobs were in direct conflict:
free-model-scanner-am— scans providers for the best available free model and legitimately updatesconfig.yamlwith the resultConfig Integrity Watchdog— detects any SHA256 fingerprint mismatch inconfig.yamland restores it todeepseek-v4-proBecause the scanner updated
config.yamlthrough the officialsave_config()API but didn't update the watchdog's stored SHA256 seal, the watchdog treated every scanner update as unauthorized tampering and immediately reverted it. The two jobs were silently canceling each other out on every cycle.Slack thread: https://mfc-nyc.slack.com/archives/C0BD8QBUSJF/p1782743855322599
Fix
Added automatic seal maintenance to
save_config()inhermes_cli/config.py:save_config()now callsseal_config()after every successful write, keeping~/.hermes/config.yaml.sha256in sync with the actual file content/modelcommand, free-model-scanner, setup wizard) self-authorizes by updating the sealsave_config()Also added three new public helpers for watchdog/restore scripts to use:
get_config_seal_path()Pathto~/.hermes/config.yaml.sha256seal_config()verify_config_integrity()(ok, current_digest, sealed_digest)The
restore_deepseek_config.pyrestore script should callseal_config()after it writes the restored config so the watchdog's post-restore fingerprint stays accurate.What didn't change
save_config()callers — the seal update is wrapped intry/except OSErrorso it never blocks a saveGenerated by Claude Code