@cardelli/ambit 0.2.3 → 0.3.0
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/README.md +38 -22
- package/esm/cli/commands/create/index.js +64 -10
- package/esm/cli/commands/create/machine.d.ts.map +1 -1
- package/esm/cli/commands/create/machine.js +1 -1
- package/esm/cli/commands/deploy/index.js +2 -4
- package/esm/cli/commands/deploy/machine.d.ts.map +1 -1
- package/esm/cli/commands/destroy/app.d.ts.map +1 -1
- package/esm/cli/commands/destroy/index.js +2 -0
- package/esm/cli/commands/destroy/network.d.ts.map +1 -1
- package/esm/cli/commands/destroy/network.js +66 -5
- package/esm/cli/commands/doctor.js +13 -4
- package/esm/cli/commands/list.js +1 -1
- package/esm/cli/commands/share.d.ts +2 -0
- package/esm/cli/commands/share.d.ts.map +1 -0
- package/esm/cli/commands/share.js +250 -0
- package/esm/cli/commands/status.js +4 -1
- package/esm/cli/mod.d.ts.map +1 -1
- package/esm/cli/mod.js +2 -0
- package/esm/deno.js +1 -1
- package/esm/lib/command.d.ts.map +1 -1
- package/esm/lib/command.js +5 -7
- package/esm/main.d.ts +1 -0
- package/esm/main.d.ts.map +1 -1
- package/esm/main.js +2 -0
- package/esm/providers/fly.d.ts.map +1 -1
- package/esm/providers/fly.js +14 -3
- package/esm/providers/tailscale.d.ts +7 -0
- package/esm/providers/tailscale.d.ts.map +1 -1
- package/esm/providers/tailscale.js +23 -1
- package/esm/util/credentials.d.ts.map +1 -1
- package/esm/util/credentials.js +1 -1
- package/esm/util/discovery.d.ts.map +1 -1
- package/esm/util/discovery.js +1 -1
- package/esm/util/tailscale-local.d.ts +41 -0
- package/esm/util/tailscale-local.d.ts.map +1 -1
- package/esm/util/tailscale-local.js +146 -0
- package/esm/util/template.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Share Command - Grant Members Access to a Network via Tailscale ACL
|
|
3
|
+
// =============================================================================
|
|
4
|
+
import { parseArgs } from "../../deps/jsr.io/@std/cli/1.0.28/mod.js";
|
|
5
|
+
import { bold } from "../../lib/cli.js";
|
|
6
|
+
import { checkArgs } from "../../lib/args.js";
|
|
7
|
+
import { createOutput } from "../../lib/output.js";
|
|
8
|
+
import { registerCommand } from "../mod.js";
|
|
9
|
+
import { z } from "../../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
10
|
+
import { findRouterApp, getRouterMachineInfo } from "../../util/discovery.js";
|
|
11
|
+
import { getRouterTag } from "../../util/naming.js";
|
|
12
|
+
import { assertAdditivePatch, isAclRuleConfigured, patchAclRule, } from "../../util/tailscale-local.js";
|
|
13
|
+
import { initSession } from "../../util/session.js";
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Validation
|
|
16
|
+
// =============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Valid members: Tailscale group/tag/autogroup prefixes, or a plain email.
|
|
19
|
+
*/
|
|
20
|
+
const MemberSchema = z.union([
|
|
21
|
+
z.string().startsWith("group:").min(7, 'Must be in the form "group:<name>"'),
|
|
22
|
+
z.string().startsWith("tag:").min(5, 'Must be in the form "tag:<name>"'),
|
|
23
|
+
z.string().startsWith("autogroup:").min(11, 'Must be in the form "autogroup:<name>"'),
|
|
24
|
+
z.email(),
|
|
25
|
+
]);
|
|
26
|
+
const parseMembers = (raw) => {
|
|
27
|
+
const members = [];
|
|
28
|
+
const errors = [];
|
|
29
|
+
for (const entry of raw) {
|
|
30
|
+
const result = MemberSchema.safeParse(String(entry));
|
|
31
|
+
if (result.success) {
|
|
32
|
+
members.push(result.data);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
errors.push(` '${entry}' — Must Be a Group ("group:team"), Tag ("tag:router"), Autogroup ("autogroup:member"), or Email`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { members, errors };
|
|
39
|
+
};
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// ACL Error Helper
|
|
42
|
+
// =============================================================================
|
|
43
|
+
const handleAclSetFailure = (out, result, action) => {
|
|
44
|
+
if (result.status === 403) {
|
|
45
|
+
out.err(`${action}: Permission Denied (HTTP 403)`);
|
|
46
|
+
return out.die("Your API Token Lacks ACL Write Permission (policy_file scope required)");
|
|
47
|
+
}
|
|
48
|
+
return out.die(`${action}: ${result.error ?? `HTTP ${result.status}`}`);
|
|
49
|
+
};
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// Stage 1: Discover Router
|
|
52
|
+
// =============================================================================
|
|
53
|
+
const stageDiscover = async (ctx) => {
|
|
54
|
+
ctx.out.header("Step 1: Discover Router").blank();
|
|
55
|
+
const routerSpinner = ctx.out.spinner(`Looking Up Router for '${ctx.network}'`);
|
|
56
|
+
const router = await findRouterApp(ctx.fly, ctx.org, ctx.network);
|
|
57
|
+
if (!router) {
|
|
58
|
+
routerSpinner.fail(`No Router Found for '${ctx.network}'`);
|
|
59
|
+
return ctx.out.die(`No Router Found for Network '${ctx.network}'. Create It with: ambit create ${ctx.network}`);
|
|
60
|
+
}
|
|
61
|
+
ctx.appName = router.appName;
|
|
62
|
+
routerSpinner.success(`Found Router: ${router.appName}`);
|
|
63
|
+
const machineSpinner = ctx.out.spinner("Getting Subnet");
|
|
64
|
+
const machine = await getRouterMachineInfo(ctx.fly, router.appName);
|
|
65
|
+
if (!machine?.subnet) {
|
|
66
|
+
machineSpinner.fail("No Subnet Found");
|
|
67
|
+
return ctx.out.die(`Router Has No Subnet Yet. Ensure the Router Is Running: ambit status network ${ctx.network}`);
|
|
68
|
+
}
|
|
69
|
+
ctx.subnet = machine.subnet;
|
|
70
|
+
machineSpinner.success(`Subnet: ${machine.subnet}`);
|
|
71
|
+
const device = await ctx.tailscale.devices.getByHostname(router.appName);
|
|
72
|
+
ctx.tag = device?.tags?.[0] ?? getRouterTag(ctx.network);
|
|
73
|
+
ctx.out.ok(`Tag: ${ctx.tag}`);
|
|
74
|
+
ctx.out.blank();
|
|
75
|
+
};
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// Stage 2: Update ACL Policy
|
|
78
|
+
// =============================================================================
|
|
79
|
+
const stageUpdateAcl = async (ctx) => {
|
|
80
|
+
ctx.out.header("Step 2: Update ACL Policy").blank();
|
|
81
|
+
const policy = await ctx.tailscale.acl.getPolicy();
|
|
82
|
+
if (!policy) {
|
|
83
|
+
return ctx.out.die("Could Not Read Tailscale ACL Policy");
|
|
84
|
+
}
|
|
85
|
+
const dnsDst = `${ctx.tag}:53`;
|
|
86
|
+
const subnetDst = `${ctx.subnet}:*`;
|
|
87
|
+
let updated = policy;
|
|
88
|
+
for (const member of ctx.members) {
|
|
89
|
+
const hasDns = isAclRuleConfigured(updated, member, dnsDst);
|
|
90
|
+
const hasSubnet = isAclRuleConfigured(updated, member, subnetDst);
|
|
91
|
+
if (hasDns && hasSubnet) {
|
|
92
|
+
ctx.out.skip(`${member} — Already Has Full Access`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (hasDns) {
|
|
96
|
+
ctx.out.skip(`${member} — DNS Rule Already Present`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
updated = patchAclRule(updated, member, dnsDst);
|
|
100
|
+
ctx.rulesAdded++;
|
|
101
|
+
}
|
|
102
|
+
if (hasSubnet) {
|
|
103
|
+
ctx.out.skip(`${member} — Subnet Rule Already Present`);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
updated = patchAclRule(updated, member, subnetDst);
|
|
107
|
+
ctx.rulesAdded++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (ctx.rulesAdded === 0) {
|
|
111
|
+
ctx.out.blank().ok(`All Members Already Have Full Access to '${ctx.network}'`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
assertAdditivePatch(policy, updated);
|
|
115
|
+
const validateSpinner = ctx.out.spinner("Validating Policy");
|
|
116
|
+
const validateResult = await ctx.tailscale.acl.validatePolicy(updated);
|
|
117
|
+
if (!validateResult.ok) {
|
|
118
|
+
validateSpinner.fail("Policy Validation Failed");
|
|
119
|
+
return handleAclSetFailure(ctx.out, validateResult, "Validating ACL Policy");
|
|
120
|
+
}
|
|
121
|
+
validateSpinner.success("Policy Valid");
|
|
122
|
+
const n = ctx.rulesAdded;
|
|
123
|
+
const patchSpinner = ctx.out.spinner(`Updating ACL Policy (${n} new rule${n !== 1 ? "s" : ""})`);
|
|
124
|
+
const result = await ctx.tailscale.acl.setPolicy(updated);
|
|
125
|
+
if (!result.ok) {
|
|
126
|
+
patchSpinner.fail("Failed to Update ACL Policy");
|
|
127
|
+
return handleAclSetFailure(ctx.out, result, "Updating ACL Policy");
|
|
128
|
+
}
|
|
129
|
+
patchSpinner.success(`ACL Policy Updated (${n} rule${n !== 1 ? "s" : ""} added)`);
|
|
130
|
+
};
|
|
131
|
+
// =============================================================================
|
|
132
|
+
// Stage 3: Summary
|
|
133
|
+
// =============================================================================
|
|
134
|
+
const stageSummary = (ctx) => {
|
|
135
|
+
const { out, network, members, tag, subnet, rulesAdded } = ctx;
|
|
136
|
+
out.done({ network, members, tag: tag, subnet: subnet, rulesAdded });
|
|
137
|
+
if (rulesAdded === 0) {
|
|
138
|
+
out.blank();
|
|
139
|
+
out.print();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
out.blank()
|
|
143
|
+
.header("=".repeat(50))
|
|
144
|
+
.header(" Access Granted!")
|
|
145
|
+
.header("=".repeat(50))
|
|
146
|
+
.blank();
|
|
147
|
+
for (const member of members) {
|
|
148
|
+
out.ok(`${member}`);
|
|
149
|
+
}
|
|
150
|
+
out.blank()
|
|
151
|
+
.dim(` DNS: → ${tag}:53`)
|
|
152
|
+
.dim(` Subnet: → ${subnet}:*`)
|
|
153
|
+
.blank()
|
|
154
|
+
.dim("Invite People to Your Tailnet:")
|
|
155
|
+
.link(" https://login.tailscale.com/admin/users")
|
|
156
|
+
.blank()
|
|
157
|
+
.dim("To Fine-Tune Which Apps They Can Reach:")
|
|
158
|
+
.link(" https://login.tailscale.com/admin/acls/visual/general-access-rules")
|
|
159
|
+
.blank();
|
|
160
|
+
out.print();
|
|
161
|
+
};
|
|
162
|
+
// =============================================================================
|
|
163
|
+
// Share Command
|
|
164
|
+
// =============================================================================
|
|
165
|
+
const share = async (argv) => {
|
|
166
|
+
const opts = {
|
|
167
|
+
string: ["org"],
|
|
168
|
+
boolean: ["help", "json"],
|
|
169
|
+
};
|
|
170
|
+
const args = parseArgs(argv, opts);
|
|
171
|
+
checkArgs(args, opts, "ambit share");
|
|
172
|
+
if (args.help) {
|
|
173
|
+
console.log(`
|
|
174
|
+
${bold("ambit share")} - Grant Members Access to a Network
|
|
175
|
+
|
|
176
|
+
${bold("USAGE")}
|
|
177
|
+
ambit share <network> <member> [<member>...] [options]
|
|
178
|
+
|
|
179
|
+
${bold("MEMBER TYPES")}
|
|
180
|
+
group:<name> A Tailscale group (e.g. group:team)
|
|
181
|
+
tag:<name> A device tag (e.g. tag:router)
|
|
182
|
+
autogroup:<name> A built-in group (e.g. autogroup:member)
|
|
183
|
+
<email> A Tailscale user (e.g. alice@example.com)
|
|
184
|
+
|
|
185
|
+
${bold("OPTIONS")}
|
|
186
|
+
--org <org> Fly.io organization slug
|
|
187
|
+
--json Output as JSON
|
|
188
|
+
|
|
189
|
+
${bold("DESCRIPTION")}
|
|
190
|
+
Grants access to a network by updating your Tailscale ACL policy.
|
|
191
|
+
For each member, ambit adds two rules:
|
|
192
|
+
1. DNS: <member> → <tag>:53 (resolve *.${args._[0] || "<network>"} names)
|
|
193
|
+
2. Subnet: <member> → <subnet>:* (reach apps on the network)
|
|
194
|
+
|
|
195
|
+
The command is idempotent — re-running it is safe.
|
|
196
|
+
|
|
197
|
+
${bold("EXAMPLES")}
|
|
198
|
+
ambit share browsers group:team
|
|
199
|
+
ambit share browsers group:team alice@example.com group:contractors
|
|
200
|
+
ambit share browsers group:team --org my-org
|
|
201
|
+
`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const out = createOutput(args.json);
|
|
205
|
+
const networkArg = args._[0];
|
|
206
|
+
if (!networkArg || typeof networkArg !== "string") {
|
|
207
|
+
return out.die("Network Name Required. Usage: ambit share <network> <member> [...]");
|
|
208
|
+
}
|
|
209
|
+
const rawMembers = args._.slice(1);
|
|
210
|
+
if (rawMembers.length === 0) {
|
|
211
|
+
return out.die("At Least One Member Required. Usage: ambit share <network> <member> [...]");
|
|
212
|
+
}
|
|
213
|
+
const { members, errors } = parseMembers(rawMembers);
|
|
214
|
+
if (errors.length > 0) {
|
|
215
|
+
for (const err of errors)
|
|
216
|
+
out.err(err);
|
|
217
|
+
return out.die(`Invalid Member${errors.length > 1 ? "s" : ""}: Must Be "group:<name>", "tag:<name>", "autogroup:<name>", or a Valid Email`);
|
|
218
|
+
}
|
|
219
|
+
out.blank()
|
|
220
|
+
.header("=".repeat(50))
|
|
221
|
+
.header(` ambit Share: ${networkArg}`)
|
|
222
|
+
.header("=".repeat(50))
|
|
223
|
+
.blank();
|
|
224
|
+
const { fly, tailscale, org } = await initSession(out, {
|
|
225
|
+
json: args.json,
|
|
226
|
+
org: args.org,
|
|
227
|
+
});
|
|
228
|
+
const ctx = {
|
|
229
|
+
fly,
|
|
230
|
+
tailscale,
|
|
231
|
+
out,
|
|
232
|
+
network: networkArg,
|
|
233
|
+
org,
|
|
234
|
+
members,
|
|
235
|
+
json: args.json,
|
|
236
|
+
rulesAdded: 0,
|
|
237
|
+
};
|
|
238
|
+
await stageDiscover(ctx);
|
|
239
|
+
await stageUpdateAcl(ctx);
|
|
240
|
+
stageSummary(ctx);
|
|
241
|
+
};
|
|
242
|
+
// =============================================================================
|
|
243
|
+
// Register Command
|
|
244
|
+
// =============================================================================
|
|
245
|
+
registerCommand({
|
|
246
|
+
name: "share",
|
|
247
|
+
description: "Grant members access to a network via Tailscale ACL rules",
|
|
248
|
+
usage: "ambit share <network> <member> [<member>...]",
|
|
249
|
+
run: share,
|
|
250
|
+
});
|
|
@@ -224,7 +224,10 @@ const stageAppStatus = async (fly, tailscale, app, network, org, json) => {
|
|
|
224
224
|
// Status App Subcommand
|
|
225
225
|
// =============================================================================
|
|
226
226
|
const statusApp = async (argv) => {
|
|
227
|
-
const opts = {
|
|
227
|
+
const opts = {
|
|
228
|
+
string: ["network", "org"],
|
|
229
|
+
boolean: ["help", "json"],
|
|
230
|
+
};
|
|
228
231
|
const args = parseArgs(argv, opts);
|
|
229
232
|
checkArgs(args, opts, "ambit status app");
|
|
230
233
|
if (args.help) {
|
package/esm/cli/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/cli/mod.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAQD,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,IAElD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,OAAO,GAAG,SAEnD,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,OAAO,EAExC,CAAC;AAQF,eAAO,MAAM,QAAQ,QAAO,
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/cli/mod.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAQD,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,IAElD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,OAAO,GAAG,SAEnD,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,OAAO,EAExC,CAAC;AAQF,eAAO,MAAM,QAAQ,QAAO,IA+B3B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAMF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAuCzD,CAAC"}
|
package/esm/cli/mod.js
CHANGED
|
@@ -32,6 +32,7 @@ ${bold("USAGE")}
|
|
|
32
32
|
${bold("COMMANDS")}
|
|
33
33
|
create Create a Tailscale subnet router on a Fly.io custom network
|
|
34
34
|
deploy Deploy an app safely on a custom private network
|
|
35
|
+
share Grant a Tailscale group access to a network via ACL rules
|
|
35
36
|
list List all discovered routers across networks
|
|
36
37
|
status Show router status, network, and tailnet info
|
|
37
38
|
destroy Destroy a network (router) or a workload app
|
|
@@ -43,6 +44,7 @@ ${bold("OPTIONS")}
|
|
|
43
44
|
|
|
44
45
|
${bold("EXAMPLES")}
|
|
45
46
|
ambit create browsers
|
|
47
|
+
ambit share browsers group:team
|
|
46
48
|
ambit list
|
|
47
49
|
ambit status --network browsers
|
|
48
50
|
ambit destroy network browsers
|
package/esm/deno.js
CHANGED
package/esm/lib/command.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lib/command.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMrC,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAMD,qBAAa,SAAS;IAIlB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IALzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;gBAGV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;IAKzB,iDAAiD;IACjD,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;IAapB,8BAA8B;IAC9B,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF;AAMD;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lib/command.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMrC,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAMD,qBAAa,SAAS;IAIlB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IALzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;gBAGV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;IAKzB,iDAAiD;IACjD,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;IAapB,8BAA8B;IAC9B,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF;AAMD;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,SAAS,CAyCnB,CAAC;AAMF,oCAAoC;AACpC,eAAO,MAAM,OAAO,GAAI,CAAC,EACvB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAuD,CAAC"}
|
package/esm/lib/command.js
CHANGED
|
@@ -48,13 +48,11 @@ export const runCommand = (args, options) => {
|
|
|
48
48
|
const child = spawn(cmd, cmdArgs, {
|
|
49
49
|
cwd: options?.cwd,
|
|
50
50
|
env: options?.env ? { ...process.env, ...options.env } : undefined,
|
|
51
|
-
stdio: interactive
|
|
52
|
-
? "inherit"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"pipe",
|
|
57
|
-
],
|
|
51
|
+
stdio: interactive ? "inherit" : [
|
|
52
|
+
options?.stdin === "inherit" ? "inherit" : "ignore",
|
|
53
|
+
"pipe",
|
|
54
|
+
"pipe",
|
|
55
|
+
],
|
|
58
56
|
});
|
|
59
57
|
if (interactive) {
|
|
60
58
|
child.on("error", () => {
|
package/esm/main.d.ts
CHANGED
package/esm/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC;AA+B7B,OAAO,gCAAgC,CAAC;AACxC,OAAO,gCAAgC,CAAC;AACxC,OAAO,yBAAyB,CAAC;AACjC,OAAO,wBAAwB,CAAC;AAChC,OAAO,0BAA0B,CAAC;AAClC,OAAO,iCAAiC,CAAC;AACzC,OAAO,0BAA0B,CAAC"}
|
package/esm/main.js
CHANGED
|
@@ -12,6 +12,7 @@ import * as dntShim from "./_dnt.shims.js";
|
|
|
12
12
|
// Commands:
|
|
13
13
|
// create Create a Tailscale subnet router on a Fly.io custom network
|
|
14
14
|
// deploy Deploy an app safely on a custom private network
|
|
15
|
+
// share Grant a group access to a network via Tailscale ACL rules
|
|
15
16
|
// status Show router status, network, and tailnet info
|
|
16
17
|
// destroy Destroy a network (router) or a workload app
|
|
17
18
|
// doctor Check that Tailscale and the router are working correctly
|
|
@@ -28,6 +29,7 @@ import { runCli } from "./cli/mod.js";
|
|
|
28
29
|
import { Spinner, statusErr } from "./lib/cli.js";
|
|
29
30
|
import "./cli/commands/create/index.js";
|
|
30
31
|
import "./cli/commands/deploy/index.js";
|
|
32
|
+
import "./cli/commands/share.js";
|
|
31
33
|
import "./cli/commands/list.js";
|
|
32
34
|
import "./cli/commands/status.js";
|
|
33
35
|
import "./cli/commands/destroy/index.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../src/providers/fly.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,UAAU,EAIf,KAAK,KAAK,EAEV,KAAK,UAAU,EAIhB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../src/providers/fly.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,UAAU,EAIf,KAAK,KAAK,EAEV,KAAK,UAAU,EAIhB,MAAM,mBAAmB,CAAC;AAa3B;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAMxC;AAMD,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;AAE9E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE;QACJ,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE;YAAE,WAAW,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACzD,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;KAC7B,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KACzC,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QACpD,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACvC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;KAClE,CAAC;IACF,QAAQ,EAAE;QACR,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QACzC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACxD,CAAC;IACF,OAAO,EAAE;QACP,GAAG,CACD,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC;KAClB,CAAC;IACF,GAAG,EAAE;QACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACrD,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9D,CAAC;IACF,KAAK,EAAE;QACL,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACtD,CAAC;IACF,MAAM,EAAE;QACN,MAAM,CACJ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;QACjB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7D,CAAC;CACH;AAMD,eAAO,MAAM,iBAAiB,QAAO,WAqcpC,CAAC"}
|
package/esm/providers/fly.js
CHANGED
|
@@ -9,7 +9,7 @@ import { dirname, resolve } from "../deps/jsr.io/@std/path/1.1.4/mod.js";
|
|
|
9
9
|
import { FlyAppInfoListSchema, FlyAppsListSchema, FlyAuthSchema, FlyIpListSchema, FlyMachinesListSchema, FlyOrgsSchema, FlyStatusSchema, } from "../schemas/fly.js";
|
|
10
10
|
import { fileExists } from "../lib/cli.js";
|
|
11
11
|
import { getWorkloadAppName } from "../util/naming.js";
|
|
12
|
-
import { extractErrorDetail, getSizeConfig, mapMachines } from "../util/fly-transforms.js";
|
|
12
|
+
import { extractErrorDetail, getSizeConfig, mapMachines, } from "../util/fly-transforms.js";
|
|
13
13
|
// =============================================================================
|
|
14
14
|
// Deploy Error
|
|
15
15
|
// =============================================================================
|
|
@@ -60,7 +60,12 @@ export const createFlyProvider = () => {
|
|
|
60
60
|
if (!loginResult.ok) {
|
|
61
61
|
return die("Fly.io Authentication Failed");
|
|
62
62
|
}
|
|
63
|
-
const checkResult = await runCommand([
|
|
63
|
+
const checkResult = await runCommand([
|
|
64
|
+
"fly",
|
|
65
|
+
"auth",
|
|
66
|
+
"whoami",
|
|
67
|
+
"--json",
|
|
68
|
+
]);
|
|
64
69
|
if (!checkResult.ok) {
|
|
65
70
|
return die("Fly.io Authentication Verification Failed");
|
|
66
71
|
}
|
|
@@ -155,7 +160,13 @@ export const createFlyProvider = () => {
|
|
|
155
160
|
}
|
|
156
161
|
},
|
|
157
162
|
async exists(name) {
|
|
158
|
-
const result = await runCommand([
|
|
163
|
+
const result = await runCommand([
|
|
164
|
+
"fly",
|
|
165
|
+
"status",
|
|
166
|
+
"-a",
|
|
167
|
+
name,
|
|
168
|
+
"--json",
|
|
169
|
+
]);
|
|
159
170
|
return result.json().match({
|
|
160
171
|
ok: (data) => {
|
|
161
172
|
const parsed = FlyStatusSchema.safeParse(data);
|
|
@@ -4,6 +4,11 @@ export interface DeviceRoutes {
|
|
|
4
4
|
enabled: string[];
|
|
5
5
|
unapproved: string[];
|
|
6
6
|
}
|
|
7
|
+
export interface AclSetResult {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
status: number;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
7
12
|
export interface TailscaleProvider {
|
|
8
13
|
auth: {
|
|
9
14
|
validateKey(): Promise<boolean>;
|
|
@@ -25,6 +30,8 @@ export interface TailscaleProvider {
|
|
|
25
30
|
};
|
|
26
31
|
acl: {
|
|
27
32
|
getPolicy(): Promise<Record<string, unknown> | null>;
|
|
33
|
+
setPolicy(policy: Record<string, unknown>): Promise<AclSetResult>;
|
|
34
|
+
validatePolicy(policy: Record<string, unknown>): Promise<AclSetResult>;
|
|
28
35
|
};
|
|
29
36
|
}
|
|
30
37
|
export declare const createTailscaleProvider: (apiKey: string, tailnet?: string) => TailscaleProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tailscale.d.ts","sourceRoot":"","sources":["../../src/providers/tailscale.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,mBAAmB,EAExB,KAAK,eAAe,EAErB,MAAM,yBAAyB,CAAC;AAYjC,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE;QACJ,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,SAAS,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACxD,CAAC;IACF,OAAO,EAAE;QACP,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;QACnC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;QACjE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACnC,CAAC;IACF,MAAM,EAAE;QACN,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC5D,CAAC;IACF,GAAG,EAAE;QACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC3C,CAAC;IACF,GAAG,EAAE;QACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"tailscale.d.ts","sourceRoot":"","sources":["../../src/providers/tailscale.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,mBAAmB,EAExB,KAAK,eAAe,EAErB,MAAM,yBAAyB,CAAC;AAYjC,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE;QACJ,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,SAAS,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACxD,CAAC;IACF,OAAO,EAAE;QACP,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;QACnC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;QACjE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACnC,CAAC;IACF,MAAM,EAAE;QACN,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC5D,CAAC;IACF,GAAG,EAAE;QACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC3C,CAAC;IACF,GAAG,EAAE;QACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QACrD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;QAClE,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;KACxE,CAAC;CACH;AAiBD,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,EACd,UAAS,MAAY,KACpB,iBA4OF,CAAC"}
|
|
@@ -21,7 +21,7 @@ export const createTailscaleProvider = (apiKey, tailnet = "-") => {
|
|
|
21
21
|
const response = await fetch(`${API_BASE}${path}`, {
|
|
22
22
|
method,
|
|
23
23
|
headers: headers(),
|
|
24
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
24
|
+
body: body ? JSON.stringify(body, null, 2) : undefined,
|
|
25
25
|
});
|
|
26
26
|
if (!response.ok) {
|
|
27
27
|
const text = await response.text();
|
|
@@ -144,6 +144,28 @@ export const createTailscaleProvider = (apiKey, tailnet = "-") => {
|
|
|
144
144
|
}
|
|
145
145
|
return result.data;
|
|
146
146
|
},
|
|
147
|
+
async setPolicy(policy) {
|
|
148
|
+
const result = await request("POST", `/tailnet/${tailnet}/acl`, policy);
|
|
149
|
+
if (!result.ok) {
|
|
150
|
+
return { ok: false, status: result.status, error: result.error };
|
|
151
|
+
}
|
|
152
|
+
return { ok: true, status: result.status };
|
|
153
|
+
},
|
|
154
|
+
async validatePolicy(policy) {
|
|
155
|
+
const result = await request("POST", `/tailnet/${tailnet}/acl/validate`, policy);
|
|
156
|
+
if (!result.ok) {
|
|
157
|
+
return { ok: false, status: result.status, error: result.error };
|
|
158
|
+
}
|
|
159
|
+
const body = result.data ?? {};
|
|
160
|
+
if (Object.keys(body).length > 0) {
|
|
161
|
+
return {
|
|
162
|
+
ok: false,
|
|
163
|
+
status: result.status,
|
|
164
|
+
error: JSON.stringify(body),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return { ok: true, status: result.status };
|
|
168
|
+
},
|
|
147
169
|
},
|
|
148
170
|
};
|
|
149
171
|
return provider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/util/credentials.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/util/credentials.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,eAAe;IAC9B,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAQD,eAAO,MAAM,2BAA2B,QAAO,eA0B9C,CAAC;AAMF,eAAO,MAAM,kBAAkB,QAAO,eAerC,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAC5B,KAAK;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;CAAE,KAC1D,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAyBlC,CAAC"}
|
package/esm/util/credentials.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// =============================================================================
|
|
4
4
|
import * as dntShim from "../_dnt.shims.js";
|
|
5
5
|
import { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
6
|
-
import { commandExists, ensureConfigDir, fileExists, getConfigDir } from "../lib/cli.js";
|
|
6
|
+
import { commandExists, ensureConfigDir, fileExists, getConfigDir, } from "../lib/cli.js";
|
|
7
7
|
import { ENV_TAILSCALE_API_KEY } from "./constants.js";
|
|
8
8
|
// =============================================================================
|
|
9
9
|
// Schema
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/util/discovery.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/util/discovery.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAQnE,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAMD,wDAAwD;AACxD,eAAO,MAAM,cAAc,GACzB,KAAK,WAAW,EAChB,KAAK,MAAM,KACV,OAAO,CAAC,SAAS,EAAE,CAerB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,aAAa,GACxB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,KACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAG1B,CAAC;AAMF,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GACpC,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,KACd,OAAO,CAAC,WAAW,EAAE,CAcvB,CAAC;AAEF;;+EAE+E;AAC/E,eAAO,MAAM,eAAe,GAC1B,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,EACf,UAAU,MAAM,KACf,OAAO,CAAC,WAAW,GAAG,IAAI,CAgC5B,CAAC;AAMF,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,GAC/B,KAAK,WAAW,EAChB,SAAS,MAAM,KACd,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAclC,CAAC;AAMF,yEAAyE;AACzE,eAAO,MAAM,sBAAsB,GACjC,WAAW,iBAAiB,EAC5B,SAAS,MAAM,KACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAcpC,CAAC;AAMF,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG;IACvC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,KAAK;IAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CAAE,EAC7D,KAAK,WAAW,EAChB,WAAW,iBAAiB,EAC5B,KAAK,MAAM,KACV,OAAO,CAAC,cAAc,EAAE,CAa1B,CAAC"}
|
package/esm/util/discovery.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// =============================================================================
|
|
15
15
|
import { getRouterSuffix, getWorkloadAppName } from "./naming.js";
|
|
16
16
|
import { extractSubnet } from "./fly-transforms.js";
|
|
17
|
-
import { DEFAULT_FLY_NETWORK, ROUTER_APP_PREFIX
|
|
17
|
+
import { DEFAULT_FLY_NETWORK, ROUTER_APP_PREFIX } from "./constants.js";
|
|
18
18
|
// =============================================================================
|
|
19
19
|
// 1. Which routers exist? (Fly REST API)
|
|
20
20
|
// =============================================================================
|
|
@@ -8,6 +8,47 @@ export declare const isAcceptRoutesEnabled: () => Promise<boolean>;
|
|
|
8
8
|
*/
|
|
9
9
|
export declare const enableAcceptRoutes: () => Promise<boolean>;
|
|
10
10
|
export declare const waitForDevice: (provider: TailscaleProvider, hostname: string, timeoutMs?: number) => Promise<TailscaleDevice>;
|
|
11
|
+
/**
|
|
12
|
+
* Asserts that a patch operation only added data and never removed any
|
|
13
|
+
* top-level key or shortened any existing array. Throws if the invariant is
|
|
14
|
+
* violated so callers can surface a hard error before writing to the API.
|
|
15
|
+
*/
|
|
16
|
+
export declare const assertAdditivePatch: (original: Record<string, unknown>, patched: Record<string, unknown>) => void;
|
|
11
17
|
export declare const isTagOwnerConfigured: (policy: Record<string, unknown> | null, tag: string) => boolean;
|
|
12
18
|
export declare const isAutoApproverConfigured: (policy: Record<string, unknown> | null, tag: string) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Returns a new policy with the given tag added to tagOwners.
|
|
21
|
+
* No-op if the tag is already present.
|
|
22
|
+
*/
|
|
23
|
+
export declare const patchTagOwner: (policy: Record<string, unknown>, tag: string, owners?: string[]) => Record<string, unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Returns a new policy with the given route + tag added to autoApprovers.
|
|
26
|
+
* No-op if the tag is already an approver for any route.
|
|
27
|
+
*/
|
|
28
|
+
export declare const patchAutoApprover: (policy: Record<string, unknown>, tag: string, route: string) => Record<string, unknown>;
|
|
29
|
+
/**
|
|
30
|
+
* Returns true if there is already an accept rule where `src` contains the
|
|
31
|
+
* given source member and `dst` contains the given destination.
|
|
32
|
+
*/
|
|
33
|
+
export declare const isAclRuleConfigured: (policy: Record<string, unknown> | null, src: string, dst: string) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Returns a new policy with an accept rule `src → dst` appended to `acls`.
|
|
36
|
+
* No-op if an identical rule already exists.
|
|
37
|
+
*/
|
|
38
|
+
export declare const patchAclRule: (policy: Record<string, unknown>, src: string, dst: string) => Record<string, unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Returns a new policy with all accept rules matching `src → dst` removed from `acls`.
|
|
41
|
+
* No-op if no such rule exists.
|
|
42
|
+
*/
|
|
43
|
+
export declare const unpatchAclRule: (policy: Record<string, unknown>, src: string, dst: string) => Record<string, unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a new policy with the given tag removed from tagOwners.
|
|
46
|
+
* No-op if the tag is not present.
|
|
47
|
+
*/
|
|
48
|
+
export declare const unpatchTagOwner: (policy: Record<string, unknown>, tag: string) => Record<string, unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns a new policy with the given tag removed from all autoApprovers routes.
|
|
51
|
+
* If a route's approver list becomes empty after removal, the route entry is dropped.
|
|
52
|
+
*/
|
|
53
|
+
export declare const unpatchAutoApprover: (policy: Record<string, unknown>, tag: string) => Record<string, unknown>;
|
|
13
54
|
//# sourceMappingURL=tailscale-local.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tailscale-local.d.ts","sourceRoot":"","sources":["../../src/util/tailscale-local.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAMnE,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,OAAO,CAE5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,OAAO,CAM7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,OAAO,CAG1D,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,UAAU,iBAAiB,EAC3B,UAAU,MAAM,EAChB,YAAW,MAAe,KACzB,OAAO,CAAC,eAAe,CAazB,CAAC;AAMF,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,KAAK,MAAM,KACV,OASF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,KAAK,MAAM,KACV,OAgBF,CAAC"}
|
|
1
|
+
{"version":3,"file":"tailscale-local.d.ts","sourceRoot":"","sources":["../../src/util/tailscale-local.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAMnE,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,OAAO,CAE5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,OAAO,CAM7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,OAAO,CAG1D,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,UAAU,iBAAiB,EAC3B,UAAU,MAAM,EAChB,YAAW,MAAe,KACzB,OAAO,CAAC,eAAe,CAazB,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,IAiBF,CAAC;AAMF,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,KAAK,MAAM,KACV,OASF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,KAAK,MAAM,KACV,OAgBF,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,MAAM,EACX,SAAQ,MAAM,EAAwB,KACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAIxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,MAAM,EACX,OAAO,MAAM,KACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAYxB,CAAC;AAaF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,KAAK,MAAM,EACX,KAAK,MAAM,KACV,OAUF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,MAAM,EACX,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAOxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,MAAM,EACX,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAaxB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAQxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,EAAE,OAAO,CA+BxB,CAAC"}
|