From 540ac650e667ef8e2992f64d6eace5608f3f76cf Mon Sep 17 00:00:00 2001 From: Percy Wegmann Date: Wed, 1 Oct 2025 13:17:36 -0500 Subject: [PATCH] delete original implementation of GitHub action This is in preparation for cherry-picking the new typescript implementation from https://github.com/tailscale/action-setup-tailscale. Updates tailscale/corp#32821 Signed-off-by: Percy Wegmann --- .github/workflows/tailscale.yml | 73 ------ LICENSE | 29 --- README.md | 117 ---------- action.yml | 394 -------------------------------- 4 files changed, 613 deletions(-) delete mode 100644 .github/workflows/tailscale.yml delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 action.yml diff --git a/.github/workflows/tailscale.yml b/.github/workflows/tailscale.yml deleted file mode 100644 index 0b14674..0000000 --- a/.github/workflows/tailscale.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: tailscale - -on: - workflow_dispatch: - push: - branches: - - main - pull_request: - branches: - - '*' - -jobs: - build: - strategy: - matrix: - 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 - - - name: Tailscale Action - uses: ./ - with: - 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/LICENSE b/LICENSE deleted file mode 100644 index 66284d3..0000000 --- a/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2020 Tailscale & AUTHORS. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md deleted file mode 100644 index 7c7873a..0000000 --- a/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# Tailscale GitHub Action - -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 -``` - -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 -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/) - -## 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 -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@v3 - with: - authkey: tskey-auth-... - statedir: /tmp/tailscale-state/ -``` - -## Defining Tailscale version - -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 -``` - -`latest` or `unstable` can also be specified to use the latest stable or unstable version respectively: - -```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 -``` - -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' -``` diff --git a/action.yml b/action.yml deleted file mode 100644 index 88b0c7c..0000000 --- a/action.yml +++ /dev/null @@ -1,394 +0,0 @@ -# Copyright (c) Tailscale Inc & AUTHORS -# SPDX-License-Identifier: BSD-3-Clause -# -name: 'Connect Tailscale' -description: 'Connect your GitHub Action workflow to Tailscale' -branding: - icon: 'arrow-right-circle' - color: 'gray-dark' -inputs: - authkey: - description: 'Your Tailscale authentication key, from the admin panel.' - required: false - deprecationMessage: 'An OAuth API client https://tailscale.com/s/oauth-clients is recommended instead of an authkey' - oauth-client-id: - description: 'Your Tailscale OAuth Client ID.' - required: false - oauth-secret: - description: 'Your Tailscale OAuth Client Secret.' - required: false - tags: - 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 development version.' - required: true - default: '1.88.3' - sha256sum: - description: 'Expected SHA256 checksum of the tarball.' - required: false - default: '' - args: - description: 'Optional additional arguments to `tailscale up`' - required: false - default: '' - tailscaled-args: - description: 'Optional additional arguments to `tailscaled`' - required: false - default: '' - hostname: - 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: - 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' - 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 - 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: - - name: Check Runner OS - if: ${{ runner.os != 'Linux' && runner.os != 'Windows' && runner.os != 'macOS'}} - shell: bash - run: | - 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 == '') }} - shell: bash - 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) - 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 - echo "RESOLVED_VERSION=$RESOLVED_VERSION" >> $GITHUB_ENV - echo "Resolved Tailscale version: $RESOLVED_VERSION" - - name: Set Tailscale Architecture - Linux - if: ${{ runner.os == 'Linux' }} - shell: bash - run: | - if [ ${{ runner.arch }} = "ARM64" ]; then - TS_ARCH="arm64" - elif [ ${{ runner.arch }} = "ARM" ]; then - TS_ARCH="arm" - elif [ ${{ runner.arch }} = "X86" ]; then - TS_ARCH="386" - 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: 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: Restore Tailscale Binary - Linux - if: ${{ inputs.use-cache == 'true' && runner.os == '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.restore-cache-tailscale-linux.outputs.cache-hit != 'true') }} - 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" - else - 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 --retry 3 --retry-all-errors --fail - 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 - - - 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: Restore Tailscale Binary - Windows - if: ${{ inputs.use-cache == 'true' && runner.os == '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.restore-cache-tailscale-windows.outputs.cache-hit != 'true') }} - 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" - else - 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 --retry 3 --retry-all-errors --fail - 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 ${{ 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' }} - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - repository: tailscale/tailscale - path: ${{ github.workspace }}/tailscale - ref: v${{ env.RESOLVED_VERSION }} - - name: Restore Tailscale - macOS - if: ${{ inputs.use-cache == 'true' && runner.os == 'macOS' }} - 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.restore-cache-tailscale-macos.outputs.cache-hit != 'true') }} - 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: 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 - 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 }} - STATEDIR: ${{ inputs.statedir }} - run: | - 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. - sudo -E tailscale status --json >/dev/null - - name: Connect to Tailscale - shell: bash - env: - ADDITIONAL_ARGS: ${{ inputs.args }} - HOSTNAME: ${{ inputs.hostname }} - TAILSCALE_AUTHKEY: ${{ inputs.authkey }} - 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 - 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 }}" - fi - 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 ${PLATFORM_SPECIFIC_ARGS} ${ADDITIONAL_ARGS} && break - 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 was able to connect 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