mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-30 15:53:45 +00:00

Cleanup nix support, make flake easier to read with nix-systems. This also harmonizes with golinks flake setup and reduces an input dependency by 1. Update deps test to ensure the vendor hash stays harmonized with go.mod. Update make tidy to ensure vendor hash stays current. Updates #16637 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
917 lines
33 KiB
YAML
917 lines
33 KiB
YAML
# This is our main "CI tests" workflow. It runs everything that should run on
|
|
# both PRs and merged commits, and for the latter reports failures to slack.
|
|
name: CI
|
|
|
|
env:
|
|
# Our fuzz job, powered by OSS-Fuzz, fails periodically because we upgrade to
|
|
# new Go versions very eagerly. OSS-Fuzz is a little more conservative, and
|
|
# ends up being unable to compile our code.
|
|
#
|
|
# When this happens, we want to disable the fuzz target until OSS-Fuzz catches
|
|
# up. However, we also don't want to forget to turn it back on when OSS-Fuzz
|
|
# can once again build our code.
|
|
#
|
|
# This variable toggles the fuzz job between two modes:
|
|
# - false: we expect fuzzing to be happy, and should report failure if it's not.
|
|
# - true: we expect fuzzing is broken, and should report failure if it start working.
|
|
TS_FUZZ_CURRENTLY_BROKEN: false
|
|
# GOMODCACHE is the same definition on all OSes. Within the workspace, we use
|
|
# toplevel directories "src" (for the checked out source code), and "gomodcache"
|
|
# and other caches as siblings to follow.
|
|
GOMODCACHE: ${{ github.workspace }}/gomodcache
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- "main"
|
|
- "release-branch/*"
|
|
pull_request:
|
|
# all PRs on all branches
|
|
merge_group:
|
|
branches:
|
|
- "main"
|
|
|
|
concurrency:
|
|
# For PRs, later CI runs preempt previous ones. e.g. a force push on a PR
|
|
# cancels running CI jobs and starts all new ones.
|
|
#
|
|
# For non-PR pushes, concurrency.group needs to be unique for every distinct
|
|
# CI run we want to have happen. Use run_id, which in practice means all
|
|
# non-PR CI runs will be allowed to run without preempting each other.
|
|
group: ${{ github.workflow }}-$${{ github.pull_request.number || github.run_id }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
gomod-cache:
|
|
runs-on: ubuntu-24.04
|
|
outputs:
|
|
cache-key: ${{ steps.hash.outputs.key }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Compute cache key from go.{mod,sum}
|
|
id: hash
|
|
run: echo "key=gomod-cross3-${{ hashFiles('src/go.mod', 'src/go.sum') }}" >> $GITHUB_OUTPUT
|
|
# See if the cache entry already exists to avoid downloading it
|
|
# and doing the cache write again.
|
|
- id: check-cache
|
|
uses: actions/cache/restore@v4
|
|
with:
|
|
path: gomodcache # relative to workspace; see env note at top of file
|
|
key: ${{ steps.hash.outputs.key }}
|
|
lookup-only: true
|
|
enableCrossOsArchive: true
|
|
- name: Download modules
|
|
if: steps.check-cache.outputs.cache-hit != 'true'
|
|
working-directory: src
|
|
run: go mod download
|
|
- name: Cache Go modules
|
|
if: steps.check-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache # relative to workspace; see env note at top of file
|
|
key: ${{ steps.hash.outputs.key }}
|
|
enableCrossOsArchive: true
|
|
|
|
race-root-integration:
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
strategy:
|
|
fail-fast: false # don't abort the entire matrix if one element fails
|
|
matrix:
|
|
include:
|
|
- shard: '1/4'
|
|
- shard: '2/4'
|
|
- shard: '3/4'
|
|
- shard: '4/4'
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: build test wrapper
|
|
working-directory: src
|
|
run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper
|
|
- name: integration tests as root
|
|
working-directory: src
|
|
run: PATH=$PWD/tool:$PATH /tmp/testwrapper -exec "sudo -E" -race ./tstest/integration/
|
|
env:
|
|
TS_TEST_SHARD: ${{ matrix.shard }}
|
|
|
|
test:
|
|
strategy:
|
|
fail-fast: false # don't abort the entire matrix if one element fails
|
|
matrix:
|
|
include:
|
|
- goarch: amd64
|
|
- goarch: amd64
|
|
buildflags: "-race"
|
|
shard: '1/3'
|
|
- goarch: amd64
|
|
buildflags: "-race"
|
|
shard: '2/3'
|
|
- goarch: amd64
|
|
buildflags: "-race"
|
|
shard: '3/3'
|
|
- goarch: "386" # thanks yaml
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: Restore Cache
|
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
# Note: unlike the other setups, this is only grabbing the mod download
|
|
# cache, rather than the whole mod directory, as the download cache
|
|
# contains zips that can be unpacked in parallel faster than they can be
|
|
# fetched and extracted by tar
|
|
path: |
|
|
~/.cache/go-build
|
|
~\AppData\Local\go-build
|
|
# The -2- here should be incremented when the scheme of data to be
|
|
# cached changes (e.g. path above changes).
|
|
key: ${{ github.job }}-${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-2-${{ hashFiles('**/go.sum') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
${{ github.job }}-${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-2-${{ hashFiles('**/go.sum') }}
|
|
${{ github.job }}-${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-2-
|
|
- name: build all
|
|
if: matrix.buildflags == '' # skip on race builder
|
|
working-directory: src
|
|
run: ./tool/go build ${{matrix.buildflags}} ./...
|
|
env:
|
|
GOARCH: ${{ matrix.goarch }}
|
|
- name: build variant CLIs
|
|
if: matrix.buildflags == '' # skip on race builder
|
|
working-directory: src
|
|
run: |
|
|
./build_dist.sh --extra-small ./cmd/tailscaled
|
|
./build_dist.sh --box ./cmd/tailscaled
|
|
./build_dist.sh --extra-small --box ./cmd/tailscaled
|
|
rm -f tailscaled
|
|
env:
|
|
GOARCH: ${{ matrix.goarch }}
|
|
- name: get qemu # for tstest/archtest
|
|
if: matrix.goarch == 'amd64' && matrix.buildflags == ''
|
|
run: |
|
|
sudo apt-get -y update
|
|
sudo apt-get -y install qemu-user
|
|
- name: build test wrapper
|
|
working-directory: src
|
|
run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper
|
|
- name: test all
|
|
working-directory: src
|
|
run: NOBASHDEBUG=true PATH=$PWD/tool:$PATH /tmp/testwrapper ./... ${{matrix.buildflags}}
|
|
env:
|
|
GOARCH: ${{ matrix.goarch }}
|
|
TS_TEST_SHARD: ${{ matrix.shard }}
|
|
- name: bench all
|
|
working-directory: src
|
|
run: ./tool/go test ${{matrix.buildflags}} -bench=. -benchtime=1x -run=^$ $(for x in $(git grep -l "^func Benchmark" | xargs dirname | sort | uniq); do echo "./$x"; done)
|
|
env:
|
|
GOARCH: ${{ matrix.goarch }}
|
|
- name: check that no tracked files changed
|
|
working-directory: src
|
|
run: git diff --no-ext-diff --name-only --exit-code || (echo "Build/test modified the files above."; exit 1)
|
|
- name: check that no new files were added
|
|
working-directory: src
|
|
run: |
|
|
# Note: The "error: pathspec..." you see below is normal!
|
|
# In the success case in which there are no new untracked files,
|
|
# git ls-files complains about the pathspec not matching anything.
|
|
# That's OK. It's not worth the effort to suppress. Please ignore it.
|
|
if git ls-files --others --exclude-standard --directory --no-empty-directory --error-unmatch -- ':/*'
|
|
then
|
|
echo "Build/test created untracked files in the repo (file names above)."
|
|
exit 1
|
|
fi
|
|
- name: Tidy cache
|
|
working-directory: src
|
|
shell: bash
|
|
run: |
|
|
find $(go env GOCACHE) -type f -mmin +90 -delete
|
|
|
|
windows:
|
|
# windows-8vpu is a 2022 GitHub-managed runner in our
|
|
# org with 8 cores and 32 GB of RAM:
|
|
# https://github.com/organizations/tailscale/settings/actions/github-hosted-runners/1
|
|
runs-on: windows-8vcpu
|
|
needs: gomod-cache
|
|
name: Windows (${{ matrix.name || matrix.shard}})
|
|
strategy:
|
|
fail-fast: false # don't abort the entire matrix if one element fails
|
|
matrix:
|
|
include:
|
|
- key: "win-bench"
|
|
name: "benchmarks"
|
|
- key: "win-tool-go"
|
|
name: "./tool/go"
|
|
- key: "win-shard-1-2"
|
|
shard: "1/2"
|
|
- key: "win-shard-2-2"
|
|
shard: "2/2"
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
|
|
- name: Install Go
|
|
if: matrix.key != 'win-tool-go'
|
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
|
with:
|
|
go-version-file: src/go.mod
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
if: matrix.key != 'win-tool-go'
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
|
|
- name: Restore Cache
|
|
if: matrix.key != 'win-tool-go'
|
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: |
|
|
~/.cache/go-build
|
|
~\AppData\Local\go-build
|
|
# The -2- here should be incremented when the scheme of data to be
|
|
# cached changes (e.g. path above changes).
|
|
key: ${{ github.job }}-${{ matrix.key }}-go-2-${{ hashFiles('**/go.sum') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
${{ github.job }}-${{ matrix.key }}-go-2-${{ hashFiles('**/go.sum') }}
|
|
${{ github.job }}-${{ matrix.key }}-go-2-
|
|
|
|
- name: test-tool-go
|
|
if: matrix.key == 'win-tool-go'
|
|
working-directory: src
|
|
run: ./tool/go version
|
|
|
|
- name: test
|
|
if: matrix.key != 'win-bench' && matrix.key != 'win-tool-go' # skip on bench builder
|
|
working-directory: src
|
|
run: go run ./cmd/testwrapper sharded:${{ matrix.shard }}
|
|
|
|
- name: bench all
|
|
if: matrix.key == 'win-bench'
|
|
working-directory: src
|
|
# Don't use -bench=. -benchtime=1x.
|
|
# Somewhere in the layers (powershell?)
|
|
# the equals signs cause great confusion.
|
|
run: go test ./... -bench . -benchtime 1x -run "^$"
|
|
|
|
- name: Tidy cache
|
|
if: matrix.key != 'win-tool-go'
|
|
working-directory: src
|
|
shell: bash
|
|
run: |
|
|
find $(go env GOCACHE) -type f -mmin +90 -delete
|
|
|
|
privileged:
|
|
needs: gomod-cache
|
|
runs-on: ubuntu-24.04
|
|
container:
|
|
image: golang:latest
|
|
options: --privileged
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: chown
|
|
working-directory: src
|
|
run: chown -R $(id -u):$(id -g) $PWD
|
|
- name: privileged tests
|
|
working-directory: src
|
|
run: ./tool/go test ./util/linuxfw ./derp/xdp
|
|
|
|
vm:
|
|
needs: gomod-cache
|
|
runs-on: ["self-hosted", "linux", "vm"]
|
|
# VM tests run with some privileges, don't let them run on 3p PRs.
|
|
if: github.repository == 'tailscale/tailscale'
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: Run VM tests
|
|
working-directory: src
|
|
run: ./tool/go test ./tstest/integration/vms -v -no-s3 -run-vm-tests -run=TestRunUbuntu2004
|
|
env:
|
|
HOME: "/var/lib/ghrunner/home"
|
|
TMPDIR: "/tmp"
|
|
XDG_CACHE_HOME: "/var/lib/ghrunner/cache"
|
|
|
|
cross: # cross-compile checks, build only.
|
|
needs: gomod-cache
|
|
strategy:
|
|
fail-fast: false # don't abort the entire matrix if one element fails
|
|
matrix:
|
|
include:
|
|
# Note: linux/amd64 is not in this matrix, because that goos/goarch is
|
|
# tested more exhaustively in the 'test' job above.
|
|
- goos: linux
|
|
goarch: arm64
|
|
- goos: linux
|
|
goarch: "386" # thanks yaml
|
|
- goos: linux
|
|
goarch: loong64
|
|
- goos: linux
|
|
goarch: arm
|
|
goarm: "5"
|
|
- goos: linux
|
|
goarch: arm
|
|
goarm: "7"
|
|
# macOS
|
|
- goos: darwin
|
|
goarch: amd64
|
|
- goos: darwin
|
|
goarch: arm64
|
|
# Windows
|
|
- goos: windows
|
|
goarch: amd64
|
|
- goos: windows
|
|
goarch: arm64
|
|
# BSDs
|
|
- goos: freebsd
|
|
goarch: amd64
|
|
- goos: openbsd
|
|
goarch: amd64
|
|
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Cache
|
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
# Note: unlike the other setups, this is only grabbing the mod download
|
|
# cache, rather than the whole mod directory, as the download cache
|
|
# contains zips that can be unpacked in parallel faster than they can be
|
|
# fetched and extracted by tar
|
|
path: |
|
|
~/.cache/go-build
|
|
~\AppData\Local\go-build
|
|
# The -2- here should be incremented when the scheme of data to be
|
|
# cached changes (e.g. path above changes).
|
|
key: ${{ github.job }}-${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-2-${{ hashFiles('**/go.sum') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
${{ github.job }}-${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-2-${{ hashFiles('**/go.sum') }}
|
|
${{ github.job }}-${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-2-
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: build all
|
|
working-directory: src
|
|
run: ./tool/go build ./cmd/...
|
|
env:
|
|
GOOS: ${{ matrix.goos }}
|
|
GOARCH: ${{ matrix.goarch }}
|
|
GOARM: ${{ matrix.goarm }}
|
|
CGO_ENABLED: "0"
|
|
- name: build tests
|
|
working-directory: src
|
|
run: ./tool/go test -exec=true ./...
|
|
env:
|
|
GOOS: ${{ matrix.goos }}
|
|
GOARCH: ${{ matrix.goarch }}
|
|
CGO_ENABLED: "0"
|
|
- name: Tidy cache
|
|
working-directory: src
|
|
shell: bash
|
|
run: |
|
|
find $(go env GOCACHE) -type f -mmin +90 -delete
|
|
|
|
ios: # similar to cross above, but iOS can't build most of the repo. So, just
|
|
# make it build a few smoke packages.
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: build some
|
|
working-directory: src
|
|
run: ./tool/go build ./ipn/... ./ssh/tailssh ./wgengine/ ./types/... ./control/controlclient
|
|
env:
|
|
GOOS: ios
|
|
GOARCH: arm64
|
|
|
|
crossmin: # cross-compile for platforms where we only check cmd/tailscale{,d}
|
|
needs: gomod-cache
|
|
strategy:
|
|
fail-fast: false # don't abort the entire matrix if one element fails
|
|
matrix:
|
|
include:
|
|
# Plan9
|
|
- goos: plan9
|
|
goarch: amd64
|
|
# AIX
|
|
- goos: aix
|
|
goarch: ppc64
|
|
# Solaris
|
|
- goos: solaris
|
|
goarch: amd64
|
|
# illumos
|
|
- goos: illumos
|
|
goarch: amd64
|
|
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Cache
|
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
# Note: unlike the other setups, this is only grabbing the mod download
|
|
# cache, rather than the whole mod directory, as the download cache
|
|
# contains zips that can be unpacked in parallel faster than they can be
|
|
# fetched and extracted by tar
|
|
path: |
|
|
~/.cache/go-build
|
|
~\AppData\Local\go-build
|
|
# The -2- here should be incremented when the scheme of data to be
|
|
# cached changes (e.g. path above changes).
|
|
key: ${{ github.job }}-${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-2-${{ hashFiles('**/go.sum') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
${{ github.job }}-${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-2-${{ hashFiles('**/go.sum') }}
|
|
${{ github.job }}-${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-2-
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: build core
|
|
working-directory: src
|
|
run: ./tool/go build ./cmd/tailscale ./cmd/tailscaled
|
|
env:
|
|
GOOS: ${{ matrix.goos }}
|
|
GOARCH: ${{ matrix.goarch }}
|
|
GOARM: ${{ matrix.goarm }}
|
|
CGO_ENABLED: "0"
|
|
- name: Tidy cache
|
|
working-directory: src
|
|
shell: bash
|
|
run: |
|
|
find $(go env GOCACHE) -type f -mmin +90 -delete
|
|
|
|
android:
|
|
# similar to cross above, but android fails to build a few pieces of the
|
|
# repo. We should fix those pieces, they're small, but as a stepping stone,
|
|
# only test the subset of android that our past smoke test checked.
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
# Super minimal Android build that doesn't even use CGO and doesn't build everything that's needed
|
|
# and is only arm64. But it's a smoke build: it's not meant to catch everything. But it'll catch
|
|
# some Android breakages early.
|
|
# TODO(bradfitz): better; see https://github.com/tailscale/tailscale/issues/4482
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: build some
|
|
working-directory: src
|
|
run: ./tool/go install ./net/netns ./ipn/ipnlocal ./wgengine/magicsock/ ./wgengine/ ./wgengine/router/ ./wgengine/netstack ./util/dnsname/ ./ipn/ ./net/netmon ./wgengine/router/ ./tailcfg/ ./types/logger/ ./net/dns ./hostinfo ./version ./ssh/tailssh
|
|
env:
|
|
GOOS: android
|
|
GOARCH: arm64
|
|
|
|
wasm: # builds tsconnect, which is the only wasm build we support
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Cache
|
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
# Note: unlike the other setups, this is only grabbing the mod download
|
|
# cache, rather than the whole mod directory, as the download cache
|
|
# contains zips that can be unpacked in parallel faster than they can be
|
|
# fetched and extracted by tar
|
|
path: |
|
|
~/.cache/go-build
|
|
~\AppData\Local\go-build
|
|
# The -2- here should be incremented when the scheme of data to be
|
|
# cached changes (e.g. path above changes).
|
|
key: ${{ github.job }}-${{ runner.os }}-go-2-${{ hashFiles('**/go.sum') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
${{ github.job }}-${{ runner.os }}-go-2-${{ hashFiles('**/go.sum') }}
|
|
${{ github.job }}-${{ runner.os }}-go-2-
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: build tsconnect client
|
|
working-directory: src
|
|
run: ./tool/go build ./cmd/tsconnect/wasm ./cmd/tailscale/cli
|
|
env:
|
|
GOOS: js
|
|
GOARCH: wasm
|
|
- name: build tsconnect server
|
|
working-directory: src
|
|
# Note, no GOOS/GOARCH in env on this build step, we're running a build
|
|
# tool that handles the build itself.
|
|
run: |
|
|
./tool/go run ./cmd/tsconnect --fast-compression build
|
|
./tool/go run ./cmd/tsconnect --fast-compression build-pkg
|
|
- name: Tidy cache
|
|
working-directory: src
|
|
shell: bash
|
|
run: |
|
|
find $(go env GOCACHE) -type f -mmin +90 -delete
|
|
|
|
tailscale_go: # Subset of tests that depend on our custom Go toolchain.
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
- name: Set GOMODCACHE env
|
|
run: echo "GOMODCACHE=$HOME/.cache/go-mod" >> $GITHUB_ENV
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: test tailscale_go
|
|
run: ./tool/go test -tags=tailscale_go,ts_enable_sockstats ./net/sockstats/...
|
|
|
|
|
|
fuzz:
|
|
# This target periodically breaks (see TS_FUZZ_CURRENTLY_BROKEN at the top
|
|
# of the file), so it's more complex than usual: the 'build fuzzers' step
|
|
# might fail, and depending on the value of 'TS_FUZZ_CURRENTLY_BROKEN', that
|
|
# might or might not be fine. The steps after the build figure out whether
|
|
# the success/failure is expected, and appropriately pass/fail the job
|
|
# overall accordingly.
|
|
#
|
|
# Practically, this means that all steps after 'build fuzzers' must have an
|
|
# explicit 'if' condition, because the default condition for steps is
|
|
# 'success()', meaning "only run this if no previous steps failed".
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: build fuzzers
|
|
id: build
|
|
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
|
# continue-on-error makes steps.build.conclusion be 'success' even if
|
|
# steps.build.outcome is 'failure'. This means this step does not
|
|
# contribute to the job's overall pass/fail evaluation.
|
|
continue-on-error: true
|
|
with:
|
|
oss-fuzz-project-name: 'tailscale'
|
|
dry-run: false
|
|
language: go
|
|
- name: report unexpectedly broken fuzz build
|
|
if: steps.build.outcome == 'failure' && env.TS_FUZZ_CURRENTLY_BROKEN != 'true'
|
|
run: |
|
|
echo "fuzzer build failed, see above for why"
|
|
echo "if the failure is due to OSS-Fuzz not being on the latest Go yet,"
|
|
echo "set TS_FUZZ_CURRENTLY_BROKEN=true in .github/workflows/test.yml"
|
|
echo "to temporarily disable fuzzing until OSS-Fuzz works again."
|
|
exit 1
|
|
- name: report unexpectedly working fuzz build
|
|
if: steps.build.outcome == 'success' && env.TS_FUZZ_CURRENTLY_BROKEN == 'true'
|
|
run: |
|
|
echo "fuzzer build succeeded, but we expect it to be broken"
|
|
echo "please set TS_FUZZ_CURRENTLY_BROKEN=false in .github/workflows/test.yml"
|
|
echo "to reenable fuzz testing"
|
|
exit 1
|
|
- name: run fuzzers
|
|
id: run
|
|
# Run the fuzzers whenever they're able to build, even if we're going to
|
|
# report a failure because TS_FUZZ_CURRENTLY_BROKEN is set to the wrong
|
|
# value.
|
|
if: steps.build.outcome == 'success'
|
|
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
|
with:
|
|
oss-fuzz-project-name: 'tailscale'
|
|
fuzz-seconds: 150
|
|
dry-run: false
|
|
language: go
|
|
- name: Set artifacts_path in env (workaround for actions/upload-artifact#176)
|
|
if: steps.run.outcome != 'success' && steps.build.outcome == 'success'
|
|
run: |
|
|
echo "artifacts_path=$(realpath .)" >> $GITHUB_ENV
|
|
- name: upload crash
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
if: steps.run.outcome != 'success' && steps.build.outcome == 'success'
|
|
with:
|
|
name: artifacts
|
|
path: ${{ env.artifacts_path }}/out/artifacts
|
|
|
|
depaware:
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Set GOMODCACHE env
|
|
run: echo "GOMODCACHE=$HOME/.cache/go-mod" >> $GITHUB_ENV
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: check depaware
|
|
working-directory: src
|
|
run: make depaware
|
|
|
|
go_generate:
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: check that 'go generate' is clean
|
|
working-directory: src
|
|
run: |
|
|
pkgs=$(./tool/go list ./... | grep -Ev 'dnsfallback|k8s-operator|xdp')
|
|
./tool/go generate $pkgs
|
|
echo
|
|
echo
|
|
git diff --name-only --exit-code || (echo "The files above need updating. Please run 'go generate'."; exit 1)
|
|
|
|
go_mod_tidy:
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: check that 'go mod tidy' is clean
|
|
working-directory: src
|
|
run: |
|
|
make tidy
|
|
echo
|
|
echo
|
|
git diff --name-only --exit-code || (echo "Please run 'go mod tidy' and ./update-flake.sh."; exit 1)
|
|
|
|
licenses:
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: check licenses
|
|
working-directory: src
|
|
run: |
|
|
grep -q TestLicenseHeaders *.go || (echo "Expected a test named TestLicenseHeaders"; exit 1)
|
|
./tool/go test -v -run=TestLicenseHeaders
|
|
|
|
staticcheck:
|
|
runs-on: ubuntu-24.04
|
|
needs: gomod-cache
|
|
name: staticcheck (${{ matrix.name }})
|
|
strategy:
|
|
fail-fast: false # don't abort the entire matrix if one element fails
|
|
matrix:
|
|
include:
|
|
- name: "macOS"
|
|
goos: "darwin"
|
|
goarch: "arm64"
|
|
flags: "--with-tags-all=darwin"
|
|
- name: "Windows"
|
|
goos: "windows"
|
|
goarch: "amd64"
|
|
flags: "--with-tags-all=windows"
|
|
- name: "Linux"
|
|
goos: "linux"
|
|
goarch: "amd64"
|
|
flags: "--with-tags-all=linux"
|
|
- name: "Portable (1/4)"
|
|
goos: "linux"
|
|
goarch: "amd64"
|
|
flags: "--without-tags-any=windows,darwin,linux --shard=1/4"
|
|
- name: "Portable (2/4)"
|
|
goos: "linux"
|
|
goarch: "amd64"
|
|
flags: "--without-tags-any=windows,darwin,linux --shard=2/4"
|
|
- name: "Portable (3/4)"
|
|
goos: "linux"
|
|
goarch: "amd64"
|
|
flags: "--without-tags-any=windows,darwin,linux --shard=3/4"
|
|
- name: "Portable (4/4)"
|
|
goos: "linux"
|
|
goarch: "amd64"
|
|
flags: "--without-tags-any=windows,darwin,linux --shard=4/4"
|
|
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
path: src
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
|
with:
|
|
path: gomodcache
|
|
key: ${{ needs.gomod-cache.outputs.cache-key }}
|
|
enableCrossOsArchive: true
|
|
- name: run staticcheck (${{ matrix.name }})
|
|
working-directory: src
|
|
run: |
|
|
export GOROOT=$(./tool/go env GOROOT)
|
|
./tool/go run -exec \
|
|
"env GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }}" \
|
|
honnef.co/go/tools/cmd/staticcheck -- \
|
|
$(./tool/go run ./tool/listpkgs --ignore-3p --goos=${{ matrix.goos }} --goarch=${{ matrix.goarch }} ${{ matrix.flags }} ./...)
|
|
|
|
notify_slack:
|
|
if: always()
|
|
# Any of these jobs failing causes a slack notification.
|
|
needs:
|
|
- android
|
|
- test
|
|
- windows
|
|
- vm
|
|
- cross
|
|
- ios
|
|
- wasm
|
|
- tailscale_go
|
|
- fuzz
|
|
- depaware
|
|
- go_generate
|
|
- go_mod_tidy
|
|
- licenses
|
|
- staticcheck
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: notify
|
|
# Only notify slack for merged commits, not PR failures.
|
|
#
|
|
# It may be tempting to move this condition into the job's 'if' block, but
|
|
# don't: Github only collapses the test list into "everything is OK" if
|
|
# all jobs succeeded. A skipped job results in the list staying expanded.
|
|
# By having the job always run, but skipping its only step as needed, we
|
|
# let the CI output collapse nicely in PRs.
|
|
if: failure() && github.event_name == 'push'
|
|
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
|
with:
|
|
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
webhook-type: incoming-webhook
|
|
payload: |
|
|
{
|
|
"attachments": [{
|
|
"title": "Failure: ${{ github.workflow }}",
|
|
"title_link": "https://github.com/${{ github.repository }}/commit/${{ github.sha }}/checks",
|
|
"text": "${{ github.repository }}@${{ github.ref_name }}: <https://github.com/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}>",
|
|
"fields": [{ "value": ${{ toJson(github.event.head_commit.message) }}, "short": false }],
|
|
"footer": "${{ github.event.head_commit.committer.name }} at ${{ github.event.head_commit.timestamp }}",
|
|
"color": "danger"
|
|
}]
|
|
}
|
|
|
|
merge_blocker:
|
|
if: always()
|
|
runs-on: ubuntu-24.04
|
|
needs:
|
|
- android
|
|
- test
|
|
- windows
|
|
- vm
|
|
- cross
|
|
- ios
|
|
- wasm
|
|
- tailscale_go
|
|
- fuzz
|
|
- depaware
|
|
- go_generate
|
|
- go_mod_tidy
|
|
- licenses
|
|
- staticcheck
|
|
steps:
|
|
- name: Decide if change is okay to merge
|
|
if: github.event_name != 'push'
|
|
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
|
|
with:
|
|
jobs: ${{ toJSON(needs) }}
|
|
|
|
# This waits on all the jobs which must never fail. Branch protection rules
|
|
# enforce these. No flaky tests are allowed in these jobs. (We don't want flaky
|
|
# tests anywhere, really, but a flaky test here prevents merging.)
|
|
check_mergeability_strict:
|
|
if: always()
|
|
runs-on: ubuntu-24.04
|
|
needs:
|
|
- android
|
|
- cross
|
|
- crossmin
|
|
- ios
|
|
- tailscale_go
|
|
- depaware
|
|
- go_generate
|
|
- go_mod_tidy
|
|
- licenses
|
|
- staticcheck
|
|
steps:
|
|
- name: Decide if change is okay to merge
|
|
if: github.event_name != 'push'
|
|
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
|
|
with:
|
|
jobs: ${{ toJSON(needs) }}
|
|
|
|
check_mergeability:
|
|
if: always()
|
|
runs-on: ubuntu-24.04
|
|
needs:
|
|
- check_mergeability_strict
|
|
- test
|
|
- windows
|
|
- vm
|
|
- wasm
|
|
- fuzz
|
|
- race-root-integration
|
|
- privileged
|
|
steps:
|
|
- name: Decide if change is okay to merge
|
|
if: github.event_name != 'push'
|
|
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
|
|
with:
|
|
jobs: ${{ toJSON(needs) }}
|