command

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 5 Imported by: 0

README

command

Process execution helpers over os/exec. No shell, no injection. Zero dependencies.

import "github.com/tinywasm/command"

The guarantee

Every function except RunShellAsync executes the binary directly, with an already tokenized argv. There is no shell in between — and that is the point of this package, not an implementation detail.

command.Run("git", "commit", "-m", userInput) // safe, whatever userInput contains

Because arguments are never re-parsed, shell metacharacters are inert: ;, |, &&, $VAR, quotes and globs reach the binary verbatim. Command injection is impossible by construction, and command.Run("echo", "*.go") prints a literal *.go. Both properties are locked by tests (TestNoShellInterpretation, TestNoGlobExpansion).

If you genuinely need a shell, RunShellAsync says so in its name — and it is the one place where you must never concatenate untrusted input.

API

Function Purpose
Run(name, args...) Run a binary; returns its combined output, trimmed.
RunInDir(dir, name, args...) Same, inside dir. Sets cmd.Dir, so it is safe under concurrency — it never mutates the process working directory.
RunWithStdin(input, name, args...) Pipes input to stdin. Use it for secrets: an argv is visible in the process table and in this package's error messages; stdin is not.
RunWithRetry(dir, name, args, attempts, delay) Retries a flaky command, returning as soon as one attempt succeeds.
RunShellAsync(commandLine) The only function that opens a shell (sh -c, or cmd.exe /C on Windows). Returns immediately, without waiting.

A non-zero exit is an error whose message carries the command, the wrapped error and whatever the command printed:

command failed in /home/me/repo: git push
Error: exit status 128
Output: fatal: could not read from remote repository

Testing

Exec is the seam. Replace it to intercept execution without running anything:

original := command.Exec
defer func() { command.Exec = original }()

command.Exec = func(name string, args ...string) *exec.Cmd {
    return exec.Command("echo", "intercepted")
}

License

MIT

Documentation

Overview

Package command runs external programs.

Every function except RunShellAsync executes the binary directly through os/exec with an already-tokenized argv — there is NO shell in between. That is the point of this package, not an implementation detail: arguments are never re-parsed, so globbing, quoting, $VAR expansion, `;`, `|` and `&&` have no meaning and command injection is impossible.

command.Run("git", "commit", "-m", userInput) // safe: userInput is one argv entry

If you genuinely need a shell, RunShellAsync says so in its name. Never build a command line by concatenating untrusted input into it.

Zero dependencies.

Index

Constants

This section is empty.

Variables

View Source
var Exec = exec.Command

Exec builds the *exec.Cmd every function here runs. Tests replace it to intercept execution; production code never touches it.

Functions

func Run added in v0.0.2

func Run(name string, args ...string) (string, error)

Run executes name with args and returns its combined output, trimmed. A non-zero exit is an error whose message carries the command and its output.

func RunInDir added in v0.0.2

func RunInDir(dir, name string, args ...string) (string, error)

RunInDir executes name with args inside dir.

func RunShellAsync added in v0.0.2

func RunShellAsync(commandLine string) error

RunShellAsync starts commandLine in the platform shell (sh -c, or cmd.exe /C on Windows) and returns immediately without waiting for it to finish.

This is the ONLY function here that opens a shell, so commandLine IS parsed: never build it from untrusted input.

func RunWithRetry added in v0.0.2

func RunWithRetry(dir, name string, args []string, attempts int, delay time.Duration) (string, error)

RunWithRetry executes name in dir, retrying up to attempts times, waiting delay between tries. It returns as soon as one attempt succeeds.

func RunWithStdin added in v0.0.2

func RunWithStdin(input, name string, args ...string) (string, error)

RunWithStdin executes name with args, piping input to its stdin. Use it for secrets: an argv is visible in the process table and in the error messages of this package, stdin is not.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL