Compare commits

..

153 commits
v2 ... main

Author SHA1 Message Date
Alex Chan
d1b6cd204f
Merge pull request #314 from tailscale/dependabot/github_actions/actions/checkout-7.0.1
Bump actions/checkout from 7.0.0 to 7.0.1
2026-07-21 10:48:05 +01:00
dependabot[bot]
f2a4d7820e
Bump actions/checkout from 7.0.0 to 7.0.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](9c091bb21b...3d3c42e5aa)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-21 03:53:30 +00:00
Alex Chan
a122c3446c
Merge pull request #312 from tailscale/dependabot/github_actions/actions/setup-node-7.0.0
Bump actions/setup-node from 6.4.0 to 7.0.0
2026-07-15 10:05:20 +01:00
dependabot[bot]
55d8693392
Bump actions/setup-node from 6.4.0 to 7.0.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.4.0 to 7.0.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](48b55a011b...8207627860)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-14 03:52:55 +00:00
dependabot[bot]
546937c0d1 Bump typescript from 5.9.3 to 6.0.3
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 6.0.3.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.9.3...v6.0.3)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 6.0.3
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-10 13:30:13 -06:00
TowyTowy
0e42fa1ff3 fix: reuse stale tailscale.tgz on self-hosted runners
On persistent self-hosted runners the XDG cache directory survives between
jobs. When GitHub's Actions cache backend doesn't return a hit (no working
backend, evicted entry, etc.), the tailscale.tgz left behind by a previous
job is still on disk, and tc.downloadTool() refuses to overwrite an existing
destination, failing with "Destination file path ... already exists".

Mirror the Windows MSI fix (#259): if the tarball already exists, reuse it
when its checksum matches, otherwise delete and re-download. Only the
cloud-cache-restore path previously avoided this collision, so the Linux
download was unconditional.

Fixes #294

Signed-off-by: TowyTowy <towy@airreps.link>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 14:36:37 -06:00
Lee Briggs
508737e196
Merge pull request #304 from tailscale/log_groups
feat: implement log grouping for better output
2026-07-02 23:37:17 -04:00
Lee Briggs
5a0d794b30
extract logging function into its own class
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2026-07-02 18:47:15 -07:00
Lee Briggs
ba16990ca0
catch errors
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2026-07-02 18:39:04 -07:00
Lee Briggs
191eb01caf
build
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2026-07-02 17:04:08 -07:00
Lee Briggs
404e7c5705
format
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2026-07-02 16:49:01 -07:00
Lee Briggs
73c8a00bae
feat: implement log grouping for better output
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2026-07-02 16:40:48 -07:00
Alex Chan
780049a30b
Merge pull request #303 from tailscale/alexc/riscv64
action: download the correct binary on riscv64
2026-06-29 14:32:24 +01:00
Alex Chan
a36a368140 action: download the correct binary on riscv64
Updates #299

Signed-off-by: Alex Chan <alexc@tailscale.com>
2026-06-29 14:27:57 +01:00
Alex Chan
60d77a38ad
Merge pull request #302 from tailscale/dependabot/github_actions/actions/checkout-7.0.0
Bump actions/checkout from 6.0.3 to 7.0.0
2026-06-19 14:51:06 +01:00
dependabot[bot]
2499098b43
Bump actions/checkout from 6.0.3 to 7.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](df4cb1c069...9c091bb21b)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-19 03:52:53 +00:00
Alex Chan
06afa10de8
Merge pull request #291 from tailscale/dependabot/npm_and_yarn/prettier-3.8.3
Bump prettier from 3.8.1 to 3.8.3
2026-06-04 07:03:37 +01:00
Alex Chan
7155a879c8
Merge pull request #295 from tailscale/dependabot/github_actions/actions/checkout-6.0.3
Bump actions/checkout from 6.0.2 to 6.0.3
2026-06-04 07:03:06 +01:00
dependabot[bot]
c175bd7aa8
Bump actions/checkout from 6.0.2 to 6.0.3
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](de0fac2e45...df4cb1c069)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 21:49:02 +00:00
dependabot[bot]
30ec0949da
Bump prettier from 3.8.1 to 3.8.3
Bumps [prettier](https://github.com/prettier/prettier) from 3.8.1 to 3.8.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.8.1...3.8.3)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 03:56:43 +00:00
Lee Briggs
586e48b2b7
Merge pull request #276 from tailscale/dependabot/npm_and_yarn/prettier-3.8.1
Bump prettier from 3.7.4 to 3.8.1
2026-04-26 12:08:05 -07:00
Lee Briggs
62a8a348b3
Merge pull request #288 from tailscale/dependabot/github_actions/actions/setup-node-6.4.0
Bump actions/setup-node from 6.3.0 to 6.4.0
2026-04-26 12:06:32 -07:00
dependabot[bot]
13ce09aa75
Bump actions/setup-node from 6.3.0 to 6.4.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.3.0 to 6.4.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](53b83947a5...48b55a011b)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 03:56:24 +00:00
maxcleme
bf966a7aba fix: typo glone -> clone
Was it on purpose? 😅

