From 721822aa670491c59ed19739e7023d0fa08f77b7 Mon Sep 17 00:00:00 2001 From: Denton Gentry Date: Wed, 4 Oct 2023 13:31:57 -0700 Subject: [PATCH 01/39] workflow: allow manual testing (#91) We periodically have reports of failures in the GitHub Action where there has been no recent change in Tailscale infrastructure and no indication of a problem in metrics or monitoring. Right now we have to generate a pull request to get this test workflow to run. Allow it to be run manually whenever desired. Signed-off-by: Denton Gentry --- .github/workflows/tailscale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 21a5d0d..3c61eb1 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -1,6 +1,7 @@ name: tailscale on: + workflow_dispatch: push: branches: - main From a5ed86cd4900e943e2aa3f760fd8472f04e46469 Mon Sep 17 00:00:00 2001 From: Denton Gentry Date: Wed, 4 Oct 2023 19:07:50 -0700 Subject: [PATCH 02/39] action.yml: output expected and actual checksum (#92) Updates https://github.com/tailscale/github-action/issues/89 Signed-off-by: Denton Gentry --- action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/action.yml b/action.yml index 4206356..e6d81c4 100644 --- a/action.yml +++ b/action.yml @@ -83,6 +83,8 @@ runs: SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}.sha256")" fi curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 + echo "Expected sha256: $SHA256SUM" + echo "Actual sha256: $(sha256sum tailscale.tgz)" echo "$SHA256SUM tailscale.tgz" | sha256sum -c tar -C /tmp -xzf tailscale.tgz rm tailscale.tgz From 7a0b30ed3517c2244d1330e39467b95f067a33bd Mon Sep 17 00:00:00 2001 From: Jack Pearce <16779171+jkpe@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:56:49 +0000 Subject: [PATCH 03/39] README.md: Add Tailscale version instructions (#98) --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 61a0a40..f66344d 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,17 @@ Nodes created by this Action are [marked as Ephemeral](https://tailscale.com/s/e be automatically removed by the coordination server a short time after they finish their run. The nodes are also [marked Preapproved](https://tailscale.com/kb/1085/auth-keys/) on tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) + +## Defining Tailscale version + +Which Tailscale version to use can be set like this: + +```yaml + - name: Tailscale + uses: tailscale/github-action@v2 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + tags: tag:ci + version: 1.52.0 +``` From 2075411ebb63dbe61f4ae09cfc045949beb9a8d1 Mon Sep 17 00:00:00 2001 From: Andrew Lytvynov Date: Tue, 23 Apr 2024 17:20:03 -0700 Subject: [PATCH 04/39] Fail if curl gets a non-200 response code (#119) If package or SHA download from pkgs.tailscale.com fails with a non-200 repsonse code, make the whole action fail. This catches things like incorrect versions. Updates #118 --- .github/workflows/tailscale.yml | 1 + README.md | 3 +++ action.yml | 5 +++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 3c61eb1..ed28c58 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -22,6 +22,7 @@ jobs: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} tags: tag:ci + version: 1.64.0 - name: check for hello.ts.net in netmap run: diff --git a/README.md b/README.md index f66344d..34c28ba 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,6 @@ Which Tailscale version to use can be set like this: tags: tag:ci version: 1.52.0 ``` + +You can find the latest Tailscale stable version number at +https://pkgs.tailscale.com/stable/#static. diff --git a/action.yml b/action.yml index e6d81c4..7bc7fef 100644 --- a/action.yml +++ b/action.yml @@ -79,10 +79,11 @@ runs: else URL="https://pkgs.tailscale.com/unstable/tailscale_${VERSION}_${TS_ARCH}.tgz" fi + echo "Downloading $URL" + curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 --fail if ! [[ "$SHA256SUM" ]] ; then - SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}.sha256")" + SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}.sha256" --fail)" fi - curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.tgz)" echo "$SHA256SUM tailscale.tgz" | sha256sum -c From 9a386869733c72a34aceccaf68bfafbd445b7936 Mon Sep 17 00:00:00 2001 From: Patrick O'Doherty Date: Tue, 14 May 2024 09:45:22 -0700 Subject: [PATCH 05/39] action.yml: bump tailscale version to 1.66.1 Signed-off-by: Patrick O'Doherty --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 7bc7fef..f7ca295 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use.' required: true - default: '1.42.0' + default: '1.66.1' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From 6ecfb8d7e8bdbfdd874e56d42ecd633cbbb85a1c Mon Sep 17 00:00:00 2001 From: Patrick O'Doherty Date: Wed, 15 May 2024 09:11:42 -0700 Subject: [PATCH 06/39] Correct default_version --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index f7ca295..f3645f7 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use.' required: true - default: '1.66.1' + default: '1.64.2' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From 3efa8e1ffc81daca71c5adbfc5f6bcfb9c95ccb8 Mon Sep 17 00:00:00 2001 From: Patrick O'Doherty Date: Wed, 15 May 2024 13:46:38 -0700 Subject: [PATCH 07/39] Bump release to 1.66.3 --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index f3645f7..a3bbe04 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use.' required: true - default: '1.64.2' + default: '1.66.3' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From 7af1b1f12d86c5c912a534d67a838b9836ae5b25 Mon Sep 17 00:00:00 2001 From: Lee Briggs Date: Sun, 7 Jul 2024 08:57:21 -0700 Subject: [PATCH 08/39] find latest version Signed-off-by: Lee Briggs --- action.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index a3bbe04..0ccd460 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use.' required: true - default: '1.66.3' + default: 'latest' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false @@ -62,6 +62,10 @@ runs: VERSION: ${{ inputs.version }} SHA256SUM: ${{ inputs.sha256sum }} run: | + if [ "$VERSION" = "latest" ]; then + VERSION=$(curl -s https://pkgs.tailscale.com/stable/ | grep -o 'value="[0-9.]*"' | sed 's/value="//;s/"//' | sort -V | tail -n 1) + echo "Latest Tailscale version: $VERSION" + fi if [ ${{ runner.arch }} = "ARM64" ]; then TS_ARCH="arm64" elif [ ${{ runner.arch }} = "ARM" ]; then From 408d716839bb0f8a62018c48edcd5a64bc9d3400 Mon Sep 17 00:00:00 2001 From: Lee Briggs Date: Sun, 7 Jul 2024 09:30:32 -0700 Subject: [PATCH 09/39] don't set default to latest Signed-off-by: Lee Briggs --- action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 0ccd460..1bfc41a 100644 --- a/action.yml +++ b/action.yml @@ -21,9 +21,9 @@ inputs: description: 'Comma separated list of Tags to be applied to nodes. The OAuth client must have permission to apply these tags.' required: false version: - description: 'Tailscale version to use.' + description: 'Tailscale version to use. Specify `latest` to use the latest stable version.' required: true - default: 'latest' + default: '1.66.3' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From 0eefde4707b1200556ed6db619fd2d209d3bad3d Mon Sep 17 00:00:00 2001 From: Lee Briggs Date: Sun, 7 Jul 2024 09:32:46 -0700 Subject: [PATCH 10/39] don't lookup latest version Signed-off-by: Lee Briggs --- action.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/action.yml b/action.yml index 1bfc41a..6231539 100644 --- a/action.yml +++ b/action.yml @@ -62,10 +62,6 @@ runs: VERSION: ${{ inputs.version }} SHA256SUM: ${{ inputs.sha256sum }} run: | - if [ "$VERSION" = "latest" ]; then - VERSION=$(curl -s https://pkgs.tailscale.com/stable/ | grep -o 'value="[0-9.]*"' | sed 's/value="//;s/"//' | sort -V | tail -n 1) - echo "Latest Tailscale version: $VERSION" - fi if [ ${{ runner.arch }} = "ARM64" ]; then TS_ARCH="arm64" elif [ ${{ runner.arch }} = "ARM" ]; then From c688cd1540188ec187964b96578a776c71b98136 Mon Sep 17 00:00:00 2001 From: Lee Briggs Date: Sun, 7 Jul 2024 09:50:18 -0700 Subject: [PATCH 11/39] Revert "don't lookup latest version" This reverts commit 0eefde4707b1200556ed6db619fd2d209d3bad3d. --- action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/action.yml b/action.yml index 6231539..1bfc41a 100644 --- a/action.yml +++ b/action.yml @@ -62,6 +62,10 @@ runs: VERSION: ${{ inputs.version }} SHA256SUM: ${{ inputs.sha256sum }} run: | + if [ "$VERSION" = "latest" ]; then + VERSION=$(curl -s https://pkgs.tailscale.com/stable/ | grep -o 'value="[0-9.]*"' | sed 's/value="//;s/"//' | sort -V | tail -n 1) + echo "Latest Tailscale version: $VERSION" + fi if [ ${{ runner.arch }} = "ARM64" ]; then TS_ARCH="arm64" elif [ ${{ runner.arch }} = "ARM" ]; then From 42b6960a760217c0326b7cc6407b9df558816618 Mon Sep 17 00:00:00 2001 From: Lee Briggs Date: Sun, 7 Jul 2024 09:52:20 -0700 Subject: [PATCH 12/39] update readme Signed-off-by: Lee Briggs --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34c28ba..646f1f6 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ with any of the Users on the tailnet, it has to Tag its nodes. Nodes created by this Action are [marked as Ephemeral](https://tailscale.com/s/ephemeral-nodes) to be automatically removed by the coordination server a short time after they finish their run. The nodes are also [marked Preapproved](https://tailscale.com/kb/1085/auth-keys/) -on tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) +on Tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) ## Defining Tailscale version @@ -41,5 +41,17 @@ Which Tailscale version to use can be set like this: version: 1.52.0 ``` +If you'd like to specify the latest version, simply set the version as `latest` + +```yaml + - name: Tailscale + uses: tailscale/github-action@v2 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + tags: tag:ci + version: latest +``` + You can find the latest Tailscale stable version number at https://pkgs.tailscale.com/stable/#static. From b2b96d3c7f5dc681fa697c2ecfb0749a63e7e1e7 Mon Sep 17 00:00:00 2001 From: Anton Tolchanov Date: Tue, 9 Jul 2024 11:54:01 +0100 Subject: [PATCH 13/39] action.yml: allow specifying a state directory Also, document usage of the action with Tailnet Lock. Fixes #132 Signed-off-by: Anton Tolchanov --- README.md | 20 ++++++++++++++++++++ action.yml | 13 ++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34c28ba..483b0c5 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,26 @@ be automatically removed by the coordination server a short time after they finish their run. The nodes are also [marked Preapproved](https://tailscale.com/kb/1085/auth-keys/) on tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) +## Tailnet Lock + +If you are using this Action in a [Tailnet +Lock](https://tailscale.com/kb/1226/tailnet-lock) enabled network, you need to: + +* Authenticate using an ephemeral reusable [pre-signed auth key]( + https://tailscale.com/kb/1226/tailnet-lock#add-a-node-using-a-pre-signed-auth-key) + rather than an OAuth client. +* Specify a [state directory]( + https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled) for the + client to store the Tailnet Key Authority data in. + +```yaml + - name: Tailscale + uses: tailscale/github-action@v2 + with: + authkey: tskey-auth-... + statedir: /tmp/tailscale-state/ +``` + ## Defining Tailscale version Which Tailscale version to use can be set like this: diff --git a/action.yml b/action.yml index a3bbe04..332cb88 100644 --- a/action.yml +++ b/action.yml @@ -40,6 +40,10 @@ inputs: description: 'Fixed hostname to use.' required: false default: '' + statedir: + description: 'Optional state directory to use (if unset, memory state is used)' + required: false + default: '' runs: using: 'composite' steps: @@ -95,8 +99,15 @@ runs: shell: bash env: ADDITIONAL_DAEMON_ARGS: ${{ inputs.tailscaled-args }} + STATEDIR: ${{ inputs.statedir }} run: | - sudo -E tailscaled --state=mem: ${ADDITIONAL_DAEMON_ARGS} 2>~/tailscaled.log & + if [ "$STATEDIR" == "" ]; then + STATE_ARGS="--state=mem:" + else + STATE_ARGS="--statedir=${STATEDIR}" + mkdir -p "$STATEDIR" + fi + sudo -E tailscaled ${STATE_ARGS} ${ADDITIONAL_DAEMON_ARGS} 2>~/tailscaled.log & # And check that tailscaled came up. The CLI will block for a bit waiting # for it. And --json will make it exit with status 0 even if we're logged # out (as we will be). Without --json it returns an error if we're not up. From eac66e8ca455e895e83315dcd97741e573e852c4 Mon Sep 17 00:00:00 2001 From: Percy Wegmann Date: Wed, 14 Aug 2024 16:28:07 -0500 Subject: [PATCH 14/39] .github/workflows: use default Tailscale version in CI This makes sure that we test with the default version as specified in action.yml Updates #cleanup Signed-off-by: Percy Wegmann --- .github/workflows/tailscale.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index ed28c58..3c61eb1 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -22,7 +22,6 @@ jobs: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} tags: tag:ci - version: 1.64.0 - name: check for hello.ts.net in netmap run: From 57133d573b3443d3f5f2be96fa3dad013378b058 Mon Sep 17 00:00:00 2001 From: Andrea Gottardo Date: Wed, 28 Aug 2024 11:21:17 -0700 Subject: [PATCH 15/39] Bump Tailscale version to v1.72.1 --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 332cb88..1e75d3d 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use.' required: true - default: '1.66.3' + default: '1.72.1' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From 16d7e0b7812f55e668628a71630a09956522baa9 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Mon, 29 Jul 2024 12:03:41 +0800 Subject: [PATCH 16/39] Force timeout during connection --- action.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 1e75d3d..1bcfe73 100644 --- a/action.yml +++ b/action.yml @@ -44,6 +44,10 @@ inputs: description: 'Optional state directory to use (if unset, memory state is used)' required: false default: '' + timeout: + description: 'Timeout for `tailscale up`' + required: false + default: '2m' runs: using: 'composite' steps: @@ -115,9 +119,10 @@ runs: - name: Connect to Tailscale shell: bash env: - TAILSCALE_AUTHKEY: ${{ inputs.authkey }} ADDITIONAL_ARGS: ${{ inputs.args }} HOSTNAME: ${{ inputs.hostname }} + TAILSCALE_AUTHKEY: ${{ inputs.authkey }} + TIMEOUT: ${{ inputs.timeout }} TS_EXPERIMENT_OAUTH_AUTHKEY: true run: | if [ -z "${HOSTNAME}" ]; then @@ -127,4 +132,4 @@ runs: TAILSCALE_AUTHKEY="${{ inputs['oauth-secret'] }}?preauthorized=true&ephemeral=true" TAGS_ARG="--advertise-tags=${{ inputs.tags }}" fi - timeout 5m sudo -E tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} + timeout --verbose --kill-after=1s ${TIMEOUT} sudo -E tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} From 67573e622a7b555a2f4e2078c6ad161201e3e91e Mon Sep 17 00:00:00 2001 From: Naman Sood Date: Thu, 21 Nov 2024 21:16:00 -0500 Subject: [PATCH 17/39] README: add note about required oauth scopes (#144) * README: add note about required oauth scopes Fixes #143. Signed-off-by: Naman Sood * english Signed-off-by: Naman Sood --------- Signed-off-by: Naman Sood --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 483b0c5..6d69900 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ Subsequent steps in the Action can then access nodes in your Tailnet. oauth-client-id and oauth-secret are an [OAuth client](https://tailscale.com/s/oauth-clients/) for the tailnet to be accessed. We recommend storing these as [GitHub Encrypted Secrets.](https://docs.github.com/en/actions/security-guides/encrypted-secrets) +OAuth clients used for this purpose must have the +[`auth_keys` scope.](https://tailscale.com/kb/1215/oauth-clients#scopes) tags is a comma-separated list of one or more [ACL Tags](https://tailscale.com/kb/1068/acl-tags/) for the node. At least one tag is required: an OAuth client is not associated From cb0029737d225a001316554e9b3836eda9ef8614 Mon Sep 17 00:00:00 2001 From: Lee Briggs Date: Thu, 12 Dec 2024 12:36:42 +0000 Subject: [PATCH 18/39] use json api for getting latest version --- README.md | 2 +- action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 646f1f6..057935a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ with any of the Users on the tailnet, it has to Tag its nodes. Nodes created by this Action are [marked as Ephemeral](https://tailscale.com/s/ephemeral-nodes) to be automatically removed by the coordination server a short time after they finish their run. The nodes are also [marked Preapproved](https://tailscale.com/kb/1085/auth-keys/) -on Tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) +on tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) ## Defining Tailscale version diff --git a/action.yml b/action.yml index 1bfc41a..d5c25de 100644 --- a/action.yml +++ b/action.yml @@ -63,7 +63,7 @@ runs: SHA256SUM: ${{ inputs.sha256sum }} run: | if [ "$VERSION" = "latest" ]; then - VERSION=$(curl -s https://pkgs.tailscale.com/stable/ | grep -o 'value="[0-9.]*"' | sed 's/value="//;s/"//' | sort -V | tail -n 1) + VERSION=$(curl -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) echo "Latest Tailscale version: $VERSION" fi if [ ${{ runner.arch }} = "ARM64" ]; then From aef4d1b9e230add42bf6adebd385de7d6ce2b76b Mon Sep 17 00:00:00 2001 From: Keli Velazquez Date: Fri, 13 Dec 2024 09:26:45 -0500 Subject: [PATCH 19/39] action.yml: bump tailscale version to 1.78.1 Updates tailscale/corp#14315 Signed-off-by: Keli Velazquez --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 338da15..a7ff309 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use. Specify `latest` to use the latest stable version.' required: true - default: '1.72.1' + default: '1.78.1' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From 2cbc2550a7562d29eebca62f6d3bf88c424d37d1 Mon Sep 17 00:00:00 2001 From: Nick O'Neill Date: Wed, 18 Dec 2024 13:48:32 -0800 Subject: [PATCH 20/39] add v3 to the readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b7ee7c9..52a29b3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ by adding a step to your workflow. ```yaml - name: Tailscale - uses: tailscale/github-action@v2 + uses: tailscale/github-action@v3 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} @@ -43,7 +43,7 @@ Lock](https://tailscale.com/kb/1226/tailnet-lock) enabled network, you need to: ```yaml - name: Tailscale - uses: tailscale/github-action@v2 + uses: tailscale/github-action@v3 with: authkey: tskey-auth-... statedir: /tmp/tailscale-state/ @@ -55,7 +55,7 @@ Which Tailscale version to use can be set like this: ```yaml - name: Tailscale - uses: tailscale/github-action@v2 + uses: tailscale/github-action@v3 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} @@ -67,7 +67,7 @@ If you'd like to specify the latest version, simply set the version as `latest` ```yaml - name: Tailscale - uses: tailscale/github-action@v2 + uses: tailscale/github-action@v3 with: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} From 5dddea1dff6c23aaec3d62cdcd0fd5d5b2bc93fd Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Thu, 13 Feb 2025 17:17:33 -0700 Subject: [PATCH 21/39] {action.yml,.github}: add support for windows Add support for running the action on windows-based GitHub runners. Updates https://github.com/tailscale/github-action/issues/157 --- .github/workflows/tailscale.yml | 6 ++- action.yml | 66 +++++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 3c61eb1..c1c17ee 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -11,7 +11,10 @@ on: jobs: build: - runs-on: ubuntu-latest + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - name: Check out code uses: actions/checkout@v2 @@ -24,5 +27,6 @@ jobs: tags: tag:ci - name: check for hello.ts.net in netmap + shell: bash run: tailscale status | grep -q hello diff --git a/action.yml b/action.yml index a7ff309..80d8ec2 100644 --- a/action.yml +++ b/action.yml @@ -52,10 +52,10 @@ runs: using: 'composite' steps: - name: Check Runner OS - if: ${{ runner.os != 'Linux' }} + if: ${{ runner.os != 'Linux' && runner.os != 'Windows' }} shell: bash run: | - echo "::error title=⛔ error hint::Support Linux Only" + echo "::error title=⛔ error hint::Support Linux or Windows Only" exit 1 - name: Check Auth Info Empty if: ${{ inputs.authkey == '' && (inputs['oauth-secret'] == '' || inputs.tags == '') }} @@ -63,15 +63,15 @@ runs: run: | echo "::error title=⛔ error hint::OAuth identity empty, Maybe you need to populate it in the Secrets for your workflow, see more in https://docs.github.com/en/actions/security-guides/encrypted-secrets and https://tailscale.com/s/oauth-clients" exit 1 - - name: Download Tailscale + - name: Download Tailscale - Linux + if: ${{ runner.os == 'Linux' }} shell: bash - id: download env: VERSION: ${{ inputs.version }} SHA256SUM: ${{ inputs.sha256sum }} run: | if [ "$VERSION" = "latest" ]; then - VERSION=$(curl -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) + VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) echo "Latest Tailscale version: $VERSION" fi if [ ${{ runner.arch }} = "ARM64" ]; then @@ -80,8 +80,6 @@ runs: TS_ARCH="arm" elif [ ${{ runner.arch }} = "X86" ]; then TS_ARCH="386" - elif [ ${{ runner.arch }} = "X64" ]; then - TS_ARCH="amd64" else TS_ARCH="amd64" fi @@ -103,7 +101,47 @@ runs: rm tailscale.tgz TSPATH=/tmp/tailscale_${VERSION}_${TS_ARCH} sudo mv "${TSPATH}/tailscale" "${TSPATH}/tailscaled" /usr/bin - - name: Start Tailscale Daemon + - name: Download Tailscale - Windows + if: ${{ runner.os == 'Windows' }} + shell: bash + env: + VERSION: ${{ inputs.version }} + SHA256SUM: ${{ inputs.sha256sum }} + run: | + if [ "$VERSION" = "latest" ]; then + VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) + echo "Latest Tailscale version: $VERSION" + fi + if [ ${{ runner.arch }} = "ARM64" ]; then + TS_ARCH="arm64" + elif [ ${{ runner.arch }} = "X86" ]; then + TS_ARCH="x86" + else + TS_ARCH="amd64" + fi + MINOR=$(echo "$VERSION" | awk -F '.' {'print $2'}) + if [ $((MINOR % 2)) -eq 0 ]; then + URL="https://pkgs.tailscale.com/stable/tailscale-setup-${VERSION}-${TS_ARCH}.msi" + else + URL="https://pkgs.tailscale.com/unstable/tailscale-setup-${VERSION}-${TS_ARCH}.msi" + fi + echo "Downloading $URL" + curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.msi --max-time 300 --fail + if ! [[ "$SHA256SUM" ]] ; then + SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}.sha256" --fail)" + fi + echo "Expected sha256: $SHA256SUM" + echo "Actual sha256: $(sha256sum tailscale.msi)" + echo "$SHA256SUM tailscale.msi" | sha256sum -c + - name: Install Tailscale - Windows + if: ${{ runner.os == 'Windows' }} + shell: pwsh + run: | + Start-Process "C:\Windows\System32\msiexec.exe" -Wait -ArgumentList @('/quiet', '/l*v tailscale.log', '/i', 'tailscale.msi') + Add-Content $env:GITHUB_PATH "C:\Program Files\Tailscale\" + Remove-Item tailscale.msi -Force; + - name: Start Tailscale Daemon - Linux + if: ${{ runner.os == 'Linux' }} shell: bash env: ADDITIONAL_DAEMON_ARGS: ${{ inputs.tailscaled-args }} @@ -127,13 +165,19 @@ runs: HOSTNAME: ${{ inputs.hostname }} TAILSCALE_AUTHKEY: ${{ inputs.authkey }} TIMEOUT: ${{ inputs.timeout }} - TS_EXPERIMENT_OAUTH_AUTHKEY: true run: | if [ -z "${HOSTNAME}" ]; then - HOSTNAME="github-$(cat /etc/hostname)" + if [ "${{ runner.os }}" == "Linux" ]; then + HOSTNAME="github-$(cat /etc/hostname)" + elif [ "${{ runner.os }}" == "Windows" ]; then + HOSTNAME="github-$COMPUTERNAME" + fi fi if [ -n "${{ inputs['oauth-secret'] }}" ]; then TAILSCALE_AUTHKEY="${{ inputs['oauth-secret'] }}?preauthorized=true&ephemeral=true" TAGS_ARG="--advertise-tags=${{ inputs.tags }}" fi - timeout --verbose --kill-after=1s ${TIMEOUT} sudo -E tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} + if [ "${{ runner.os }}" == "Linux" ]; then + MAYBE_SUDO="sudo -E" + fi + timeout --verbose --kill-after=1s ${TIMEOUT} ${MAYBE_SUDO} tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} From f0c3dac2f5923212131323444e354f5840acf91b Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Tue, 25 Feb 2025 11:28:30 -0700 Subject: [PATCH 22/39] {action.yml,.github}: add support for macOS Add support for running the action on macOS-based GitHub runners. Updates https://github.com/tailscale/github-action/issues/157 Co-authored-by: Derek Gurchik <602444+gurchik@users.noreply.github.com> --- .github/workflows/tailscale.yml | 2 +- action.yml | 72 +++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index c1c17ee..40fd822 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -13,7 +13,7 @@ jobs: build: strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - name: Check out code diff --git a/action.yml b/action.yml index 80d8ec2..e5f589d 100644 --- a/action.yml +++ b/action.yml @@ -52,10 +52,10 @@ runs: using: 'composite' steps: - name: Check Runner OS - if: ${{ runner.os != 'Linux' && runner.os != 'Windows' }} + if: ${{ runner.os != 'Linux' && runner.os != 'Windows' && runner.os != 'macOS'}} shell: bash run: | - echo "::error title=⛔ error hint::Support Linux or Windows Only" + echo "::error title=⛔ error hint::Support Linux, Windows, and macOS Only" exit 1 - name: Check Auth Info Empty if: ${{ inputs.authkey == '' && (inputs['oauth-secret'] == '' || inputs.tags == '') }} @@ -63,17 +63,23 @@ runs: run: | echo "::error title=⛔ error hint::OAuth identity empty, Maybe you need to populate it in the Secrets for your workflow, see more in https://docs.github.com/en/actions/security-guides/encrypted-secrets and https://tailscale.com/s/oauth-clients" exit 1 + - name: Set Resolved Version + shell: bash + run: | + VERSION=${{ inputs.version }} + if [ "$VERSION" = "latest" ]; then + RESOLVED_VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) + else + RESOLVED_VERSION=$VERSION + fi + echo "RESOLVED_VERSION=$RESOLVED_VERSION" >> $GITHUB_ENV + echo "Resolved Tailscale version: $RESOLVED_VERSION" - name: Download Tailscale - Linux if: ${{ runner.os == 'Linux' }} shell: bash env: - VERSION: ${{ inputs.version }} SHA256SUM: ${{ inputs.sha256sum }} run: | - if [ "$VERSION" = "latest" ]; then - VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) - echo "Latest Tailscale version: $VERSION" - fi if [ ${{ runner.arch }} = "ARM64" ]; then TS_ARCH="arm64" elif [ ${{ runner.arch }} = "ARM" ]; then @@ -83,11 +89,11 @@ runs: else TS_ARCH="amd64" fi - MINOR=$(echo "$VERSION" | awk -F '.' {'print $2'}) + MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) if [ $((MINOR % 2)) -eq 0 ]; then - URL="https://pkgs.tailscale.com/stable/tailscale_${VERSION}_${TS_ARCH}.tgz" + URL="https://pkgs.tailscale.com/stable/tailscale_${RESOLVED_VERSION}_${TS_ARCH}.tgz" else - URL="https://pkgs.tailscale.com/unstable/tailscale_${VERSION}_${TS_ARCH}.tgz" + URL="https://pkgs.tailscale.com/unstable/tailscale_${RESOLVED_VERSION}_${TS_ARCH}.tgz" fi echo "Downloading $URL" curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 --fail @@ -99,19 +105,14 @@ runs: echo "$SHA256SUM tailscale.tgz" | sha256sum -c tar -C /tmp -xzf tailscale.tgz rm tailscale.tgz - TSPATH=/tmp/tailscale_${VERSION}_${TS_ARCH} + TSPATH=/tmp/tailscale_${RESOLVED_VERSION}_${TS_ARCH} sudo mv "${TSPATH}/tailscale" "${TSPATH}/tailscaled" /usr/bin - name: Download Tailscale - Windows if: ${{ runner.os == 'Windows' }} shell: bash env: - VERSION: ${{ inputs.version }} SHA256SUM: ${{ inputs.sha256sum }} run: | - if [ "$VERSION" = "latest" ]; then - VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) - echo "Latest Tailscale version: $VERSION" - fi if [ ${{ runner.arch }} = "ARM64" ]; then TS_ARCH="arm64" elif [ ${{ runner.arch }} = "X86" ]; then @@ -119,11 +120,11 @@ runs: else TS_ARCH="amd64" fi - MINOR=$(echo "$VERSION" | awk -F '.' {'print $2'}) + MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) if [ $((MINOR % 2)) -eq 0 ]; then - URL="https://pkgs.tailscale.com/stable/tailscale-setup-${VERSION}-${TS_ARCH}.msi" + URL="https://pkgs.tailscale.com/stable/tailscale-setup-${RESOLVED_VERSION}-${TS_ARCH}.msi" else - URL="https://pkgs.tailscale.com/unstable/tailscale-setup-${VERSION}-${TS_ARCH}.msi" + URL="https://pkgs.tailscale.com/unstable/tailscale-setup-${RESOLVED_VERSION}-${TS_ARCH}.msi" fi echo "Downloading $URL" curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.msi --max-time 300 --fail @@ -140,8 +141,29 @@ runs: Start-Process "C:\Windows\System32\msiexec.exe" -Wait -ArgumentList @('/quiet', '/l*v tailscale.log', '/i', 'tailscale.msi') Add-Content $env:GITHUB_PATH "C:\Program Files\Tailscale\" Remove-Item tailscale.msi -Force; - - name: Start Tailscale Daemon - Linux - if: ${{ runner.os == 'Linux' }} + - name: Checkout Tailscale repo - macOS + if: ${{ runner.os == 'macOS' }} + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: tailscale/tailscale + path: ${{ github.workspace }}/tailscale + ref: v${{ env.RESOLVED_VERSION }} + - name: Build Tailscale binaries - macOS + if: ${{ runner.os == 'macOS' }} + shell: bash + run: | + cd tailscale + export TS_USE_TOOLCHAIN=1 + ./build_dist.sh ./cmd/tailscale + ./build_dist.sh ./cmd/tailscaled + sudo mv tailscale tailscaled /usr/local/bin + - name: Install timeout - macOS + if: ${{ runner.os == 'macOS' }} + shell: bash + run: + brew install coreutils # for 'timeout' + - name: Start Tailscale Daemon - non-Windows + if: ${{ runner.os != 'Windows' }} shell: bash env: ADDITIONAL_DAEMON_ARGS: ${{ inputs.tailscaled-args }} @@ -167,17 +189,17 @@ runs: TIMEOUT: ${{ inputs.timeout }} run: | if [ -z "${HOSTNAME}" ]; then - if [ "${{ runner.os }}" == "Linux" ]; then - HOSTNAME="github-$(cat /etc/hostname)" - elif [ "${{ runner.os }}" == "Windows" ]; then + if [ "${{ runner.os }}" == "Windows" ]; then HOSTNAME="github-$COMPUTERNAME" + else + HOSTNAME="github-$(hostname)" fi fi if [ -n "${{ inputs['oauth-secret'] }}" ]; then TAILSCALE_AUTHKEY="${{ inputs['oauth-secret'] }}?preauthorized=true&ephemeral=true" TAGS_ARG="--advertise-tags=${{ inputs.tags }}" fi - if [ "${{ runner.os }}" == "Linux" ]; then + if [ "${{ runner.os }}" != "Windows" ]; then MAYBE_SUDO="sudo -E" fi timeout --verbose --kill-after=1s ${TIMEOUT} ${MAYBE_SUDO} tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} From b09fabcbedb41622a8fa97d966388399b1132d19 Mon Sep 17 00:00:00 2001 From: Brian Palmer Date: Tue, 1 Apr 2025 09:05:57 -0600 Subject: [PATCH 23/39] CI: fix the connection check Checking for hello is not the best way to verify that Tailscale is connected, and it recently broke because we stopped giving ephemeral nodes access to hello. Instead, check for connection by parsing the status output as recommended in our KB article https://tailscale.com/kb/1073/hello --- .github/workflows/tailscale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 40fd822..5f85d70 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -26,7 +26,7 @@ jobs: oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} tags: tag:ci - - name: check for hello.ts.net in netmap + - name: check for tailscale connection shell: bash run: - tailscale status | grep -q hello + tailscale status -json | jq -r .BackendState | grep -q Running From b4a7d2da83a9cdeb3ab124f957b0f3d57b74f27b Mon Sep 17 00:00:00 2001 From: kari-ts Date: Mon, 31 Mar 2025 12:42:47 -0700 Subject: [PATCH 24/39] action.yml: bump release to 1.82.0 Signed-off-by: kari-ts --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index e5f589d..cdfe558 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: version: description: 'Tailscale version to use. Specify `latest` to use the latest stable version.' required: true - default: '1.78.1' + default: '1.82.0' sha256sum: description: 'Expected SHA256 checksum of the tarball.' required: false From a31fee8af4449a46f6d4ec478d4def05f1aec649 Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Wed, 2 Apr 2025 13:36:29 -0600 Subject: [PATCH 25/39] .github/workflows: pin GitHub action versions Pin versions of GitHub actions that are used in our workflows. Updates #cleanup Signed-off-by: Mario Minardi --- .github/workflows/tailscale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 5f85d70..4b93970 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Tailscale Action uses: ./ From 694e85d253ba9dd991926d965dbee4ce719e3269 Mon Sep 17 00:00:00 2001 From: jang whoemoon Date: Thu, 3 Apr 2025 12:57:58 +0900 Subject: [PATCH 26/39] Cache tailscale artifact --- action.yml | 58 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/action.yml b/action.yml index cdfe558..213e49e 100644 --- a/action.yml +++ b/action.yml @@ -63,6 +63,7 @@ runs: run: | echo "::error title=⛔ error hint::OAuth identity empty, Maybe you need to populate it in the Secrets for your workflow, see more in https://docs.github.com/en/actions/security-guides/encrypted-secrets and https://tailscale.com/s/oauth-clients" exit 1 + - name: Set Resolved Version shell: bash run: | @@ -74,11 +75,9 @@ runs: fi echo "RESOLVED_VERSION=$RESOLVED_VERSION" >> $GITHUB_ENV echo "Resolved Tailscale version: $RESOLVED_VERSION" - - name: Download Tailscale - Linux + - name: Set Tailscale Architecture - Linux if: ${{ runner.os == 'Linux' }} shell: bash - env: - SHA256SUM: ${{ inputs.sha256sum }} run: | if [ ${{ runner.arch }} = "ARM64" ]; then TS_ARCH="arm64" @@ -89,6 +88,35 @@ runs: else TS_ARCH="amd64" fi + echo "TS_ARCH=$TS_ARCH" >> $GITHUB_ENV + + - name: Set Tailscale Architecture - Windows + if: ${{ runner.os == 'Windows' }} + shell: bash + run: | + if [ ${{ runner.arch }} = "ARM64" ]; then + TS_ARCH="arm64" + elif [ ${{ runner.arch }} = "X86" ]; then + TS_ARCH="x86" + else + TS_ARCH="amd64" + fi + echo "TS_ARCH=$TS_ARCH" >> $GITHUB_ENV + + - name: Cache Tailscale Binary - Linux + if: ${{ runner.os == 'Linux' }} + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: cache-tailscale-linux + with: + path: tailscale.tgz + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }} + + - name: Download Tailscale - Linux + if: ${{ runner.os == 'Linux' && steps.cache-tailscale-linux.outputs.cache-hit != 'true' }} + shell: bash + env: + SHA256SUM: ${{ inputs.sha256sum }} + run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) if [ $((MINOR % 2)) -eq 0 ]; then URL="https://pkgs.tailscale.com/stable/tailscale_${RESOLVED_VERSION}_${TS_ARCH}.tgz" @@ -103,23 +131,29 @@ runs: echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.tgz)" echo "$SHA256SUM tailscale.tgz" | sha256sum -c + + - name: Install Tailscale - Linux + if: ${{ runner.os == 'Linux' }} + shell: bash + run: | tar -C /tmp -xzf tailscale.tgz - rm tailscale.tgz TSPATH=/tmp/tailscale_${RESOLVED_VERSION}_${TS_ARCH} sudo mv "${TSPATH}/tailscale" "${TSPATH}/tailscaled" /usr/bin - - name: Download Tailscale - Windows + + - name: Cache Tailscale Binary - Windows if: ${{ runner.os == 'Windows' }} + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: cache-tailscale-windows + with: + path: tailscale.msi + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }} + + - name: Download Tailscale - Windows + if: ${{ runner.os == 'Windows' && steps.cache-tailscale-windows.outputs.cache-hit != 'true' }} shell: bash env: SHA256SUM: ${{ inputs.sha256sum }} run: | - if [ ${{ runner.arch }} = "ARM64" ]; then - TS_ARCH="arm64" - elif [ ${{ runner.arch }} = "X86" ]; then - TS_ARCH="x86" - else - TS_ARCH="amd64" - fi MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) if [ $((MINOR % 2)) -eq 0 ]; then URL="https://pkgs.tailscale.com/stable/tailscale-setup-${RESOLVED_VERSION}-${TS_ARCH}.msi" From d954cb872744258e6ea1c03f5dabddb8fc94b24e Mon Sep 17 00:00:00 2001 From: jang whoemoon Date: Thu, 3 Apr 2025 13:35:12 +0900 Subject: [PATCH 27/39] Check sha256 checksum for cache --- action.yml | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/action.yml b/action.yml index 213e49e..48e2d06 100644 --- a/action.yml +++ b/action.yml @@ -103,19 +103,35 @@ runs: fi echo "TS_ARCH=$TS_ARCH" >> $GITHUB_ENV + - name: Set SHA256 - Linux + if: ${{ runner.os == 'Linux' }} + shell: bash + run: | + MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) + if [ $((MINOR % 2)) -eq 0 ]; then + URL="https://pkgs.tailscale.com/stable/tailscale_${RESOLVED_VERSION}_${TS_ARCH}.tgz.sha256" + else + URL="https://pkgs.tailscale.com/unstable/tailscale_${RESOLVED_VERSION}_${TS_ARCH}.tgz.sha256" + fi + + if [[ "${{ inputs.sha256sum }}" ]]; then + SHA256SUM="${{ inputs.sha256sum }}" + else + SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}" --fail)" + fi + echo "SHA256SUM=$SHA256SUM" >> $GITHUB_ENV + - name: Cache Tailscale Binary - Linux if: ${{ runner.os == 'Linux' }} uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 id: cache-tailscale-linux with: path: tailscale.tgz - key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }} + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Download Tailscale - Linux if: ${{ runner.os == 'Linux' && steps.cache-tailscale-linux.outputs.cache-hit != 'true' }} shell: bash - env: - SHA256SUM: ${{ inputs.sha256sum }} run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) if [ $((MINOR % 2)) -eq 0 ]; then @@ -125,9 +141,6 @@ runs: fi echo "Downloading $URL" curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 --fail - if ! [[ "$SHA256SUM" ]] ; then - SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}.sha256" --fail)" - fi echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.tgz)" echo "$SHA256SUM tailscale.tgz" | sha256sum -c @@ -140,19 +153,35 @@ runs: TSPATH=/tmp/tailscale_${RESOLVED_VERSION}_${TS_ARCH} sudo mv "${TSPATH}/tailscale" "${TSPATH}/tailscaled" /usr/bin + - name: Set SHA256 - Windows + if: ${{ runner.os == 'Windows' }} + shell: bash + run: | + MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) + if [ $((MINOR % 2)) -eq 0 ]; then + URL="https://pkgs.tailscale.com/stable/tailscale-setup-${RESOLVED_VERSION}-${TS_ARCH}.msi.sha256" + else + URL="https://pkgs.tailscale.com/unstable/tailscale-setup-${RESOLVED_VERSION}-${TS_ARCH}.msi.sha256" + fi + + if [[ "${{ inputs.sha256sum }}" ]]; then + SHA256SUM="${{ inputs.sha256sum }}" + else + SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}" --fail)" + fi + echo "SHA256SUM=$SHA256SUM" >> $GITHUB_ENV + - name: Cache Tailscale Binary - Windows if: ${{ runner.os == 'Windows' }} uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 id: cache-tailscale-windows with: path: tailscale.msi - key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }} + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Download Tailscale - Windows if: ${{ runner.os == 'Windows' && steps.cache-tailscale-windows.outputs.cache-hit != 'true' }} shell: bash - env: - SHA256SUM: ${{ inputs.sha256sum }} run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) if [ $((MINOR % 2)) -eq 0 ]; then @@ -162,9 +191,6 @@ runs: fi echo "Downloading $URL" curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.msi --max-time 300 --fail - if ! [[ "$SHA256SUM" ]] ; then - SHA256SUM="$(curl -H user-agent:tailscale-github-action -L "${URL}.sha256" --fail)" - fi echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.msi)" echo "$SHA256SUM tailscale.msi" | sha256sum -c From 4c25f5bef4497a14496f607cfe729e086d1a62c7 Mon Sep 17 00:00:00 2001 From: twelsh-aw <84401379+twelsh-aw@users.noreply.github.com> Date: Fri, 4 Apr 2025 11:15:42 -0400 Subject: [PATCH 28/39] feat: Add optional caching to skip repeated Tailscale downloads and builds This commit introduces a new `use-cache` input to the Tailscale GitHub Action. When set to `true`, the action will attempt to restore/install Tailscale binaries from a GitHub Actions cache, rather than always downloading or rebuilding them. If the cache is a hit, the download/build steps are skipped, reducing network flakes and speeding up workflows. The default `false` preserves the original behavior, ensuring full backward compatibility. --- action.yml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index 48e2d06..c0b5fad 100644 --- a/action.yml +++ b/action.yml @@ -48,6 +48,10 @@ inputs: description: 'Timeout for `tailscale up`' required: false default: '2m' + use-cache: + description: 'Whether to cache the Tailscale binaries (Linux/macOS) or installer (Windows)' + required: false + default: 'false' runs: using: 'composite' steps: @@ -122,7 +126,7 @@ runs: echo "SHA256SUM=$SHA256SUM" >> $GITHUB_ENV - name: Cache Tailscale Binary - Linux - if: ${{ runner.os == 'Linux' }} + if: ${{ inputs.use-cache == 'true' && runner.os == 'Linux' }} uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 id: cache-tailscale-linux with: @@ -130,7 +134,7 @@ runs: key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Download Tailscale - Linux - if: ${{ runner.os == 'Linux' && steps.cache-tailscale-linux.outputs.cache-hit != 'true' }} + if: ${{ runner.os == 'Linux' && (inputs.use-cache != 'true' || steps.cache-tailscale-linux.outputs.cache-hit != 'true') }} shell: bash run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) @@ -172,7 +176,7 @@ runs: echo "SHA256SUM=$SHA256SUM" >> $GITHUB_ENV - name: Cache Tailscale Binary - Windows - if: ${{ runner.os == 'Windows' }} + if: ${{ inputs.use-cache == 'true' && runner.os == 'Windows' }} uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 id: cache-tailscale-windows with: @@ -180,7 +184,7 @@ runs: key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Download Tailscale - Windows - if: ${{ runner.os == 'Windows' && steps.cache-tailscale-windows.outputs.cache-hit != 'true' }} + if: ${{ runner.os == 'Windows' && (inputs.use-cache != 'true' || steps.cache-tailscale-windows.outputs.cache-hit != 'true') }} shell: bash run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) @@ -202,14 +206,24 @@ runs: Add-Content $env:GITHUB_PATH "C:\Program Files\Tailscale\" Remove-Item tailscale.msi -Force; - name: Checkout Tailscale repo - macOS + id: checkout-tailscale-macos if: ${{ runner.os == 'macOS' }} uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: tailscale/tailscale path: ${{ github.workspace }}/tailscale ref: v${{ env.RESOLVED_VERSION }} + - name: Cache Tailscale - macOS + if: ${{ inputs.use-cache == 'true' && runner.os == 'macOS' }} + id: cache-tailscale-macos + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: | + /usr/local/bin/tailscale + /usr/local/bin/tailscaled + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ runner.arch }}-${{ steps.checkout-tailscale-macos.outputs.commit }} - name: Build Tailscale binaries - macOS - if: ${{ runner.os == 'macOS' }} + if: ${{ runner.os == 'macOS' && (inputs.use-cache != 'true' || steps.cache-tailscale-macos.outputs.cache-hit != 'true') }} shell: bash run: | cd tailscale From 7af7df6221135969d53fc24f9247f48a37a5e5ee Mon Sep 17 00:00:00 2001 From: Whoemoon Jang Date: Mon, 7 Apr 2025 09:06:23 +0900 Subject: [PATCH 29/39] Update `Download Tailscale - Windows` step not to remove tailscale.msi after installation Co-authored-by: Mario Minardi --- action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/action.yml b/action.yml index c0b5fad..45d8b4b 100644 --- a/action.yml +++ b/action.yml @@ -204,7 +204,6 @@ runs: run: | Start-Process "C:\Windows\System32\msiexec.exe" -Wait -ArgumentList @('/quiet', '/l*v tailscale.log', '/i', 'tailscale.msi') Add-Content $env:GITHUB_PATH "C:\Program Files\Tailscale\" - Remove-Item tailscale.msi -Force; - name: Checkout Tailscale repo - macOS id: checkout-tailscale-macos if: ${{ runner.os == 'macOS' }} From 91154e3930aee096df76317b6454ca3bae0d36fc Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Tue, 8 Apr 2025 13:37:06 -0600 Subject: [PATCH 30/39] README.md: document the `use-cache` input Document the `use-cache` input added in https://github.com/tailscale/github-action/pull/166 Updates: https://github.com/tailscale/github-action/issues/87 Signed-off-by: Mario Minardi --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 52a29b3..57d306f 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,19 @@ If you'd like to specify the latest version, simply set the version as `latest` You can find the latest Tailscale stable version number at https://pkgs.tailscale.com/stable/#static. + + +## Cache Tailscale binaries + +Caching can reduce download times and download failures on runners with slower network connectivity. Although caching is not enabled by default, it is generally recommended. + +You can opt in to caching Tailscale binaries by passing `'true'` to the `use-cache` input: + +```yaml + - name: Tailscale + uses: tailscale/github-action@v3 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + use-cache: 'true' +``` From 5d536117a7378beffcd6d8523ce73c50fa98684d Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Wed, 9 Apr 2025 13:41:26 -0600 Subject: [PATCH 31/39] action.yml: properly remove temporary files after downloading Remove `.tgz` and `.msi` files after they have been downloaded. This was the behaviour of the action previous to `v3.2.0`, but our logic for caching removed the deletion of these files. Can look at downloading these to temp folders to avoid the more complex logic here as a follow up, but this should unblock / fix the immediate regression. Also, on Windows, write `tailscale.log` to the temp dir. Also, on MacOS, delete the `tailscale` directory that was used to build the `tailscale(d)` commands. Updates: #170 Co-authored-by: Mario Minardi Signed-off-by: Percy Wegmann --- .github/workflows/tailscale.yml | 12 +++++++ action.yml | 59 +++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 4b93970..48f87ed 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -14,6 +14,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] + cache: ['false', 'true'] runs-on: ${{ matrix.os }} steps: - name: Check out code @@ -25,8 +26,19 @@ jobs: oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} tags: tag:ci + use-cache: ${{ matrix.cache }} - name: check for tailscale connection shell: bash run: tailscale status -json | jq -r .BackendState | grep -q Running + + - name: ensure no dirty files from Tailscale Action remain + shell: bash + run: | + extra_files=$(git ls-files . --exclude-standard --others) + if [ ! -z "$extra_files" ]; then + echo "::error::Unexpected extra files: $extra_files" + exit 1 + fi + diff --git a/action.yml b/action.yml index 45d8b4b..f617813 100644 --- a/action.yml +++ b/action.yml @@ -125,16 +125,16 @@ runs: fi echo "SHA256SUM=$SHA256SUM" >> $GITHUB_ENV - - name: Cache Tailscale Binary - Linux + - name: Restore Tailscale Binary - Linux if: ${{ inputs.use-cache == 'true' && runner.os == 'Linux' }} - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - id: cache-tailscale-linux + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: restore-cache-tailscale-linux with: path: tailscale.tgz key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Download Tailscale - Linux - if: ${{ runner.os == 'Linux' && (inputs.use-cache != 'true' || steps.cache-tailscale-linux.outputs.cache-hit != 'true') }} + if: ${{ runner.os == 'Linux' && (inputs.use-cache != 'true' || steps.restore-cache-tailscale-linux.outputs.cache-hit != 'true') }} shell: bash run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) @@ -148,12 +148,21 @@ runs: echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.tgz)" echo "$SHA256SUM tailscale.tgz" | sha256sum -c + + - name: Save Tailscale Binary - Linux + if: ${{ inputs.use-cache == 'true' && steps.restore-cache-tailscale-linux.outputs.cache-hit != 'true' && runner.os == 'Linux' }} + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: save-cache-tailscale-linux + with: + path: tailscale.tgz + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Install Tailscale - Linux if: ${{ runner.os == 'Linux' }} shell: bash run: | tar -C /tmp -xzf tailscale.tgz + rm tailscale.tgz TSPATH=/tmp/tailscale_${RESOLVED_VERSION}_${TS_ARCH} sudo mv "${TSPATH}/tailscale" "${TSPATH}/tailscaled" /usr/bin @@ -175,16 +184,16 @@ runs: fi echo "SHA256SUM=$SHA256SUM" >> $GITHUB_ENV - - name: Cache Tailscale Binary - Windows + - name: Restore Tailscale Binary - Windows if: ${{ inputs.use-cache == 'true' && runner.os == 'Windows' }} - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - id: cache-tailscale-windows + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: restore-cache-tailscale-windows with: path: tailscale.msi key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} - name: Download Tailscale - Windows - if: ${{ runner.os == 'Windows' && (inputs.use-cache != 'true' || steps.cache-tailscale-windows.outputs.cache-hit != 'true') }} + if: ${{ runner.os == 'Windows' && (inputs.use-cache != 'true' || steps.restore-cache-tailscale-windows.outputs.cache-hit != 'true') }} shell: bash run: | MINOR=$(echo "$RESOLVED_VERSION" | awk -F '.' {'print $2'}) @@ -198,12 +207,22 @@ runs: echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.msi)" echo "$SHA256SUM tailscale.msi" | sha256sum -c + + - name: Save Tailscale Binary - Windows + if: ${{ inputs.use-cache == 'true' && steps.restore-cache-tailscale-windows.outputs.cache-hit != 'true' && runner.os == 'Windows' }} + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: save-cache-tailscale-windows + with: + path: tailscale.msi + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ env.TS_ARCH }}-${{ env.SHA256SUM }} + - name: Install Tailscale - Windows if: ${{ runner.os == 'Windows' }} shell: pwsh run: | - Start-Process "C:\Windows\System32\msiexec.exe" -Wait -ArgumentList @('/quiet', '/l*v tailscale.log', '/i', 'tailscale.msi') + Start-Process "C:\Windows\System32\msiexec.exe" -Wait -ArgumentList @('/quiet', '/l*v ${{ runner.temp }}/tailscale.log', '/i', 'tailscale.msi') Add-Content $env:GITHUB_PATH "C:\Program Files\Tailscale\" + Remove-Item tailscale.msi -Force; - name: Checkout Tailscale repo - macOS id: checkout-tailscale-macos if: ${{ runner.os == 'macOS' }} @@ -212,17 +231,17 @@ runs: repository: tailscale/tailscale path: ${{ github.workspace }}/tailscale ref: v${{ env.RESOLVED_VERSION }} - - name: Cache Tailscale - macOS + - name: Restore Tailscale - macOS if: ${{ inputs.use-cache == 'true' && runner.os == 'macOS' }} - id: cache-tailscale-macos - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + id: restore-cache-tailscale-macos + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: | /usr/local/bin/tailscale /usr/local/bin/tailscaled key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ runner.arch }}-${{ steps.checkout-tailscale-macos.outputs.commit }} - name: Build Tailscale binaries - macOS - if: ${{ runner.os == 'macOS' && (inputs.use-cache != 'true' || steps.cache-tailscale-macos.outputs.cache-hit != 'true') }} + if: ${{ runner.os == 'macOS' && (inputs.use-cache != 'true' || steps.restore-cache-tailscale-macos.outputs.cache-hit != 'true') }} shell: bash run: | cd tailscale @@ -230,6 +249,20 @@ runs: ./build_dist.sh ./cmd/tailscale ./build_dist.sh ./cmd/tailscaled sudo mv tailscale tailscaled /usr/local/bin + - name: Remove tailscale checkout - macOS + if: ${{ runner.os == 'macOS' }} + shell: bash + run: | + rm -Rf ${{ github.workspace }}/tailscale + - name: Save Tailscale - macOS + if: ${{ inputs.use-cache == 'true' && runner.os == 'macOS' }} + id: save-cache-tailscale-macos + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: | + /usr/local/bin/tailscale + /usr/local/bin/tailscaled + key: ${{ runner.os }}-tailscale-${{ env.RESOLVED_VERSION }}-${{ runner.arch }}-${{ steps.checkout-tailscale-macos.outputs.commit }} - name: Install timeout - macOS if: ${{ runner.os == 'macOS' }} shell: bash From 029c99af76d53fa362a1168429bcb3aff9793c45 Mon Sep 17 00:00:00 2001 From: mcoulombe Date: Fri, 23 May 2025 15:16:17 -0400 Subject: [PATCH 32/39] action: add retry on tailscale up to make the action more reliable Updates #177 Signed-off-by: mcoulombe Co-authored-by: andrea-armstrong * make retries configurable * switch to c-style for loop --- action.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index f617813..5ccc757 100644 --- a/action.yml +++ b/action.yml @@ -48,6 +48,10 @@ inputs: description: 'Timeout for `tailscale up`' required: false default: '2m' + retry: + description: 'Number of retries for `tailscale up`' + required: false + default: '5' use-cache: description: 'Whether to cache the Tailscale binaries (Linux/macOS) or installer (Windows)' required: false @@ -293,6 +297,7 @@ runs: HOSTNAME: ${{ inputs.hostname }} TAILSCALE_AUTHKEY: ${{ inputs.authkey }} TIMEOUT: ${{ inputs.timeout }} + RETRY: ${{ inputs.retry }} run: | if [ -z "${HOSTNAME}" ]; then if [ "${{ runner.os }}" == "Windows" ]; then @@ -308,4 +313,9 @@ runs: if [ "${{ runner.os }}" != "Windows" ]; then MAYBE_SUDO="sudo -E" fi - timeout --verbose --kill-after=1s ${TIMEOUT} ${MAYBE_SUDO} tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} + for ((i=1;i<=$RETRY;i++)); do + echo "Attempt $i to bring up Tailscale..." + timeout --verbose --kill-after=1s ${TIMEOUT} ${MAYBE_SUDO} tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} && break + echo "Tailscale up failed. Retrying in $((i * 5)) seconds..." + sleep $((i * 5)) + done From 8fe6f78f60376ad69bd035d1d3d5cae8a7b085d1 Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Mon, 23 Jun 2025 10:07:15 -0600 Subject: [PATCH 33/39] {.github/workflows,action.yml}: run windows in unattended mode Add the `--unattended` flag when running the action on windows-based machines. This allows the action to properly connect on windows machines that do not have full GUI support under the hood (e.g., for the current batch of `windows-11-arm` runners). Fixes https://github.com/tailscale/github-action/issues/180 Signed-off-by: Mario Minardi --- .github/workflows/tailscale.yml | 2 +- action.yml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index 48f87ed..aaa128e 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -13,7 +13,7 @@ jobs: build: strategy: matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest, macos-latest, windows-11-arm] cache: ['false', 'true'] runs-on: ${{ matrix.os }} steps: diff --git a/action.yml b/action.yml index 5ccc757..26bcf45 100644 --- a/action.yml +++ b/action.yml @@ -313,9 +313,12 @@ runs: if [ "${{ runner.os }}" != "Windows" ]; then MAYBE_SUDO="sudo -E" fi + if [ "${{ runner.os }}" == "Windows" ]; then + PLATFORM_SPECIFIC_ARGS="--unattended" + fi for ((i=1;i<=$RETRY;i++)); do echo "Attempt $i to bring up Tailscale..." - timeout --verbose --kill-after=1s ${TIMEOUT} ${MAYBE_SUDO} tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${ADDITIONAL_ARGS} && break + timeout --verbose --kill-after=1s ${TIMEOUT} ${MAYBE_SUDO} tailscale up ${TAGS_ARG} --authkey=${TAILSCALE_AUTHKEY} --hostname=${HOSTNAME} --accept-routes ${PLATFORM_SPECIFIC_ARGS} ${ADDITIONAL_ARGS} && break echo "Tailscale up failed. Retrying in $((i * 5)) seconds..." sleep $((i * 5)) done From c66619accfddcb61845cab86ac1342aac357c389 Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Fri, 4 Jul 2025 10:17:47 -0600 Subject: [PATCH 34/39] .github/workflows: add tests for new / granular minimal OAuth scopes Change the default matrix test to use an OAuth client which has the new set of more granular minimal OAuth scopes necessary to successfully use the action. Add a new job that uses the previous OAuth client to ensure that we don't break legacy clients. Fixes https://github.com/tailscale/github-action/issues/184 Signed-off-by: Mario Minardi --- .github/workflows/tailscale.yml | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml index aaa128e..0b14674 100644 --- a/.github/workflows/tailscale.yml +++ b/.github/workflows/tailscale.yml @@ -16,6 +16,36 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, windows-11-arm] cache: ['false', 'true'] runs-on: ${{ matrix.os }} + steps: + - name: Check out code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Tailscale Action + uses: ./ + with: + oauth-client-id: ${{ secrets.TS_OAUTH_GRANULAR_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_GRANULAR_SECRET }} + tags: tag:ci + use-cache: ${{ matrix.cache }} + + - name: check for tailscale connection + shell: bash + run: + tailscale status -json | jq -r .BackendState | grep -q Running + + - name: ensure no dirty files from Tailscale Action remain + shell: bash + run: | + extra_files=$(git ls-files . --exclude-standard --others) + if [ ! -z "$extra_files" ]; then + echo "::error::Unexpected extra files: $extra_files" + exit 1 + fi + + # This job runs as a sanity check to ensure we have not broken the ability for OAuth clients using + # our legacy scopes to successfully connect to tailnets using this action. + legacyScopesCheck: + runs-on: ubuntu-latest steps: - name: Check out code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -41,4 +71,3 @@ jobs: echo "::error::Unexpected extra files: $extra_files" exit 1 fi - From c7fc043ee07dd665bc66af1496a498934ca512a5 Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Sun, 24 Aug 2025 01:13:42 +0900 Subject: [PATCH 35/39] Support `unstable` version alias Signed-off-by: Koichi Shiraishi --- action.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 26bcf45..454c639 100644 --- a/action.yml +++ b/action.yml @@ -21,7 +21,7 @@ inputs: description: 'Comma separated list of Tags to be applied to nodes. The OAuth client must have permission to apply these tags.' required: false version: - description: 'Tailscale version to use. Specify `latest` to use the latest stable version.' + description: 'Tailscale version to use. Specify `latest` to use the latest stable version, and `unstable` to use the latest unstable version.' required: true default: '1.82.0' sha256sum: @@ -78,6 +78,8 @@ runs: VERSION=${{ inputs.version }} if [ "$VERSION" = "latest" ]; then RESOLVED_VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/stable/?mode=json" | jq -r .Version) + elif [ "$VERSION" = "unstable" ]; then + RESOLVED_VERSION=$(curl -H user-agent:tailscale-github-action -s "https://pkgs.tailscale.com/unstable/?mode=json" | jq -r .Version) else RESOLVED_VERSION=$VERSION fi From 59c4d745754d29e42a50a93d250c8a452cda5c80 Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Sun, 24 Aug 2025 01:30:24 +0900 Subject: [PATCH 36/39] Fix inputs.version.description Signed-off-by: Koichi Shiraishi --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 454c639..31ae3bd 100644 --- a/action.yml +++ b/action.yml @@ -21,7 +21,7 @@ inputs: description: 'Comma separated list of Tags to be applied to nodes. The OAuth client must have permission to apply these tags.' required: false version: - description: 'Tailscale version to use. Specify `latest` to use the latest stable version, and `unstable` to use the latest unstable version.' + description: 'Tailscale version to use. Specify `latest` to use the latest stable version, and `unstable` to use the latest development version.' required: true default: '1.82.0' sha256sum: From dc4930bf3866fec98936c4a82eb23f90cc58d799 Mon Sep 17 00:00:00 2001 From: mcoulombe Date: Tue, 23 Sep 2025 14:09:54 -0400 Subject: [PATCH 37/39] action: auto-sanitize default or error on invalid user-defined hostname Fixes #192 --- action.yml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 31ae3bd..7076d5a 100644 --- a/action.yml +++ b/action.yml @@ -37,7 +37,7 @@ inputs: required: false default: '' hostname: - description: 'Fixed hostname to use.' + description: 'Fixed hostname to use. Must be a valid DNS label (alphanumeric and dashes only, 1-63 characters, cannot start or end with a dash). If not provided, a hostname will be generated based on the runner name.' required: false default: '' statedir: @@ -301,13 +301,42 @@ runs: TIMEOUT: ${{ inputs.timeout }} RETRY: ${{ inputs.retry }} run: | + sanitize_hostname() { + local hostname="$1" + hostname=$(echo "$hostname" | sed 's/[^a-zA-Z0-9-]/-/g') # Replace invalid characters with dashes + hostname=$(echo "$hostname" | cut -c1-63) # Truncate to 63 characters maximum + hostname=$(echo "$hostname" | sed 's/^-*//;s/-*$//') # Remove leading/trailing dashes + echo "$hostname" + } + + is_valid_dns_label() { + local hostname="$1" + if [ ${#hostname} -eq 0 ] || [ ${#hostname} -gt 63 ]; then # Check length (1-63 characters) + return 1 + fi + if ! echo "$hostname" | grep -qE '^[a-zA-Z0-9-]+$'; then # Check for valid characters (alphanumeric and dashes only) + return 1 + fi + if echo "$hostname" | grep -qE '^-|-$'; then # Check that it doesn't start or end with dash + return 1 + fi + return 0 + } + if [ -z "${HOSTNAME}" ]; then if [ "${{ runner.os }}" == "Windows" ]; then HOSTNAME="github-$COMPUTERNAME" - else + else HOSTNAME="github-$(hostname)" fi + HOSTNAME=$(sanitize_hostname "$HOSTNAME") + else + if ! is_valid_dns_label "$HOSTNAME"; then + echo "::error::HOSTNAME '$HOSTNAME' is not a valid DNS label. It should contain only alphanumeric characters and dashes, be 1-63 characters long, and not start or end with a dash." + exit 1 + fi fi + if [ -n "${{ inputs['oauth-secret'] }}" ]; then TAILSCALE_AUTHKEY="${{ inputs['oauth-secret'] }}?preauthorized=true&ephemeral=true" TAGS_ARG="--advertise-tags=${{ inputs.tags }}" From 3eef1cc07c30596963de6fbac00d1276f92bd6a3 Mon Sep 17 00:00:00 2001 From: mcoulombe Date: Fri, 12 Sep 2025 16:51:45 -0400 Subject: [PATCH 38/39] + added argument to test target connectivity Update action.yml Co-authored-by: Mario Minardi --- README.md | 84 ++++++++++++++++++++++++++++++++++-------------------- action.yml | 43 ++++++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 57d306f..2fa51b8 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ This GitHub Action connects to your [Tailscale network](https://tailscale.com) by adding a step to your workflow. ```yaml - - name: Tailscale - uses: tailscale/github-action@v3 - with: - oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} - oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} - tags: tag:ci +- name: Tailscale + uses: tailscale/github-action@v3 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + tags: tag:ci ``` Subsequent steps in the Action can then access nodes in your Tailnet. @@ -29,6 +29,28 @@ be automatically removed by the coordination server a short time after they finish their run. The nodes are also [marked Preapproved](https://tailscale.com/kb/1085/auth-keys/) on tailnets which use [Device Approval](https://tailscale.com/kb/1099/device-approval/) +## Eventual consistency + +Propagating information about new peers - such as the node created by this action - across your tailnet +is an eventually consistent process, and brief delays are expected. Until the GitHub workflow node +becomes visible, other peers will not accept connections. It is best to verify connectivity to the +intended nodes before executing steps that rely on them. + +You can do this by adding a list of targets to the action configuration: + +```yaml +- name: Tailscale + uses: tailscale/github-action@v3 + with: + targets: 100.x.y.z,my-machine.my-tailnet.ts.net +``` + +or with the [tailscale ping](https://tailscale.com/kb/1080/cli#ping) command if you do not know the targets at the time of installing Tailscale in the workflow: + +```bash +tailscale ping my-target.my-tailnet.ts.net +``` + ## Tailnet Lock If you are using this Action in a [Tailnet @@ -42,11 +64,11 @@ Lock](https://tailscale.com/kb/1226/tailnet-lock) enabled network, you need to: client to store the Tailnet Key Authority data in. ```yaml - - name: Tailscale - uses: tailscale/github-action@v3 - with: - authkey: tskey-auth-... - statedir: /tmp/tailscale-state/ +- name: Tailscale + uses: tailscale/github-action@v3 + with: + authkey: tskey-auth-... + statedir: /tmp/tailscale-state/ ``` ## Defining Tailscale version @@ -54,25 +76,25 @@ Lock](https://tailscale.com/kb/1226/tailnet-lock) enabled network, you need to: Which Tailscale version to use can be set like this: ```yaml - - name: Tailscale - uses: tailscale/github-action@v3 - with: - oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} - oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} - tags: tag:ci - version: 1.52.0 +- name: Tailscale + uses: tailscale/github-action@v3 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + tags: tag:ci + version: 1.52.0 ``` If you'd like to specify the latest version, simply set the version as `latest` ```yaml - - name: Tailscale - uses: tailscale/github-action@v3 - with: - oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} - oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} - tags: tag:ci - version: latest +- name: Tailscale + uses: tailscale/github-action@v3 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + tags: tag:ci + version: latest ``` You can find the latest Tailscale stable version number at @@ -86,10 +108,10 @@ Caching can reduce download times and download failures on runners with slower n You can opt in to caching Tailscale binaries by passing `'true'` to the `use-cache` input: ```yaml - - name: Tailscale - uses: tailscale/github-action@v3 - with: - oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} - oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} - use-cache: 'true' +- name: Tailscale + uses: tailscale/github-action@v3 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + use-cache: 'true' ``` diff --git a/action.yml b/action.yml index 7076d5a..f678897 100644 --- a/action.yml +++ b/action.yml @@ -56,6 +56,10 @@ inputs: description: 'Whether to cache the Tailscale binaries (Linux/macOS) or installer (Windows)' required: false default: 'false' + targets: + description: 'Comma separated list of targets (Tailscale IP addresses or machine names if MagicDNS is enabled on the tailnet) to `tailscale ping` for connectivity verification after `tailscale up` completes' + required: false + default: '' runs: using: 'composite' steps: @@ -150,7 +154,7 @@ runs: URL="https://pkgs.tailscale.com/unstable/tailscale_${RESOLVED_VERSION}_${TS_ARCH}.tgz" fi echo "Downloading $URL" - curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 --fail + curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.tgz --max-time 300 --retry 3 --retry-all-errors --fail echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.tgz)" echo "$SHA256SUM tailscale.tgz" | sha256sum -c @@ -209,7 +213,7 @@ runs: URL="https://pkgs.tailscale.com/unstable/tailscale-setup-${RESOLVED_VERSION}-${TS_ARCH}.msi" fi echo "Downloading $URL" - curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.msi --max-time 300 --fail + curl -H user-agent:tailscale-github-action -L "$URL" -o tailscale.msi --max-time 300 --retry 3 --retry-all-errors --fail echo "Expected sha256: $SHA256SUM" echo "Actual sha256: $(sha256sum tailscale.msi)" echo "$SHA256SUM tailscale.msi" | sha256sum -c @@ -353,3 +357,38 @@ runs: echo "Tailscale up failed. Retrying in $((i * 5)) seconds..." sleep $((i * 5)) done + - name: Verify Target Connectivity + if: ${{ inputs.targets != '' }} + shell: bash + env: + TARGETS: ${{ inputs.targets }} + run: | + IFS=',' read -ra TARGET_ARRAY <<< "$TARGETS" + + if [ "${{ runner.os }}" != "Windows" ]; then + MAYBE_SUDO="sudo -E" + fi + + failed_targets=() + for target in "${TARGET_ARRAY[@]}"; do + target=$(echo "$target" | xargs) # trim whitespace + if [ -n "$target" ]; then + output=$(${MAYBE_SUDO} tailscale ping --c=36 $target 2>&1) + exit_code=$? + + if [ $exit_code -eq 0 ]; then + echo "Successfully reached $target" + elif echo "$output" | grep -q "direct connection not established"; then + echo "::warning title=Target Connectivity Warning::Failed to establish direct connection to $target, but connection may still work via DERP" + else + # Regular failure case + echo "Failed to reach $target" + failed_targets+=("$target") + fi + fi + done + + if [ ${#failed_targets[@]} -gt 0 ]; then + echo "::error title=Target Connectivity Failed::Failed to reach the following targets: ${failed_targets[*]}" + exit 1 + fi From 2208a5a58b38b9571b0c01b362502f331e307268 Mon Sep 17 00:00:00 2001 From: Max Coulombe Date: Thu, 25 Sep 2025 11:40:17 -0400 Subject: [PATCH 39/39] Update action.yml Co-authored-by: Mario Minardi --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index f678897..ba92d07 100644 --- a/action.yml +++ b/action.yml @@ -379,7 +379,7 @@ runs: if [ $exit_code -eq 0 ]; then echo "Successfully reached $target" elif echo "$output" | grep -q "direct connection not established"; then - echo "::warning title=Target Connectivity Warning::Failed to establish direct connection to $target, but connection may still work via DERP" + echo "::warning title=Target Connectivity Warning::Failed to establish direct connection to $target but was able to connect via DERP" else # Regular failure case echo "Failed to reach $target"