diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b80ee59..4051561 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,16 +48,3 @@ jobs: GOARCH: ${{ matrix.goarch }} CGO_ENABLED: "0" run: go build ./... - - lint: - name: golangci-lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: "1.25" - cache: true - - uses: golangci/golangci-lint-action@v6 - with: - version: latest diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index dc65243..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,33 +0,0 @@ -# golangci-lint configuration for aitori. -# Conservative, widely-accepted linters suitable for an open-source codebase. - -run: - timeout: 5m - # The project targets Go 1.25, but golangci-lint-action's prebuilt binary is - # built with go1.24 and refuses to analyze a module targeting a newer Go. Pin - # the analysis target to 1.24 to keep lint green. Drop this once the action - # ships a go1.25-built golangci-lint. - go: "1.24" - -linters: - enable: - - govet - - ineffassign - - staticcheck - - unused - - errcheck - - misspell - - revive - - gofmt - - goimports - -linters-settings: - goimports: - local-prefixes: github.com/truefoundry/aitori - -issues: - exclude-rules: - # Best-effort cleanup paths and stream copies intentionally ignore errors. - - path: _test\.go - linters: - - errcheck diff --git a/README.md b/README.md index a6114d2..e01629e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,10 @@ Install the binary (macOS/Linux): curl -fsSL https://raw.githubusercontent.com/truefoundry/aitori/main/install.sh | sh ``` +To remove aitori later, see [Uninstall](docs/getting-started.md#1-install) (revert +system changes with `sudo aitori down` and `sudo aitori ca remove` before deleting +the binaries). + Then govern this machine and watch the traffic live — no gateway, no config: ```bash diff --git a/docs/getting-started.md b/docs/getting-started.md index 54d2588..006407b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -13,8 +13,12 @@ curl -fsSL https://raw.githubusercontent.com/truefoundry/aitori/main/install.sh ``` This downloads the release tarball for your OS/arch, verifies its checksum, and -installs `aitori` and `aitori-gateway` to `/usr/local/bin`. Set -`AITORI_INSTALL_DIR` to install elsewhere, or `VERSION=vX.Y.Z` to pin a release. +installs `aitori` and `aitori-gateway`. The install location is `~/.local/bin` +when it's already on your `PATH` (a no-sudo install); otherwise `/usr/local/bin` +(always on `PATH`, but root-owned, so you'll be prompted for `sudo`). Set +`AITORI_INSTALL_DIR` to force a location, or `VERSION=vX.Y.Z` to pin a release. +The installer prints the exact paths it wrote and the uninstall steps when it +finishes. > **macOS note:** binaries are unsigned. A `curl`-downloaded binary runs as-is. > If you instead download the tarball in a browser, clear Gatekeeper quarantine @@ -23,6 +27,33 @@ installs `aitori` and `aitori-gateway` to `/usr/local/bin`. Set Windows isn't covered by the installer — grab the tarball from the [Releases page](https://github.com/truefoundry/aitori/releases). +
+Uninstall + +aitori changes system state beyond the binaries (a per-device CA in the trust +store, the system proxy, and edits to client configs like Claude Code's +`settings.json`). **Revert that first, while the binary still exists** — `down` +and `ca remove` *are* the uninstall logic, so deleting the binary first strands +those changes. + +```bash +sudo aitori down # revert the system proxy + undo client-config edits +sudo aitori ca remove # remove the per-device CA from the system trust store + +# then delete the binaries (use the path the installer printed): +rm -f /usr/local/bin/aitori /usr/local/bin/aitori-gateway # or ~/.local/bin/... + +# optional: drop the local state (CA private key, gateway token, trace DBs): +rm -rf ~/.aitori +``` + +There is no `aitori uninstall` command — the steps above are the supported path. +Upgrading, by contrast, needs none of this: just re-run the install command (it +overwrites the binaries in place); the CA is reused, so it doesn't need +reinstalling. + +
+ ## 2. See your traffic (no gateway needed) ```bash diff --git a/install.sh b/install.sh index b080f80..79c3524 100755 --- a/install.sh +++ b/install.sh @@ -14,7 +14,8 @@ # # Overrides (env vars): # VERSION install a specific tag (e.g. v0.1.0); default: latest -# AITORI_INSTALL_DIR install location; default: /usr/local/bin +# AITORI_INSTALL_DIR install location; default: ~/.local/bin if it's already +# on your PATH (no sudo), else /usr/local/bin # AITORI_REPO owner/repo; default: truefoundry/aitori # # NOTE: requires a *published* (non-draft) GitHub release. To test against a @@ -23,7 +24,19 @@ set -eu REPO="${AITORI_REPO:-truefoundry/aitori}" -INSTALL_DIR="${AITORI_INSTALL_DIR:-/usr/local/bin}" + +# Default install dir: prefer ~/.local/bin when it's already on PATH (a no-sudo +# install that's immediately findable); otherwise fall back to /usr/local/bin +# (always on PATH on macOS, but root-owned, so it needs sudo). An explicit +# AITORI_INSTALL_DIR always wins. +if [ -n "${AITORI_INSTALL_DIR:-}" ]; then + INSTALL_DIR="$AITORI_INSTALL_DIR" +else + INSTALL_DIR="/usr/local/bin" + case ":$PATH:" in + *":$HOME/.local/bin:"*) INSTALL_DIR="$HOME/.local/bin" ;; + esac +fi info() { printf 'aitori: %s\n' "$1" >&2; } fail() { printf 'aitori: error: %s\n' "$1" >&2; exit 1; } @@ -112,11 +125,23 @@ if [ -z "$sudo" ] && [ ! -w "$INSTALL_DIR" ] && [ "$(id -u)" != "0" ]; then fi fi -$sudo mkdir -p "$INSTALL_DIR" -$sudo mv -f "$tmp/aitori" "$INSTALL_DIR/aitori" -[ -f "$tmp/aitori-gateway" ] && $sudo mv -f "$tmp/aitori-gateway" "$INSTALL_DIR/aitori-gateway" +# Do the mkdir + both moves in a single elevated shell, so sudo prompts at most +# once (some hosts disable sudo's credential cache, which would otherwise prompt +# for every separate sudo call). `set -e` inside makes any step abort the +# subshell with a non-zero status; the outer `set -e` then aborts the install — +# so a failed mkdir/mv can't be masked as success. The gateway move is wrapped +# so a legitimately-absent gateway binary isn't itself treated as a failure. +$sudo sh -e -c ' + mkdir -p "$1" + mv -f "$2/aitori" "$1/aitori" + if [ -f "$2/aitori-gateway" ]; then + mv -f "$2/aitori-gateway" "$1/aitori-gateway" + fi +' sh "$INSTALL_DIR" "$tmp" || fail "failed to install binaries to $INSTALL_DIR" -info "installed aitori $tag to $INSTALL_DIR" +info "installed aitori $tag to:" +info " $INSTALL_DIR/aitori" +info " $INSTALL_DIR/aitori-gateway" case ":$PATH:" in *":$INSTALL_DIR:"*) ;; *) info "note: $INSTALL_DIR is not on your PATH — add it (e.g. export PATH=\"$INSTALL_DIR:\$PATH\")" ;; @@ -128,5 +153,11 @@ Next: sudo aitori up --ui # govern this machine (built-in profiles) + live UI open http://127.0.0.1:9100 # watch traffic flow through +To uninstall (revert system changes BEFORE deleting the binaries): + sudo aitori down # revert system proxy + client-config edits + sudo aitori ca remove # remove the per-device CA from the trust store + rm -f $INSTALL_DIR/aitori $INSTALL_DIR/aitori-gateway + rm -rf ~/.aitori # optional: CA key, token, local state + Docs: https://github.com/$REPO EOF