[AUTOMATION] fix(clawpatch): preserve claude hook file permissions#243
[AUTOMATION] fix(clawpatch): preserve claude hook file permissions#243michiosw wants to merge 1 commit into
Conversation
Greptile SummaryThis PR preserves Claude settings file permissions when guard hooks update them. The main changes are:
Confidence Score: 4/5This is close, but the backup permission case should be fixed before merging.
|
| Filename | Overview |
|---|---|
| internal/guard/cli/cli.go | Adds permission preservation for Claude settings writes and backups, with one remaining backup rewrite mode gap. |
| internal/guard/cli/cli_test.go | Adds regression coverage for fresh restrictive settings and backup modes during install. |
Reviews (1): Last reviewed commit: "fix(clawpatch): preserve claude hook fil..." | Re-trigger Greptile
| @@ -450,7 +451,7 @@ func backupFile(path, label string) error { | |||
| if err != nil { | |||
| return err | |||
| } | |||
| return os.WriteFile(backupPath, input, 0o644) | |||
| return os.WriteFile(backupPath, input, info.Mode().Perm()) | |||
| } | |||
There was a problem hiding this comment.
Existing backups stay readable
When backupPath already exists, os.WriteFile truncates and rewrites it without changing its mode. The backup name only has second-level precision, so two hook operations in the same second can reuse the same path; the path can also already exist from a previous install that created a 0644 backup. In that case this writes private 0600 settings content into a backup that remains world-readable, so the permission fix does not cover the backup file.
| func backupFile(path, label string) error { | |
| info, err := os.Stat(path) | |
| if os.IsNotExist(err) { | |
| return nil | |
| } else if err != nil { | |
| return err | |
| } | |
| mode := info.Mode().Perm() | |
| backupPath := fmt.Sprintf("%s.%s-backup-%s", path, label, time.Now().UTC().Format("20060102T150405Z")) | |
| input, err := os.ReadFile(path) | |
| if err != nil { | |
| return err | |
| } | |
| if err := os.WriteFile(backupPath, input, mode); err != nil { | |
| return err | |
| } | |
| return os.Chmod(backupPath, mode) | |
| } |

Where We Are
Installing or uninstalling Claude guard hooks rewrites
~/.claude/settings.jsonand its backup with broad permissions. A user can start from0600and end up with readable files for other local users.Where We Want To Go
Keep the Claude settings file and backup private when guard hooks update them. Existing restrictive modes should stay in place, and new writes should default to
0600.How do we get there
Preserve the current file mode in
backupFileandwriteJSONFile, with a0600fallback for new files. Add a regression test that seedssettings.jsonat0600, runs hook install, and checks both the rewritten settings file and backup mode. Verified withgo test ./...,go vet ./...,npm exec --yes --package pnpm@10.0.0 -- pnpm install --frozen-lockfile,npm exec --yes --package pnpm@10.0.0 -- pnpm --dir web/guard-dashboard typecheck, andgit diff --check.