summaryrefslogtreecommitdiffhomepage
path: root/brew
diff options
context:
space:
mode:
Diffstat (limited to 'brew')
-rw-r--r--brew/.gitignore1
-rw-r--r--brew/README.md96
-rwxr-xr-xbrew/dl-tarball-sha.sh10
-rwxr-xr-xbrew/generate-formula.sh109
-rwxr-xr-xbrew/generate-formulae.sh19
-rwxr-xr-xbrew/install-start-with-checks.sh102
-rwxr-xr-xbrew/make-test-source-tarball.sh17
-rwxr-xr-xbrew/search-interesting.sh6
-rwxr-xr-xbrew/serve-tarball.sh14
-rwxr-xr-xbrew/status.sh83
-rwxr-xr-xbrew/stop-uninstall-wipe.sh33
-rw-r--r--brew/tailscale.commit-pin.rb87
-rw-r--r--brew/tailscale.rb87
-rw-r--r--brew/tailscale.tb-github.rb86
-rw-r--r--brew/tailscale.tb-local.rb86
-rwxr-xr-xbrew/test.sh39
-rwxr-xr-xbrew/up.sh6
-rwxr-xr-xbrew/vars.sh23
18 files changed, 904 insertions, 0 deletions
diff --git a/brew/.gitignore b/brew/.gitignore
new file mode 100644
index 000000000..51b4cfda1
--- /dev/null
+++ b/brew/.gitignore
@@ -0,0 +1 @@
+local/
diff --git a/brew/README.md b/brew/README.md
new file mode 100644
index 000000000..9364255a4
--- /dev/null
+++ b/brew/README.md
@@ -0,0 +1,96 @@
+# Tailscale Mac Homebrew Maintainer Guide
+
+
+***********
+*** WIP ***
+***********
+
+
+Homebrew packaging of the non-IPNExtension, unsandboxed tailscale{d} releases for macOS/darwin.
+
+So the public can "brew install" tailscale and start it as a global boot daemon via brew services.
+
+
+## Platforms Supported
+
+These platform versions and permutations have been tested and are known to work well:
+
+| role | brew | golang | os | arch | repo |
+| ----------- | --------------------------- | --------------------- | ---------------------- | ------------------ | ---------- |
+| maintainer: | Homebrew 3.0.1-120-g5ca03ab | go1.15.8 darwin/amd64 | macOS Catalina 10.15.3 | Intel 64-bit | |
+| | | | macOS Big Sur 11.x (?) | Apple M1 ARM64 (?) | |
+| | | | | | |
+| | | | | | |
+| pkg target: | Homebrew 3.0.1-120-g5ca03ab | go1.15.8 darwin/amd64 | macOS Catalina 10.15.3 | Intel 64-bit | tailscale: |
+| | | | macOS Big Sur 11.x (?) | Apple M1 ARM64 (?) | 188bb14269 |
+| | | | | | HEAD |
+| | | | | | likely 1.5 |
+
+
+## Directory Contents
+
+| type | name | purpose |
+| ------------------ | ---------------------------- | -------------------------------------------------------------- |
+| formulae | tailscale.rb | The default packaging "formula" in Ruby, based on a |
+| | | a pinned commit from the tailscale/tailscale GitHub repo |
+| | | |
+| | tailscale.*.rb | Alternate formulae (mainly used for testing now, |
+| | | and includes some variants based on tagged release source |
+| | | tarballs, and local test standin candidates) |
+| | | |
+| maintainer scripts | vars.sh | role for brew like version/version.sh for build_dist.sh |
+| | generate-formulae.sh | regenerates all formulae (default, plus some alternates) |
+| | generate-formula.sh | generates formula from an embedded template, to stdout |
+| | make-test-source-tarball.sh | |
+| | serve-tarball.sh | |
+| | dl-tarball-sha.sh | |
+| | search-interesting.sh | nice to keep these on maintainer's radar |
+| | test.sh | tests all supported permutations |
+| | install-start-with-checks.sh | install test run for maintainer |
+| | up.sh | |
+| | status.sh | |
+| | stop-uninstall-wipe.sh | closing counterpart to the install*.sh script |
+| | | |
+| subdirs | brew/local/ | .gitignored tree created and used during brew maintenance work |
+
+
+## Use Cases
+
+For the ultimate endusers (ONLY ONCE READY & AVAIL)...
+
+```
+brew install tailscale
+sudo brew services start tailscale
+```
+
+TODO(mkramlich): add context, details, variants to the above
+
+For an early adopter who wants to try an unofficial sneak preview of a local brew install of the WIP formula:
+
+```
+git clone https://github.com/mkramlich/tailscale
+cd tailscale
+git switch mkramlich/macos-brew
+brew install --formula brew/tailscale.rb # default formula draws from a recent good commit from tailscale/tailscale
+sudo brew services start tailscale
+# tailscaled is now running and registered as a global boot daemon (via launchctl/launchd)
+brew/up.sh # then do your auth
+# tailscaled is now authorized and providing normal service to your VPN
+```
+
+For maintainers...
+
+All scripts assume you are in the cloned repo root, just above brew/
+ (EXCEPT make-test-source-tarball.sh, TODO)
+
+To edit the formula source, regen and retest:
+
+```
+# modify the template fragments inside generate-formula.sh
+# and/or the var values in brew/vars.sh or brew/generate-formulae.sh
+brew/generate-formulae.sh
+brew/serve-tarball.sh # ensure running in background; only needed for the local source tarball test in test.sh
+brew/test.sh # this is very WIP, but generally the goal is if it exits 0 then the tests are green
+```
+
+TODO(mkramlich): flesh out much further; topics: formula vs bottle, sudo vs not, prefix diffs, local vs public ts tap vs core, testing, submission and bumping
diff --git a/brew/dl-tarball-sha.sh b/brew/dl-tarball-sha.sh
new file mode 100755
index 000000000..cf0184007
--- /dev/null
+++ b/brew/dl-tarball-sha.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+set -eu
+
+eval $(brew/vars.sh)
+
+#URLBASE=https://github.com
+URLBASE=http://localhost
+TARBALL=v$TS_VER.tar.gz
+curl -OL $URLBASE/tailscale/tailscale/archive/$TARBALL
+shasum -a256 ./$TARBALL # TODO(mkramlich): not the proper point in lifecycle to calc this
diff --git a/brew/generate-formula.sh b/brew/generate-formula.sh
new file mode 100755
index 000000000..cd0dd0ea1
--- /dev/null
+++ b/brew/generate-formula.sh
@@ -0,0 +1,109 @@
+#!/usr/bin/env sh
+#set -u # TODO(mkramlich): recreate
+
+# TODO(mkramlich): in form where the url is a .git, the url can also have a tag arg, like: tag: "v1.5.0"
+
+cat <<TEMPLATE
+# typed: false
+# frozen_string_literal: true
+
+# Homebrew formula for Tailscale
+class Tailscale < Formula
+ desc "Easiest, secure, crossplatform WireGuard Go-based VPN w/oauth2, 2FA/SSO"
+ homepage "https://www.tailscale.com"
+TEMPLATE
+
+if [ "$FORMULA_TYPE" = "tarball" ]; then
+ cat <<TEMPLATE2
+ url "$URL"
+ sha256 "$SHA256"
+TEMPLATE2
+elif [ "$FORMULA_TYPE" = "commit" ]; then
+ cat <<TEMPLATE3
+ url "$URL",
+ revision: "$REVISION"
+ version "$VERSION" # TODO(mkramlich): WIP, so not necessarily; brew required a version
+TEMPLATE3
+else
+ exit 1
+fi
+
+cat <<TEMPLATE4
+ license "BSD-3-Clause"
+ head "$HEAD",
+ branch: "$BRANCH"
+
+ depends_on "go" => :build
+
+ def install
+ ENV["GOPATH"] = buildpath
+ tailscale_path = buildpath/"src/github.com/tailscale/tailscale"
+ tailscale_path.install buildpath.children
+ cd tailscale_path do
+ # TODO(mkramlich): refactor down the 'version.sh to ENV sets':
+ output = Utils.safe_popen_read("./version/version.sh")
+ lines = output.split("\n")
+ lines.each do |line|
+ parts = line.split("=")
+ key = parts.at(0)
+ val = parts.at(1)
+ system "echo adding to ENV for go builds: key #{key}, val #{val}"
+ ENV[key] = val
+ end
+ # TODO(mkramlich): make brew audit happy again
+ # TODO(mkramlich): lose the breaking quotes around the vals in the #{ENV["FOO"]} renders in the go builds
+ # go builds equiv to how done by tailscale repo's build_dist.sh:
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscale"
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscaled"
+ bin.install "tailscale"
+ bin.install "tailscaled"
+ end
+ end
+
+ def post_install
+ (var/"run/tailscale").mkpath
+ (var/"lib/tailscale").mkpath
+ end
+
+ plist_options manual: "sudo tailscaled --socket=#{HOMEBREW_PREFIX}/run/tailscale/tailscaled.sock --state=#{HOMEBREW_PREFIX}/lib/tailscale/tailscaled.state"
+
+ def plist
+ <<~EOS
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>KeepAlive</key>
+ <dict>
+ <key>SuccessfulExit</key>
+ <false/>
+ <key>NetworkState</key>
+ <true/>
+ </dict>
+ <key>Label</key>
+ <string>#{plist_name}</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>#{opt_bin}/tailscaled</string>
+ <string>--socket=#{var}/run/tailscale/tailscaled.sock</string>
+ <string>--state=#{var}/lib/tailscale/tailscaled.state</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>WorkingDirectory</key>
+ <string>#{var}/lib/tailscale</string>
+ <key>StandardErrorPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stderr.log</string>
+ <key>StandardOutPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stdout.log</string>
+ </dict>
+ </plist>
+ EOS
+ end
+
+ test do
+ system bin/"tailscale", "--version"
+ system bin/"tailscale", "netcheck"
+ end
+end
+TEMPLATE4
diff --git a/brew/generate-formulae.sh b/brew/generate-formulae.sh
new file mode 100755
index 000000000..a0244e806
--- /dev/null
+++ b/brew/generate-formulae.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env sh
+set -eu
+
+eval $(brew/vars.sh)
+
+GIT_URL=https://github.com/tailscale/tailscale.git
+BRANCH=main
+VERSION=$TS_VER # TODO(mkramlich): WIP. do this right
+
+# default formula (pinned against a commmit in the Tailscale GitHub repo)
+FORMULA_TYPE=commit URL=$GIT_URL BRANCH=$BRANCH REVISION=$TS_COMMIT_PIN HEAD=$GIT_URL BRANCH=$BRANCH VERSION=$VERSION brew/generate-formula.sh > brew/tailscale.commit-pin.rb
+
+# alt formula using local HTTP source tarball of a release standin/mock
+FORMULA_TYPE=tarball URL="http://localhost:$TS_TARBALL_PORT/tailscale/tailscale/archive/v1.5.0.tar.gz" SHA256="a62caf2eb5c84d2d1775cd8a17eeb0e8ad3b8dbc9453399862d908227e0af721" HEAD=$GIT_URL BRANCH=$BRANCH VERSION=$VERSION brew/generate-formula.sh > brew/tailscale.tb-local.rb
+
+# alt formula using Tailscale GitHub HTTPS source tarball of a release tag -- the LATEST tag
+FORMULA_TYPE=tarball URL="https://github.com/tailscale/tailscale/archive/v1.4.4.tar.gz" SHA256="5312c6d075a32049912e0932a89269869def9ac8ea9d0fdccc6b41db60fc2d4c" HEAD=$GIT_URL BRANCH=$BRANCH VERSION=$VERSION brew/generate-formula.sh > brew/tailscale.tb-github.rb
+
+cp brew/tailscale{.commit-pin,}.rb
diff --git a/brew/install-start-with-checks.sh b/brew/install-start-with-checks.sh
new file mode 100755
index 000000000..b9a4ed8ca
--- /dev/null
+++ b/brew/install-start-with-checks.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env sh
+set -eu
+
+eval $(brew/vars.sh)
+
+echo
+echo SUDO is $SUDO
+
+echo
+echo versions...
+brew --version
+brew config
+go version
+echo maintainer VERSION.txt: `cat VERSION.TXT`
+echo maintainer script version/version.sh exec:
+version/version.sh # we don't truly use this (yet?), just print here as helpful info for later analysis
+# TODO(mkramlich) make distinction clear between maintainer script source ver and target package vers
+
+echo
+echo brew doctor...
+set +e # to turn -e off (relax this only for time being)
+brew doctor # TODO(mkramlich): for brew maintainer, best if have no findings and exit 0
+set -e # to turn back on
+
+echo
+echo audit formula...
+# requires Internet access for some audit checks:
+set +e # TODO(mkramlich): tmp allow a nonclean formula audit until build_dist fixes/refactor done
+brew audit --strict --online --formula $TS_FORMULA # keep this run output blank and exit 0
+set -e
+
+echo
+echo installing...
+#brew install -v --build-from-source $TS_FORMULA
+brew install -v --formula $TS_FORMULA
+
+echo
+echo checking exe location and diffs...
+diff $TS_BIN/tailscale $TS_CELLAR/$TS_VER/bin/tailscale # TODO(mkramlich): FIXME in test case global,tb-github; want 1.5.0, got 1.4.4, SHOULD want 1.4.4 cuz 1.4.4 correct
+diff $TS_BIN/tailscaled $TS_CELLAR/$TS_VER/bin/tailscaled
+
+echo
+echo check if brew has formula...
+brew list tailscale
+
+echo
+echo check if installed formula matches orig...
+diff $TS_FORMULA $TS_CELLAR/$TS_VER/.$TS_FORMULA
+
+echo
+echo lint of the generated launchctl plist for homebrew tailscale...
+# should print "<filepath>: OK" and exit 0; brew services (or launchctl) below
+# might reject (or silently allow) any given !0 case so better to catch an issue
+# early/wider than not, and automate extra clues for maintainer
+plutil -lint $TS_CELLAR/$TS_VER/$TS_PLIST
+
+echo
+echo brew test before starting...
+brew test $TS_FORMULA
+
+echo
+echo starting...
+$SUDO brew services start tailscale
+
+echo
+echo pausing as tailscaled starts...
+sleep 8
+
+echo
+echo checking that our registered Global Daemons plist matches expected...
+diff $TS_CELLAR/$TS_VER/$TS_PLIST $INSTALLED_PLIST_DIR/$TS_PLIST
+
+echo
+echo brew service shows tailscale as started...
+$SUDO brew services list | grep tailscale
+
+echo
+echo launchctl lists tailscale...
+$SUDO launchctl list | grep tailscale
+
+echo
+echo tailscale version...
+$TS_BIN/tailscale --version # should be found, executable and exit 0
+
+echo
+echo tailscale netcheck...
+$TS_BIN/tailscale netcheck # should be found, executable and exit 0
+
+echo
+echo tailscale up \(and wait for human to do the auth dance if needed\)...
+brew/up.sh # this will block, displaying the auth url, if it needs to auth. then/or proceed once happy
+
+echo
+echo list all tailscale files installed or generated...
+$SUDO find $BREW | grep -i tailscale
+
+echo
+echo pausing to give tailscaled enough time to finish post-auth setup...
+sleep 15 # otherwise some of my early status pings sometimes fail (esp hello.ipn.dev; then work on all subsequent attempts)
+echo
+echo status...
+brew/status.sh
diff --git a/brew/make-test-source-tarball.sh b/brew/make-test-source-tarball.sh
new file mode 100755
index 000000000..abaa747ae
--- /dev/null
+++ b/brew/make-test-source-tarball.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env sh
+set -eu
+
+# does not create an official release source tarball per GitHub. creates a standin for it, for brew test purposes only
+
+eval $(tailscale/brew/vars.sh) # TODO(mkramlich): doc the path deviance or automate away
+
+TARBALL_ARCHIVE=tailscale/brew/local/tarball-serve-root/tailscale/tailscale/archive
+
+mkdir -p $TARBALL_ARCHIVE
+
+TARBALL=$TARBALL_ARCHIVE/v$TS_VER.tar.gz
+
+# assume a repo is cloned at that dir tree location, and its file state is what we want
+echo making $TARBALL
+tar -czf $TARBALL tailscale-$TS_VER/.gitignore tailscale-$TS_VER/.github/* tailscale-$TS_VER/.gitattributes tailscale-$TS_VER/*
+shasum -a256 ./$TARBALL
diff --git a/brew/search-interesting.sh b/brew/search-interesting.sh
new file mode 100755
index 000000000..4d5ab850d
--- /dev/null
+++ b/brew/search-interesting.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env sh
+
+brew search tailscale
+brew search wireguard
+brew search vpn
+brew search golang
diff --git a/brew/serve-tarball.sh b/brew/serve-tarball.sh
new file mode 100755
index 000000000..059d797ca
--- /dev/null
+++ b/brew/serve-tarball.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env sh
+set -eu
+
+# only for Tailscale brew maintainer, to local-only serve a source tarball standin, during brew testing
+
+eval $(brew/vars.sh)
+
+python3 -m http.server --directory brew/local/tarball-serve-root --bind localhost $TS_TARBALL_PORT
+
+# why the above? during one formula/release test brew may expect to fetch a tarball from (w/version varying):
+# http://localhost:$TS_TARBALL_PORT/tailscale/tailscale/archive/v$TS_VER.tar.gz
+# where $TS_VER is like 1.5.0
+# therefore under tarball-serve-root/ that file should be in:
+# tailscale/tailscale/archive/
diff --git a/brew/status.sh b/brew/status.sh
new file mode 100755
index 000000000..61b2724f0
--- /dev/null
+++ b/brew/status.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env sh
+set -u
+
+eval $(brew/vars.sh)
+
+# everything you see below is not expected to be rigorous, or decisive or even always relevant,
+# but gives useful data and a nice smoke test of a candidate install for the brew maintainer
+
+echo file checks \(exes, state, socket\)...
+ls -la $TS_BIN/tailscale*
+ls -l $TS_STATE
+ls -l $TS_SOCK
+
+echo
+$TS_BIN/tailscale version
+
+echo
+$TS_BIN/tailscale netcheck
+
+echo
+echo tailscale status:
+sudo $TS_BIN/tailscale -socket=$TS_SOCK status
+
+echo
+ifconfig -r en0
+
+# TODO(mkramlich): learn the utun<NUM> it picked and handle tun/gateway right everywhere below
+
+echo
+ifconfig -r utun5
+
+echo Routing\\n
+
+echo \(Destination Gateway Flags Netif Expire\):
+netstat -r -n -f inet | grep utun
+
+echo IPv4 routes:
+netstat -r -n -f inet -ll
+echo IPv4 route stats:
+netstat -r -n -f inet -s
+echo IPv6 routes:
+netstat -r -n -f inet6 -ll
+echo IPv6 route stats:
+netstat -r -n -f inet6 -s
+
+echo
+echo checking if host IP forwarding is enabled...
+sysctl -a | grep forward
+
+echo
+echo pinging the TS login/coord server...
+ping -c1 login.tailscale.com # only to help rule out other issues during a brew test
+
+echo
+echo pinging the TS log server...
+ping -c1 log.tailscale.io
+
+echo
+echo pinging the common hello node by name...
+ping -c1 hello.ipn.dev # a nice smoke test
+echo ... by tailscale ping DNS...
+sudo $TS_BIN/tailscale -socket=$TS_SOCK ping -c 1 hello.ipn.dev
+echo ... by ping IPv4...
+ping -c1 100.101.102.103
+echo ... by tailscale ping IPv4...
+sudo $TS_BIN/tailscale -socket=$TS_SOCK ping -c 1 100.101.102.103
+echo ... by ping6 IPv6...
+ping6 -c1 fd7a:115c:a1e0:ab12:4843:cd96:6265:6667 # TODO(mkramlich): do right or drop
+
+# TODO(mkramlich): below is personal node Ts addr, so either drop or make overridable by maintainer
+echo
+echo pinging my android node...
+ping -c1 100.119.147.125
+sudo $TS_BIN/tailscale -socket=$TS_SOCK ping -c 1 100.119.147.125
+ping6 -c1 fd7a:115c:a1e0:ab12:4843:cd96:6277:937d
+
+echo
+echo check stderr log for any recent error, warn, fail, missing or weird...
+# NOTE we dont do a 'set -e' style fail assert on this error log tail here because this is for human consumption,
+# plus, not quite sure/ready about what specifc messages are scary enough to potentially fail a test
+#sudo grep -i -e error -e warn -e fail -e missing -e weird $TS_LOG_DIR/tailscaled-stderr.log
+sudo tail -100 $TS_LOG_DIR/tailscaled-stderr.log | grep -i -e error -e warn -e fail -e missing -e weird
+
diff --git a/brew/stop-uninstall-wipe.sh b/brew/stop-uninstall-wipe.sh
new file mode 100755
index 000000000..132b9ce0a
--- /dev/null
+++ b/brew/stop-uninstall-wipe.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env sh
+set -u # also -e?
+
+eval $(brew/vars.sh)
+
+echo
+echo SUDO is $SUDO
+
+echo
+echo stopping...
+$SUDO brew services stop tailscale
+$SUDO brew services list | grep tailscale
+ps -ef | grep tailscaled | grep -v "grep tailscaled" # TODO(mkramlich): do better
+# TODO(mkramlich): the installed plist is gone?
+
+echo
+echo uninstalling...
+brew uninstall --force tailscale
+$SUDO brew services list | grep tailscale
+
+echo
+echo deleting...
+$SUDO rm -rf $TS_CELLAR/$TS_VER
+$SUDO rm -f $BREW/var/lib/tailscale/*
+$SUDO rm -f $TS_LOG_DIR/*
+rmdir $BREW/var/lib/tailscale
+rmdir $TS_LOG_DIR
+rmdir $BREW/var/run/tailscale
+rm $BREW/opt/tailscale # was symlink to $TS_CELLAR/$TS_VER
+rmdir $TS_CELLAR
+find $BREW | grep -i tailscale
+find /opt | grep -i tailscale
+# TODO(mkramlich): wipeout brew git checkout cache and/or add test for with-vs-without
diff --git a/brew/tailscale.commit-pin.rb b/brew/tailscale.commit-pin.rb
new file mode 100644
index 000000000..c7e6e7eb4
--- /dev/null
+++ b/brew/tailscale.commit-pin.rb
@@ -0,0 +1,87 @@
+# typed: false
+# frozen_string_literal: true
+
+# Homebrew formula for Tailscale
+class Tailscale < Formula
+ desc "Easiest, secure, crossplatform WireGuard Go-based VPN w/oauth2, 2FA/SSO"
+ homepage "https://www.tailscale.com"
+ url "https://github.com/tailscale/tailscale.git",
+ revision: "188bb142691c8b97673a9cb2aebd9f1521e9bb12"
+ version "1.5.0" # TODO(mkramlich): WIP, so not necessarily; brew required a version
+ license "BSD-3-Clause"
+ head "https://github.com/tailscale/tailscale.git",
+ branch: "main"
+
+ depends_on "go" => :build
+
+ def install
+ ENV["GOPATH"] = buildpath
+ tailscale_path = buildpath/"src/github.com/tailscale/tailscale"
+ tailscale_path.install buildpath.children
+ cd tailscale_path do
+ # TODO(mkramlich): refactor down the 'version.sh to ENV sets':
+ output = Utils.safe_popen_read("./version/version.sh")
+ lines = output.split("\n")
+ lines.each do |line|
+ parts = line.split("=")
+ key = parts.at(0)
+ val = parts.at(1)
+ system "echo adding to ENV for go builds: key #{key}, val #{val}"
+ ENV[key] = val
+ end
+ # TODO(mkramlich): make brew audit happy again
+ # TODO(mkramlich): lose the breaking quotes around the vals in the #{ENV["FOO"]} renders in the go builds
+ # go builds equiv to how done by tailscale repo's build_dist.sh:
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscale"
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscaled"
+ bin.install "tailscale"
+ bin.install "tailscaled"
+ end
+ end
+
+ def post_install
+ (var/"run/tailscale").mkpath
+ (var/"lib/tailscale").mkpath
+ end
+
+ plist_options manual: "sudo tailscaled --socket=#{HOMEBREW_PREFIX}/run/tailscale/tailscaled.sock --state=#{HOMEBREW_PREFIX}/lib/tailscale/tailscaled.state"
+
+ def plist
+ <<~EOS
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>KeepAlive</key>
+ <dict>
+ <key>SuccessfulExit</key>
+ <false/>
+ <key>NetworkState</key>
+ <true/>
+ </dict>
+ <key>Label</key>
+ <string>#{plist_name}</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>#{opt_bin}/tailscaled</string>
+ <string>--socket=#{var}/run/tailscale/tailscaled.sock</string>
+ <string>--state=#{var}/lib/tailscale/tailscaled.state</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>WorkingDirectory</key>
+ <string>#{var}/lib/tailscale</string>
+ <key>StandardErrorPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stderr.log</string>
+ <key>StandardOutPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stdout.log</string>
+ </dict>
+ </plist>
+ EOS
+ end
+
+ test do
+ system bin/"tailscale", "--version"
+ system bin/"tailscale", "netcheck"
+ end
+end
diff --git a/brew/tailscale.rb b/brew/tailscale.rb
new file mode 100644
index 000000000..c7e6e7eb4
--- /dev/null
+++ b/brew/tailscale.rb
@@ -0,0 +1,87 @@
+# typed: false
+# frozen_string_literal: true
+
+# Homebrew formula for Tailscale
+class Tailscale < Formula
+ desc "Easiest, secure, crossplatform WireGuard Go-based VPN w/oauth2, 2FA/SSO"
+ homepage "https://www.tailscale.com"
+ url "https://github.com/tailscale/tailscale.git",
+ revision: "188bb142691c8b97673a9cb2aebd9f1521e9bb12"
+ version "1.5.0" # TODO(mkramlich): WIP, so not necessarily; brew required a version
+ license "BSD-3-Clause"
+ head "https://github.com/tailscale/tailscale.git",
+ branch: "main"
+
+ depends_on "go" => :build
+
+ def install
+ ENV["GOPATH"] = buildpath
+ tailscale_path = buildpath/"src/github.com/tailscale/tailscale"
+ tailscale_path.install buildpath.children
+ cd tailscale_path do
+ # TODO(mkramlich): refactor down the 'version.sh to ENV sets':
+ output = Utils.safe_popen_read("./version/version.sh")
+ lines = output.split("\n")
+ lines.each do |line|
+ parts = line.split("=")
+ key = parts.at(0)
+ val = parts.at(1)
+ system "echo adding to ENV for go builds: key #{key}, val #{val}"
+ ENV[key] = val
+ end
+ # TODO(mkramlich): make brew audit happy again
+ # TODO(mkramlich): lose the breaking quotes around the vals in the #{ENV["FOO"]} renders in the go builds
+ # go builds equiv to how done by tailscale repo's build_dist.sh:
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscale"
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscaled"
+ bin.install "tailscale"
+ bin.install "tailscaled"
+ end
+ end
+
+ def post_install
+ (var/"run/tailscale").mkpath
+ (var/"lib/tailscale").mkpath
+ end
+
+ plist_options manual: "sudo tailscaled --socket=#{HOMEBREW_PREFIX}/run/tailscale/tailscaled.sock --state=#{HOMEBREW_PREFIX}/lib/tailscale/tailscaled.state"
+
+ def plist
+ <<~EOS
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>KeepAlive</key>
+ <dict>
+ <key>SuccessfulExit</key>
+ <false/>
+ <key>NetworkState</key>
+ <true/>
+ </dict>
+ <key>Label</key>
+ <string>#{plist_name}</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>#{opt_bin}/tailscaled</string>
+ <string>--socket=#{var}/run/tailscale/tailscaled.sock</string>
+ <string>--state=#{var}/lib/tailscale/tailscaled.state</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>WorkingDirectory</key>
+ <string>#{var}/lib/tailscale</string>
+ <key>StandardErrorPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stderr.log</string>
+ <key>StandardOutPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stdout.log</string>
+ </dict>
+ </plist>
+ EOS
+ end
+
+ test do
+ system bin/"tailscale", "--version"
+ system bin/"tailscale", "netcheck"
+ end
+end
diff --git a/brew/tailscale.tb-github.rb b/brew/tailscale.tb-github.rb
new file mode 100644
index 000000000..33b420885
--- /dev/null
+++ b/brew/tailscale.tb-github.rb
@@ -0,0 +1,86 @@
+# typed: false
+# frozen_string_literal: true
+
+# Homebrew formula for Tailscale
+class Tailscale < Formula
+ desc "Easiest, secure, crossplatform WireGuard Go-based VPN w/oauth2, 2FA/SSO"
+ homepage "https://www.tailscale.com"
+ url "https://github.com/tailscale/tailscale/archive/v1.4.4.tar.gz"
+ sha256 "5312c6d075a32049912e0932a89269869def9ac8ea9d0fdccc6b41db60fc2d4c"
+ license "BSD-3-Clause"
+ head "https://github.com/tailscale/tailscale.git",
+ branch: "main"
+
+ depends_on "go" => :build
+
+ def install
+ ENV["GOPATH"] = buildpath
+ tailscale_path = buildpath/"src/github.com/tailscale/tailscale"
+ tailscale_path.install buildpath.children
+ cd tailscale_path do
+ # TODO(mkramlich): refactor down the 'version.sh to ENV sets':
+ output = Utils.safe_popen_read("./version/version.sh")
+ lines = output.split("\n")
+ lines.each do |line|
+ parts = line.split("=")
+ key = parts.at(0)
+ val = parts.at(1)
+ system "echo adding to ENV for go builds: key #{key}, val #{val}"
+ ENV[key] = val
+ end
+ # TODO(mkramlich): make brew audit happy again
+ # TODO(mkramlich): lose the breaking quotes around the vals in the #{ENV["FOO"]} renders in the go builds
+ # go builds equiv to how done by tailscale repo's build_dist.sh:
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscale"
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscaled"
+ bin.install "tailscale"
+ bin.install "tailscaled"
+ end
+ end
+
+ def post_install
+ (var/"run/tailscale").mkpath
+ (var/"lib/tailscale").mkpath
+ end
+
+ plist_options manual: "sudo tailscaled --socket=#{HOMEBREW_PREFIX}/run/tailscale/tailscaled.sock --state=#{HOMEBREW_PREFIX}/lib/tailscale/tailscaled.state"
+
+ def plist
+ <<~EOS
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>KeepAlive</key>
+ <dict>
+ <key>SuccessfulExit</key>
+ <false/>
+ <key>NetworkState</key>
+ <true/>
+ </dict>
+ <key>Label</key>
+ <string>#{plist_name}</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>#{opt_bin}/tailscaled</string>
+ <string>--socket=#{var}/run/tailscale/tailscaled.sock</string>
+ <string>--state=#{var}/lib/tailscale/tailscaled.state</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>WorkingDirectory</key>
+ <string>#{var}/lib/tailscale</string>
+ <key>StandardErrorPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stderr.log</string>
+ <key>StandardOutPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stdout.log</string>
+ </dict>
+ </plist>
+ EOS
+ end
+
+ test do
+ system bin/"tailscale", "--version"
+ system bin/"tailscale", "netcheck"
+ end
+end
diff --git a/brew/tailscale.tb-local.rb b/brew/tailscale.tb-local.rb
new file mode 100644
index 000000000..6c0c2d540
--- /dev/null
+++ b/brew/tailscale.tb-local.rb
@@ -0,0 +1,86 @@
+# typed: false
+# frozen_string_literal: true
+
+# Homebrew formula for Tailscale
+class Tailscale < Formula
+ desc "Easiest, secure, crossplatform WireGuard Go-based VPN w/oauth2, 2FA/SSO"
+ homepage "https://www.tailscale.com"
+ url "http://localhost:8901/tailscale/tailscale/archive/v1.5.0.tar.gz"
+ sha256 "a62caf2eb5c84d2d1775cd8a17eeb0e8ad3b8dbc9453399862d908227e0af721"
+ license "BSD-3-Clause"
+ head "https://github.com/tailscale/tailscale.git",
+ branch: "main"
+
+ depends_on "go" => :build
+
+ def install
+ ENV["GOPATH"] = buildpath
+ tailscale_path = buildpath/"src/github.com/tailscale/tailscale"
+ tailscale_path.install buildpath.children
+ cd tailscale_path do
+ # TODO(mkramlich): refactor down the 'version.sh to ENV sets':
+ output = Utils.safe_popen_read("./version/version.sh")
+ lines = output.split("\n")
+ lines.each do |line|
+ parts = line.split("=")
+ key = parts.at(0)
+ val = parts.at(1)
+ system "echo adding to ENV for go builds: key #{key}, val #{val}"
+ ENV[key] = val
+ end
+ # TODO(mkramlich): make brew audit happy again
+ # TODO(mkramlich): lose the breaking quotes around the vals in the #{ENV["FOO"]} renders in the go builds
+ # go builds equiv to how done by tailscale repo's build_dist.sh:
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscale"
+ system "go", "build", "-o", ".", "-tags", "xversion", "-ldflags", "\"-X tailscale.com/version.Long=#{ENV["VERSION_LONG"]} -X tailscale.com/version.Short=#{ENV["VERSION_SHORT"]} -X tailscale.com/version.GitCommit=#{ENV["VERSION_GIT_HASH"]}\"", "tailscale.com/cmd/tailscaled"
+ bin.install "tailscale"
+ bin.install "tailscaled"
+ end
+ end
+
+ def post_install
+ (var/"run/tailscale").mkpath
+ (var/"lib/tailscale").mkpath
+ end
+
+ plist_options manual: "sudo tailscaled --socket=#{HOMEBREW_PREFIX}/run/tailscale/tailscaled.sock --state=#{HOMEBREW_PREFIX}/lib/tailscale/tailscaled.state"
+
+ def plist
+ <<~EOS
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>KeepAlive</key>
+ <dict>
+ <key>SuccessfulExit</key>
+ <false/>
+ <key>NetworkState</key>
+ <true/>
+ </dict>
+ <key>Label</key>
+ <string>#{plist_name}</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>#{opt_bin}/tailscaled</string>
+ <string>--socket=#{var}/run/tailscale/tailscaled.sock</string>
+ <string>--state=#{var}/lib/tailscale/tailscaled.state</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>WorkingDirectory</key>
+ <string>#{var}/lib/tailscale</string>
+ <key>StandardErrorPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stderr.log</string>
+ <key>StandardOutPath</key>
+ <string>#{var}/log/tailscale/tailscaled-stdout.log</string>
+ </dict>
+ </plist>
+ EOS
+ end
+
+ test do
+ system bin/"tailscale", "--version"
+ system bin/"tailscale", "netcheck"
+ end
+end
diff --git a/brew/test.sh b/brew/test.sh
new file mode 100755
index 000000000..b4f72e6d4
--- /dev/null
+++ b/brew/test.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env sh
+set -eu
+
+# TODO(mkramlich):
+# dl-tarball-sha.sh
+# make-test-source-tarball.sh
+
+
+echo test variant: global, tb-local
+#TODO(mkramlich): for the tb-local tests, server-tarball.sh should be running, with tarball in place
+cp brew/tailscale{.tb-local,}.rb
+# brew services (via launchd) start as a global boot daemon (in /Library/LaunchDaemons), running as root
+# TODO(mkramlich): confirm at reboot starts & works
+SUDO="sudo" INSTALLED_PLIST_DIR=/Library/LaunchDaemons brew/install-start-with-checks.sh
+SUDO="sudo" INSTALLED_PLIST_DIR=/Library/LaunchDaemons brew/stop-uninstall-wipe.sh
+
+
+echo test variant: global, tb-github
+cp brew/tailscale{.tb-github,}.rb
+# brew services (via launchd) start as a global boot daemon (in /Library/LaunchDaemons), running as root
+# TODO(mkramlich): confirm at reboot starts & works
+SUDO="sudo" INSTALLED_PLIST_DIR=/Library/LaunchDaemons brew/install-start-with-checks.sh
+SUDO="sudo" INSTALLED_PLIST_DIR=/Library/LaunchDaemons brew/stop-uninstall-wipe.sh
+
+
+echo test variant: global, commit-pin
+cp brew/tailscale{.commit-pin,}.rb
+# brew services (via launchd) start as a global boot daemon (in /Library/LaunchDaemons), running as root
+# TODO(mkramlich): confirm at reboot starts & works
+SUDO="sudo" INSTALLED_PLIST_DIR=/Library/LaunchDaemons brew/install-start-with-checks.sh
+SUDO="sudo" INSTALLED_PLIST_DIR=/Library/LaunchDaemons brew/stop-uninstall-wipe.sh
+
+
+#####################################
+
+# brew services (via launchd) start as a user login agent (in ~/Library/LaunchAgents), BUT runs as sudo
+# TODO(mkramlich): just a WIP POC, much lower priority than boot perm, might drop
+#SUDO="" INSTALLED_PLIST_DIR=~/Library/LaunchAgents brew/install-start-with-checks.sh
+#SUDO="" INSTALLED_PLIST_DIR=~/Library/LaunchAgents brew/stop-uninstall-wipe.sh
diff --git a/brew/up.sh b/brew/up.sh
new file mode 100755
index 000000000..efff5a661
--- /dev/null
+++ b/brew/up.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env sh
+set -eu
+
+eval $(brew/vars.sh)
+
+sudo $TS_BIN/tailscale -socket=$TS_SOCK up
diff --git a/brew/vars.sh b/brew/vars.sh
new file mode 100755
index 000000000..5234c44e6
--- /dev/null
+++ b/brew/vars.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env sh
+set -eu
+
+# TODO(mkramlich): elim redundancy with or otherwise maybe take advantage of version/version.sh
+
+BREW=`brew --prefix` # because varies; /usr/local on Intel, /opt/homebrew on ARM64/M1/AppleSilicon
+
+# TODO(mkramlich): Cellar
+
+cat <<EOF
+TS_VER=1.5.0
+TS_COMMIT_PIN=188bb142691c8b97673a9cb2aebd9f1521e9bb12
+TS_BIN=$BREW/bin
+TS_SOCK=$BREW/var/run/tailscale/tailscaled.sock
+TS_STATE=$BREW/var/lib/tailscale/tailscaled.state
+TS_LOG_DIR=$BREW/var/log/tailscale
+TS_CELLAR=$BREW/Cellar/tailscale
+TS_PLIST=homebrew.mxcl.tailscale.plist
+TS_TARBALL_PORT=8901
+TS_FORMULA=brew/tailscale.rb
+BREW=$BREW
+INSTALLED_PLIST_DIR=/Library/LaunchDaemons
+EOF