diff --git a/.github/workflows/checklocks.yml b/.github/workflows/checklocks.yml deleted file mode 100644 index 5768cf05a..000000000 --- a/.github/workflows/checklocks.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: checklocks - -on: - push: - branches: - - main - pull_request: - paths: - - '**/*.go' - - '.github/workflows/checklocks.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - checklocks: - runs-on: [ ubuntu-latest ] - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Build checklocks - run: ./tool/go build -o /tmp/checklocks gvisor.dev/gvisor/tools/checklocks/cmd/checklocks - - - name: Run checklocks vet - # TODO(#12625): add more packages as we add annotations - run: |- - ./tool/go vet -vettool=/tmp/checklocks \ - ./envknob \ - ./ipn/store/mem \ - ./net/stun/stuntest \ - ./net/wsconn \ - ./proxymap diff --git a/.github/workflows/cigocacher.yml b/.github/workflows/cigocacher.yml deleted file mode 100644 index 9e7f01725..000000000 --- a/.github/workflows/cigocacher.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Build cigocacher - -on: - # Released on-demand. The commit will be used as part of the tag, so generally - # prefer to release from main where the commit is stable in linear history. - workflow_dispatch: - -jobs: - build: - strategy: - matrix: - GOOS: ["linux", "darwin", "windows"] - GOARCH: ["amd64", "arm64"] - runs-on: ubuntu-24.04 - env: - GOOS: "${{ matrix.GOOS }}" - GOARCH: "${{ matrix.GOARCH }}" - CGO_ENABLED: "0" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Build - run: | - OUT="cigocacher$(./tool/go env GOEXE)" - ./tool/go build -o "${OUT}" ./cmd/cigocacher/ - tar -zcf cigocacher-${{ matrix.GOOS }}-${{ matrix.GOARCH }}.tar.gz "${OUT}" - - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: cigocacher-${{ matrix.GOOS }}-${{ matrix.GOARCH }} - path: cigocacher-${{ matrix.GOOS }}-${{ matrix.GOARCH }}.tar.gz - - release: - runs-on: ubuntu-24.04 - needs: build - permissions: - contents: write - steps: - - name: Download all artifacts - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - pattern: 'cigocacher-*' - merge-multiple: true - # This step is a simplified version of actions/create-release and - # actions/upload-release-asset, which are archived and unmaintained. - - name: Create release - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const fs = require('fs'); - const path = require('path'); - - const { data: release } = await github.rest.repos.createRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - tag_name: `cmd/cigocacher/${{ github.sha }}`, - name: `cigocacher-${{ github.sha }}`, - draft: false, - prerelease: true, - target_commitish: `${{ github.sha }}` - }); - - const files = fs.readdirSync('.').filter(f => f.endsWith('.tar.gz')); - - for (const file of files) { - await github.rest.repos.uploadReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: release.id, - name: file, - data: fs.readFileSync(file) - }); - console.log(`Uploaded ${file}`); - } diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index abe6a2c3a..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,83 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ main, release-branch/* ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - merge_group: - branches: [ main ] - schedule: - - cron: '31 14 * * 5' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - # Install a more recent Go that understands modern go.mod content. - - name: Install Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 - with: - go-version-file: go.mod - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 diff --git a/.github/workflows/docker-base.yml b/.github/workflows/docker-base.yml deleted file mode 100644 index a3eac2c24..000000000 --- a/.github/workflows/docker-base.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: "Validate Docker base image" -on: - workflow_dispatch: - pull_request: - paths: - - "Dockerfile.base" - - ".github/workflows/docker-base.yml" -jobs: - build-and-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: "build and test" - run: | - set -e - IMG="test-base:$(head -c 8 /dev/urandom | xxd -p)" - docker build -t "$IMG" -f Dockerfile.base . - - iptables_version=$(docker run --rm "$IMG" iptables --version) - if [[ "$iptables_version" != *"(legacy)"* ]]; then - echo "ERROR: Docker base image should contain legacy iptables; found ${iptables_version}" - exit 1 - fi - - ip6tables_version=$(docker run --rm "$IMG" ip6tables --version) - if [[ "$ip6tables_version" != *"(legacy)"* ]]; then - echo "ERROR: Docker base image should contain legacy ip6tables; found ${ip6tables_version}" - exit 1 - fi diff --git a/.github/workflows/docker-file-build.yml b/.github/workflows/docker-file-build.yml deleted file mode 100644 index 7ee246868..000000000 --- a/.github/workflows/docker-file-build.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: "Dockerfile build" -on: - push: - branches: - - main - pull_request: -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: "Build Docker image" - run: docker build . diff --git a/.github/workflows/flakehub-publish-tagged.yml b/.github/workflows/flakehub-publish-tagged.yml deleted file mode 100644 index c781e30e5..000000000 --- a/.github/workflows/flakehub-publish-tagged.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: update-flakehub - -on: - push: - tags: - - "v[0-9]+.*[02468].[0-9]+" - workflow_dispatch: - inputs: - tag: - description: "The existing tag to publish to FlakeHub" - type: "string" - required: true -jobs: - flakehub-publish: - runs-on: "ubuntu-latest" - permissions: - id-token: "write" - contents: "read" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: "${{ (inputs.tag != null) && format('refs/tags/{0}', inputs.tag) || '' }}" - - uses: DeterminateSystems/nix-installer-action@c5a866b6ab867e88becbed4467b93592bce69f8a # v21 - - uses: DeterminateSystems/flakehub-push@71f57208810a5d299fc6545350981de98fdbc860 # v6 - with: - visibility: "public" - tag: "${{ inputs.tag }}" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml deleted file mode 100644 index 66b8497e6..000000000 --- a/.github/workflows/golangci-lint.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: golangci-lint -on: - # For now, only lint pull requests, not the main branches. - pull_request: - paths: - - ".github/workflows/golangci-lint.yml" - - "**.go" - - "go.mod" - - "go.sum" - # TODO(andrew): enable for main branch after an initial waiting period. - #push: - # branches: - # - main - - workflow_dispatch: - -permissions: - contents: read - pull-requests: read - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 - with: - go-version-file: go.mod - cache: true - - - name: golangci-lint - uses: golangci/golangci-lint-action@b7bcab6379029e905e3f389a6bf301f1bc220662 # head as of 2026-03-04 - with: - version: v2.10.1 - - # Show only new issues if it's a pull request. - only-new-issues: true - - # Loading packages with a cold cache takes a while: - args: --timeout=10m - diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml deleted file mode 100644 index 2b46aa9b0..000000000 --- a/.github/workflows/govulncheck.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: govulncheck - -on: - schedule: - - cron: "0 12 * * *" # 8am EST / 10am PST / 12pm UTC - workflow_dispatch: # allow manual trigger for testing - pull_request: - paths: - - ".github/workflows/govulncheck.yml" - -jobs: - source-scan: - runs-on: ubuntu-latest - - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Install govulncheck - run: ./tool/go install golang.org/x/vuln/cmd/govulncheck@latest - - - name: Scan source code for known vulnerabilities - run: PATH=$PWD/tool/:$PATH "$(./tool/go env GOPATH)/bin/govulncheck" -test ./... - - - name: Post to slack - if: failure() && github.event_name == 'schedule' - uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 - with: - method: chat.postMessage - token: ${{ secrets.GOVULNCHECK_BOT_TOKEN }} - payload: | - { - "channel": "C08FGKZCQTW", - "blocks": [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "Govulncheck failed in ${{ github.repository }}" - }, - "accessory": { - "type": "button", - "text": { - "type": "plain_text", - "text": "View results" - }, - "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - } - } - ] - } diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml deleted file mode 100644 index 6fc8913c4..000000000 --- a/.github/workflows/installer.yml +++ /dev/null @@ -1,143 +0,0 @@ -name: test installer.sh - -on: - schedule: - - cron: '0 15 * * *' # 10am EST (UTC-4/5) - push: - branches: - - "main" - paths: - - scripts/installer.sh - - .github/workflows/installer.yml - pull_request: - paths: - - scripts/installer.sh - - .github/workflows/installer.yml - -jobs: - test: - strategy: - # Don't abort the entire matrix if one element fails. - fail-fast: false - # Don't start all of these at once, which could saturate Github workers. - max-parallel: 4 - matrix: - image: - # This is a list of Docker images against which we test our installer. - # If you find that some of these no longer exist, please feel free - # to remove them from the list. - # When adding new images, please only use official ones. - - "debian:oldstable-slim" - - "debian:stable-slim" - - "debian:testing-slim" - - "debian:sid-slim" - - "ubuntu:20.04" - - "ubuntu:22.04" - - "ubuntu:24.04" - - "elementary/docker:stable" - - "elementary/docker:unstable" - - "parrotsec/core:latest" - - "kalilinux/kali-rolling" - - "kalilinux/kali-dev" - - "oraclelinux:9" - - "oraclelinux:8" - - "fedora:latest" - - "rockylinux:8.7" - - "rockylinux:9" - - "amazonlinux:latest" - - "opensuse/leap:latest" - - "opensuse/tumbleweed:latest" - - "archlinux:latest" - - "alpine:3.21" - - "alpine:latest" - - "alpine:edge" - deps: - # Run all images installing curl as a dependency. - - curl - include: - # Check a few images with wget rather than curl. - - { image: "debian:oldstable-slim", deps: "wget" } - - { image: "debian:sid-slim", deps: "wget" } - - { image: "debian:stable-slim", deps: "curl" } - - { image: "ubuntu:24.04", deps: "curl" } - - { image: "fedora:latest", deps: "curl" } - # Test TAILSCALE_VERSION pinning on a subset of distros. - # Skip Alpine as community repos don't reliably keep old versions. - - { image: "debian:stable-slim", deps: "curl", version: "1.80.0" } - - { image: "ubuntu:24.04", deps: "curl", version: "1.80.0" } - - { image: "fedora:latest", deps: "curl", version: "1.80.0" } - runs-on: ubuntu-latest - container: - image: ${{ matrix.image }} - options: --user root - steps: - - name: install dependencies (pacman) - # Refresh the package databases to ensure that the tailscale package is - # defined. - run: pacman -Sy - if: contains(matrix.image, 'archlinux') - - name: install dependencies (yum) - # tar and gzip are needed by the actions/checkout below. - run: yum install -y --allowerasing tar gzip ${{ matrix.deps }} - if: | - contains(matrix.image, 'centos') || - contains(matrix.image, 'oraclelinux') || - contains(matrix.image, 'fedora') || - contains(matrix.image, 'amazonlinux') - - name: install dependencies (zypper) - # tar and gzip are needed by the actions/checkout below. - run: zypper --non-interactive install tar gzip ${{ matrix.deps }} - if: contains(matrix.image, 'opensuse') - - name: install dependencies (apt-get) - run: | - apt-get update - apt-get install -y ${{ matrix.deps }} - if: | - contains(matrix.image, 'debian') || - contains(matrix.image, 'ubuntu') || - contains(matrix.image, 'elementary') || - contains(matrix.image, 'parrotsec') || - contains(matrix.image, 'kalilinux') - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: run installer - run: scripts/installer.sh - env: - TAILSCALE_VERSION: ${{ matrix.version }} - # Package installation can fail in docker because systemd is not running - # as PID 1, so ignore errors at this step. The real check is the - # `tailscale --version` command below. - continue-on-error: true - - name: check tailscale version - run: | - tailscale --version - if [ -n "${{ matrix.version }}" ]; then - tailscale --version | grep -q "^${{ matrix.version }}" || { echo "Version mismatch!"; exit 1; } - fi - notify-slack: - needs: test - runs-on: ubuntu-latest - steps: - - name: Notify Slack of failure on scheduled runs - if: failure() && github.event_name == 'schedule' - uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 - with: - webhook: ${{ secrets.SLACK_WEBHOOK_URL }} - webhook-type: incoming-webhook - payload: | - { - "attachments": [{ - "title": "Tailscale installer test failed", - "title_link": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}", - "text": "One or more OSes in the test matrix failed. See the run for details.", - "fields": [ - { - "title": "Ref", - "value": "${{ github.ref_name }}", - "short": true - } - ], - "footer": "${{ github.workflow }} on schedule", - "color": "danger" - }] - } diff --git a/.github/workflows/kubemanifests.yaml b/.github/workflows/kubemanifests.yaml deleted file mode 100644 index 40734a015..000000000 --- a/.github/workflows/kubemanifests.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: "Kubernetes manifests" -on: - pull_request: - paths: - - 'cmd/k8s-operator/**' - - 'k8s-operator/**' - - '.github/workflows/kubemanifests.yaml' - -# Cancel workflow run if there is a newer push to the same PR for which it is -# running -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - testchart: - runs-on: [ ubuntu-latest ] - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Build and lint Helm chart - run: | - eval `./tool/go run ./cmd/mkversion` - ./tool/helm package --app-version="${VERSION_SHORT}" --version=${VERSION_SHORT} './cmd/k8s-operator/deploy/chart' - ./tool/helm lint "tailscale-operator-${VERSION_SHORT}.tgz" - - name: Verify that static manifests are up to date - run: | - make kube-generate-all - echo - echo - git diff --name-only --exit-code || (echo "Generated files for Tailscale Kubernetes operator are out of date. Please run 'make kube-generate-all' and commit the diff."; exit 1) diff --git a/.github/workflows/natlab-integrationtest.yml b/.github/workflows/natlab-integrationtest.yml deleted file mode 100644 index 162153cb2..000000000 --- a/.github/workflows/natlab-integrationtest.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Run some natlab integration tests. -# See https://github.com/tailscale/tailscale/issues/13038 -name: "natlab-integrationtest" - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - push: - branches: - - "main" - - "release-branch/*" - pull_request: - # all PRs on all branches - merge_group: - branches: - - "main" -jobs: - natlab-integrationtest: - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Install qemu - run: | - sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -y update - sudo apt-get -y remove man-db - sudo apt-get install -y qemu-system-x86 qemu-utils - - name: Run natlab integration tests - run: | - ./tool/go test -v -run=^TestEasyEasy$ -timeout=3m -count=1 ./tstest/integration/nat --run-vm-tests diff --git a/.github/workflows/pin-github-actions.yml b/.github/workflows/pin-github-actions.yml deleted file mode 100644 index 836ae46db..000000000 --- a/.github/workflows/pin-github-actions.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Pin images used in github actions to a hash instead of a version tag. -name: pin-github-actions -on: - pull_request: - branches: - - main - paths: - - ".github/workflows/**" - - workflow_dispatch: - -permissions: - contents: read - pull-requests: read - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - run: - name: pin-github-actions - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: pin - run: make pin-github-actions - - name: check for changed workflow files - run: git diff --no-ext-diff --exit-code .github/workflows || (echo "Some github actions versions need pinning, run make pin-github-actions."; exit 1) diff --git a/.github/workflows/request-dataplane-review.yml b/.github/workflows/request-dataplane-review.yml deleted file mode 100644 index 78bd8ff58..000000000 --- a/.github/workflows/request-dataplane-review.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: request-dataplane-review - -on: - pull_request: - types: [ opened, synchronize, reopened, ready_for_review ] - paths: - - ".github/workflows/request-dataplane-review.yml" - - "**/*derp*" - - "**/derp*/**" - - "!**/depaware.txt" - -jobs: - request-dataplane-review: - if: github.event.pull_request.draft == false - name: Request Dataplane Review - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Get access token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 - id: generate-token - with: - # Get token for app: https://github.com/apps/change-visibility-bot - app-id: ${{ secrets.VISIBILITY_BOT_APP_ID }} - private-key: ${{ secrets.VISIBILITY_BOT_APP_PRIVATE_KEY }} - - name: Add reviewers - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - url: ${{ github.event.pull_request.html_url }} - run: | - gh pr edit "$url" --add-reviewer tailscale/dataplane diff --git a/.github/workflows/ssh-integrationtest.yml b/.github/workflows/ssh-integrationtest.yml deleted file mode 100644 index afe2dd2f7..000000000 --- a/.github/workflows/ssh-integrationtest.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Run the ssh integration tests with `make sshintegrationtest`. -# These tests can also be running locally. -name: "ssh-integrationtest" - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - pull_request: - paths: - - "ssh/**" - - "tempfork/gliderlabs/ssh/**" - - ".github/workflows/ssh-integrationtest" -jobs: - ssh-integrationtest: - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Run SSH integration tests - run: | - make sshintegrationtest \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 38ebd1291..000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,1004 +0,0 @@ -# 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 - CMD_GO_USE_GIT_HASH: "true" - -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - name: Restore Cache - id: restore-cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only restoring the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}-${{ github.job }}- - ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}- - ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go- - - 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 NOPWSHDEBUG=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 - - name: Save Cache - # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. - if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only saving the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - - windows: - permissions: - id-token: write # This is required for requesting the GitHub action identity JWT that can auth to cigocached - contents: read # This is required for actions/checkout - # ci-windows-github-1 is a 2022 GitHub-managed runner in our org with 8 cores - # and 32 GB of RAM. It is connected to a private Azure VNet that hosts cigocached. - # https://github.com/organizations/tailscale/settings/actions/github-hosted-runners/5 - runs-on: ci-windows-github-1 - 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-shard-1-2" - shard: "1/2" - - key: "win-shard-2-2" - shard: "2/2" - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: ${{ github.workspace }}/src - - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - - name: Set up cigocacher - id: cigocacher-setup - uses: ./src/.github/actions/go-cache - with: - checkout-path: ${{ github.workspace }}/src - cache-dir: ${{ github.workspace }}/cigocacher - cigocached-url: ${{ vars.CIGOCACHED_AZURE_URL }} - cigocached-host: ${{ vars.CIGOCACHED_AZURE_HOST }} - - - name: test - if: matrix.key != 'win-bench' # skip on bench builder - working-directory: src - run: ./tool/go run ./cmd/testwrapper sharded:${{ matrix.shard }} - env: - NOPWSHDEBUG: "true" # to quiet tool/gocross/gocross-wrapper.ps1 in CI - - - name: bench all - if: matrix.key == 'win-bench' - working-directory: src - run: ./tool/go test ./... -bench=. -benchtime=1x -run="^$" - env: - NOPWSHDEBUG: "true" # to quiet tool/gocross/gocross-wrapper.ps1 in CI - - - name: Print stats - shell: pwsh - if: steps.cigocacher-setup.outputs.success == 'true' - env: - GOCACHEPROG: ${{ env.GOCACHEPROG }} - run: | - Invoke-Expression "$env:GOCACHEPROG --stats" | jq . - - macos: - runs-on: macos-latest - needs: gomod-cache - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - name: Restore Cache - id: restore-cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: ~/Library/Caches/go-build - key: ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}-${{ github.job }}- - ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-go-test- - - name: build test wrapper - working-directory: src - run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper - - name: test all - working-directory: src - run: PATH=$PWD/tool:$PATH /tmp/testwrapper ./... - - 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 - run: | - find $(./tool/go env GOCACHE) -type f -mmin +90 -delete - - name: Save Cache - # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. - if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: ~/Library/Caches/go-build - key: ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - - privileged: - needs: gomod-cache - runs-on: ubuntu-24.04 - container: - image: golang:latest - options: --privileged - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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=TestRunUbuntu2404 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - name: Restore Cache - id: restore-cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only restoring the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}- - ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go- - - 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 - - name: Save Cache - # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. - if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only saving the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - name: Restore Cache - id: restore-cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only restoring the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}- - ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go- - - 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 - - name: Save Cache - # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. - if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only saving the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - name: Restore Cache - id: restore-cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only restoring the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}- - ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-js-wasm-go- - - 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 - - name: Save Cache - # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. - if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' - uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - # Note: this is only saving the build cache. Mod cache is shared amongst - # all jobs in the workflow. - path: | - ~/.cache/go-build - ~\AppData\Local\go-build - key: ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} - - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Set GOMODCACHE env - run: echo "GOMODCACHE=$HOME/.cache/go-mod" >> $GITHUB_ENV - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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 - # As of 12 February 2026, this repo doesn't tag releases, so this commit - # hash is just the tip of master. - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@f277aafb36f358582fdb24a41a9a52f2e097a2fd - # 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' - # As of 12 February 2026, this repo doesn't tag releases, so this commit - # hash is just the tip of master. - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@f277aafb36f358582fdb24a41a9a52f2e097a2fd - 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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 - git add -N . # ensure untracked files are noticed - echo - echo - git diff --name-only --exit-code || (echo "The files above need updating. Please run 'go generate'."; exit 1) - - make_tidy: - runs-on: ubuntu-24.04 - needs: gomod-cache - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - with: - path: gomodcache - key: ${{ needs.gomod-cache.outputs.cache-key }} - enableCrossOsArchive: true - - name: check that 'make tidy' is clean - working-directory: src - run: | - make tidy - echo - echo - git diff --name-only --exit-code || (echo "Please run 'make tidy'"; exit 1) - - licenses: - runs-on: ubuntu-24.04 - needs: gomod-cache - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - name: Restore Go module cache - uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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 - - macos - - vm - - cross - - ios - - wasm - - tailscale_go - - fuzz - - depaware - - go_generate - - make_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 }}: ", - "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 - - macos - - vm - - cross - - ios - - wasm - - tailscale_go - - fuzz - - depaware - - go_generate - - make_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 - - make_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 - - macos - - 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) }} diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml deleted file mode 100644 index 1304fb222..000000000 --- a/.github/workflows/update-flake.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: update-flake - -on: - # run action when a change lands in the main branch which updates go.mod. Also - # allow manual triggering. - push: - branches: - - main - paths: - - go.mod - - .github/workflows/update-flake.yml - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - update-flake: - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Run update-flakes - run: ./update-flake.sh - - - name: Get access token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 - id: generate-token - with: - # Get token for app: https://github.com/apps/tailscale-code-updater - app-id: ${{ secrets.CODE_UPDATER_APP_ID }} - private-key: ${{ secrets.CODE_UPDATER_APP_PRIVATE_KEY }} - - - name: Send pull request - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0 - with: - token: ${{ steps.generate-token.outputs.token }} - author: Flakes Updater - committer: Flakes Updater - branch: flakes - commit-message: "go.mod.sri: update SRI hash for go.mod changes" - title: "go.mod.sri: update SRI hash for go.mod changes" - body: Triggered by ${{ github.repository }}@${{ github.sha }} - signoff: true - delete-branch: true - reviewers: danderson diff --git a/.github/workflows/update-webclient-prebuilt.yml b/.github/workflows/update-webclient-prebuilt.yml deleted file mode 100644 index 5bb0573a1..000000000 --- a/.github/workflows/update-webclient-prebuilt.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: update-webclient-prebuilt - -on: - # manually triggered - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - update-webclient-prebuilt: - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Run go get - run: | - ./tool/go version # build gocross if needed using regular GOPROXY - GOPROXY=direct ./tool/go get github.com/tailscale/web-client-prebuilt - ./tool/go mod tidy - - - name: Get access token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 - id: generate-token - with: - # Get token for app: https://github.com/apps/tailscale-code-updater - app-id: ${{ secrets.CODE_UPDATER_APP_ID }} - private-key: ${{ secrets.CODE_UPDATER_APP_PRIVATE_KEY }} - - - name: Send pull request - id: pull-request - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0 - with: - token: ${{ steps.generate-token.outputs.token }} - author: OSS Updater - committer: OSS Updater - branch: actions/update-webclient-prebuilt - commit-message: "go.mod: update web-client-prebuilt module" - title: "go.mod: update web-client-prebuilt module" - body: Triggered by ${{ github.repository }}@${{ github.sha }} - signoff: true - delete-branch: true - reviewers: ${{ github.triggering_actor }} - - - name: Summary - if: ${{ steps.pull-request.outputs.pull-request-number }} - run: echo "${{ steps.pull-request.outputs.pull-request-operation}} ${{ steps.pull-request.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/vet.yml b/.github/workflows/vet.yml deleted file mode 100644 index c03190e4f..000000000 --- a/.github/workflows/vet.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: tailscale.com/cmd/vet - -env: - HOME: ${{ github.workspace }} - # 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 - CMD_GO_USE_GIT_HASH: "true" - -on: - push: - branches: - - main - - "release-branch/*" - paths: - - "**.go" - pull_request: - paths: - - "**.go" - -jobs: - vet: - runs-on: [ self-hosted, linux ] - timeout-minutes: 5 - - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - path: src - - - name: Build 'go vet' tool - working-directory: src - run: ./tool/go build -o /tmp/vettool tailscale.com/cmd/vet - - - name: Run 'go vet' - working-directory: src - # Use listpkgs --ignore-3p to skip tempfork/ packages, which - # intentionally match upstream and may not follow our style rules. - # Must use ./... instead of tailscale.com/... because the latter will - # include the v2 go client (tailscale.com/client/tailscale/v2) if it's - # a dependency in our go.mod file. Possibly a go vet bug, but avoid - # cross-repo vetting for now so we can safely add the dependency. - run: ./tool/go vet -vettool=/tmp/vettool $(./tool/go run ./tool/listpkgs --ignore-3p ./...) diff --git a/.github/workflows/webclient.yml b/.github/workflows/webclient.yml deleted file mode 100644 index 1a65eacf5..000000000 --- a/.github/workflows/webclient.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: webclient -on: - workflow_dispatch: - # For now, only run on requests, not the main branches. - pull_request: - paths: - - "client/web/**" - - ".github/workflows/webclient.yml" - - "!**.md" - # TODO(soniaappasamy): enable for main branch after an initial waiting period. - #push: - # branches: - # - main - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - webclient: - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Install deps - run: ./tool/yarn --cwd client/web - - name: Run lint - run: ./tool/yarn --cwd client/web run --silent lint - - name: Run test - run: ./tool/yarn --cwd client/web run --silent test - - name: Run formatter check - run: | - ./tool/yarn --cwd client/web run --silent format-check || ( \ - echo "Run this command on your local device to fix the error:" && \ - echo "" && \ - echo " ./tool/yarn --cwd client/web format" && \ - echo "" && exit 1)