From 0fe93f5558fac06d1877061138b307d85b54533d Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Fri, 19 Dec 2025 15:04:26 -0800 Subject: [PATCH 01/10] feat(action.yml): add caching option for Twingate .deb packages to speed up installation process --- action.yml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 03a75b3..021acf6 100644 --- a/action.yml +++ b/action.yml @@ -11,6 +11,10 @@ inputs: description: 'Enable debug output' required: false default: "false" + cache: + description: 'Enable caching of Twingate .deb packages to speed up installation' + required: false + default: "true" runs: using: "composite" steps: @@ -21,8 +25,33 @@ runs: echo "Unsupported Runner OS: ${{ runner.os }}" exit 1 - - name: Install Twingate (Linux) - if: runner.os == 'Linux' + - name: Cache Twingate package + if: runner.os == 'Linux' && inputs.cache == 'true' + uses: actions/cache@v4 + id: cache-twingate + with: + path: /tmp/twingate-cache + key: twingate-deb-${{ runner.os }}-${{ runner.arch }} + + - name: Download Twingate package (Linux) + if: runner.os == 'Linux' && inputs.cache == 'true' && steps.cache-twingate.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p /tmp/twingate-cache + echo "deb [trusted=yes] https://packages.twingate.com/apt/ /" | sudo tee /etc/apt/sources.list.d/twingate.list + sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/twingate.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" + cd /tmp/twingate-cache + apt-get download twingate + + - name: Install Twingate from cache (Linux) + if: runner.os == 'Linux' && inputs.cache == 'true' + shell: bash + run: | + sudo dpkg -i /tmp/twingate-cache/twingate*.deb || true + sudo apt-get install -f -yq + + - name: Install Twingate without cache (Linux) + if: runner.os == 'Linux' && inputs.cache != 'true' shell: bash run: | sudo apt update From 5b3151a71a60e4c3de7339d828c32623fc8ea879 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Fri, 19 Dec 2025 15:31:48 -0800 Subject: [PATCH 02/10] chore(action.yml): update actions/cache from v4 to v5 for improved caching functionality --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 021acf6..21102df 100644 --- a/action.yml +++ b/action.yml @@ -27,7 +27,7 @@ runs: - name: Cache Twingate package if: runner.os == 'Linux' && inputs.cache == 'true' - uses: actions/cache@v4 + uses: actions/cache@v5 id: cache-twingate with: path: /tmp/twingate-cache From 9d5d4444d1f4330cea60ccbf461bcd24185db785 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Fri, 19 Dec 2025 16:43:56 -0800 Subject: [PATCH 03/10] feat(action.yml): add step to fetch latest Twingate version for caching logic improvement --- action.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 21102df..c61a2b8 100644 --- a/action.yml +++ b/action.yml @@ -25,13 +25,22 @@ runs: echo "Unsupported Runner OS: ${{ runner.os }}" exit 1 + - name: Get latest Twingate version + if: runner.os == 'Linux' && inputs.cache == 'true' + id: twingate-version + shell: bash + run: | + VERSION=$(curl -s https://packages.twingate.com/apt/Packages | awk '/^Version:/ {print $2}' | sort -V | tail -1) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Latest Twingate version: $VERSION" + - name: Cache Twingate package if: runner.os == 'Linux' && inputs.cache == 'true' uses: actions/cache@v5 id: cache-twingate with: path: /tmp/twingate-cache - key: twingate-deb-${{ runner.os }}-${{ runner.arch }} + key: twingate-deb-${{ runner.os }}-${{ runner.arch }}-${{ steps.twingate-version.outputs.version }} - name: Download Twingate package (Linux) if: runner.os == 'Linux' && inputs.cache == 'true' && steps.cache-twingate.outputs.cache-hit != 'true' From c3d1b05e87051c1722a5410df04e0784f0be8e58 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Fri, 19 Dec 2025 16:49:43 -0800 Subject: [PATCH 04/10] feat(action.yml): add caching and version retrieval for Twingate installer on Windows to optimize installation process --- action.yml | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index c61a2b8..578cfc0 100644 --- a/action.yml +++ b/action.yml @@ -113,12 +113,43 @@ runs: exit 1 fi - - name: Install and Start Twingate (Windows) - if: runner.os == 'Windows' + - name: Get latest Twingate version (Windows) + if: runner.os == 'Windows' && inputs.cache == 'true' + id: twingate-version-windows + shell: powershell + run: | + $response = Invoke-WebRequest -Uri "https://api.twingate.com/download/windows?installer=msi" -MaximumRedirection 0 -ErrorAction SilentlyContinue + $location = $response.Headers.Location + if ($location -match '/versions/([^/]+)/') { + $version = $matches[1] + echo "version=$version" >> $env:GITHUB_OUTPUT + Write-Host "Latest Twingate version: $version" + } + + - name: Cache Twingate package (Windows) + if: runner.os == 'Windows' && inputs.cache == 'true' + uses: actions/cache@v5 + id: cache-twingate-windows + with: + path: twingate_client.msi + key: twingate-msi-${{ runner.os }}-${{ runner.arch }}-${{ steps.twingate-version-windows.outputs.version }} + + - name: Download Twingate installer (Windows) + if: runner.os == 'Windows' && inputs.cache == 'true' && steps.cache-twingate-windows.outputs.cache-hit != 'true' shell: powershell run: | Invoke-WebRequest https://api.twingate.com/download/windows?installer=msi -OutFile .\twingate_client.msi + - name: Download Twingate installer without cache (Windows) + if: runner.os == 'Windows' && inputs.cache != 'true' + shell: powershell + run: | + Invoke-WebRequest https://api.twingate.com/download/windows?installer=msi -OutFile .\twingate_client.msi + + - name: Install and Start Twingate (Windows) + if: runner.os == 'Windows' + shell: powershell + run: | Set-Content .\key.json '${{ inputs.service-key }}' $key_path = (Get-Item .\key.json | Resolve-Path).ProviderPath From ab74c5580eaf6659156890a17e11120caf17c668 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Fri, 19 Dec 2025 16:57:53 -0800 Subject: [PATCH 05/10] Windows cache --- action.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/action.yml b/action.yml index 578cfc0..1ec924a 100644 --- a/action.yml +++ b/action.yml @@ -43,9 +43,10 @@ runs: key: twingate-deb-${{ runner.os }}-${{ runner.arch }}-${{ steps.twingate-version.outputs.version }} - name: Download Twingate package (Linux) - if: runner.os == 'Linux' && inputs.cache == 'true' && steps.cache-twingate.outputs.cache-hit != 'true' + if: runner.os == 'Linux' && steps.cache-twingate.outputs.cache-hit != 'true' shell: bash run: | + echo "No cache - creating cache folder" mkdir -p /tmp/twingate-cache echo "deb [trusted=yes] https://packages.twingate.com/apt/ /" | sudo tee /etc/apt/sources.list.d/twingate.list sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/twingate.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" @@ -56,17 +57,9 @@ runs: if: runner.os == 'Linux' && inputs.cache == 'true' shell: bash run: | + echo "Installing Twingate from cache" sudo dpkg -i /tmp/twingate-cache/twingate*.deb || true sudo apt-get install -f -yq - - - name: Install Twingate without cache (Linux) - if: runner.os == 'Linux' && inputs.cache != 'true' - shell: bash - run: | - sudo apt update - echo "deb [trusted=yes] https://packages.twingate.com/apt/ /" | sudo tee /etc/apt/sources.list.d/twingate.list - sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/twingate.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" - sudo apt install -yq twingate - name: Setup and start Twingate (Linux) if: runner.os == 'Linux' From 12d349ec691b33dbc95c2a67465382e124786e90 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Fri, 19 Dec 2025 17:01:20 -0800 Subject: [PATCH 06/10] fix windows --- action.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/action.yml b/action.yml index 1ec924a..4e99e33 100644 --- a/action.yml +++ b/action.yml @@ -111,12 +111,20 @@ runs: id: twingate-version-windows shell: powershell run: | - $response = Invoke-WebRequest -Uri "https://api.twingate.com/download/windows?installer=msi" -MaximumRedirection 0 -ErrorAction SilentlyContinue - $location = $response.Headers.Location - if ($location -match '/versions/([^/]+)/') { - $version = $matches[1] - echo "version=$version" >> $env:GITHUB_OUTPUT - Write-Host "Latest Twingate version: $version" + try { + $response = Invoke-WebRequest -Uri "https://api.twingate.com/download/windows?installer=msi" -Method Head -MaximumRedirection 0 -ErrorAction Ignore + if ($response -and $response.Headers -and $response.Headers.Location) { + $location = $response.Headers.Location + if ($location -match '/versions/([^/]+)/') { + $version = $matches[1] + echo "version=$version" >> $env:GITHUB_OUTPUT + Write-Host "Latest Twingate version: $version" + } + } else { + Write-Host "Warning: Could not determine version from redirect" + } + } catch { + Write-Host "Warning: Error checking version - $($_.Exception.Message)" } - name: Cache Twingate package (Windows) From c123f3ea21a2b4b0ba472c37a84560b365e316b5 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Sat, 20 Dec 2025 20:29:13 -0800 Subject: [PATCH 07/10] fix win --- action.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/action.yml b/action.yml index 4e99e33..a0166bf 100644 --- a/action.yml +++ b/action.yml @@ -112,19 +112,22 @@ runs: shell: powershell run: | try { - $response = Invoke-WebRequest -Uri "https://api.twingate.com/download/windows?installer=msi" -Method Head -MaximumRedirection 0 -ErrorAction Ignore - if ($response -and $response.Headers -and $response.Headers.Location) { - $location = $response.Headers.Location + $response = Invoke-WebRequest -Uri "https://api.twingate.com/download/windows?installer=msi" -Method Head -MaximumRedirection 0 -ErrorAction Stop + } catch { + # When MaximumRedirection is 0, redirects cause an exception + # The redirect location is in the exception response + if ($_.Exception.Response -and $_.Exception.Response.Headers -and $_.Exception.Response.Headers.Location) { + $location = $_.Exception.Response.Headers.Location if ($location -match '/versions/([^/]+)/') { $version = $matches[1] echo "version=$version" >> $env:GITHUB_OUTPUT Write-Host "Latest Twingate version: $version" + } else { + Write-Host "Warning: Could not parse version from redirect location: $location" } } else { - Write-Host "Warning: Could not determine version from redirect" + Write-Host "Warning: Error checking version - $($_.Exception.Message)" } - } catch { - Write-Host "Warning: Error checking version - $($_.Exception.Message)" } - name: Cache Twingate package (Windows) From bc2e5ab946b43b2ac675c30fa42e905367b33d9d Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Sat, 20 Dec 2025 20:32:37 -0800 Subject: [PATCH 08/10] nicer powershell code --- action.yml | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/action.yml b/action.yml index a0166bf..31f7932 100644 --- a/action.yml +++ b/action.yml @@ -111,24 +111,41 @@ runs: id: twingate-version-windows shell: powershell run: | - try { - $response = Invoke-WebRequest -Uri "https://api.twingate.com/download/windows?installer=msi" -Method Head -MaximumRedirection 0 -ErrorAction Stop - } catch { - # When MaximumRedirection is 0, redirects cause an exception - # The redirect location is in the exception response - if ($_.Exception.Response -and $_.Exception.Response.Headers -and $_.Exception.Response.Headers.Location) { - $location = $_.Exception.Response.Headers.Location - if ($location -match '/versions/([^/]+)/') { - $version = $matches[1] - echo "version=$version" >> $env:GITHUB_OUTPUT - Write-Host "Latest Twingate version: $version" - } else { - Write-Host "Warning: Could not parse version from redirect location: $location" - } - } else { - Write-Host "Warning: Error checking version - $($_.Exception.Message)" - } - } + $uri = "https://api.twingate.com/download/windows?installer=msi" + try { + # Make request without following redirects + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method Get ` + -MaximumRedirection 0 ` + -ErrorAction Stop + } + catch { + # When MaximumRedirection = 0, PowerShell throws on 302 — grab the response anyway + $response = $_.Exception.Response + } + + if (-not $response) { + throw "No HTTP response received" + } + if ($response.StatusCode -ne 302) { + throw "Expected HTTP 302, got $($response.StatusCode)" + } + + if (-not $location) { + throw "Missing Location header" + } + + # Extract version from URL + # Example: + # https://binaries.twingate.com/client/windows/versions/2025.338.1789/TwingateWindowsInstaller.msi + if ($location -match "https://binaries.twingate.com/client/windows/versions/([^/]+)/") { + $version = $Matches[1] + echo "version=$version" >> $env:GITHUB_OUTPUT + Write-Host "Latest Twingate version: $version" + } else { + throw "Could not parse version from Location header: $location" + } - name: Cache Twingate package (Windows) if: runner.os == 'Windows' && inputs.cache == 'true' From 35a3ddaafe5fd2aa0f7d0c9d519e2fb861b9d966 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Sat, 20 Dec 2025 20:36:34 -0800 Subject: [PATCH 09/10] nicer --- action.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index 31f7932..636bc70 100644 --- a/action.yml +++ b/action.yml @@ -114,11 +114,7 @@ runs: $uri = "https://api.twingate.com/download/windows?installer=msi" try { # Make request without following redirects - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method Get ` - -MaximumRedirection 0 ` - -ErrorAction Stop + $response = Invoke-WebRequest -Uri $uri -Method Get -MaximumRedirection 0 -ErrorAction Stop } catch { # When MaximumRedirection = 0, PowerShell throws on 302 — grab the response anyway @@ -132,6 +128,8 @@ runs: throw "Expected HTTP 302, got $($response.StatusCode)" } + # Extract Location header + $location = $response.Headers['Location'] if (-not $location) { throw "Missing Location header" } From 3063c9fa216908f34e032177c706e3608a05dfe6 Mon Sep 17 00:00:00 2001 From: Eran Kampf Date: Sat, 20 Dec 2025 20:40:54 -0800 Subject: [PATCH 10/10] try --- action.yml | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/action.yml b/action.yml index 636bc70..fffe4c3 100644 --- a/action.yml +++ b/action.yml @@ -112,37 +112,22 @@ runs: shell: powershell run: | $uri = "https://api.twingate.com/download/windows?installer=msi" - try { - # Make request without following redirects - $response = Invoke-WebRequest -Uri $uri -Method Get -MaximumRedirection 0 -ErrorAction Stop - } - catch { - # When MaximumRedirection = 0, PowerShell throws on 302 — grab the response anyway - $response = $_.Exception.Response - } - if (-not $response) { - throw "No HTTP response received" - } - if ($response.StatusCode -ne 302) { - throw "Expected HTTP 302, got $($response.StatusCode)" - } + # Follow the redirect and get the final URL + $response = Invoke-WebRequest -Uri $uri -Method Head -UseBasicParsing + $finalUrl = $response.BaseResponse.ResponseUri.AbsoluteUri - # Extract Location header - $location = $response.Headers['Location'] - if (-not $location) { - throw "Missing Location header" - } + Write-Host "Final URL: $finalUrl" # Extract version from URL # Example: # https://binaries.twingate.com/client/windows/versions/2025.338.1789/TwingateWindowsInstaller.msi - if ($location -match "https://binaries.twingate.com/client/windows/versions/([^/]+)/") { + if ($finalUrl -match "/versions/([^/]+)/") { $version = $Matches[1] echo "version=$version" >> $env:GITHUB_OUTPUT Write-Host "Latest Twingate version: $version" } else { - throw "Could not parse version from Location header: $location" + throw "Could not parse version from URL: $finalUrl" } - name: Cache Twingate package (Windows)