Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,26 @@ jobs:
arch: arm64
version: latest

# macOS intel
# macOS 13 (AMD64)
- os: macos-13
runner-os: macOS
arch: amd64
version: latest
ping: 100.99.0.2 # hostnames aren't resolving on MacOS, just ping IP lax-pve.pineapplefish.ts.net,lax-pve
ping: 100.99.0.2,lax-pve.pineapplefish.ts.net,lax-pve

# macOS ARM
# 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

# 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

runs-on: ${{ matrix.os }}

Expand Down Expand Up @@ -104,6 +112,13 @@ jobs:
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'
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ tailscale ping my-target.my-tailnet.ts.net

The `ping` option will wait up to to 3 minutes for a connection (direct or relayed).

> ⚠️ On macOS runners, one can only ping IP addresses, not hostnames.

## Tailnet Lock

If you are using this Action in a [Tailnet
Expand Down
29 changes: 29 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41244,6 +41244,9 @@ async function run() {
core.debug(`Tailscale status: ${JSON.stringify(status)}`);
if (status.BackendState === "Running") {
core.info("✅ Tailscale is running and connected!");
if (runnerOS === runnerMacOS) {
await configureDNSOnMacOS(status);
}
await pingHostsIfNecessary(config);
// Explicitly exit to prevent hanging
process.exit(0);
Expand All @@ -41255,6 +41258,10 @@ async function run() {
}
catch (err) {
core.warning(`Failed to get Tailscale status: ${err}`);
if (runnerOS === runnerMacOS) {
core.setFailed(`❌ Tailscale status is required in order to configure macOS`);
process.exit(2);
}
// Still exit successfully since the main connection worked
core.info("✅ Tailscale daemon is connected!");
await pingHostsIfNecessary(config);
Expand Down Expand Up @@ -41750,6 +41757,28 @@ async function installCachedBinaries(toolPath, runnerOS) {
}
}
}
async function configureDNSOnMacOS(status) {
if (!status.CurrentTailnet.MagicDNSEnabled) {
core.info("MagicDNS is disabled, not configuring DNS");
return;
}
core.info(`Setting system DNS server to 100.100.100.100 and searchdomains to ${status.CurrentTailnet.MagicDNSSuffix}`);
try {
await exec.exec("networksetup", [
"-setdnsservers",
"Ethernet",
"100.100.100.100",
]);
await exec.exec("networksetup", [
"-setsearchdomains",
"Ethernet",
status.CurrentTailnet.MagicDNSSuffix,
]);
}
catch (e) {
throw Error(`Failed to configure DNS on macOS: ${e}`);
}
}
run();


Expand Down
10 changes: 10 additions & 0 deletions dist/logout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25689,6 +25689,16 @@ const exec = __importStar(__nccwpck_require__(5236));
async function logout() {
try {
const runnerOS = process.env.RUNNER_OS || "";
if (runnerOS === "macOS") {
// The below is required to allow GitHub's post job cleanup to complete.
core.info("Resetting DNS settings on macOS");
await exec.exec("networksetup", ["-setdnsservers", "Ethernet", "Empty"]);
await exec.exec("networksetup", [
"-setsearchdomains",
"Ethernet",
"Empty",
]);
}
core.info("🔄 Logging out of Tailscale...");
// Check if tailscale is available first
try {
Expand Down
11 changes: 11 additions & 0 deletions src/logout/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ async function logout(): Promise<void> {
try {
const runnerOS = process.env.RUNNER_OS || "";

if (runnerOS === "macOS") {
// The below is required to allow GitHub's post job cleanup to complete.
core.info("Resetting DNS settings on macOS");
await exec.exec("networksetup", ["-setdnsservers", "Ethernet", "Empty"]);
await exec.exec("networksetup", [
"-setsearchdomains",
"Ethernet",
"Empty",
]);
}

core.info("🔄 Logging out of Tailscale...");

// Check if tailscale is available first
Expand Down
46 changes: 45 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,18 @@ interface TailscaleConfig {
pingHosts: string[];
}

type tailnetInfo = {
MagicDNSSuffix: string;
MagicDNSEnabled: boolean;
};

type tailscaleStatus = {
BackendState: string;
CurrentTailnet: tailnetInfo;
};

// Cross-platform Tailscale local API status check
async function getTailscaleStatus(): Promise<any> {
async function getTailscaleStatus(): Promise<tailscaleStatus> {
const platform = os.platform();

if (platform === platformWin32) {
Expand Down Expand Up @@ -171,6 +181,9 @@ async function run(): Promise<void> {
core.debug(`Tailscale status: ${JSON.stringify(status)}`);
if (status.BackendState === "Running") {
core.info("✅ Tailscale is running and connected!");
if (runnerOS === runnerMacOS) {
await configureDNSOnMacOS(status);
}
await pingHostsIfNecessary(config);
// Explicitly exit to prevent hanging
process.exit(0);
Expand All @@ -180,6 +193,12 @@ async function run(): Promise<void> {
}
} catch (err) {
core.warning(`Failed to get Tailscale status: ${err}`);
if (runnerOS === runnerMacOS) {
core.setFailed(
`❌ Tailscale status is required in order to configure macOS`
);
process.exit(2);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we exit with status code 2 here specifically?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just wanted something different so that one can distinguish this particular condition if need be.

}
// Still exit successfully since the main connection worked
core.info("✅ Tailscale daemon is connected!");
await pingHostsIfNecessary(config);
Expand Down Expand Up @@ -799,4 +818,29 @@ async function installCachedBinaries(
}
}

async function configureDNSOnMacOS(status: tailscaleStatus): Promise<void> {
if (!status.CurrentTailnet.MagicDNSEnabled) {
core.info("MagicDNS is disabled, not configuring DNS");
return;
}

core.info(
`Setting system DNS server to 100.100.100.100 and searchdomains to ${status.CurrentTailnet.MagicDNSSuffix}`
);
try {
await exec.exec("networksetup", [
"-setdnsservers",
"Ethernet",
"100.100.100.100",
]);
await exec.exec("networksetup", [
"-setsearchdomains",
"Ethernet",
status.CurrentTailnet.MagicDNSSuffix,
]);
} catch (e) {
throw Error(`Failed to configure DNS on macOS: ${e}`);
}
}

run();
Loading