From 0d3c9b5214fb4d3b673472ee7f89fa08fe7c5329 Mon Sep 17 00:00:00 2001 From: Micheal Wilkinson Date: Sat, 21 Mar 2026 13:05:08 +0000 Subject: [PATCH] chore(security): resolve gosec findings with permission fixes and #nosec suppressions --- internal/homesick/core/core.go | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/internal/homesick/core/core.go b/internal/homesick/core/core.go index 6668437..402220b 100644 --- a/internal/homesick/core/core.go +++ b/internal/homesick/core/core.go @@ -71,7 +71,7 @@ func (a *App) Clone(uri string, destination string) error { return fmt.Errorf("unable to derive destination from uri %q", uri) } - if err := os.MkdirAll(a.ReposDir, 0o755); err != nil { + if err := os.MkdirAll(a.ReposDir, 0o750); err != nil { return fmt.Errorf("create repos directory: %w", err) } @@ -96,7 +96,7 @@ func (a *App) Clone(uri string, destination string) error { } func (a *App) List() error { - if err := os.MkdirAll(a.ReposDir, 0o755); err != nil { + if err := os.MkdirAll(a.ReposDir, 0o750); err != nil { return err } @@ -297,7 +297,7 @@ func (a *App) Open(castle string) error { } castleRoot := filepath.Join(a.ReposDir, castle) - cmd := exec.Command("sh", "-c", editor+" .") + cmd := exec.Command(editor, ".") // #nosec G204 — EDITOR environment variable is user-set cmd.Dir = castleRoot cmd.Stdout = a.Stdout cmd.Stderr = a.Stderr @@ -327,7 +327,7 @@ func (a *App) Exec(castle string, command []string) error { return nil } - cmd := exec.Command("sh", "-c", commandString) + cmd := exec.Command("sh", "-c", commandString) // #nosec G204 — intentional shell command execution feature cmd.Dir = castleRoot cmd.Stdout = a.Stdout cmd.Stderr = a.Stderr @@ -393,7 +393,7 @@ func (a *App) Generate(castlePath string) error { return err } - if err := os.MkdirAll(absCastle, 0o755); err != nil { + if err := os.MkdirAll(absCastle, 0o750); err != nil { return err } @@ -414,7 +414,7 @@ func (a *App) Generate(castlePath string) error { } } - return os.MkdirAll(filepath.Join(absCastle, "home"), 0o755) + return os.MkdirAll(filepath.Join(absCastle, "home"), 0o750) } func (a *App) Link(castle string) error { @@ -538,7 +538,7 @@ func (a *App) TrackPath(filePath string, castle string) error { if relativeDir == "." { castleTargetDir = castleHome } - if err := os.MkdirAll(castleTargetDir, 0o755); err != nil { + if err := os.MkdirAll(castleTargetDir, 0o750); err != nil { return err } @@ -605,7 +605,7 @@ func appendUniqueSubdir(path string, subdir string) (bool, error) { } } - file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644) + file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o600) // #nosec G304 — internal metadata file if err != nil { return false, err } @@ -718,7 +718,7 @@ func (a *App) linkPath(source string, destination string) error { return err } - if err := os.MkdirAll(filepath.Dir(destination), 0o755); err != nil { + if err := os.MkdirAll(filepath.Dir(destination), 0o750); err != nil { return err } @@ -750,7 +750,7 @@ func (a *App) linkPath(source string, destination string) error { } func readSubdirs(path string) ([]string, error) { - data, err := os.ReadFile(path) + data, err := os.ReadFile(path) // #nosec G304 — internal metadata file if err != nil { if errors.Is(err, os.ErrNotExist) { return []string{}, nil @@ -866,7 +866,7 @@ func (a *App) Rc(castle string) error { if _, err := os.Stat(homesickRc); err == nil { wrapperPath := filepath.Join(homesickD, "parity.rb") if _, err := os.Stat(wrapperPath); errors.Is(err, os.ErrNotExist) { - if mkErr := os.MkdirAll(homesickD, 0o755); mkErr != nil { + if mkErr := os.MkdirAll(homesickD, 0o750); mkErr != nil { return fmt.Errorf("create .homesick.d: %w", mkErr) } wrapperContent := "#!/usr/bin/env ruby\n" + @@ -874,9 +874,13 @@ func (a *App) Rc(castle string) error { "# Evaluates .homesickrc in the context of the castle root.\n" + "rc_file = File.join(__dir__, '..', '.homesickrc')\n" + "eval(File.read(rc_file), binding, rc_file) if File.exist?(rc_file)\n" - if writeErr := os.WriteFile(wrapperPath, []byte(wrapperContent), 0o755); writeErr != nil { + if writeErr := os.WriteFile(wrapperPath, []byte(wrapperContent), 0o600); writeErr != nil { return fmt.Errorf("write parity.rb: %w", writeErr) } + // #nosec G302 -- script wrapper must be executable to run properly + if chmodErr := os.Chmod(wrapperPath, 0o700); chmodErr != nil { + return fmt.Errorf("chmod parity.rb: %w", chmodErr) + } } } @@ -906,7 +910,7 @@ func (a *App) Rc(castle string) error { continue } scriptPath := filepath.Join(homesickD, entry.Name()) - cmd := exec.Command(scriptPath) + cmd := exec.Command(scriptPath) // #nosec G204 — path validated from app-controlled .homesick.d directory cmd.Dir = castleRoot cmd.Stdout = a.Stdout cmd.Stderr = a.Stderr