Signed-off-by: maxcleme <maxime.clement@docker.com>
2026-04-16 11:11:24 -06:00
dependabot[bot]
0c9f54d028
Bump prettier from 3.7.4 to 3.8.1
Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.1)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-27 12:18:10 +00:00
Alex Chan
0611d734da
Merge pull request #275 from tailscale/mpminardi/remove-actions-github
package.json,package-lock.json: remove @actions/github dependency
2026-03-27 12:16:59 +00:00
Mario Minardi
85073788ab
package.json,package-lock.json: remove @actions/github dependency
Remove @actions/github since we don't actually seem to use this
dependency in the action. We can add this back in if / when we do need
it, otherwise it is just causing noise with dependabot updates for no
reason.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-03-11 12:58:21 -06:00
dependabot[bot]
306e68a486 Bump @actions/cache from 5.0.1 to 5.0.2
Bumps [@actions/cache](https://github.com/actions/toolkit/tree/HEAD/packages/cache) from 5.0.1 to 5.0.2.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/cache/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/cache)

---
updated-dependencies:
- dependency-name: "@actions/cache"
  dependency-version: 5.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-03-11 12:54:23 -06:00
dependabot[bot]
989d9be101 Bump @actions/tool-cache from 2.0.2 to 3.0.0
Bumps [@actions/tool-cache](https://github.com/actions/toolkit/tree/HEAD/packages/tool-cache) from 2.0.2 to 3.0.0.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/tool-cache/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/tool-cache)

---
updated-dependencies:
- dependency-name: "@actions/tool-cache"
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 12:48:58 -06:00
dependabot[bot]
69584d71ae Bump @actions/github from 6.0.1 to 7.0.0
Bumps [@actions/github](https://github.com/actions/toolkit/tree/HEAD/packages/github) from 6.0.1 to 7.0.0.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/github/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/github)

---
updated-dependencies:
- dependency-name: "@actions/github"
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-03-11 12:15:08 -06:00
dependabot[bot]
cda17d523f Bump @actions/core from 2.0.1 to 2.0.2
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 2.0.1 to 2.0.2.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-version: 2.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-03-11 12:07:56 -06:00
dependabot[bot]
81231eb3b2 Bump actions/setup-node from 6.2.0 to 6.3.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](6044e13b5d...53b83947a5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 12:00:59 -06:00
Mario Minardi
48c6d0317a action,dist,src: bump default version to 1.94.2
Bump default version used by the action to 1.94.2. This will resolve
warnings in the admin console about known security vulnerabilities in
the previous default of 1.90.4 which aren't applicable for the GitHub
action.

The security vulnerabilities are specifically related to MDM policies
for MacOS (see https://tailscale.com/security-bulletins#ts-2026-001) and
related to using Tailnet lock without passing `--statedir` or `--state`
to tailscaled (see https://tailscale.com/security-bulletins#ts-2025-008).

Neither of these impact the GitHub action as MacOS runners aren't
managed by MDM policies and we pass either `--statedir` or `--state` to
the tailscale daemon.

Fixes https://github.com/tailscale/github-action/issues/272

Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-03-11 12:00:14 -06:00
fbrv
cfed5b8999 store tailscale.tgz and tailscaled.pid in XDG cache/runtime dirs instead of the working directory 2026-03-11 11:55:28 -06:00
Mario Minardi
31d93e60e2 .github/workflows: run integration test if event is a push
Run the integration tests if the event that triggered them is a push to
main. Previous changes to skip these tests on pull requests from forks
or dependabot had the unintended impact of disabling them on merges into
main.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-03-05 19:49:52 -07:00
Lukas Mracek
564fe381c8 chore: run make build to resolve linter error 2026-02-25 16:50:39 -07:00
git-mracek
127daded26 fix: add missing parentheses to core.isDebug() 2026-02-25 16:50:39 -07:00
dependabot[bot]
94b700f285 Bump actions/setup-node from 6.1.0 to 6.2.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](395ad32622...6044e13b5d)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-11 21:06:52 -07:00
dependabot[bot]
ec0ada4dce Bump actions/checkout from 6.0.1 to 6.0.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](8e8c483db8...de0fac2e45)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-11 21:06:25 -07:00
Dorin Geman
9c1802ce6b fix: Windows MSI download on self-hosted runners
On self-hosted runners, the tool cache directory persists between runs.
When GitHub's cloud cache doesn't have an entry (first run, evicted, etc.), but the local MSI file exists from a previous run, tc.downloadTool() fails with "Destination file path already exists".

This fix checks if the existing MSI has a valid checksum before downloading:
- If valid: reuse it (skip download)
- If invalid: delete and re-download

Signed-off-by: Dorin Geman <dorin.geman@docker.com>
2026-01-15 16:39:13 -07:00
Mario Minardi
61e1192a01 .github/workflows: fix check to skip integration test for PRs from forks
Check that the full name of the repo from pull request events matches
the repo from the GitHub context to ensure we are properly skipping
integration tests coming from forks.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-01-14 13:18:36 -07:00
dependabot[bot]
53acf82332 Bump @actions/core from 2.0.0 to 2.0.1
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 2.0.0 to 2.0.1.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/@actions/artifact@2.0.1/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-version: 2.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-23 08:52:08 -07:00
dependabot[bot]
376b8a186d Bump @actions/exec from 1.1.1 to 2.0.0
Bumps [@actions/exec](https://github.com/actions/toolkit/tree/HEAD/packages/exec) from 1.1.1 to 2.0.0.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/exec/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/exec)

---
updated-dependencies:
- dependency-name: "@actions/exec"
  dependency-version: 2.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-23 08:46:03 -07:00
dependabot[bot]
6b3a1307e5 Bump @actions/cache from 4.1.0 to 5.0.1
Bumps [@actions/cache](https://github.com/actions/toolkit/tree/HEAD/packages/cache) from 4.1.0 to 5.0.1.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/cache/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/cache)

---
updated-dependencies:
- dependency-name: "@actions/cache"
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-23 08:38:59 -07:00
dependabot[bot]
f166a64f7b Bump prettier-plugin-organize-imports from 3.2.4 to 4.3.0
Bumps [prettier-plugin-organize-imports](https://github.com/simonhaenisch/prettier-plugin-organize-imports) from 3.2.4 to 4.3.0.
- [Release notes](https://github.com/simonhaenisch/prettier-plugin-organize-imports/releases)
- [Changelog](https://github.com/simonhaenisch/prettier-plugin-organize-imports/blob/master/changelog.md)
- [Commits](https://github.com/simonhaenisch/prettier-plugin-organize-imports/compare/v3.2.4...v4.3.0)

---
updated-dependencies:
- dependency-name: prettier-plugin-organize-imports
  dependency-version: 4.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 13:11:02 -07:00
dependabot[bot]
2d4cde5889 Bump prettier from 2.8.8 to 3.7.4
Bumps [prettier](https://github.com/prettier/prettier) from 2.8.8 to 3.7.4.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.8.8...3.7.4)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.7.4
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 13:05:11 -07:00
dependabot[bot]
afff14da14 Bump semver from 6.3.1 to 7.7.3
Bumps [semver](https://github.com/npm/node-semver) from 6.3.1 to 7.7.3.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v6.3.1...v7.7.3)

---
updated-dependencies:
- dependency-name: semver
  dependency-version: 7.7.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 12:52:06 -07:00
dependabot[bot]
fb25ad2e95 Bump @types/node from 20.19.21 to 24.10.2
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.19.21 to 24.10.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.10.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 12:32:18 -07:00
dependabot[bot]
e8244c1283 Bump @actions/core from 1.11.1 to 2.0.0
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.11.1 to 2.0.0.
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-version: 2.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 08:43:18 -07:00
Mario Minardi
d197c1d0f5 package.json: specify required node version
Specify node >= 24.0.0 in the engines block as that is what we use and
test with in CI.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-12-15 08:41:22 -07:00
Mario Minardi
8d0691471a .github/workflows: disable integration tests for dependabot PRs
Disable integration tests for dependabot PRs since it does not have
access to the integration testing tailnet.

Updates https://github.com/tailscale/corp/issues/33791

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-12-15 08:23:09 -07:00
dependabot[bot]
95e09948b8 Bump actions/setup-node from 5.0.0 to 6.1.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](a0853c2454...395ad32622)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 08:11:01 -07:00
dependabot[bot]
1cc03b2f9b Bump actions/checkout from 4.2.2 to 6.0.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 6.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...8e8c483db8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 08:00:42 -07:00
Mario Minardi
67f81e554b dist: run make build to generated updated index.js
Running make build was missed on #235 and subsequently missed by me
when reviewing that PR (whoops).

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-12-11 11:09:57 -07:00
Lucino772
fee37da258 fix: use correct arch on macOs 2025-12-11 10:54:47 -07:00
Mario Minardi
bfc6672599 .github/workflows: remove tests for retired macOS 13 runners
Remove tests for macOS-13 based runner images as they are now retired.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-12-10 13:40:02 -07:00
Mario Minardi
1ab6ecf072 .github/workflows: skip integration tests for forks
Skip the integration test workflows for forked versions of the repo.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-12-10 13:13:40 -07:00
Max Coulombe
dea278bd44
Merge pull request #228 from tailscale/max/clarify-writable-auth_key-scope
README: clarify auth_key scope must be writable
2025-11-10 09:48:04 -05:00
mcoulombe
f987cba5e9 README: clarify auth_key scope must be writable
Fixes #217
Signed-off-by: mcoulombe <max@tailscale.com>
2025-11-10 09:36:35 -05:00
Mario Minardi
a392da0a18
Merge pull request #221 from tailscale/mpminardi/workload-identity
action.yml,src: add support for workload identity federation
2025-10-30 08:07:50 -06:00
Mario Minardi
ef403f0d06
action.yml,src: add support for workload identity federation
Add support for workload identity federation based authentication.

Updates https://github.com/tailscale/corp/issues/31264

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-10-29 07:51:52 -06:00
Mario Minardi
c8de7faf7a
Merge pull request #220 from tailscale/mpminardi/latest-fix
src: check against platform specific versions for latest and unstable
2025-10-27 09:15:11 -06:00
Mario Minardi
bf5cb7c4d7
src: check against platform specific versions for latest and unstable
Check against platform and package specific version numbers returned
from pkgs.tailscale.com instead of defaulting to "Version" as this can
be incorrect for certain platforms when a release has only been built
for a subset of platforms.

For example. 1.90.2 is available for linux at the time of writing so
"Version" is 1.90.2, but only 1.90.1 is available for windows which
causes an error when using latest as the version specifier on windows
machines.

Fixes https://github.com/tailscale/github-action/issues/219

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-10-26 18:34:14 -06:00
Mario Minardi
bd97ec6ea8
Merge pull request #218 from tailscale/mpminardi/gitattributes
.gitattributes: mark dist as a generated folder
2025-10-26 18:33:49 -06:00
Mario Minardi
c17f550392
.gitattributes: mark dist as a generated folder
Mark dist as a generated folder so that files within it are collapsed
by default in code review.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-10-26 18:00:05 -06:00
Percy Wegmann
3a217367ca validate that when using an OAuth client, tags are specified
Also include a troubleshooting section in the README with information about the
requested tags are invalid or not permitted error.

Updates #78

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-20 14:38:46 -05:00
Mario Minardi
1293ebc018 .github: add dependabot config
Add basic dependabot config to check for actions / npm updates daily.
This mirrors the config we currently have in the terraform provider repo
but with go swapped for npm.

Fixes https://github.com/tailscale/github-action/issues/207

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-10-20 14:18:35 -05:00
Percy Wegmann
2ddbe90864 stop tailscale service after CI workload finishes
Updates #205

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-20 12:53:03 -05:00
Percy Wegmann
aa604318b6 run all commands silently
To avoid leaking any potentially sensitive information, all commands are now run
without logging to the console. Logging can be enabled by turning on debug logging
as described at https://docs.github.com/en/actions/how-tos/monitor-workflows/enable-debug-logging.

Updates tailscale/corp#33405

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-15 14:31:02 -05:00
Lee Briggs
b69384a992
Merge pull request #203 from tailscale/secrets
use `setSecret` to mask secrets from logs
2025-10-15 15:03:34 -04:00
Lee Briggs
0edb496506
mask secrets
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2025-10-15 14:59:05 -04:00
Percy Wegmann
ac425ca194 stop echoing tailscale status to console
Updates #201

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 16:46:07 -05:00
Percy Wegmann
2976a889fc miscellaneous cleanup items from upgrading to TypeScript action
Updates tailscale/corp#32821

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
2c45c8a0fd configure DNS on macOS runners
On macOS, `tailscaled` does not manage DNS. Configure it manually in the GitHub action to make
sure MagicDNS name resolution works.

Updates tailscale/corp#32821

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
d4729ea54c miscellaneous cleanup items from upgrading to TypeScript action
Updates tailscale/corp#32821

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
392b48279b fix bugs in ping logic, ping hosts in parallel, and tweak README and LICENSE
The ping logic had some bugs in the wait logic which are now fixed.

Pinging hosts in parallel will speed up CI.

LICENSE and README got small updates in preparation for moving this code
to tailscale/github-action.

Updates tailscale/corp#32862

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
d2d502c92b update documentation and LICENSE to match existing github-action and document new features
Documented new features:

- Logout functionality
- Ping functionality

Also removed speed-comparison CI flow in preparation for replacing the official GitHub
action with this one.

Updates tailscale/corp#32820

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
cff51cdb0c stop pinging hosts as soon as any connectivity is available
Even if we just have DERP connectivity, stop pinging so that action can continue sooner.

Updates tailscale/corp#32862

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
fc77efa75d adjust action parameters based on original tailscale/github-action
`oauth-client-secret` is renamed to `oauth-secret` to match the original action.

Not all of the descriptions matched exactly, but this attempts to take the best from both versions.

Default Tailscale version is updated to 1.88.3.

Updates tailscale/corp#32814

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
75aaac9f12 add support for testing peer connectivity
The new argument `ping` allows users to specify a comma-seperated list
of hosts (IP or hostname) to ping in order to verify connectivity.
Ping is considered successful as soon as the peer is reachable either
directly or via DERP.

Updates tailscale/corp#32817

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
90629cdeb4 factor out commonly repeated constants
Updates tailscale/corp#31655

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
cf94bd9cf6 support "unstable" version option on all platforms except macOS
The tailscale repo does not get tagged for unstable builds, so the best we can do when
building macOS from source is to build from the HEAD of `main`.

Updates tailscale/corp#32813

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
660d7be521 CI: check that code has been formatted and dist built
Updates tailscale/corp#32815

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
39ac0a5882 add dependency on prettier and apply autoformatting
Updates tailscale/corp#30483

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
391d5e0792 get tests running in new repo
- Use secrets from the new repo
- Build MacOS from source

Updates tailscale/corp#31655

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Lee Briggs
ed8cd4e9bf check status
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Lee Briggs
b9a346ef11 change name
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Lee Briggs
992dc80701 move speed test into its own workflow
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Lee Briggs
ea786a8afe update performance claims
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Lee Briggs
ece0596be3 initial commit
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
540ac650e6 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 <percy@tailscale.com>
2025-10-14 13:12:31 -05:00
Percy Wegmann
7bdbdbb519 action.yml: bump tailscale version to 1.88.3
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-09-29 14:09:53 -05:00
Mario Minardi
1db1f8e300
Merge pull request #197 from tailscale/mpminardi/document-unstable
README.md: document ability to specify unstable for version
2025-09-25 09:58:49 -06:00
Mario Minardi
a8723264f7
README.md: document ability to specify unstable for version
Doucment that "unstable" is now a valid input for version.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-09-25 09:55:07 -06:00
Max Coulombe
6cae46e2d7
Merge pull request #195 from tailscale/max/test-target-connectivity-check
Added argument to test targets connectivity
2025-09-25 11:43:46 -04:00
Max Coulombe
2208a5a58b
Update action.yml
Co-authored-by: Mario Minardi <mario@tailscale.com>
2025-09-25 11:40:17 -04:00
mcoulombe
3eef1cc07c + added argument to test target connectivity
Update action.yml

Co-authored-by: Mario Minardi <mario@tailscale.com>
2025-09-25 10:25:14 -04:00
Max Coulombe
0263d9e6d7
Merge pull request #196 from tailscale/max/sanitize-hostnames
action: auto-sanitize default or error on invalid user-defined hostname
2025-09-23 15:36:50 -04:00
mcoulombe
dc4930bf38 action: auto-sanitize default or error on invalid user-defined hostname
Fixes #192
2025-09-23 15:02:42 -04:00
Mario Minardi
6d2f2497d7
Merge pull request #189 from zchee/version-unstable
Support `unstable` version alias
2025-09-12 08:47:56 -06:00
Koichi Shiraishi
59c4d74575
Fix inputs.version.description
Signed-off-by: Koichi Shiraishi <zchee.io@gmail.com>
2025-08-24 01:30:24 +09:00
Koichi Shiraishi
c7fc043ee0
Support unstable version alias
Signed-off-by: Koichi Shiraishi <zchee.io@gmail.com>
2025-08-24 01:13:42 +09:00
Mario Minardi
fd5642846a
Merge pull request #183 from tailscale/mpminardi/granular-scope-testing
.github/workflows: add tests for new / granular minimal OAuth scopes
2025-07-21 10:07:29 -06:00
Mario Minardi
c66619accf
.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 <mario@tailscale.com>
2025-07-04 12:27:49 -06:00
Mario Minardi
84a3f23bb4
Merge pull request #181 from tailscale/mpminardi/windows-unattended-mode
{.github/workflows,action.yml}: run windows in unattended mode
2025-06-26 09:36:38 -06:00
Mario Minardi
8fe6f78f60
{.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 <mario@tailscale.com>
2025-06-23 10:07:15 -06:00
Max Coulombe
6986d2c82a
Merge pull request #178 from tailscale/max/add-retry
action: add retry on tailscale up to make the action more reliable
2025-05-23 17:47:38 -04:00
mcoulombe
029c99af76 action: add retry on tailscale up to make the action more reliable
Updates #177
Signed-off-by: mcoulombe <max@tailscale.com>

Co-authored-by: andrea-armstrong

* make retries configurable

* switch to c-style for loop
2025-05-23 17:42:50 -04:00
Mario Minardi
5d536117a7 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 <mario@tailscale.com>
Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-04-09 16:17:15 -05:00
Mario Minardi
9a0fda8cbb
Merge pull request #169 from tailscale/mpminardi/document-use-cache
README.md: document the `use-cache` input
2025-04-09 10:51:29 -06:00
Mario Minardi
91154e3930
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 <mario@tailscale.com>
2025-04-09 10:48:25 -06:00
Mario Minardi
32856f8a74
Merge pull request #166 from palindrom615/main
Cache tailscale binary file
2025-04-09 10:47:19 -06:00
Whoemoon Jang
7af7df6221
Update Download Tailscale - Windows step not to remove tailscale.msi after installation
Co-authored-by: Mario Minardi <mminardi@shaw.ca>
2025-04-07 09:06:23 +09:00
twelsh-aw
4c25f5bef4 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.
2025-04-05 10:16:16 +09:00
jang whoemoon
d954cb8727 Check sha256 checksum for cache 2025-04-03 14:01:19 +09:00
jang whoemoon
694e85d253 Cache tailscale artifact 2025-04-03 13:30:02 +09:00
Mario Minardi
09e4120d08
Merge pull request #165 from tailscale/mpminardi/pin-github-actions
.github/workflows: pin GitHub action versions
2025-04-02 16:36:32 -06:00
Mario Minardi
a31fee8af4
.github/workflows: pin GitHub action versions
Pin versions of GitHub actions that are used in our workflows.

Updates #cleanup

Signed-off-by: Mario Minardi <mario@tailscale.com>
2025-04-02 13:36:29 -06:00
kari-ts
76ab37942a
Merge pull request #162 from tailscale/kari/bump
action.yml: bump release to 1.82.0
2025-04-01 11:48:30 -07:00
kari-ts
b4a7d2da83 action.yml: bump release to 1.82.0
Signed-off-by: kari-ts <kari@tailscale.com>
2025-04-01 11:46:09 -07:00
Brian Palmer
19a6f4f99f
Merge pull request #164 from tailscale/brianp/ci-conn-check
CI: fix the connection check
2025-04-01 10:30:09 -06:00
Brian Palmer
b09fabcbed 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
2025-04-01 09:08:04 -06:00
Mario Minardi
93605f7b8f
Merge pull request #161 from tailscale/mpminardi/mac-support
{action.yml,.github}: add support for macOS
2025-03-13 16:00:11 -06:00
Mario Minardi
d32d8550d2
Merge pull request #160 from tailscale/mpminardi/windows-support
{action.yml,.github}: add support for windows
2025-03-13 15:31:08 -06:00
Mario Minardi
f0c3dac2f5
{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>
2025-03-05 12:35:38 -07:00
Mario Minardi
5dddea1dff
{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
2025-03-03 12:37:06 -07:00
Nick O'Neill
2b498977f3
Merge pull request #151 from tailscale/nickoneill/readme-v3
README: add v3 to the action snippets
2024-12-18 13:56:44 -08:00
Nick O'Neill
2cbc2550a7 add v3 to the readme 2024-12-18 13:48:32 -08:00
Keli
8688eb839e
Merge pull request #148 from tailscale/keli/update-1.78.1
action.yml: bump tailscale version to 1.78.1
2024-12-13 09:32:02 -05:00
Keli Velazquez
aef4d1b9e2 action.yml: bump tailscale version to 1.78.1
Updates tailscale/corp#14315

Signed-off-by: Keli Velazquez <keli@tailscale.com>
2024-12-13 09:26:45 -05:00
Lee Briggs
1ec4a5d914
Merge pull request #131 from jaxxstorm/latest_version
Always pull latest version
2024-12-12 22:33:39 -08:00
Lee Briggs
cb0029737d
use json api for getting latest version 2024-12-12 12:36:42 +00:00
Naman Sood
67573e622a
README: add note about required oauth scopes (#144)
* README: add note about required oauth scopes

Fixes #143.

Signed-off-by: Naman Sood <mail@nsood.in>

* english

Signed-off-by: Naman Sood <mail@nsood.in>

---------

Signed-off-by: Naman Sood <mail@nsood.in>
2024-11-21 21:16:00 -05:00
John Vandenberg
16d7e0b781 Force timeout during connection 2024-09-09 15:16:08 -07:00
Andrea Gottardo
0893401420
Merge pull request #138 from tailscale/vbump-1721
Bump Tailscale version to v1.72.1
2024-08-28 11:41:05 -07:00
Andrea Gottardo
57133d573b
Bump Tailscale version to v1.72.1 2024-08-28 11:21:17 -07:00
Percy Wegmann
eac66e8ca4 .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 <percy@tailscale.com>
2024-08-14 20:10:14 -05:00
Anton Tolchanov
b2b96d3c7f action.yml: allow specifying a state directory
Also, document usage of the action with Tailnet Lock.

Fixes #132

Signed-off-by: Anton Tolchanov <anton@tailscale.com>
2024-07-10 08:37:27 -07:00
Lee Briggs
42b6960a76
update readme
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2024-07-07 09:52:27 -07:00
Lee Briggs
c688cd1540
Revert "don't lookup latest version"
This reverts commit 0eefde4707.
2024-07-07 09:50:18 -07:00
Lee Briggs
0eefde4707
don't lookup latest version
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2024-07-07 09:32:46 -07:00
Lee Briggs
408d716839
don't set default to latest
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2024-07-07 09:30:32 -07:00
Lee Briggs
7af1b1f12d
find latest version
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
2024-07-07 09:06:11 -07:00
Patrick O'Doherty
0bf9b9f36b
Merge pull request #127 from tailscale/patrickod-patch-1
Bump release to 1.66.3
2024-05-15 13:51:43 -07:00
Patrick O'Doherty
3efa8e1ffc
Bump release to 1.66.3 2024-05-15 13:46:38 -07:00
Patrick O'Doherty
ca42c49ccd
Merge pull request #125 from tailscale/patrickod-patch-1
Correct default_version
2024-05-15 09:19:34 -07:00
Patrick O'Doherty
6ecfb8d7e8
Correct default_version 2024-05-15 09:11:42 -07:00
Patrick O'Doherty
92fe4f860b
Merge pull request #124 from tailscale/patrickod/bump
action.yml: bump tailscale version to 1.66.1
2024-05-14 09:56:11 -07:00
Patrick O'Doherty
9a38686973
action.yml: bump tailscale version to 1.66.1
Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
2024-05-14 09:45:22 -07:00
Andrew Lytvynov
2075411ebb
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
2024-04-23 18:20:03 -06:00
Jack Pearce
7a0b30ed35
README.md: Add Tailscale version instructions (#98) 2023-11-02 05:56:49 -07:00
Denton Gentry
a5ed86cd49
action.yml: output expected and actual checksum (#92)
Updates https://github.com/tailscale/github-action/issues/89

Signed-off-by: Denton Gentry <dgentry@tailscale.com>
2023-10-04 19:07:50 -07:00
Denton Gentry
721822aa67
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 <dgentry@tailscale.com>
2023-10-04 13:31:57 -07:00
20 changed files with 126803 additions and 128 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
dist/** linguist-generated=true

10
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: daily
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily

44
.github/workflows/lint.yml vendored Normal file
View file

@ -0,0 +1,44 @@
name: "Lint Checks"
on:
pull_request:
workflow_dispatch:
push:
branches:
- main
jobs:
# Basic linter check
lint-check:
name: Lint check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
cache: "npm"
- name: Install Dependencies
run: npm ci
- name: Run formatter check
run: |
./node_modules/.bin/prettier --check --loglevel silent "src/**/*.ts" || ( \
echo "Run this command on your local device to fix the error:" && \
echo "" && \
echo " make format" && \
echo "" && exit 1)
- name: Run build check
run: |
npm run build && test -z "$(git status --porcelain)" || ( \
echo "dist is out of date, run this command on your local device to fix the error:" && \
echo "" && \
echo " make build" && \
echo "" && exit 1)

52
.github/workflows/smoke-test.yml vendored Normal file
View file

@ -0,0 +1,52 @@
name: "Smoke Tests"
on:
pull_request:
workflow_dispatch:
push:
branches:
- main
jobs:
# Basic smoke test that doesn't require secrets
smoke-test:
name: Smoke Test (${{ matrix.os }})
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
cache: "npm"
- name: Install Dependencies
run: npm ci
- name: Build Action
run: npm run build
- name: Test Action Loading (No Auth)
uses: ./
with:
version: "latest"
continue-on-error: true
id: smoke-test
# The action should fail gracefully with a proper error message
- name: Verify Expected Failure
shell: bash
run: |
if [ "${{ steps.smoke-test.outcome }}" == "success" ]; then
echo "❌ Expected action to fail without authentication, but it succeeded"
exit 1
else
echo "✅ Action correctly failed without authentication as expected"
fi

View file

@ -1,27 +0,0 @@
name: tailscale
on:
push:
branches:
- main
pull_request:
branches:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Tailscale Action
uses: ./
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
- name: check for hello.ts.net in netmap
run:
tailscale status | grep -q hello

168
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,168 @@
name: "Integration Tests"
permissions:
id-token: write # This is required for requesting the JWT for workload identity
on:
pull_request:
workflow_dispatch:
push:
branches:
- main
jobs:
# Matrix test for all supported platforms and architectures
integration-tests:
# Skip our integration tests if the PR is from a fork. This has the consequence of
# disabling these even if the PR is from a forked repo into itself, but given that
# these tests are very specific to our internal test environment that is a good thing.
#
# Similarly, skip if this is running from a PR that has been opened by dependabot as
# the bot does not have credentials for the integration testing tailnet.
# TODO(mpminardi): revisit / remove this if / when we give dependabot a tailnet for
# testing with a smaller blast radius.
if: ${{ github.event_name == 'push' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') }}
name: ${{ matrix.os }} (${{ matrix.arch }}) (${{ matrix.credential-type }}) tailscale-${{ matrix.version }}
strategy:
fail-fast: false
matrix:
include:
# Linux tests (AMD64)
- os: ubuntu-latest
runner-os: Linux
arch: amd64
version: latest
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
credential-type: oauth
# Try unstable too
- os: ubuntu-latest
runner-os: Linux
arch: amd64
version: unstable
credential-type: oauth
# Try a pinned version
- os: ubuntu-latest
runner-os: Linux
arch: amd64
credential-type: oauth
# leave version blank to fall back to default
# Linux tests (ARM64)
- os: ubuntu-24.04-arm
runner-os: Linux
arch: arm64
version: latest
credential-type: oauth
# Windows tests (AMD64)
- os: windows-latest
runner-os: Windows
arch: amd64
version: latest
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
credential-type: oauth
# Windows tests (ARM64)
- os: windows-11-arm
runner-os: Windows
arch: arm64
version: latest
credential-type: oauth
# macOS 14 (ARM)
- os: macos-14
runner-os: macOS
arch: arm64
version: latest
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
credential-type: oauth
# macOS latest (ARM)
- os: macos-latest
runner-os: macOS
arch: arm64
version: latest
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
credential-type: oauth
# Try workload identity for each platform
- os: macos-latest
runner-os: macOS
arch: amd64
version: latest
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
credential-type: workload-identity
- os: windows-latest
runner-os: Windows
arch: amd64
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve
credential-type: workload-identity
# leave version blank to fall back to default
# Try adding in an unstable
- os: ubuntu-latest
runner-os: Linux
arch: amd64
version: unstable
credential-type: workload-identity
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
cache: "npm"
- name: Install Dependencies
run: npm ci
- name: Build Action
run: npm run build
# Test with OAuth authentication
- name: Test Action
id: tailscale-oauth
uses: ./
with:
oauth-client-id: ${{ matrix.credential-type == 'oauth' && secrets.TS_AUTH_KEYS_OAUTH_CLIENT_ID || secrets.TS_WORKLOAD_IDENTITY_CLIENT_ID }}
oauth-secret: ${{ matrix.credential-type == 'oauth' && secrets.TS_AUTH_KEYS_OAUTH_CLIENT_SECRET || '' }}
audience: ${{ matrix.credential-type == 'workload-identity' && secrets.TS_AUDIENCE || ''}}
tags: "tag:ci"
version: "${{ matrix.version }}"
use-cache: false
timeout: "5m"
retry: 3
ping: "${{ matrix.ping }}"
# Look up names to make sure MagicDNS is working
- name: Look up qualified name
run: nslookup lax-pve.pineapplefish.ts.net
- name: Look up unqualified name
run: nslookup lax-pve
# Test Tailscale status command
- name: Check Tailscale Status
if: steps.tailscale-oauth.outcome == 'success'
run: |
echo "Testing Tailscale status command..."
if [ "${{ matrix.runner-os }}" == "Windows" ]; then
# Windows uses system-installed binary without sudo
tailscale status
tailscale version
else
# Linux and macOS use system-installed binary with sudo
sudo -E tailscale status
tailscale version
fi
shell: bash

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules

View file

@ -1,6 +1,7 @@
BSD 3-Clause License
Copyright (c) 2020 Tailscale & AUTHORS.
Copyright (c) 2020 Tailscale Inc & Contributors
Copyright (c) 2025 Lee Briggs
All rights reserved.
Redistribution and use in source and binary forms, with or without

42
Makefile Normal file
View file

@ -0,0 +1,42 @@
# Makefile for building a TypeScript GitHub Action
# Variables
SHELL := /bin/bash
SRC_DIR := src
BUILD_DIR := dist
ENTRY_POINT := $(SRC_DIR)/index.ts
# Binaries
TS_NODE := ./node_modules/.bin/ts-node
TS_C := ./node_modules/.bin/tsc
ESLINT := ./node_modules/.bin/eslint
PRETTIER := ./node_modules/.bin/prettier
# Targets
.PHONY: all clean install build format
all: clean install build
# Clean up the lib directory
clean:
rm -rf $(BUILD_DIR)
# Install npm dependencies
install:
npm install
# Build the TypeScript code
build: clean format
npm run build
# Lint the TypeScript code
lint:
$(ESLINT) $(SRC_DIR)
# Format the TypeScript code
format:
$(PRETTIER) --write "$(SRC_DIR)/**/*.ts"
# Run the action locally (for testing purposes)
run: build

201
README.md
View file

@ -4,25 +4,202 @@ 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@v2
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
- name: Tailscale
uses: tailscale/github-action@v4
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/)
oauth-client-id and oauth-secret are an [OAuth client][kb-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 writable
[`auth_keys` scope.][kb-trust-credentials-scopes]
tags is a comma-separated list of one or more [ACL Tags](https://tailscale.com/kb/1068/acl-tags/)
tags is a comma-separated list of one or more [Tags][kb-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/)
Nodes created by this Action are [marked as Ephemeral][kb-ephemeral-nodes] to
and log out immediately after finishing their CI run, at which point they are automatically removed
by the coordination server. The nodes are also [marked Preapproved][kb-auth-keys]
on tailnets which use [Device Approval][kb-device-approval]
### Workload identity federation
[Workload identity federation][kb-workload-identity-federation] can also be used for authenticating nodes with your tailnet:
```yaml
- name: Tailscale
uses: tailscale/github-action@v4
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
audience: ${{ secrets.TS_AUDIENCE }}
tags: tag:ci
```
Workload identity federation requires the `id-token: write` [permission setting](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-cloud-providers#adding-permissions-settings) for the workflow:
```yaml
permissions:
id-token: write # This is required for the tailscale action to request a JWT from GitHub
```
OIDC federated identity credentials used for this purpose must have the writable [`auth_keys` scope.][kb-trust-credentials-scopes]
tags is a comma-separated list of one or more [Tags][kb-tags]
for the node. At least one tag is required: a federated identity is not associated
with any of the Users on the tailnet, it has to Tag its nodes.
> [!IMPORTANT]
> Tailscale version `1.90.1` or later is required for workload identity federation.
## Prerequisites
Before using the Tailscale GitHub Action, ensure you have the following:
1. A Tailscale account with Owner, Admin, or Network admin permissions.
1. A GitHub repository that you have admin access to (required to set up the GitHub Action).
1. At least one configured [tag][kb-tags] if using OAuth or workload identity federation.
1. An [OAuth client][kb-oauth-clients] ID and secret, [federated identity][kb-workload-identity-federation] client ID and audience, OR an [auth key][kb-auth-keys].
1. A runner image version >= 2.237.1 (required to support running Node.js 24).
## 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 hosts to ping to the action configuration:
```yaml
- name: Tailscale
uses: tailscale/github-action@v4
with:
ping: 100.x.y.z,my-machine.my-tailnet.ts.net
```
or with the [tailscale ping][kb-cli-ping] command if you do not know the peers at the time of installing Tailscale in the workflow:
```bash
tailscale ping my-target.my-tailnet.ts.net
```
The `ping` option will wait up to 3 minutes for a connection (direct or relayed).
## Log mode
By default, this action folds its major setup and cleanup phases into GitHub Actions log groups.
You can change this with the `log-mode` input:
```yaml
- name: Tailscale
uses: tailscale/github-action@v4
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
log-mode: normal
```
Supported values are:
- `grouped`: fold major action phases in the log. This is the default.
- `normal`: print routine action logs without grouping.
- `quiet`: suppress routine informational output while preserving warnings and errors.
## Tailnet Lock
If you are using this Action in a [Tailnet Lock][kb-tailnet-lock] enabled network, you need to:
- Authenticate using an ephemeral reusable [pre-signed auth key][kb-tailnet-lock-pre-signed]
rather than an OAuth client.
- Specify a [state directory][kb-tailscaled-flags] for the
client to store the Tailnet Key Authority data in.
```yaml
- name: Tailscale
uses: tailscale/github-action@v4
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@v4
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@v4
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.
You can also specify `version: unstable` to use the latest unstable version of Tailscale.
For Linux and Windows, this uses the version published at https://pkgs.tailscale.com/unstable,
and for MacOS it uses the HEAD of the `main` branch of https://github.com/tailscale/tailscale/.
## Cache Tailscale binaries
Caching can reduce download times and download failures on runners with slower network connectivity.
As of v4 of this action, caching is enabled by default.
Although caching is generally recommended, you can disable it by passing `'false'` to the `use-cache` input:
```yaml
- name: Tailscale
uses: tailscale/github-action@v4
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
use-cache: "false"
```
## Usage on persistent self-hosted runners
When running on self-hosted runners that persist after CI jobs have finished,
the GitHub Action leaves tailscale binaries installed but stops the tailscale background processes.
## Troubleshooting
### requested tags [tag:mytag] are invalid or not permitted
You may encounter this error when using a trust credential (OAuth client or OIDC federated identity).
Trust credentials must have the writable [`auth_keys` scope][kb-trust-credentials-scopes] with one or more [tags][kb-tags],
and the tags specified with `tags` must match all tags on the trust credential or be tags owned by the tags on the trust credential.
[kb-auth-keys]: https://tailscale.com/kb/1085/auth-keys
[kb-cli-ping]: https://tailscale.com/kb/1080/cli#ping
[kb-device-approval]: https://tailscale.com/kb/1099/device-approval
[kb-ephemeral-nodes]: https://tailscale.com/kb/1111/ephemeral-nodes
[kb-oauth-clients]: https://tailscale.com/kb/1215/oauth-clients
[kb-tags]: https://tailscale.com/kb/1068/tags
[kb-tailnet-lock]: https://tailscale.com/kb/1226/tailnet-lock
[kb-tailnet-lock-pre-signed]: https://tailscale.com/kb/1226/tailnet-lock#add-a-node-using-a-pre-signed-auth-key
[kb-tailscaled-flags]: https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled
[kb-trust-credentials-scopes]: https://tailscale.com/kb/1623/trust-credentials#scopes
[kb-workload-identity-federation]: https://tailscale.com/kb/1581/workload-identity-federation

5
README_CI.md Normal file
View file

@ -0,0 +1,5 @@
### CI Notes
CI tests run against the pineapplefish-tailnet.org.github tailnet. Check our usual credential store for credentials.
`tag:ci` must have access to the `lax-pve` server.

View file

@ -1,116 +1,75 @@
# Copyright (c) Tailscale Inc & AUTHORS
# Copyright (c) Lee Briggs, Tailscale Inc, & Contributors
# 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.'
description: 'Your Tailscale OAuth or OIDC Federated Identity clientID.'
required: false
audience:
description: 'Your Tailscale OIDC Federated Identity Audience'
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.'
description: 'Comma separated list of Tags to be applied to nodes. When using an OAuth client, the OAuth client must have the `auth_keys` scope and alls tags on the OAuth client must match all tags specified here.'
required: false
version:
description: 'Tailscale version to use.'
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.42.0'
default: '1.94.2'
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: ''
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: 'Enable caching of Tailscale binaries to speed up subsequent runs.'
required: false
default: 'true'
statedir:
description: 'Directory to store Tailscale state. If empty, uses in-memory storage.'
required: false
default: ''
sha256sum:
description: 'Expected SHA256 checksum of the tarball.'
required: false
default: ''
args:
description: 'Optional additional arguments to `tailscale up`'
ping:
description: 'Comma separated list of hosts (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: ''
tailscaled-args:
description: 'Optional additional arguments to `tailscaled`'
log-mode:
description: 'Controls action log output mode. Use `grouped` to fold major setup and cleanup phases, `normal` for ungrouped logs, or `quiet` to suppress routine informational output.'
required: false
default: ''
hostname:
description: 'Fixed hostname to use.'
required: false
default: ''
default: 'grouped'
runs:
using: 'composite'
steps:
- name: Check Runner OS
if: ${{ runner.os != 'Linux' }}
shell: bash
run: |
echo "::error title=⛔ error hint::Support Linux 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: Download Tailscale
shell: bash
id: download
env:
VERSION: ${{ inputs.version }}
SHA256SUM: ${{ inputs.sha256sum }}
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"
elif [ ${{ runner.arch }} = "X64" ]; then
TS_ARCH="amd64"
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_${VERSION}_${TS_ARCH}.tgz"
else
URL="https://pkgs.tailscale.com/unstable/tailscale_${VERSION}_${TS_ARCH}.tgz"
fi
if ! [[ "$SHA256SUM" ]] ; then
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 "$SHA256SUM tailscale.tgz" | sha256sum -c
tar -C /tmp -xzf tailscale.tgz
rm tailscale.tgz
TSPATH=/tmp/tailscale_${VERSION}_${TS_ARCH}
sudo mv "${TSPATH}/tailscale" "${TSPATH}/tailscaled" /usr/bin
- name: Start Tailscale Daemon
shell: bash
env:
ADDITIONAL_DAEMON_ARGS: ${{ inputs.tailscaled-args }}
run: |
sudo -E tailscaled --state=mem: ${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:
TAILSCALE_AUTHKEY: ${{ inputs.authkey }}
ADDITIONAL_ARGS: ${{ inputs.args }}
HOSTNAME: ${{ inputs.hostname }}
TS_EXPERIMENT_OAUTH_AUTHKEY: true
run: |
if [ -z "${HOSTNAME}" ]; then
HOSTNAME="github-$(cat /etc/hostname)"
fi
if [ -n "${{ inputs['oauth-secret'] }}" ]; then
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}
using: 'node24'
main: 'dist/index.js'
post: 'dist/logout/index.js'

96019
dist/index.js generated vendored Normal file

File diff suppressed because one or more lines are too long

28072
dist/logout/index.js generated vendored Normal file

File diff suppressed because one or more lines are too long

771
package-lock.json generated Normal file
View file

@ -0,0 +1,771 @@
{
"name": "github-action",
"version": "4.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "github-action",
"version": "4.0.0",
"license": "BSD-3-Clause",
"dependencies": {
"@actions/cache": "^5.0.2",
"@actions/core": "^2.0.2",
"@actions/exec": "^2.0.0",
"@actions/tool-cache": "^3.0.0",
"semver": "^7.7.3"
},
"devDependencies": {
"@types/node": "^24.10.2",
"@vercel/ncc": "^0.38.3",
"prettier": "^3.8.3",
"prettier-plugin-organize-imports": "^4.3.0",
"typescript": "^6.0.3"
},
"engines": {
"node": ">=24.0.0"
}
},
"node_modules/@actions/cache": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-5.0.2.tgz",
"integrity": "sha512-6w3i9n12eWJyut6TOnh7SIxGmeIepB5wbXMvlPv9+6CjvTD4OYKi1Wjh7TQrjEf8xLb6hxsVCpPsL/1gxnlTtw==",
"license": "MIT",
"dependencies": {
"@actions/core": "^2.0.0",
"@actions/exec": "^2.0.0",
"@actions/glob": "^0.5.0",
"@actions/http-client": "^3.0.1",
"@actions/io": "^2.0.0",
"@azure/abort-controller": "^1.1.0",
"@azure/core-rest-pipeline": "^1.22.0",
"@azure/storage-blob": "^12.29.1",
"@protobuf-ts/runtime-rpc": "^2.11.1",
"semver": "^6.3.1"
}
},
"node_modules/@actions/cache/node_modules/@actions/http-client": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.1.tgz",
"integrity": "sha512-SbGS8c/vySbNO3kjFgSW77n83C4MQx/Yoe+b1hAdpuvfHxnkHzDq2pWljUpAA56Si1Gae/7zjeZsV0CYjmLo/w==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.28.5"
}
},
"node_modules/@actions/cache/node_modules/@actions/io": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz",
"integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==",
"license": "MIT"
},
"node_modules/@actions/cache/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@actions/core": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-2.0.2.tgz",
"integrity": "sha512-Ast1V7yHbGAhplAsuVlnb/5J8Mtr/Zl6byPPL+Qjq3lmfIgWF1ak1iYfF/079cRERiuTALTXkSuEUdZeDCfGtA==",
"license": "MIT",
"dependencies": {
"@actions/exec": "^2.0.0",
"@actions/http-client": "^3.0.1"
}
},
"node_modules/@actions/core/node_modules/@actions/http-client": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.1.tgz",
"integrity": "sha512-SbGS8c/vySbNO3kjFgSW77n83C4MQx/Yoe+b1hAdpuvfHxnkHzDq2pWljUpAA56Si1Gae/7zjeZsV0CYjmLo/w==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.28.5"
}
},
"node_modules/@actions/exec": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-2.0.0.tgz",
"integrity": "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==",
"license": "MIT",
"dependencies": {
"@actions/io": "^2.0.0"
}
},
"node_modules/@actions/exec/node_modules/@actions/io": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz",
"integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==",
"license": "MIT"
},
"node_modules/@actions/glob": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.5.0.tgz",
"integrity": "sha512-tST2rjPvJLRZLuT9NMUtyBjvj9Yo0MiJS3ow004slMvm8GFM+Zv9HvMJ7HWzfUyJnGrJvDsYkWBaaG3YKXRtCw==",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.9.1",
"minimatch": "^3.0.4"
}
},
"node_modules/@actions/glob/node_modules/@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
"license": "MIT",
"dependencies": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1"
}
},
"node_modules/@actions/glob/node_modules/@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"license": "MIT",
"dependencies": {
"@actions/io": "^1.0.1"
}
},
"node_modules/@actions/http-client": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
}
},
"node_modules/@actions/io": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
"license": "MIT"
},
"node_modules/@actions/tool-cache": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-3.0.0.tgz",
"integrity": "sha512-JBx8gEWuu8Lqaqx/hEnL6QdKvF06suBR4y+dBDi9vJbHx1r+p6QtmBKhQYhiKjDUYIoDX1bUrbyAYPChoPK+XA==",
"license": "MIT",
"dependencies": {
"@actions/core": "^2.0.1",
"@actions/exec": "^2.0.0",
"@actions/http-client": "^3.0.1",
"@actions/io": "^2.0.0",
"semver": "^6.1.0"
}
},
"node_modules/@actions/tool-cache/node_modules/@actions/http-client": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.1.tgz",
"integrity": "sha512-SbGS8c/vySbNO3kjFgSW77n83C4MQx/Yoe+b1hAdpuvfHxnkHzDq2pWljUpAA56Si1Gae/7zjeZsV0CYjmLo/w==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.28.5"
}
},
"node_modules/@actions/tool-cache/node_modules/@actions/io": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz",
"integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==",
"license": "MIT"
},
"node_modules/@actions/tool-cache/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@azure/abort-controller": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
"integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==",
"license": "MIT",
"dependencies": {
"tslib": "^2.2.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@azure/core-auth": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz",
"integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-util": "^1.13.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-auth/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-client": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
"integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.10.0",
"@azure/core-rest-pipeline": "^1.22.0",
"@azure/core-tracing": "^1.3.0",
"@azure/core-util": "^1.13.0",
"@azure/logger": "^1.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-client/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-http-compat": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.1.tgz",
"integrity": "sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-client": "^1.10.0",
"@azure/core-rest-pipeline": "^1.22.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-lro": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz",
"integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-util": "^1.2.0",
"@azure/logger": "^1.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-lro/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-paging": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz",
"integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-rest-pipeline": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz",
"integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.10.0",
"@azure/core-tracing": "^1.3.0",
"@azure/core-util": "^1.13.0",
"@azure/logger": "^1.3.0",
"@typespec/ts-http-runtime": "^0.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-tracing": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz",
"integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-util": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz",
"integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@typespec/ts-http-runtime": "^0.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-util/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/core-xml": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.5.0.tgz",
"integrity": "sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw==",
"license": "MIT",
"dependencies": {
"fast-xml-parser": "^5.0.7",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/logger": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz",
"integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==",
"license": "MIT",
"dependencies": {
"@typespec/ts-http-runtime": "^0.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/storage-blob": {
"version": "12.29.1",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.29.1.tgz",
"integrity": "sha512-7ktyY0rfTM0vo7HvtK6E3UvYnI9qfd6Oz6z/+92VhGRveWng3kJwMKeUpqmW/NmwcDNbxHpSlldG+vsUnRFnBg==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.9.0",
"@azure/core-client": "^1.9.3",
"@azure/core-http-compat": "^2.2.0",
"@azure/core-lro": "^2.2.0",
"@azure/core-paging": "^1.6.2",
"@azure/core-rest-pipeline": "^1.19.1",
"@azure/core-tracing": "^1.2.0",
"@azure/core-util": "^1.11.0",
"@azure/core-xml": "^1.4.5",
"@azure/logger": "^1.1.4",
"@azure/storage-common": "^12.1.1",
"events": "^3.0.0",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/storage-blob/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@azure/storage-common": {
"version": "12.1.1",
"resolved": "https://registry.npmjs.org/@azure/storage-common/-/storage-common-12.1.1.tgz",
"integrity": "sha512-eIOH1pqFwI6UmVNnDQvmFeSg0XppuzDLFeUNO/Xht7ODAzRLgGDh7h550pSxoA+lPDxBl1+D2m/KG3jWzCUjTg==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.9.0",
"@azure/core-http-compat": "^2.2.0",
"@azure/core-rest-pipeline": "^1.19.1",
"@azure/core-tracing": "^1.2.0",
"@azure/core-util": "^1.11.0",
"@azure/logger": "^1.1.4",
"events": "^3.3.0",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@azure/storage-common/node_modules/@azure/abort-controller": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@protobuf-ts/runtime": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz",
"integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==",
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@protobuf-ts/runtime-rpc": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz",
"integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==",
"license": "Apache-2.0",
"dependencies": {
"@protobuf-ts/runtime": "^2.11.1"
}
},
"node_modules/@types/node": {
"version": "24.10.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz",
"integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@typespec/ts-http-runtime": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz",
"integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==",
"license": "MIT",
"dependencies": {
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@vercel/ncc": {
"version": "0.38.4",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.4.tgz",
"integrity": "sha512-8LwjnlP39s08C08J5NstzriPvW1SP8Zfpp1BvC2sI35kPeZnHfxVkCwu4/+Wodgnd60UtT1n8K8zw+Mp7J9JmQ==",
"dev": true,
"license": "MIT",
"bin": {
"ncc": "dist/ncc/cli.js"
}
},
"node_modules/agent-base": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
"license": "MIT",
"engines": {
"node": ">= 14"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/fast-xml-parser": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.3.tgz",
"integrity": "sha512-2O3dkPAAC6JavuMm8+4+pgTk+5hoAs+CjZ+sWcQLkX9+/tHRuTkQh/Oaifr8qDmZ8iEHb771Ea6G8CdwkrgvYA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"strnum": "^2.1.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
"node_modules/http-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.0",
"debug": "^4.3.4"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/https-proxy-agent": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "4"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/prettier": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-plugin-organize-imports": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.3.0.tgz",
"integrity": "sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"prettier": ">=2.0",
"typescript": ">=2.9",
"vue-tsc": "^2.1.0 || 3"
},
"peerDependenciesMeta": {
"vue-tsc": {
"optional": true
}
}
},
"node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/strnum": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz",
"integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT"
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"license": "MIT",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/typescript": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
}
}
}

36
package.json Normal file
View file

@ -0,0 +1,36 @@
{
"name": "github-action",
"version": "4.0.0",
"description": "Connect your GitHub Action workflow to Tailscale",
"main": "dist/main.js",
"engines": {
"node": ">=24.0.0"
},
"scripts": {
"build": "ncc build src/main.ts -o dist && ncc build src/logout/logout.ts -o dist/logout"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tailscale/github-action"
},
"author": "Lee Briggs, Tailscale Inc, & Contributors",
"license": "BSD-3-Clause",
"dependencies": {
"@actions/cache": "^5.0.2",
"@actions/core": "^2.0.2",
"@actions/exec": "^2.0.0",
"@actions/tool-cache": "^3.0.0",
"semver": "^7.7.3"
},
"devDependencies": {
"@types/node": "^24.10.2",
"@vercel/ncc": "^0.38.3",
"typescript": "^6.0.3",
"prettier": "^3.8.3",
"prettier-plugin-organize-imports": "^4.3.0"
},
"overrides": {
"glob": "^10.3.10",
"inflight": "npm:@isaacs/inflight@^1.0.6"
}
}

92
src/logging.ts Normal file
View file

@ -0,0 +1,92 @@
// Copyright (c) Lee Briggs, Tailscale Inc, & Contributors
// SPDX-License-Identifier: BSD-3-Clause
import * as core from "@actions/core";
import * as exec from "@actions/exec";
import * as process from "process";
export type LogMode = "grouped" | "normal" | "quiet";
export class ExecError {
msg: string;
exitCode: number;
stderr: string;
public constructor(msg: string, exitCode: number, stderr: string) {
this.msg = msg;
this.exitCode = exitCode;
this.stderr = stderr;
}
public toString(): string {
return this.msg;
}
}
export function getLogMode(): LogMode {
const logMode = core.getInput("log-mode") || "grouped";
if (logMode !== "grouped" && logMode !== "normal" && logMode !== "quiet") {
throw new Error(
`Invalid log-mode "${logMode}". Expected "grouped", "normal", or "quiet".`,
);
}
return logMode;
}
export function logInfo(logMode: LogMode, message: string): void {
if (logMode !== "quiet") {
core.info(message);
}
}
export function logDebug(logMode: LogMode, message: string): void {
if (logMode !== "quiet") {
core.debug(message);
}
}
export async function withLogGroup<T>(
logMode: LogMode,
name: string,
fn: () => Promise<T>,
): Promise<T> {
if (logMode !== "grouped") {
return fn();
}
core.startGroup(name);
try {
return await fn();
} finally {
core.endGroup();
}
}
export async function execCommand(
commandLine: string,
args?: string[],
opts?: exec.ExecOptions & { label?: string; logMode?: LogMode },
): Promise<exec.ExecOutput> {
const { label, logMode = "normal", ...execOpts } = opts || {};
if (label) {
logInfo(logMode, `▶️ ${label}`);
}
const silent = execOpts.silent || logMode === "quiet" || !core.isDebug();
const out = await exec.getExecOutput(commandLine, args, {
...execOpts,
silent,
ignoreReturnCode: true,
});
if (out.exitCode !== 0) {
if (silent) {
process.stderr.write(out.stderr);
}
throw new ExecError(
`${commandLine} failed with exit code ${out.exitCode}`,
out.exitCode,
out.stderr,
);
}
return out;
}

111
src/logout/logout.ts Normal file
View file

@ -0,0 +1,111 @@
// Copyright (c) Lee Briggs, Tailscale Inc, & Contributors
// SPDX-License-Identifier: BSD-3-Clause
import * as core from "@actions/core";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { execCommand, getLogMode, logInfo, withLogGroup } from "../logging";
const runnerWindows = "Windows";
const runnerMacOS = "macOS";
async function logout(): Promise<void> {
try {
const runnerOS = process.env.RUNNER_OS || "";
const logMode = getLogMode();
await withLogGroup(logMode, "Cleaning up Tailscale", async () => {
if (runnerOS === runnerMacOS) {
// The below is required to allow GitHub's post job cleanup to complete.
logInfo(logMode, "Resetting DNS settings on macOS");
await execCommand(
"networksetup",
["-setdnsservers", "Ethernet", "Empty"],
{ logMode },
);
await execCommand(
"networksetup",
["-setsearchdomains", "Ethernet", "Empty"],
{ logMode },
);
}
logInfo(logMode, "🔄 Logging out of Tailscale...");
// Check if tailscale is available first
try {
await execCommand("tailscale", ["--version"], {
logMode,
silent: true,
});
// Determine the correct command based on OS
let execArgs: string[];
if (runnerOS === runnerWindows) {
execArgs = ["tailscale", "logout"];
} else {
// Linux and macOS - use system-installed binary with sudo
execArgs = ["sudo", "-E", "tailscale", "logout"];
}
logInfo(logMode, `Running: ${execArgs.join(" ")}`);
try {
await execCommand(execArgs[0], execArgs.slice(1), { logMode });
logInfo(logMode, "✅ Successfully logged out of Tailscale");
} catch (error) {
// Don't fail the action if logout fails - it's just cleanup
core.warning(`Failed to logout from Tailscale: ${error}`);
logInfo(
logMode,
"Your ephemeral node will eventually be cleaned up by Tailscale",
);
}
} catch (error) {
logInfo(
logMode,
"Tailscale not found or not accessible, skipping logout",
);
return;
}
logInfo(logMode, "Stopping tailscale");
try {
if (runnerOS === runnerWindows) {
await execCommand("net", ["stop", "Tailscale"], { logMode });
await execCommand("taskkill", ["/F", "/IM", "tailscale-ipn.exe"], {
logMode,
});
} else {
const xdgRuntimeDir =
process.env.XDG_RUNTIME_DIR ||
process.env.XDG_CACHE_HOME ||
path.join(os.homedir(), ".cache");
const pid = fs
.readFileSync(path.join(xdgRuntimeDir, "tailscaled.pid"))
.toString();
if (pid === "") {
throw new Error("pid file empty");
}
// The pid is actually the pid of the `sudo` parent of tailscaled, so use pkill -P to kill children of that parent
await execCommand("sudo", ["pkill", "-P", pid], { logMode });
// Clean up DNS and routes.
await execCommand("sudo", ["tailscaled", "--cleanup"], { logMode });
}
logInfo(logMode, "✅ Stopped tailscale");
} catch (error) {
core.warning(`Failed to stop tailscale: ${error}`);
}
});
} catch (error) {
// Don't fail the action for post-cleanup issues
core.warning(`Post-action cleanup error: ${error}`);
}
}
// Run the logout function
logout().catch((error) => {
// Even if logout fails, don't fail the action
core.warning(`Logout process failed: ${error}`);
});

1078
src/main.ts Normal file

File diff suppressed because it is too large Load diff

63
tsconfig.json Normal file
View file

@ -0,0 +1,63 @@
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "NodeNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
"moduleResolution": "NodeNext", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
"types": ["node"], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"exclude": ["node_modules", "**/*.test.ts"]
}