common/hexec: Remove github.com/cli/safeexec

We began using the safeexec package in v0.79.1 to address
https://github.com/gohugoio/hugo/security/advisories/GHSA-8j34-9876-pvfq.

The vulnerability was addressed by the Go team in 1.19, so the safeexec
package is no longer needed.

Closes #13516
This commit is contained in:
Joe Mooring 2025-03-22 12:26:41 -07:00 committed by Bjørn Erik Pedersen
parent f34cdc382a
commit a6bd67793b
5 changed files with 12 additions and 27 deletions

View file

@ -189,7 +189,6 @@ github.com/bep/simplecobra="v0.5.0"
github.com/bep/tmc="v0.5.1" github.com/bep/tmc="v0.5.1"
github.com/cespare/xxhash/v2="v2.3.0" github.com/cespare/xxhash/v2="v2.3.0"
github.com/clbanning/mxj/v2="v2.7.0" github.com/clbanning/mxj/v2="v2.7.0"
github.com/cli/safeexec="v1.0.1"
github.com/cpuguy83/go-md2man/v2="v2.0.4" github.com/cpuguy83/go-md2man/v2="v2.0.4"
github.com/disintegration/gift="v1.2.1" github.com/disintegration/gift="v1.2.1"
github.com/dlclark/regexp2="v1.11.5" github.com/dlclark/regexp2="v1.11.5"

View file

