Skip to content

fix: make SaveIdentity atomic (temp+rename+fsync) (PILOT-248)#6

Merged
TeoSlayer merged 2 commits into
mainfrom
openclaw/pilot-248-20260529-203800
May 29, 2026
Merged

fix: make SaveIdentity atomic (temp+rename+fsync) (PILOT-248)#6
TeoSlayer merged 2 commits into
mainfrom
openclaw/pilot-248-20260529-203800

Conversation

@matthew-pilot
Copy link
Copy Markdown
Collaborator

Summary

  • Ticket: PILOT-248
  • Problem: crypto/identity.go:98 used os.WriteFile directly, which is not atomic. A crash between file-open and final write leaves a 0-byte or partial JSON file on disk. Next daemon start fails to unmarshal and regenerates a new identity — peer trust graph is lost.
  • Fix: Replace os.WriteFile with fsutil.AtomicWrite (temp + rename + fsync pattern, already in this same repo at fsutil/fsutil.go). This ensures the identity file is never left truncated.
  • Files: 1 (crypto/identity.go, +5/-1)
  • Tier: small (matthew-fix)
  • Verification: go build ./... ✅, go vet ./... ✅, go test ./... ✅ (all 13 packages pass, including crypto package tests)
  • Canary: not applicable (common has artifact: none)

Diff

--- a/crypto/identity.go
+++ b/crypto/identity.go
@@ -95,7 +97,10 @@ func SaveIdentity(path string, id *Identity) error {
-	if err := os.WriteFile(path, data, 0600); err != nil {
+	// AtomicWrite prevents a truncated identity file from a crash
+	// mid-write (temp + rename + fsync pattern).
+	if err := fsutil.AtomicWrite(path, data); err != nil {

…te) (PILOT-248)

Replace os.WriteFile with fsutil.AtomicWrite to prevent truncated
identity files from crashes mid-write. Previously a crash between
file-open and the final write could leave a 0-byte or partial JSON
file — next daemon start would fail to unmarshal and regenerate a
new identity, losing the peer trust graph.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

🦞 Matthew PR Check — #6 PILOT-248

Status

  • State: OPEN · MERGEABLE
  • CI: 2/2 green (test ✅, codecov/patch ✅)
  • Canary: not yet triggered (common ref — cascades to downstream canary on use)

Summary

fix: make SaveIdentity atomic (temp+rename+fsync) (PILOT-248)

Commit

Branch openclaw/pilot-248-20260529-203800
Ready for operator review.

@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

🦞 Matthew PR Explain — #6 PILOT-248

What this changes

SaveIdentity previously wrote the identity file directly in-place, which could leave a truncated/corrupt file on disk if the write was interrupted (crash, disk full). This PR makes the write atomic: write to a temp file → rename → fsync directory.

Why

A torn identity file causes silent load failures or key corruption on next daemon start. The temp+rename+fsync pattern is the standard POSIX-safe approach for atomic file writes.

Risk

Small — ≤3 files, ≤50 LoC. Only changes the write path; read path unchanged. Temp file is in the same directory (same filesystem) for rename atomicity.

🔗 PILOT-248

@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

🦾 Matthew PR Check — #6 PILOT-248

Status

  • State: OPEN · MERGEABLE ✅
  • CI: 2/2 passing (test ✅, codecov/patch ✅)
  • Files: 1 (+5/−1 in crypto/identity.go)
  • Canary: not-configured

Verdict

CLEAN — all CI green, atomic save pattern is well-scoped. Ready for operator review.

@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

🦜 Matthew Explains — #6 PILOT-248

What this does

Makes SaveIdentity atomic by:

  1. Writing to a temporary file first
  2. Calling os.Rename (atomic on POSIX)
  3. Calling f.Sync() on the final file

This prevents a crash or power loss mid-write from leaving a truncated/corrupt identity file on disk. The old code wrote directly to the target path with os.WriteFile, which can leave partial files.

Why it matters

A corrupted identity file on restart means the daemon silently loses its identity — no warning, no crash, just a new keypair. This is a durability bug in a security-critical path.

@TeoSlayer TeoSlayer merged commit 7c2ed19 into main May 29, 2026
1 check passed
@TeoSlayer TeoSlayer deleted the openclaw/pilot-248-20260529-203800 branch May 29, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants