@rubytech/taskmaster 1.9.5 → 1.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build-info.json
CHANGED
|
@@ -122,6 +122,29 @@ export const tailscaleHandlers = {
|
|
|
122
122
|
message: typeof errObj.message === "string" ? errObj.message : "",
|
|
123
123
|
};
|
|
124
124
|
};
|
|
125
|
+
const needsSudo = (output) => {
|
|
126
|
+
const lower = output.toLowerCase();
|
|
127
|
+
return (lower.includes("access denied") ||
|
|
128
|
+
lower.includes("permission denied") ||
|
|
129
|
+
lower.includes("use 'sudo tailscale") ||
|
|
130
|
+
lower.includes("requires root"));
|
|
131
|
+
};
|
|
132
|
+
// Run `tailscale up` (with optional extra args) and capture output.
|
|
133
|
+
// If the command fails with a permission error, retries with `sudo -n`.
|
|
134
|
+
// `tailscale up` blocks until auth completes, so timeouts are expected —
|
|
135
|
+
// the auth URL appears in stdout/stderr before the timeout kills it.
|
|
136
|
+
const runTailscaleUp = async (binary, extraArgs = []) => {
|
|
137
|
+
const args = ["up", ...extraArgs];
|
|
138
|
+
const execOpts = { timeoutMs: 60_000, maxBuffer: 100_000 };
|
|
139
|
+
const result = await runExec(binary, args, execOpts).catch((err) => captureExecOutput(err));
|
|
140
|
+
const output = `${result.stdout}\n${result.stderr}`;
|
|
141
|
+
if (!needsSudo(output))
|
|
142
|
+
return output;
|
|
143
|
+
// Permission denied — retry with sudo -n (non-interactive)
|
|
144
|
+
context.logGateway.info(`tailscale.enable: permission denied, retrying with sudo: ${args.join(" ")}`);
|
|
145
|
+
const sudoResult = await runExec("sudo", ["-n", binary, ...args], execOpts).catch((err) => captureExecOutput(err));
|
|
146
|
+
return `${sudoResult.stdout}\n${sudoResult.stderr}`;
|
|
147
|
+
};
|
|
125
148
|
try {
|
|
126
149
|
const binary = await findTailscaleBinary();
|
|
127
150
|
if (!binary) {
|
|
@@ -149,20 +172,7 @@ export const tailscaleHandlers = {
|
|
|
149
172
|
// Other status errors (e.g. NeedsLogin) are fine — continue to `tailscale up`
|
|
150
173
|
}
|
|
151
174
|
// ── Attempt 1: `tailscale up` ──
|
|
152
|
-
|
|
153
|
-
// "To authenticate, visit:\n\n\thttps://login.tailscale.com/a/..."
|
|
154
|
-
// The command blocks until auth completes, so we run it with a
|
|
155
|
-
// timeout and parse the auth URL from the output. The URL appears
|
|
156
|
-
// within seconds; the timeout just kills the blocking wait.
|
|
157
|
-
const child = await runExec(binary, ["up"], {
|
|
158
|
-
timeoutMs: 60_000,
|
|
159
|
-
maxBuffer: 100_000,
|
|
160
|
-
}).catch((err) => {
|
|
161
|
-
// `tailscale up` exits non-zero while waiting for auth but still
|
|
162
|
-
// prints the URL to stdout/stderr before the timeout kills it.
|
|
163
|
-
return captureExecOutput(err);
|
|
164
|
-
});
|
|
165
|
-
const combined = `${child.stdout}\n${child.stderr}`;
|
|
175
|
+
const combined = await runTailscaleUp(binary);
|
|
166
176
|
const authUrl = extractAuthUrl(combined);
|
|
167
177
|
if (authUrl) {
|
|
168
178
|
respond(true, { authUrl });
|
|
@@ -184,11 +194,7 @@ export const tailscaleHandlers = {
|
|
|
184
194
|
// state where plain `tailscale up` doesn't produce a new auth URL.
|
|
185
195
|
// --force-reauth forces a fresh login flow that always emits a URL.
|
|
186
196
|
context.logGateway.info("tailscale.enable: no auth URL from initial attempt, retrying with --force-reauth");
|
|
187
|
-
const
|
|
188
|
-
timeoutMs: 60_000,
|
|
189
|
-
maxBuffer: 100_000,
|
|
190
|
-
}).catch((err) => captureExecOutput(err));
|
|
191
|
-
const retryCombined = `${retry.stdout}\n${retry.stderr}`;
|
|
197
|
+
const retryCombined = await runTailscaleUp(binary, ["--force-reauth"]);
|
|
192
198
|
const retryUrl = extractAuthUrl(retryCombined);
|
|
193
199
|
if (retryUrl) {
|
|
194
200
|
respond(true, { authUrl: retryUrl });
|