fix(process): guard program run inputs

This commit is contained in:
Virgil 2026-04-04 00:18:14 +00:00
parent 214cf4cfa8
commit fa79e4eee7
2 changed files with 30 additions and 0 deletions

View file

@ -14,6 +14,12 @@ import (
// Callers may use errors.Is to detect this condition.
var ErrProgramNotFound = coreerr.E("", "program: binary not found in PATH", nil)
// ErrProgramContextRequired is returned when Run or RunDir is called without a context.
var ErrProgramContextRequired = coreerr.E("", "program: command context is required", nil)
// ErrProgramNameRequired is returned when Run or RunDir is called without a program name.
var ErrProgramNameRequired = coreerr.E("", "program: program name is empty", nil)
// Program represents a named executable located on the system PATH.
// Create one with a Name, call Find to resolve its path, then Run or RunDir.
type Program struct {
@ -48,11 +54,19 @@ func (p *Program) Run(ctx context.Context, args ...string) (string, error) {
// Returns trimmed combined stdout+stderr output and any error.
// If dir is empty, the process inherits the caller's working directory.
func (p *Program) RunDir(ctx context.Context, dir string, args ...string) (string, error) {
if ctx == nil {
return "", coreerr.E("Program.RunDir", "program: command context is required", ErrProgramContextRequired)
}
binary := p.Path
if binary == "" {
binary = p.Name
}
if binary == "" {
return "", coreerr.E("Program.RunDir", "program name is empty", ErrProgramNameRequired)
}
var out bytes.Buffer
cmd := exec.CommandContext(ctx, binary, args...)
cmd.Stdout = &out

View file

@ -78,3 +78,19 @@ func TestProgram_Run_FailingCommand(t *testing.T) {
_, err := p.Run(testCtx(t))
require.Error(t, err)
}
func TestProgram_Run_NilContextRejected(t *testing.T) {
p := &process.Program{Name: "echo"}
_, err := p.Run(nil, "test")
require.Error(t, err)
assert.ErrorIs(t, err, process.ErrProgramContextRequired)
}
func TestProgram_RunDir_EmptyNameRejected(t *testing.T) {
p := &process.Program{}
_, err := p.RunDir(testCtx(t), "", "test")
require.Error(t, err)
assert.ErrorIs(t, err, process.ErrProgramNameRequired)
}