@ -27,7 +27,6 @@ import (
"sync" "sync"
"github.com/bep/logg" "github.com/bep/logg"
"github.com/cli/safeexec"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
@ -113,18 +112,6 @@ func IsNotFound(err error) bool {
return errors.As(err, &notFoundErr) return errors.As(err, &notFoundErr)
} }
// SafeCommand is a wrapper around os/exec Command which uses a LookPath
// implementation that does not search in current directory before looking in PATH.
// See https://github.com/cli/safeexec and the linked issues.
func SafeCommand(name string, arg ...string) (*exec.Cmd, error) {
bin, err := safeexec.LookPath(name)
if err != nil {
return nil, err
}
return exec.Command(bin, arg...), nil
}
// Exec enforces a security policy for commands run via os/exec. // Exec enforces a security policy for commands run via os/exec.
type Exec struct { type Exec struct {
sc security.Config sc security.Config
@ -197,7 +184,7 @@ func (e *Exec) Npx(name string, arg ...any) (Runner, error) {
tryFuncs := map[binaryLocation]tryFunc{ tryFuncs := map[binaryLocation]tryFunc{
binaryLocationNodeModules: func() func(...any) (Runner, error) { binaryLocationNodeModules: func() func(...any) (Runner, error) {
nodeBinFilename := filepath.Join(e.workingDir, nodeModulesBinPath, name) nodeBinFilename := filepath.Join(e.workingDir, nodeModulesBinPath, name)
_, err := safeexec.LookPath(nodeBinFilename) _, err := exec.LookPath(nodeBinFilename)
if err != nil { if err != nil {
return nil return nil
} }
@ -215,7 +202,7 @@ func (e *Exec) Npx(name string, arg ...any) (Runner, error) {
} }
}, },
binaryLocationPath: func() func(...any) (Runner, error) { binaryLocationPath: func() func(...any) (Runner, error) {
if _, err := safeexec.LookPath(name); err != nil { if _, err := exec.LookPath(name); err != nil {
return nil return nil
} }
return func(arg2 ...any) (Runner, error) { return func(arg2 ...any) (Runner, error) {
@ -346,7 +333,7 @@ func (c *commandeer) command(arg ...any) (*cmdWrapper, error) {
bin = c.fullyQualifiedName bin = c.fullyQualifiedName
} else { } else {
var err error var err error
bin, err = safeexec.LookPath(c.name) bin, err = exec.LookPath(c.name)
if err != nil { if err != nil {
return nil, &NotFoundError{ return nil, &NotFoundError{
name: c.name, name: c.name,
@ -384,7 +371,7 @@ func InPath(binaryName string) bool {
if strings.Contains(binaryName, "/") { if strings.Contains(binaryName, "/") {
panic("binary name should not contain any slash") panic("binary name should not contain any slash")
} }
_, err := safeexec.LookPath(binaryName) _, err := exec.LookPath(binaryName)
return err == nil return err == nil
} }
@ -394,7 +381,7 @@ func LookPath(binaryName string) string {
if strings.Contains(binaryName, "/") { if strings.Contains(binaryName, "/") {
panic("binary name should not contain any slash") panic("binary name should not contain any slash")
} }
s, err := safeexec.LookPath(binaryName) s, err := exec.LookPath(binaryName)
if err != nil { if err != nil {
return "" return ""
} }

2
go.mod
View file

@ -24,7 +24,6 @@ require (
github.com/bep/tmc v0.5.1 github.com/bep/tmc v0.5.1
github.com/cespare/xxhash/v2 v2.3.0 github.com/cespare/xxhash/v2 v2.3.0
github.com/clbanning/mxj/v2 v2.7.0 github.com/clbanning/mxj/v2 v2.7.0
github.com/cli/safeexec v1.0.1
github.com/disintegration/gift v1.2.1 github.com/disintegration/gift v1.2.1
github.com/dustin/go-humanize v1.0.1 github.com/dustin/go-humanize v1.0.1
github.com/evanw/esbuild v0.24.2 github.com/evanw/esbuild v0.24.2
@ -120,6 +119,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.22.2 // indirect github.com/aws/smithy-go v1.22.2 // indirect
github.com/cli/safeexec v1.0.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect

View file

@ -19,11 +19,11 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/common/hugo"
) )
@ -222,7 +222,7 @@ func (r *ReleaseHandler) replaceInFile(filename string, oldNew ...string) error
} }
func git(args ...string) (string, error) { func git(args ...string) (string, error) {
cmd, _ := hexec.SafeCommand("git", args...) cmd := exec.Command("git", args...)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return "", fmt.Errorf("git failed: %q: %q (%q)", err, out, args) return "", fmt.Errorf("git failed: %q: %q (%q)", err, out, args)

View file

@ -4,12 +4,11 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/common/hugio"
"github.com/spf13/afero" "github.com/spf13/afero"
@ -208,7 +207,7 @@ func removeAll(expression, content string) string {
} }
func rewrite(filename, rule string) { func rewrite(filename, rule string) {
cmf, _ := hexec.SafeCommand("gofmt", "-w", "-r", rule, filename) cmf := exec.Command("gofmt", "-w", "-r", rule, filename)
out, err := cmf.CombinedOutput() out, err := cmf.CombinedOutput()
if err != nil { if err != nil {
log.Fatal("gofmt failed:", string(out)) log.Fatal("gofmt failed:", string(out))
@ -217,7 +216,7 @@ func rewrite(filename, rule string) {
func goimports(dir string) { func goimports(dir string) {
// Needs go install golang.org/x/tools/cmd/goimports@latest // Needs go install golang.org/x/tools/cmd/goimports@latest
cmf, _ := hexec.SafeCommand("goimports", "-w", dir) cmf := exec.Command("goimports", "-w", dir)
out, err := cmf.CombinedOutput() out, err := cmf.CombinedOutput()
if err != nil { if err != nil {
log.Fatal("goimports failed:", string(out)) log.Fatal("goimports failed:", string(out))
@ -225,7 +224,7 @@ func goimports(dir string) {
} }
func gofmt(dir string) { func gofmt(dir string) {
cmf, _ := hexec.SafeCommand("gofmt", "-w", dir) cmf := exec.Command("gofmt", "-w", dir)
out, err := cmf.CombinedOutput() out, err := cmf.CombinedOutput()
if err != nil { if err != nil {
log.Fatal("gofmt failed:", string(out)) log.Fatal("gofmt failed:", string(out))