Skip to content

[AUTOMATION] fix(clawpatch): preserve claude hook file permissions#243

Open
michiosw wants to merge 1 commit into
mainfrom
fix/clawpatch-daily-20260602T083429Z
Open

[AUTOMATION] fix(clawpatch): preserve claude hook file permissions#243
michiosw wants to merge 1 commit into
mainfrom
fix/clawpatch-daily-20260602T083429Z

Conversation

@michiosw

@michiosw michiosw commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Where We Are

Installing or uninstalling Claude guard hooks rewrites ~/.claude/settings.json and its backup with broad permissions. A user can start from 0600 and 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 backupFile and writeJSONFile, with a 0600 fallback for new files. Add a regression test that seeds settings.json at 0600, runs hook install, and checks both the rewritten settings file and backup mode. Verified with go 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, and git diff --check.

michiosw commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Jun 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR preserves Claude settings file permissions when guard hooks update them. The main changes are:

  • Reuses the existing settings file mode when rewriting JSON.
  • Defaults newly created settings writes to 0600.
  • Writes guard backup files with the source settings mode.
  • Adds a regression test for restrictive settings and backup modes during hook install.

Confidence Score: 4/5

This is close, but the backup permission case should be fixed before merging.

  • Existing backup paths can keep broad permissions after being rewritten.

  • The settings file write path itself preserves restrictive modes as intended.

  • The issue is isolated to backup creation and rewrite behavior.

  • internal/guard/cli/cli.go backup file rewrite path.

Security Review

  • Data exposure: internal/guard/cli/cli.go backupFile can leave an existing Claude settings backup at a broad mode while rewriting it with private settings content.

Important Files Changed

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

Comment thread internal/guard/cli/cli.go
Comment on lines 442 to 455
@@ -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())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security 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.

Suggested change
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)
}

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.

1 participant