Centralize durable atomic file writes - #12653
Conversation
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The helper does not sync parent-directory metadata and silently ignores cleanup failures.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Centralizes atomic persistence for logger data and delegation recovery.
Changes:
- Adds a shared synced temporary-file/rename helper.
- Migrates logger and delegation persistence and adds coverage.
File summaries
| File | Description |
|---|---|
internal/util/atomic_write.go |
Implements shared atomic writes. |
internal/util/atomic_write_test.go |
Tests content, permissions, and failures. |
internal/logger/fileutil.go |
Delegates logger writes to the helper. |
internal/logger/atomic_write_test.go |
Updates logger atomic-write tests. |
internal/delegation/recovery.go |
Migrates secure state persistence. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if err := os.Rename(tempPath, filePath); err != nil { | ||
| return fmt.Errorf("failed to rename temp file: %w", err) | ||
| } |
| import ( | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
| ) | ||
|
|
||
| // AtomicWriteFile writes data to filePath by syncing a uniquely named | ||
| // temporary file in the destination directory before renaming it into place. | ||
| func AtomicWriteFile(filePath string, data []byte, perm os.FileMode) error { | ||
| temp, err := os.CreateTemp(filepath.Dir(filePath), "."+filepath.Base(filePath)+"-*") | ||
| if err != nil { | ||
| return fmt.Errorf("failed to write temp file: %w", err) | ||
| } | ||
| tempPath := temp.Name() | ||
| defer os.Remove(tempPath) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@copilot address review feedback |
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Addressed in |
🔒 mcpg Read-Only Stress — defaultSurface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Overall: INCONCLUSIVE Notes:
|
🔒 mcpg Read-Only Stress — docker-sbxSurface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Overall: INCONCLUSIVE No write leaked in any part. Gaps: (1) the gateway-backed
|
🔒 mcpg Read-Only Stress — gvisorSurface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Overall: INCONCLUSIVE No write leaked on any surface. Part B is inconclusive because gh-aw's
|
Logger persistence and delegation recovery each implemented their own temp-file/rename flow, with inconsistent durability and collision guarantees.
Shared helper
internal/util.AtomicWriteFile, using a same-directory temporary file, explicit permissions,Sync,Close, and atomicRename.Call-site migration
0600permissions and crash-safe writes.Coverage