config

package
v1.3.4 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package config loads, defaults, validates, and resolves MachineProxy configuration. It receives TOML, JSON or YAML files plus CLI overrides from cmd/machineproxy, and feeds runtime wiring for backends, namespace setup, FUSE mounts, environment filtering, and component discovery.

Index

Constants

View Source
const (
	// UIDGIDModeTransparent forwards the remote UID/GID through unchanged.
	UIDGIDModeTransparent = "transparent"
	// UIDGIDModeOverride rewrites reads to the local user's UID/GID and
	// silently drops chown attempts that would otherwise propagate the
	// local user's view of ownership onto the remote.
	UIDGIDModeOverride = "override"
)

Recognized values for Container.UIDMode and Container.GIDMode.

Variables

View Source
var (
	// DefaultCacheDir overrides the local-side cache parent directory
	// used to derive the PATH-stub bind target (and any future cache
	// locations). A leading "~" is expanded against the local user's
	// home directory at use time. When empty (the default), local
	// callers resolve $XDG_CACHE_HOME/machineproxy, falling back to
	// ~/.cache/machineproxy when XDG_CACHE_HOME is unset or relative.
	DefaultCacheDir = ""

	// DefaultAgentRemotePath is the upload destination for mproxy-agent
	// on the remote host. A leading "~" is expanded against the remote
	// user's home directory at SFTP-use time. This stays independent
	// of DefaultCacheDir because remote-side env vars aren't visible at
	// config-load time.
	DefaultAgentRemotePath = "~/.cache/machineproxy/mproxy-agent"

	// DefaultPathStubFallbackDir is the absolute path used in place of
	// the resolved local cache dir when home-directory lookup fails.
	DefaultPathStubFallbackDir = "/tmp/machineproxy/pathstub"
)

Packager-overridable path defaults. These are var (not const) so a downstream packager can repoint them at build time via, e.g.:

go build -ldflags "-X github.com/jamesits/machineproxy/pkg/config.LibDir=/opt/machineproxy/lib"

LibDir's default is OS-specific and lives in paths_<goos>.go.

View Source
var (
	Version = "0.0.0"
	Commit  = ""
	Date    = ""
)

Build-time metadata, populated via ldflags.

View Source
var LibDir = "/usr/lib/machineproxy"

LibDir is the install location for machineproxy support binaries (mproxy-shim, mproxy-tracer, and the per-OS/arch agent layout under <LibDir>/agent/<goos>/<goarch>/). Override at link time via -ldflags "-X github.com/jamesits/machineproxy/pkg/config.LibDir=..." for downstream packagers.

Functions

func ExpandLocalHome added in v1.1.0

func ExpandLocalHome(p string) (string, error)

ExpandLocalHome resolves a leading "~" or "~/" against the local user's home directory. Other paths are returned unchanged. Returns an error only if "~" is used but the home dir cannot be looked up.

func ExpandRemoteHome added in v1.1.0

func ExpandRemoteHome(p, remoteHome string) (string, error)

