Skip to content

Commit 20d4cff

Browse files
committed
fix atomic binary install to prevent macOS code signature cache rejection
1 parent 56d7c90 commit 20d4cff

3 files changed

Lines changed: 44 additions & 15 deletions

File tree

internal/installer/archive.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,30 @@ func FindBinary(dir, pattern string) (string, error) {
4040
}
4141
return "", fmt.Errorf("binary not found matching pattern %s in %s", pattern, dir)
4242
}
43+
44+
func AtomicInstallBinary(srcPath, destPath string) error {
45+
data, err := os.ReadFile(srcPath)
46+
if err != nil {
47+
return err
48+
}
49+
dir := filepath.Dir(destPath)
50+
tmp, err := os.CreateTemp(dir, ".cps-tmp-*")
51+
if err != nil {
52+
return err
53+
}
54+
tmpPath := tmp.Name()
55+
if _, err := tmp.Write(data); err != nil {
56+
tmp.Close()
57+
os.Remove(tmpPath)
58+
return err
59+
}
60+
if err := tmp.Close(); err != nil {
61+
os.Remove(tmpPath)
62+
return err
63+
}
64+
if err := os.Chmod(tmpPath, 0755); err != nil {
65+
os.Remove(tmpPath)
66+
return err
67+
}
68+
return os.Rename(tmpPath, destPath)
69+
}

internal/installer/direct_download.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,27 @@ func (d *DirectDownloadInstaller) Install(tool *registry.Tool, p platform.Platfo
7171
}
7272

7373
destPath := filepath.Join(destDir, tool.BinaryName)
74-
f, err := os.Create(destPath)
74+
tmp, err := os.CreateTemp(destDir, ".cps-tmp-*")
7575
if err != nil {
7676
return Result{Tool: tool.Name, Err: err}
7777
}
78-
defer f.Close()
78+
tmpPath := tmp.Name()
7979

80-
if _, err := io.Copy(f, resp.Body); err != nil {
80+
if _, err := io.Copy(tmp, resp.Body); err != nil {
81+
tmp.Close()
82+
os.Remove(tmpPath)
8183
return Result{Tool: tool.Name, Err: err}
8284
}
83-
84-
if err := os.Chmod(destPath, 0755); err != nil {
85+
if err := tmp.Close(); err != nil {
86+
os.Remove(tmpPath)
87+
return Result{Tool: tool.Name, Err: err}
88+
}
89+
if err := os.Chmod(tmpPath, 0755); err != nil {
90+
os.Remove(tmpPath)
91+
return Result{Tool: tool.Name, Err: err}
92+
}
93+
if err := os.Rename(tmpPath, destPath); err != nil {
94+
os.Remove(tmpPath)
8595
return Result{Tool: tool.Name, Err: err}
8696
}
8797

@@ -157,11 +167,7 @@ func (d *DirectDownloadInstaller) installArchive(tool *registry.Tool, url, versi
157167
}
158168

159169
destPath := filepath.Join(destDir, tool.BinaryName)
160-
data, err := os.ReadFile(binaryPath)
161-
if err != nil {
162-
return Result{Tool: tool.Name, Err: err}
163-
}
164-
if err := os.WriteFile(destPath, data, 0755); err != nil {
170+
if err := AtomicInstallBinary(binaryPath, destPath); err != nil {
165171
return Result{Tool: tool.Name, Err: err}
166172
}
167173

internal/installer/github_release.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,7 @@ func (g *GitHubReleaseInstaller) Install(tool *registry.Tool, p platform.Platfor
107107
}
108108

109109
destPath := filepath.Join(destDir, tool.BinaryName)
110-
data, err := os.ReadFile(binaryPath)
111-
if err != nil {
112-
return Result{Tool: tool.Name, Err: err}
113-
}
114-
if err := os.WriteFile(destPath, data, 0755); err != nil {
110+
if err := AtomicInstallBinary(binaryPath, destPath); err != nil {
115111
return Result{Tool: tool.Name, Err: err}
116112
}
117113

0 commit comments

Comments
 (0)