diff options
| author | srdusr <[email protected]> | 2026-05-25 23:13:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2026-05-25 23:13:00 +0200 |
| commit | dc059db6db67abad249fa153593a89a45fa37486 (patch) | |
| tree | 2b30974599b66975906c3dc8c1a3258418147648 | |
| parent | 0d1ce88962fe31ce1d204634e6ea10998a02827a (diff) | |
| download | mitmux-dc059db6db67abad249fa153593a89a45fa37486.tar.gz mitmux-dc059db6db67abad249fa153593a89a45fa37486.zip | |
Version flag, Makefile, and honest cross-platform documentation
Neither binary had a -version flag - a basic expectation for any CLI
tool, and useful for anyone reporting a bug ("which build is this").
internal/version holds Version/Commit/Date, set via -ldflags "-X
mitmux/internal/version.X=..." at build time and defaulting to "dev"
for a plain `go build` with no ldflags, so -version is never blank or
misleading about whether a given binary is a tagged release or a local
build. Both mitmux and mitmuxd gained a -version flag that prints it
and exits.
Makefile: `make build` (both binaries for the current platform, version
info from `git describe`), `make test` (the same build/vet/gofmt/test
checks expected before every commit here), `make install` (a thin
wrapper over `go install`, respecting GOBIN/GOPATH as usual - not
reimplementing Go's own path resolution), `make release` (cross-compiles
both binaries for linux/darwin/windows/freebsd, amd64+arm64 where it
makes sense, into dist/). Every target is CGO_ENABLED=0:
modernc.org/sqlite is pure Go, so no C toolchain is needed anywhere,
cross-compiling included - this was already true before this commit,
just not verified or made easy to use.
Verified live, every target actually run rather than just written:
`make build` produces working binaries with version info correctly
picked up from git (confirmed against a real -version invocation, both
the "dev" default and an ldflags-injected release-style version
string); `make test` runs clean; `make release` was run for real and
produced 6 platform/arch binaries, each confirmed with `file` to be a
genuinely correctly-formatted executable for its target (Mach-O for
both macOS architectures, PE32+ for Windows, ELF for both Linux
architectures and FreeBSD) - not just "the command exited zero." `make
install`'s correctness rests on `go install` itself, Go's own
well-tested mechanism; deliberately not run for real here since it
writes into the real GOPATH/bin outside this repo, unprompted.
README gained an honest Platforms section: Linux is what's actually
been run and verified throughout this project's development; macOS,
Windows, and FreeBSD cross-compile cleanly and pass go vet, and the
code has nothing Linux-specific in it (CA/history storage already used
Go's own cross-platform os.UserConfigDir, not a hardcoded XDG path -
also fixed the README's install-directory example, which had been
Linux-only text), but they haven't run on real hardware, so they're
documented as "should work, not yet verified" rather than a claim this
session can't actually back up. Also flagged a concrete, real gotcha:
macOS's shorter Unix domain socket path limit combined with the deeper
~/Library/Application Support default control-socket location could
matter for a long username, with the existing -socket flag as the
workaround.
go build/vet/gofmt/test/mod tidy all clean.
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 59 | ||||
| -rw-r--r-- | README.md | 47 | ||||
| -rw-r--r-- | cmd/mitmux/main.go | 7 | ||||
| -rw-r--r-- | cmd/mitmuxd/main.go | 7 | ||||
| -rw-r--r-- | internal/version/version.go | 30 | ||||
| -rw-r--r-- | internal/version/version_test.go | 32 |
7 files changed, 179 insertions, 4 deletions
@@ -1,4 +1,5 @@ /bin/ +/dist/ *.pem *.db *.db-wal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..58f2f3f --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +# mitmux build automation. Plain `make` builds both binaries for the +# current platform into bin/; `make release` cross-compiles every +# binary for every platform in PLATFORMS into dist/. Every target here +# is CGO_ENABLED=0 - modernc.org/sqlite is pure Go, so no C toolchain +# is needed on any platform, cross-compiling included. + +BIN_DIR := bin +DIST_DIR := dist + +VERSION := $(shell git describe --tags --dirty --always 2>/dev/null || echo dev) +COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) +DATE := $(shell date -u +%Y-%m-%d) +LDFLAGS := -X mitmux/internal/version.Version=$(VERSION) -X mitmux/internal/version.Commit=$(COMMIT) -X mitmux/internal/version.Date=$(DATE) + +# darwin/amd64 and freebsd/amd64 cross-compile and pass `go vet` cleanly +# (verified) but, unlike linux/amd64, have not been run on real hardware +# - see README's Platforms section. +PLATFORMS := linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 freebsd/amd64 + +.PHONY: all build test check clean release install + +all: build + +build: + mkdir -p $(BIN_DIR) + CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BIN_DIR)/mitmuxd ./cmd/mitmuxd + CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BIN_DIR)/mitmux ./cmd/mitmux + +# Same checks expected before every commit in this repo - see PLAN.md. +test: + go build ./... + go vet ./... + test -z "$$(gofmt -l .)" + go test ./... + +check: test + +clean: + rm -rf $(BIN_DIR) $(DIST_DIR) + +install: + go install -ldflags "$(LDFLAGS)" ./cmd/mitmuxd + go install -ldflags "$(LDFLAGS)" ./cmd/mitmux + +# Cross-compiles both binaries for every platform in PLATFORMS into +# dist/mitmux-<os>-<arch>/. +release: + @for p in $(PLATFORMS); do \ + os=$$(echo $$p | cut -d/ -f1); \ + arch=$$(echo $$p | cut -d/ -f2); \ + out=$(DIST_DIR)/mitmux-$$os-$$arch; \ + ext=""; \ + if [ "$$os" = "windows" ]; then ext=".exe"; fi; \ + mkdir -p $$out; \ + echo "building $$os/$$arch..."; \ + CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -ldflags "$(LDFLAGS)" -o $$out/mitmuxd$$ext ./cmd/mitmuxd || exit 1; \ + CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -ldflags "$(LDFLAGS)" -o $$out/mitmux$$ext ./cmd/mitmux || exit 1; \ + done + @echo "release binaries in $(DIST_DIR)/" @@ -69,20 +69,57 @@ list of what's deliberately not implemented (and why), see ## Install / build -Requires Go 1.26.5+ (see `go.mod`). +Requires Go 1.26.5+ (see `go.mod`). No other dependencies - the SQLite +driver ([modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite)) is +pure Go, so there's no C toolchain to install and nothing to link +against, on any platform. ```sh git clone <this repo> cd mitmux +make build # -> bin/mitmuxd, bin/mitmux +``` + +`make build` covers the common case; see the [`Makefile`](Makefile) +itself for the rest - `make install` (via `go install`, respecting +`GOBIN`/`GOPATH` as usual), `make release` (cross-compiles both +binaries for every platform in `PLATFORMS` into `dist/`), `make test` +(the same build/vet/gofmt/test checks expected before every commit - +see `PLAN.md`). Building without `make` works identically: + +```sh go build -o bin/mitmuxd ./cmd/mitmuxd go build -o bin/mitmux ./cmd/mitmux ``` +### Platforms + +Linux is the primary target and the only one this has actually run on +during development - every feature in this document was verified live +against a real daemon and real traffic there. macOS, Windows, and +FreeBSD all cross-compile cleanly with `CGO_ENABLED=0` and pass `go +vet` (`make release` builds all of them), and the code itself has +nothing Linux-specific in it - CA/history storage uses Go's own +cross-platform `os.UserConfigDir()`, not a hardcoded XDG path - but +they haven't been run on real hardware, so treat them as "should work, +not yet verified" rather than a tested claim. If you try one and hit +something, that's useful to know about. + +One concrete thing worth knowing on macOS specifically: its Unix +domain socket path limit is shorter than Linux's, and the default +control-socket location lives under `~/Library/Application +Support/mitmux/` - a deeper path than Linux's usual +`$XDG_RUNTIME_DIR`. A long username or home directory path could push +past the limit; if `mitmuxd` fails to bind its control socket, pass a +shorter `-socket /tmp/mitmux.sock` (and the matching `-socket` to +`mitmux`) to both binaries. + ## Quick start 1. **Start the daemon.** By default it listens on `127.0.0.1:8080` and - stores its CA and history database under `~/.config/mitmux` (XDG - config dir): + stores its CA and history database under your OS's standard config + directory (Linux: `~/.config/mitmux`, macOS: `~/Library/Application + Support/mitmux`, Windows: `%AppData%\mitmux`): ```sh ./bin/mitmuxd @@ -124,7 +161,9 @@ go build -o bin/mitmux ./cmd/mitmux Both binaries take flags for non-default setups - `-listen`, `-socket`, `-ca-dir`, `-db`, `-upstream-proxy` on `mitmuxd`; `-socket` on `mitmux`. -Run either with `-h` for the full list. +Both also take `-version` (prints version/commit/date and exits - `dev` +for a plain `go build`; `make build`/`make release` fill it in from +`git describe`) and `-h` for the full list. `-listen` takes a comma-separated list to bind more than one address (`-listen "127.0.0.1:8080,127.0.0.1:8081"`) - one logical proxy on diff --git a/cmd/mitmux/main.go b/cmd/mitmux/main.go index 7ffe9b9..c9563fe 100644 --- a/cmd/mitmux/main.go +++ b/cmd/mitmux/main.go @@ -23,6 +23,7 @@ import ( "mitmux/internal/rules" "mitmux/internal/scope" "mitmux/internal/store" + "mitmux/internal/version" ) func defaultSocketPath() string { @@ -38,8 +39,14 @@ func defaultSocketPath() string { func main() { socketPath := flag.String("socket", "", "daemon control socket path (default: $XDG_RUNTIME_DIR/mitmux.sock, else <ca-dir>/mitmux.sock)") + showVersion := flag.Bool("version", false, "print version and exit") flag.Parse() + if *showVersion { + fmt.Println(version.String("mitmux")) + return + } + path := *socketPath if path == "" { path = defaultSocketPath() diff --git a/cmd/mitmuxd/main.go b/cmd/mitmuxd/main.go index baaba85..0114871 100644 --- a/cmd/mitmuxd/main.go +++ b/cmd/mitmuxd/main.go @@ -22,6 +22,7 @@ import ( "mitmux/internal/ipc" "mitmux/internal/proxy" "mitmux/internal/store" + "mitmux/internal/version" ) func main() { @@ -31,8 +32,14 @@ func main() { socketPath := flag.String("socket", "", "control socket path (default: $XDG_RUNTIME_DIR/mitmux.sock, else <ca-dir>/mitmux.sock)") installCA := flag.Bool("install-ca", false, "generate the CA if needed, print OS-specific trust-store install steps, and exit (doesn't start the proxy)") upstreamProxy := flag.String("upstream-proxy", "", "chain all outbound connections through this HTTP CONNECT proxy (host:port, optional http:// prefix) instead of dialing origins directly") + showVersion := flag.Bool("version", false, "print version and exit") flag.Parse() + if *showVersion { + fmt.Println(version.String("mitmuxd")) + return + } + var listenAddrs []string for _, a := range strings.Split(*listen, ",") { if a = strings.TrimSpace(a); a != "" { diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..030bd4e --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,30 @@ +// Package version holds build-time version information for both +// binaries, set via -ldflags "-X mitmux/internal/version.Version=..." +// (see the Makefile's release target). Defaults to "dev" for a plain +// `go build` with no ldflags, so `-version` is never blank or +// misleading about whether a given binary is a tagged release or a +// local build. +package version + +var ( + Version = "dev" + Commit = "" + Date = "" +) + +// String returns a one-line version summary for component ("mitmux" or +// "mitmuxd"): "mitmux dev" for an untagged build, or +// "mitmux 1.2.3 (abc1234, 2026-01-02)" once Commit/Date are set. +func String(component string) string { + s := component + " " + Version + if Commit != "" || Date != "" { + s += " (" + s += Commit + if Commit != "" && Date != "" { + s += ", " + } + s += Date + s += ")" + } + return s +} diff --git a/internal/version/version_test.go b/internal/version/version_test.go new file mode 100644 index 0000000..d2d501b --- /dev/null +++ b/internal/version/version_test.go @@ -0,0 +1,32 @@ +package version + +import "testing" + +func TestStringDefault(t *testing.T) { + orig := Version + Version, Commit, Date = "dev", "", "" + defer func() { Version = orig }() + if got := String("mitmux"); got != "mitmux dev" { + t.Errorf("String(%q) = %q, want %q", "mitmux", got, "mitmux dev") + } +} + +func TestStringWithCommitAndDate(t *testing.T) { + origV, origC, origD := Version, Commit, Date + Version, Commit, Date = "1.2.3", "abc1234", "2026-01-02" + defer func() { Version, Commit, Date = origV, origC, origD }() + want := "mitmuxd 1.2.3 (abc1234, 2026-01-02)" + if got := String("mitmuxd"); got != want { + t.Errorf("String(%q) = %q, want %q", "mitmuxd", got, want) + } +} + +func TestStringCommitOnly(t *testing.T) { + origV, origC, origD := Version, Commit, Date + Version, Commit, Date = "1.2.3", "abc1234", "" + defer func() { Version, Commit, Date = origV, origC, origD }() + want := "mitmux 1.2.3 (abc1234)" + if got := String("mitmux"); got != want { + t.Errorf("String(%q) = %q, want %q", "mitmux", got, want) + } +} |