diff --git a/packages/core/config/protect.go b/packages/core/config/protect.go index f3c8b46..0e946b4 100644 --- a/packages/core/config/protect.go +++ b/packages/core/config/protect.go @@ -22,7 +22,12 @@ func lockFile(file string) { run("chflags", "uchg", file) default: run("chattr", "+i", file) - _ = os.Chmod(file, 0o400) + // 0o500, not 0o400: protectedTargets() includes the guard binary, and + // chattr commonly fails without CAP_LINUX_IMMUTABLE (containers, + // rootless), so this chmod is the fallback that actually runs. Keeping + // the execute bit matches the windows ACL above (grants RX) and the + // directory mode in protectpaths.go's LockPath. + _ = os.Chmod(file, 0o500) } } diff --git a/packages/core/config/protect_test.go b/packages/core/config/protect_test.go index 4a6c621..8b756f6 100644 --- a/packages/core/config/protect_test.go +++ b/packages/core/config/protect_test.go @@ -22,8 +22,8 @@ func TestLockFileThenUnlockFileRoundTrip(t *testing.T) { if err != nil { t.Fatal(err) } - if info.Mode().Perm() != 0o400 { - t.Errorf("after lockFile, perm = %v, want 0400", info.Mode().Perm()) + if info.Mode().Perm() != 0o500 { + t.Errorf("after lockFile, perm = %v, want 0500", info.Mode().Perm()) } unlockFile(file) @@ -90,8 +90,8 @@ func TestWriteProtectedFileOverLockedFileUnlocksRewritesAndRelocks(t *testing.T) if err != nil { t.Fatal(err) } - if info.Mode().Perm() != 0o400 { - t.Errorf("perm after relock = %v, want 0400", info.Mode().Perm()) + if info.Mode().Perm() != 0o500 { + t.Errorf("perm after relock = %v, want 0500", info.Mode().Perm()) } }