Documentation
¶
Overview ¶
Package shellwrap provides platform-level helpers for wrapping commands in the user's login shell and for resolving tool binaries (e.g. docker) with PATH caching.
It exists so that both the upstream proxy code (internal/upstream/core) and the security scanner (internal/security/scanner) can share a single, well-tested implementation of shell quoting + login-shell wrapping instead of each rolling their own.
Index ¶
- func LoginShellPATH(logger *zap.Logger) string
- func MinimalEnv() []string
- func MinimalEnvWithLogger(logger *zap.Logger) []string
- func ResolveDockerPath(logger *zap.Logger) (string, error)
- func Shellescape(s string) string
- func WrapWithUserShell(logger *zap.Logger, command string, args []string) (shell string, shellArgs []string)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LoginShellPATH ¶ added in v0.24.2
LoginShellPATH returns the PATH value emitted by the user's login shell. It is captured exactly once per process via `<shell> -l -c 'printf %s "$PATH"'` and cached for the rest of the process lifetime.
Why this exists: when mcpproxy runs as a macOS App Bundle or LaunchAgent, os.Getenv("PATH") is often `/usr/bin:/bin`. That is enough for Go's exec.LookPath to find a docker binary once shellwrap.ResolveDockerPath has cached its absolute path, but it is NOT enough for the docker CLI itself, which re-execs credential helpers like `docker-credential-desktop` via its own $PATH lookup. Those helpers typically live in /usr/local/bin or /opt/homebrew/bin — directories that only exist in the interactive login PATH.
On Windows, this function returns "" (credential-helper PATH drift is not the same problem there, and interactive-shell PATH capture would require cmd.exe or PowerShell gymnastics we explicitly avoid).
Callers should treat an empty return value as "no override available" and fall back to os.Getenv("PATH").
func MinimalEnv ¶
func MinimalEnv() []string
MinimalEnv returns a minimal, allow-listed environment suitable for subprocesses that must NOT inherit the user's ambient credentials (e.g. AWS_ACCESS_KEY_ID, GITHUB_TOKEN, etc). It includes PATH + HOME on Unix and PATH + USERPROFILE on Windows so that `docker` itself still functions.
Callers that need TLS or Docker-specific variables (DOCKER_HOST, DOCKER_CONFIG, …) should append them explicitly.
On Unix, PATH is built by merging the user's login-shell PATH (captured once via LoginShellPATH) with the process's ambient PATH. Login-shell entries come first so that docker's own credential-helper lookups can find binaries installed in /opt/homebrew/bin or /usr/local/bin even when mcpproxy was started from a LaunchAgent with a minimal inherited PATH. See issue #381.
func MinimalEnvWithLogger ¶ added in v0.24.2
MinimalEnvWithLogger is MinimalEnv with an optional logger used while capturing the login-shell PATH on the first call. Subsequent calls return the cached value without logging.
func ResolveDockerPath ¶
ResolveDockerPath returns the absolute path to the `docker` binary. The result is cached for the process lifetime so that repeated calls from hot paths (health checks, connection diagnostics) do not re-spawn a login shell on every invocation.
Resolution order:
- exec.LookPath("docker") — cheap, works when mcpproxy was started from a terminal or when the LaunchAgent PATH already contains docker.
- Fallback: ask the user's login shell `command -v docker` so we pick up Homebrew / Colima / Docker Desktop installs that only exist in the interactive PATH. This fallback is only run once.
func Shellescape ¶
Shellescape escapes a single argument for safe inclusion in a shell command string. On Unix it uses POSIX single-quoting; on Windows it performs a best-effort cmd.exe quoting.
This mirrors the implementation in internal/upstream/core so both code paths can converge on one function.
func WrapWithUserShell ¶
func WrapWithUserShell(logger *zap.Logger, command string, args []string) (shell string, shellArgs []string)
WrapWithUserShell wraps a command and its arguments in the user's login shell so the child process inherits the interactive PATH (important when mcpproxy is launched from a GUI / LaunchAgent on macOS).
It returns the shell to exec and the shell arguments (e.g. ["-l", "-c", "docker run ..."] on Unix, ["/c", "docker run ..."] on Windows cmd).
logger may be nil; when non-nil a debug line is emitted mirroring the existing upstream/core helper.
Types ¶
This section is empty.