ExpandRemoteHome resolves a leading "~" or "~/" against remoteHome (typically the SFTP server's default working directory). Other paths are returned unchanged. SFTP servers do not expand "~" themselves and session.Start single-quotes its argument, so this rewrite must happen client-side before any remote use.

func LocalCacheDir added in v1.3.2

func LocalCacheDir() (string, error)

LocalCacheDir resolves the local-side cache parent directory:

  • DefaultCacheDir (with "~" expanded) when non-empty
  • $XDG_CACHE_HOME/machineproxy when XDG_CACHE_HOME is an absolute path
  • ~/.cache/machineproxy otherwise

Returns an error only when "~" expansion is required and the local home directory cannot be determined.

func LookupGroupGID added in v1.3.0

func LookupGroupGID(name string) (uint32, error)

LookupGroupGID resolves a local group name to its GID.

func LookupUID added in v1.3.0

func LookupUID(name string) (uint32, error)

LookupUID resolves a local username to its UID.

func MatchLocalCommand

func MatchLocalCommand(entry, pathname string) bool

MatchLocalCommand is a convenience that compiles entry and matches in one step. Returns false for malformed entries.

func ResolveAgentBinaryPath

func ResolveAgentBinaryPath(configPath, goos, goarch string) (string, error)

ResolveAgentBinaryPath finds the mproxy-agent binary. It checks the MPROXY_AGENT_BIN env var first, then the config value, adjacent binary, and well-known install paths. The goos and goarch parameters select the correct platform-specific binary for the remote host.

func ResolveInterposerPath added in v1.3.0

func ResolveInterposerPath(configPath string) (string, error)

ResolveInterposerPath finds the libmproxy_interposer.dylib bundle for the local darwin host. It looks adjacent to the running machineproxy binary first (development layout), then under <LibDir>/agent/darwin/ <goarch>/ (install layout, mirroring ResolveAgentBinaryPath). On non-darwin hosts the dylib is not used; callers should branch on runtime.GOOS before invoking this.

func ResolveShimPath

func ResolveShimPath(configPath string) (string, error)

ResolveShimPath finds the mproxy-shim binary using the config value, then falling back to adjacent binary and well-known install paths.

func ResolveTracerPath

func ResolveTracerPath(configPath string) (string, error)

ResolveTracerPath finds the mproxy-tracer binary using the config value, then falling back to adjacent binary and well-known install paths.

Types

type Config

type Config struct {
	LogLevel string `yaml:"log_level" toml:"log_level" json:"log_level"` // trace, debug, info, warn, error
	LogFile  string `yaml:"log_file"  toml:"log_file"  json:"log_file"`  // empty = stderr

	Remote struct {
		// Type selects the backend implementation: "ssh" (default) or
		// "docker". The CLI --backend flag overrides this when set.
		Type string `yaml:"type" toml:"type" json:"type"`
		// SSH is resolved via the user's ssh_config (see ssh_config(5)).
		// Host accepts either a literal hostname/IP or a Host alias defined
		// in ~/.ssh/config; User and Port, when set, override the resolved
		// values from ssh_config.
		SSH struct {
			Host string `yaml:"host" toml:"host" json:"host"`
			User string `yaml:"user" toml:"user" json:"user"`
			Port int    `yaml:"port" toml:"port" json:"port"`
		} `yaml:"ssh" toml:"ssh" json:"ssh"`
		// Docker selects a running container by name or ID. Host (when
		// set) overrides the DOCKER_HOST env var for this invocation.
		Docker struct {
			Container string `yaml:"container" toml:"container" json:"container"`
			Host      string `yaml:"host" toml:"host" json:"host"`
		} `yaml:"docker" toml:"docker" json:"docker"`
		// Compose selects a running container by Docker Compose project and
		// service name. Project "." resolves from the working directory.
		// Sequence (1-based) picks a specific replica of a scaled service;
		// 0 means auto (errors if more than one container matches).
		// Host, when set, overrides the DOCKER_HOST env var.
		Compose struct {
			Project  string `yaml:"project"  toml:"project"  json:"project"`
			Service  string `yaml:"service"  toml:"service"  json:"service"`
			Sequence int    `yaml:"sequence" toml:"sequence" json:"sequence"`
			Host     string `yaml:"host"     toml:"host"     json:"host"`
		} `yaml:"compose" toml:"compose" json:"compose"`
		// OS selects the remote-side agent binary's GOOS. When empty,
		// the runtime first asks the backend to detect it and only
		// falls back to the local runtime.GOOS if detection fails.
		OS string `yaml:"os" toml:"os" json:"os"`
		// Arch selects the remote-side agent binary's GOARCH. Empty
		// triggers the same detection/fallback chain as OS.
		Arch string `yaml:"arch" toml:"arch" json:"arch"`
	} `yaml:"remote" toml:"remote" json:"remote"`

	Container struct {
		LocalCommands []string `yaml:"local_commands" toml:"local_commands" json:"local_commands"`
		Mounts        []string `yaml:"mounts" toml:"mounts" json:"mounts"`                // docker-compose style: [local:]remote
		WorkingDir    string   `yaml:"working_dir" toml:"working_dir" json:"working_dir"` // override container working directory; defaults to first mount's local path
		EnvRemove     []string `yaml:"env_remove" toml:"env_remove" json:"env_remove"`    // glob/regex patterns for env vars to strip from the container process
		// PathProxy controls the FUSE-backed PATH-stub directory that
		// surfaces remote-side executables inside the container.
		//   "prepend"  — stubs win over locally-installed binaries (default)
		//   "append"   — local binaries win; stubs only fill gaps
		//   "disabled" — skip enumeration entirely
		PathProxy string `yaml:"path_proxy" toml:"path_proxy" json:"path_proxy"`
		// PathStubDir is the in-container directory where the stub FUSE
		// is bind-mounted. Defaults to $HOME/.cache/machineproxy/pathstub
		// so bwrap (which lacks privilege to mkdir parents under /var)
		// can create the bind target. A leading "~" is expanded against
		// the local user's home; the resulting path must be absolute.
		PathStubDir string `yaml:"path_stub_dir" toml:"path_stub_dir" json:"path_stub_dir"`
		// ForceResolveInitialCommandLocally controls whether the
		// resolved entrypoint command, its shebang interpreter, and
		// any env-target are auto-appended to LocalCommands. The
		// initial exec is always resolved against the local PATH
		// (the path-stub directory is skipped) because the path-stub
		// serves remote binaries that the local kernel may not load;
		// whitelisting the resolved chain prevents the exec
		// interception layer from later routing those same paths to
		// the remote when they are re-execed (for instance by the
		// kernel's binfmt_script interpreter). Defaults to true; set
		// false to opt out.
		ForceResolveInitialCommandLocally *bool `` /* 134-byte string literal not displayed */
		// UIDMode controls how the workspace FUSE mount reports file
		// owner UIDs and how chown(uid, _) calls are forwarded:
		//   "transparent" — pass the remote UID through unchanged
		//   "override"    — always report the local user's UID for
		//                   reads, and silently no-op uid changes on
		//                   write. This is the default because the
		//                   remote often runs as a different user
		//                   (e.g. root) than the local process, and
		//                   transparent ownership reporting trips
		//                   default_permissions in the kernel.
		UIDMode string `yaml:"uid_mode" toml:"uid_mode" json:"uid_mode"`
		// GIDMode is the GID counterpart to UIDMode; same semantics.
		GIDMode string `yaml:"gid_mode" toml:"gid_mode" json:"gid_mode"`
		// UIDMap is a list of /etc/subuid-like entries that translate
		// remote-reported UIDs to the local view (and back, on chown).
		// Each entry has one of these shapes:
		//   "uid:mapped_uid"
		//   "username:mapped_uid"          (username resolved via getpwnam)
		//   "uid:mapped_uid:count"
		//   "username:mapped_uid:count"
		// A UID covered by any entry takes the mapped value regardless
		// of UIDMode; UIDs not covered fall back to UIDMode behaviour.
		// See CompileIDMapEntry for the full grammar.
		UIDMap []string `yaml:"uid_map" toml:"uid_map" json:"uid_map"`
		// GIDMap is the GID counterpart to UIDMap. Names in the first
		// field are resolved via getgrnam instead of getpwnam.
		GIDMap []string `yaml:"gid_map" toml:"gid_map" json:"gid_map"`
	} `yaml:"container" toml:"container" json:"container"`

	Agent struct {
		EnvKeep   []string `yaml:"env_keep" toml:"env_keep" json:"env_keep"`       // glob/regex patterns for inherited env vars to forward to remote
		EnvRemove []string `yaml:"env_remove" toml:"env_remove" json:"env_remove"` // glob/regex patterns for env vars to always strip from remote
	} `yaml:"agent" toml:"agent" json:"agent"`

	Components struct {
		ShimPath        string `yaml:"shim_path" toml:"shim_path" json:"shim_path"`
		TracerPath      string `yaml:"tracer_path" toml:"tracer_path" json:"tracer_path"`
		InterposerPath  string `yaml:"interposer_path" toml:"interposer_path" json:"interposer_path"`
		AgentLocalPath  string `yaml:"agent_local_path" toml:"agent_local_path" json:"agent_local_path"`
		AgentRemotePath string `yaml:"agent_remote_path" toml:"agent_remote_path" json:"agent_remote_path"`
	} `yaml:"components" toml:"components" json:"components"`

	Recording struct {
		Path string `yaml:"path" toml:"path" json:"path"` // empty disables recording
	} `yaml:"recording" toml:"recording" json:"recording"`
}

Config describes machineproxy runtime behavior.

func Load

func Load(r io.Reader) (*Config, error)

Load reads from r, auto-detecting YAML vs TOML by sniffing the bytes, and applies defaults plus validation. Use LoadFile when you have a path so the extension hint applies first.

func LoadFile

func LoadFile(path string) (*Config, error)

LoadFile reads and decodes the config at path, applies defaults, and validates. Format is detected by file extension first (.yaml/.yml/.json → YAML, .toml → TOML); if the extension is unrecognized, the contents are sniffed (see detectFormat).

func LoadFileRaw added in v1.1.0

func LoadFileRaw(path string) (*Config, error)

LoadFileRaw reads and decodes the config at path without applying defaults or validating. Callers that need to mutate the result before use (for instance, applying CLI overrides) should call Finalize after their mutations. Format detection matches LoadFile.

func (*Config) Finalize added in v1.1.0

func (c *Config) Finalize() error

Finalize applies defaults and validates the config. Call this after decoding (via LoadFileRaw) and any post-decode mutations such as CLI overrides. LoadFile and Load call Finalize automatically.

func (*Config) Validate

func (c *Config) Validate() error

type Format

type Format int

Format identifies the on-disk format of a config file.

const (
	FormatYAML Format = iota
	FormatTOML
)

type IDLookup added in v1.3.0

type IDLookup func(name string) (uint32, error)

IDLookup resolves a name to a numeric ID. LookupUID and LookupGroupGID are the production implementations used by Validate; tests can pass an in-memory stub.

type IDMapEntry added in v1.3.0

type IDMapEntry struct {
	RemoteID uint32
	LocalID  uint32
	Count    uint32
}

IDMapEntry is a parsed uid_map/gid_map line. A single entry maps a contiguous range of [Count] remote IDs starting at RemoteID to local IDs starting at LocalID.

func CompileIDMapEntry added in v1.3.0

func CompileIDMapEntry(s string, lookup IDLookup) (IDMapEntry, error)

CompileIDMapEntry parses a single uid_map / gid_map entry in /etc/subuid-like format. Supported forms:

uid:mapped_uid
username:mapped_uid
uid:mapped_uid:count
username:mapped_uid:count

The first column identifies the remote-side ID (either as a numeric ID or as a name resolved via lookup); the second column is the local ID to surface for that range; count (default 1) extends the range. lookup may be nil when every entry uses a numeric first column.

type LocalCommandRule

type LocalCommandRule struct {
	// contains filtered or unexported fields
}

LocalCommandRule is a compiled local_commands entry that can match against executable pathnames. Supported forms:

  • "/absolute/path" — exact full path match
  • "/regex/" — regex matched against the full pathname
  • "basename" — matched against the last segment of the path

func CompileLocalCommand

func CompileLocalCommand(s string) (*LocalCommandRule, error)

CompileLocalCommand parses and validates a local_commands entry, returning a rule that can match pathnames.

func (*LocalCommandRule) Match

func (r *LocalCommandRule) Match(pathname string) bool

Match reports whether pathname matches this rule.

type Mount

type Mount struct {
	// RemotePath is the path on the remote machine (FUSE source).
	RemotePath string
	// ContainerPath is the path inside the container (bind target).
	// Equals RemotePath when no explicit local path is given.
	ContainerPath string
}

Mount represents a parsed container mount entry in docker-compose style. Format: [local_path:]remote_path

func ParseMount

func ParseMount(s string) (Mount, error)

ParseMount parses a docker-compose style mount string.

Either side may start with "~" or "~/"; the local side is expanded against the local user's home immediately so the resulting ContainerPath is always absolute. The remote side is returned in its raw form (still possibly "~/..."), to be expanded against the remote user's home at SFTP-use time — see ExpandRemoteHome.

Jump to

Keyboard shortcuts

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