Skip to content

Commit 823070e

Browse files
TowyTowyclaude
andcommitted
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>
1 parent 508737e commit 823070e

2 files changed

Lines changed: 65 additions & 18 deletions

File tree

dist/index.js

Lines changed: 29 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -472,19 +472,46 @@ async function installTailscaleLinux(
472472

473473
// Download and extract
474474
const downloadUrl = `${baseUrl}/tailscale_${config.resolvedVersion}_${config.arch}.tgz`;
475-
logInfo(config.logMode, `Downloading ${downloadUrl}`);
475+
const expectedSha = config.sha256Sum.trim().toLowerCase();
476476

477477
const tarDest = path.join(xdgCacheDir(), "tailscale.tgz");
478478
fs.mkdirSync(path.dirname(tarDest), { recursive: true });
479-
const tarPath = await tc.downloadTool(downloadUrl, tarDest);
480479

481-
// Verify checksum
482-
const actualSha = await calculateFileSha256(tarPath);
483-
const expectedSha = config.sha256Sum.trim().toLowerCase();
484-
logInfo(config.logMode, `Expected sha256: ${expectedSha}`);
485-
logInfo(config.logMode, `Actual sha256: ${actualSha}`);
486-
if (actualSha !== expectedSha) {
487-
throw new Error("SHA256 checksum mismatch");
480+
// Check if the tarball already exists with the correct checksum (for
481+
// persistent self-hosted runners). tc.downloadTool refuses to overwrite an
482+
// existing destination, so a tarball leaked by a previous job would
483+
// otherwise fail with "Destination file path already exists" whenever the
484+
// GitHub Actions cache backend doesn't return a hit.
485+
let tarPath = tarDest;
486+
let needsDownload = true;
487+
if (fs.existsSync(tarDest)) {
488+
const existingSha = await calculateFileSha256(tarDest);
489+
if (existingSha === expectedSha) {
490+
logInfo(
491+
config.logMode,
492+
`Using existing tarball at ${tarDest} (checksum verified)`,
493+
);
494+
needsDownload = false;
495+
} else {
496+
logInfo(
497+
config.logMode,
498+
`Existing tarball checksum mismatch, re-downloading`,
499+
);
500+
fs.unlinkSync(tarDest);
501+
}
502+
}
503+
504+
if (needsDownload) {
505+
logInfo(config.logMode, `Downloading ${downloadUrl}`);
506+
tarPath = await tc.downloadTool(downloadUrl, tarDest);
507+
508+
// Verify checksum
509+
const actualSha = await calculateFileSha256(tarPath);
510+
logInfo(config.logMode, `Expected sha256: ${expectedSha}`);
511+
logInfo(config.logMode, `Actual sha256: ${actualSha}`);
512+
if (actualSha !== expectedSha) {
513+
throw new Error("SHA256 checksum mismatch");
514+
}
488515
}
489516

490517
// Extract to tool path

0 commit comments

Comments
 (0)