Skip to content

Commit ee75be7

Browse files
authored
fix validations and bump go version (#240)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
1 parent 2d08c73 commit ee75be7

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

.github/actions/bootstrap/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ inputs:
44
go-version:
55
description: "Go version to install"
66
required: true
7-
default: "1.24.x"
7+
default: "1.26.x"
88
cache-key-prefix:
99
description: "Prefix all cache keys with this value"
1010
required: true

tool/gobuild/source.go

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"io"
78
"os"
89
"os/exec"
910
"path/filepath"
@@ -177,42 +178,75 @@ func downloadFromProxy(ctx context.Context, module, version string) (string, fun
177178
// copyDir recursively copies a directory tree, handling symlinks.
178179
// Directories are created with write permissions to allow file creation inside them,
179180
// which is necessary when copying from read-only sources like the go module cache.
181+
// Uses os.Root for safe, race-free filesystem operations within the source and destination directories.
180182
func copyDir(src, dst string) error {
183+
srcRoot, err := os.OpenRoot(src)
184+
if err != nil {
185+
return fmt.Errorf("failed to open source directory: %w", err)
186+
}
187+
defer srcRoot.Close()
188+
189+
dstRoot, err := os.OpenRoot(dst)
190+
if err != nil {
191+
return fmt.Errorf("failed to open destination directory: %w", err)
192+
}
193+
defer dstRoot.Close()
194+
181195
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
182196
if err != nil {
183197
return err
184198
}
185199

186-
// compute destination path
200+
// compute relative path for root-scoped operations
187201
relPath, err := filepath.Rel(src, path)
188202
if err != nil {
189203
return err
190204
}
191-
dstPath := filepath.Join(dst, relPath)
192205

193-
// handle symlinks
206+
// skip the root directory itself
207+
if relPath == "." {
208+
return nil
209+
}
210+
211+
// handle symlinks - read target and recreate in destination.
212+
// Note: os.Root.Readlink/Symlink require Go 1.25+, so we use standard functions here.
213+
// This is safe because we're copying from controlled sources (go module cache or our git clone)
214+
// to a temp directory we created.
194215
if info.Mode()&os.ModeSymlink != 0 {
195216
target, err := os.Readlink(path)
196217
if err != nil {
197218
return err
198219
}
199-
return os.Symlink(target, dstPath)
220+
dstPath := filepath.Join(dst, relPath)
221+
return os.Symlink(target, dstPath) //nolint:gosec // G122: destination is our temp directory
200222
}
201223

202224
if info.IsDir() {
203225
// ensure directories are writable so we can create files inside them
204226
// (go module cache directories are read-only)
205227
perm := info.Mode().Perm() | 0200 // add user write permission
206-
return os.MkdirAll(dstPath, perm)
228+
return dstRoot.Mkdir(relPath, perm)
207229
}
208230

209-
// copy file with write permission to allow go build to work
210-
data, err := os.ReadFile(path)
211-
if err != nil {
212-
return err
213-
}
214-
// ensure files are writable (go module cache files are read-only)
215-
perm := info.Mode().Perm() | 0200 // add user write permission
216-
return os.WriteFile(dstPath, data, perm)
231+
// copy file using root-scoped operations
232+
return copyFileWithRoot(srcRoot, dstRoot, relPath, info.Mode().Perm()|0200)
217233
})
218234
}
235+
236+
// copyFileWithRoot copies a single file using root-scoped file handles for safe operations.
237+
func copyFileWithRoot(srcRoot, dstRoot *os.Root, relPath string, perm os.FileMode) error {
238+
srcFile, err := srcRoot.Open(relPath)
239+
if err != nil {
240+
return err
241+
}
242+
defer srcFile.Close()
243+
244+
dstFile, err := dstRoot.OpenFile(relPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
245+
if err != nil {
246+
return err
247+
}
248+
defer dstFile.Close()
249+
250+
_, err = io.Copy(dstFile, srcFile)
251+
return err
252+
}

0 commit comments

Comments
 (0)