@cardelli/ambit 0.2.1 → 0.2.2
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/esm/cli/commands/create/index.js +56 -52
- package/esm/deno.js +1 -1
- package/esm/lib/output.d.ts +1 -0
- package/esm/lib/output.d.ts.map +1 -1
- package/esm/lib/output.js +6 -1
- package/package.json +1 -1
- /package/esm/{src/router → router}/Dockerfile +0 -0
- /package/esm/{src/router → router}/fly.toml +0 -0
- /package/esm/{src/router → router}/start.sh +0 -0
|
@@ -12,7 +12,7 @@ import { isPublicTld } from "../../../util/guard.js";
|
|
|
12
12
|
import { createFlyProvider, } from "../../../providers/fly.js";
|
|
13
13
|
import { createTailscaleProvider, } from "../../../providers/tailscale.js";
|
|
14
14
|
import { getCredentialStore } from "../../../util/credentials.js";
|
|
15
|
-
import { FLY_PRIVATE_SUBNET,
|
|
15
|
+
import { FLY_PRIVATE_SUBNET, TAILSCALE_API_KEY_PREFIX, } from "../../../util/constants.js";
|
|
16
16
|
import { resolveOrg } from "../../../util/resolve.js";
|
|
17
17
|
import { isAutoApproverConfigured, isTagOwnerConfigured } from "../../../util/tailscale-local.js";
|
|
18
18
|
import { createTransition, hydrateCreate, reportSkipped, } from "./machine.js";
|
|
@@ -43,7 +43,7 @@ const stageTailscaleConfig = async (out, opts) => {
|
|
|
43
43
|
return out.die("--api-key Is Required in JSON Mode");
|
|
44
44
|
}
|
|
45
45
|
out.dim("Ambit Needs an API Access Token (Not an Auth Key) to Manage Your Tailnet.")
|
|
46
|
-
.dim("Create One at:
|
|
46
|
+
.dim("Create One at:").link(" https://login.tailscale.com/admin/settings/keys")
|
|
47
47
|
.blank();
|
|
48
48
|
apiKey = await readSecret("API access token (tskey-api-...): ");
|
|
49
49
|
if (!apiKey) {
|
|
@@ -66,35 +66,39 @@ const stageTailscaleConfig = async (out, opts) => {
|
|
|
66
66
|
const policy = await tailscale.acl.getPolicy();
|
|
67
67
|
const hasTagOwner = isTagOwnerConfigured(policy, opts.tag);
|
|
68
68
|
if (!hasTagOwner) {
|
|
69
|
-
tagOwnerSpinner.fail(
|
|
69
|
+
tagOwnerSpinner.fail(`${opts.tag} Not Set Up Yet`);
|
|
70
70
|
out.blank()
|
|
71
|
-
.text(`
|
|
72
|
-
.text(
|
|
71
|
+
.text(` You need to grant yourself permission to create the "${opts.network}"`)
|
|
72
|
+
.text(` network by setting up ${opts.tag} in Tailscale.`)
|
|
73
73
|
.blank()
|
|
74
|
-
.text(
|
|
75
|
-
.
|
|
74
|
+
.text(` You can create the tag and assign it to yourself or a group`)
|
|
75
|
+
.text(` you're a part of in the Tailscale dashboard:`)
|
|
76
|
+
.link(" https://login.tailscale.com/admin/acls/visual/tags")
|
|
76
77
|
.blank()
|
|
78
|
+
.dim(" Or you can do it manually in the JSON editor:")
|
|
79
|
+
.link(" https://login.tailscale.com/admin/acls/file")
|
|
77
80
|
.dim(` "tagOwners": { "${opts.tag}": ["autogroup:admin"] }`)
|
|
78
81
|
.blank();
|
|
79
|
-
return out.die(`
|
|
82
|
+
return out.die(`Set Up ${opts.tag} in Tailscale, Then Try Again`);
|
|
80
83
|
}
|
|
81
|
-
tagOwnerSpinner.success(
|
|
84
|
+
tagOwnerSpinner.success(`${opts.tag} Found in Tailscale ACL`);
|
|
82
85
|
if (opts.json) {
|
|
83
86
|
const approverSpinner = out.spinner(`Checking autoApprovers for ${opts.tag}`);
|
|
84
87
|
const hasApprover = isAutoApproverConfigured(policy, opts.tag);
|
|
85
88
|
if (!hasApprover) {
|
|
86
|
-
approverSpinner.fail(`
|
|
89
|
+
approverSpinner.fail(`Auto-approve Not Configured for ${opts.tag}`);
|
|
87
90
|
out.blank()
|
|
88
|
-
.text(" JSON mode
|
|
89
|
-
.text(`
|
|
91
|
+
.text(" In JSON mode, ambit can't interactively approve subnet routes.")
|
|
92
|
+
.text(` Add an autoApprovers rule so Tailscale automatically trusts`)
|
|
93
|
+
.text(` routes advertised by ${opts.tag}:`)
|
|
90
94
|
.blank()
|
|
91
|
-
.dim("
|
|
95
|
+
.dim(" https://login.tailscale.com/admin/acls/file")
|
|
92
96
|
.blank()
|
|
93
97
|
.dim(` "autoApprovers": { "routes": { "${FLY_PRIVATE_SUBNET}": ["${opts.tag}"] } }`)
|
|
94
98
|
.blank();
|
|
95
|
-
return out.die(`
|
|
99
|
+
return out.die(`Add autoApprovers for ${opts.tag} to Use --json`);
|
|
96
100
|
}
|
|
97
|
-
approverSpinner.success(`
|
|
101
|
+
approverSpinner.success(`Auto-approve Configured for ${opts.tag}`);
|
|
98
102
|
}
|
|
99
103
|
out.blank();
|
|
100
104
|
return tailscale;
|
|
@@ -157,52 +161,52 @@ const stageSummary = async (out, fly, tailscale, ctx, opts) => {
|
|
|
157
161
|
.header(" Router Created!")
|
|
158
162
|
.header("=".repeat(50))
|
|
159
163
|
.blank()
|
|
160
|
-
.text(`
|
|
161
|
-
.text(` <app-name>.${opts.network}`)
|
|
162
|
-
.blank();
|
|
163
|
-
if (ctx.subnet) {
|
|
164
|
-
const machines = await fly.machines.list(ctx.appName);
|
|
165
|
-
const routerMachine = machines.find((m) => m.private_ip);
|
|
166
|
-
if (routerMachine?.private_ip) {
|
|
167
|
-
out.text("SOCKS5 Proxy Available at:")
|
|
168
|
-
.text(` socks5://[${routerMachine.private_ip}]:${SOCKS_PROXY_PORT}`)
|
|
169
|
-
.dim("Containers on This Network Can Use It to Reach Your Tailnet.")
|
|
170
|
-
.blank();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
out.dim("Deploy an App to This Network:")
|
|
174
|
-
.dim(` ambit deploy my-app --network ${opts.network}`)
|
|
164
|
+
.text(`The "${opts.network}" Network Is Ready.`)
|
|
175
165
|
.blank()
|
|
176
|
-
.
|
|
177
|
-
.
|
|
178
|
-
.
|
|
179
|
-
|
|
166
|
+
.text(`You Can Deploy Apps to It With:`)
|
|
167
|
+
.text(` npx @cardelli/ambit deploy <app-name>.${opts.network}`)
|
|
168
|
+
.blank();
|
|
169
|
+
out.dim("Invite People to Your Tailnet:")
|
|
170
|
+
.link(" https://login.tailscale.com/admin/users")
|
|
180
171
|
.blank();
|
|
181
|
-
if (ctx.subnet && !hasAutoApprover) {
|
|
182
|
-
out.header("Recommended: Configure autoApprovers")
|
|
183
|
-
.blank()
|
|
184
|
-
.dim(" Add to Your Tailnet Policy File at:")
|
|
185
|
-
.dim(" https://login.tailscale.com/admin/acls/file")
|
|
186
|
-
.blank()
|
|
187
|
-
.text(` "autoApprovers": { "routes": { "${ctx.subnet}": ["${opts.tag}"] } }`)
|
|
188
|
-
.blank()
|
|
189
|
-
.dim(" Routes Were Approved via API for This Session.")
|
|
190
|
-
.dim(" autoApprovers Will Auto-Approve on Future Restarts.")
|
|
191
|
-
.blank();
|
|
192
|
-
}
|
|
193
172
|
if (ctx.subnet) {
|
|
194
|
-
out.header("
|
|
173
|
+
out.header("Next: Allow Traffic Through the Router")
|
|
174
|
+
.blank()
|
|
175
|
+
.text(" You must configure Tailscale so that traffic can flow from your")
|
|
176
|
+
.text(` devices through the router and into the "${opts.network}" network.`);
|
|
177
|
+
if (!hasAutoApprover) {
|
|
178
|
+
out.blank()
|
|
179
|
+
.text(" 1. Automatically Allow Traffic Through the Router:")
|
|
180
|
+
.dim(" Tailscale needs to trust the router's network connections.")
|
|
181
|
+
.blank()
|
|
182
|
+
.dim(" You can do this from the Tailscale dashboard:")
|
|
183
|
+
.link(" https://login.tailscale.com/admin/acls/visual/auto-approvers")
|
|
184
|
+
.dim(` Route: ${ctx.subnet} Owner: ${opts.tag}`)
|
|
185
|
+
.blank()
|
|
186
|
+
.dim(" Or you can do it manually with this JSON config:")
|
|
187
|
+
.link(" https://login.tailscale.com/admin/acls/file")
|
|
188
|
+
.dim(` "autoApprovers": { "routes": { "${ctx.subnet}": ["${opts.tag}"] } }`);
|
|
189
|
+
if (opts.shouldApprove) {
|
|
190
|
+
out.blank().dim(" Traffic Was Allowed via API for This Session.");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
out.blank()
|
|
194
|
+
.text(` ${hasAutoApprover ? "1" : "2"}. Control Who Can Reach Apps on This Network:`)
|
|
195
|
+
.dim(" This lets you restrict which users or devices can access your apps.")
|
|
195
196
|
.blank()
|
|
196
|
-
.dim("
|
|
197
|
-
.
|
|
197
|
+
.dim(" You can do this from the Tailscale dashboard:")
|
|
198
|
+
.link(" https://login.tailscale.com/admin/acls/visual/general-access-rules")
|
|
199
|
+
.dim(` Source: group:YOUR_GROUP Destination: ${opts.tag}:*`)
|
|
198
200
|
.blank()
|
|
199
|
-
.dim(
|
|
200
|
-
.
|
|
201
|
+
.dim(" Or you can do it manually with this JSON config:")
|
|
202
|
+
.link(" https://login.tailscale.com/admin/acls/file")
|
|
203
|
+
.dim(` {"action": "accept", "src": ["group:YOUR_GROUP"], "dst": ["${opts.tag}:53"]}`)
|
|
204
|
+
.dim(` {"action": "accept", "src": ["group:YOUR_GROUP"], "dst": ["${ctx.subnet}:*"]}`)
|
|
201
205
|
.blank();
|
|
202
206
|
}
|
|
203
207
|
if (!opts.shouldApprove) {
|
|
204
208
|
out.dim("Route Approval Was Skipped. To Complete Setup:")
|
|
205
|
-
.dim(` ambit doctor
|
|
209
|
+
.dim(` ambit doctor network ${opts.network}`)
|
|
206
210
|
.blank();
|
|
207
211
|
}
|
|
208
212
|
out.print();
|
package/esm/deno.js
CHANGED
package/esm/lib/output.d.ts
CHANGED
package/esm/lib/output.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,CAAC,CAAC;AAChD,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAMvD,qBAAa,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnD,OAAO,CAAC,MAAM,CAGE;IAChB,OAAO,CAAC,QAAQ,CAAU;gBAEd,QAAQ,EAAE,OAAO;IAS7B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAMnB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAKzD,KAAK,IAAI,IAAI;IAUb,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKtB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK1B,KAAK,IAAI,IAAI;IAKb,OAAO,CACL,OAAO,EAAE,MAAM,GACd;QAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,IAAI,IAAI,CAAA;KAAE;IAiBlE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgB9D,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK;IAS3B,MAAM,IAAI,OAAO;CAGlB;AAMD,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,CAAC,CAAC,CAEX"}
|
package/esm/lib/output.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
2
|
// Output - Unified Output Handling for CLI Commands
|
|
3
3
|
// =============================================================================
|
|
4
|
-
import { bold, dim, Spinner, statusErr, statusInfo, statusOk, statusWarn, } from "./cli.js";
|
|
4
|
+
import { blue, bold, dim, Spinner, statusErr, statusInfo, statusOk, statusWarn, } from "./cli.js";
|
|
5
5
|
// =============================================================================
|
|
6
6
|
// Output Class
|
|
7
7
|
// =============================================================================
|
|
@@ -67,6 +67,11 @@ export class Output {
|
|
|
67
67
|
console.log(dim(text));
|
|
68
68
|
return this;
|
|
69
69
|
}
|
|
70
|
+
link(text) {
|
|
71
|
+
if (!this.jsonMode)
|
|
72
|
+
console.log(blue(text));
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
70
75
|
header(text) {
|
|
71
76
|
if (!this.jsonMode)
|
|
72
77
|
console.log(bold(text));
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|