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.

supported: Homebrew 3.0, go1.15 darwin/amd64, macOS Catalina 10.15.3, Intel 64-bit
probably also but unconfirmed: BigSur 11 and Apple M1 ARM64

NOTE: lots of upgrades and polish since 1st squashed WIP PR, and applies most prior feedback

Part of #177. (WIP)

Signed-off-by: Mike Kramlich <groglogic@gmail.com>
This commit is contained in:
Mike Kramlich 2020-12-06 18:54:18 -07:00
parent e9e4f1063d
commit d2eeba5adb
19 changed files with 905 additions and 1 deletions

1
brew/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
local/

96
brew/README.md Normal file
View File

@ -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

10
brew/dl-tarball-sha.sh Executable file
View File

@ -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

109
brew/generate-formula.sh Executable file
View File

@ -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

19
brew/generate-formulae.sh Executable file
View File

@ -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

102
brew/install-start-with-checks.sh Executable file
View File

@ -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

View File

@ -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

6
brew/search-interesting.sh Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env sh
brew search tailscale
brew search wireguard
brew search vpn
brew search golang

14
brew/serve-tarball.sh Executable file
View File

@ -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/

83
brew/status.sh Executable file
View File

@ -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

33
brew/stop-uninstall-wipe.sh Executable file
View File

@ -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

View File

@ -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

87
brew/tailscale.rb Normal file
View File

@ -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

View File

@ -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

View File

@ -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

39
brew/test.sh Executable file
View File

@ -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

6
brew/up.sh Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env sh
set -eu
eval $(brew/vars.sh)
sudo $TS_BIN/tailscale -socket=$TS_SOCK up

23
brew/vars.sh Executable file
View File

@ -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

View File

@ -187,7 +187,7 @@ func packageType() string {
}
case "darwin":
// Using tailscaled or IPNExtension?
exe, _ := os.Executable()
exe, _ := os.Executable() // TODO(mkramlich): for tailscaled, distinguish if brew
return filepath.Base(exe)
}
return ""