@takodotid/circuit 0.34.3 → 0.35.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 +13 -14
- package/dist/chunks/index-20kcjxjg.js +174 -0
- package/dist/chunks/index-2r4bbhac.js +977 -0
- package/dist/chunks/index-n7w3tg5y.js +149 -0
- package/dist/chunks/new-w3zys5y4.js +172 -0
- package/dist/chunks/server-gzsf5me5.js +259 -0
- package/dist/cli/index.js +11345 -9024
- package/dist/helpers/index.js +594 -0
- package/dist/index.js +9 -28
- package/dist/types/core/{addresses.d.ts → address-space.d.ts} +23 -7
- package/dist/types/core/address.d.ts +44 -0
- package/dist/types/core/cabling.d.ts +41 -0
- package/dist/types/core/cross-checks.d.ts +28 -0
- package/dist/types/core/define.d.ts +25 -3
- package/dist/types/core/project-files.d.ts +12 -0
- package/dist/types/core/schema-docs.d.ts +13 -4
- package/dist/types/core/secrets.d.ts +62 -21
- package/dist/types/core/{graph.d.ts → topology.d.ts} +32 -12
- package/dist/types/core/utils.d.ts +8 -0
- package/dist/types/core/validator.d.ts +19 -0
- package/dist/types/helpers/bgp.d.ts +97 -0
- package/dist/types/helpers/checks.d.ts +32 -0
- package/dist/types/helpers/exchange.d.ts +49 -0
- package/dist/types/helpers/filters.d.ts +51 -0
- package/dist/types/helpers/index.d.ts +10 -0
- package/dist/types/helpers/route-server.d.ts +52 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/integrations/librenms.d.ts +60 -0
- package/dist/types/integrations/netbox.d.ts +89 -0
- package/dist/types/integrations/peeringdb.d.ts +24 -0
- package/dist/types/integrations/prometheus.d.ts +24 -0
- package/dist/types/integrations/registries.d.ts +8 -0
- package/dist/types/platforms/bgp-wait.d.ts +18 -0
- package/dist/types/platforms/catalog.d.ts +109 -0
- package/dist/types/platforms/derive.d.ts +17 -0
- package/dist/types/platforms/fortios/firewall.d.ts +45 -0
- package/dist/types/platforms/fortios/index.d.ts +134 -0
- package/dist/types/platforms/fortios/names.d.ts +52 -0
- package/dist/types/platforms/fortios/plan.d.ts +104 -0
- package/dist/types/platforms/fortios/render.d.ts +75 -0
- package/dist/types/platforms/fortios/routing.d.ts +56 -0
- package/dist/types/platforms/fortios/tree.d.ts +37 -0
- package/dist/types/platforms/index.d.ts +13 -0
- package/dist/types/platforms/junos/bgp.d.ts +44 -0
- package/dist/types/platforms/junos/index.d.ts +114 -0
- package/dist/types/platforms/junos/render.d.ts +154 -0
- package/dist/types/platforms/line-diff.d.ts +67 -0
- package/dist/types/platforms/platform.d.ts +120 -0
- package/dist/types/platforms/raisecom-ros/index.d.ts +71 -0
- package/dist/types/platforms/raisecom-ros/render.d.ts +41 -0
- package/dist/types/platforms/routeros/export.d.ts +59 -0
- package/dist/types/platforms/routeros/index.d.ts +96 -0
- package/dist/types/{adapters/devices → platforms}/routeros/models.d.ts +4 -0
- package/dist/types/platforms/routeros/plan.d.ts +54 -0
- package/dist/types/platforms/routeros/render.d.ts +240 -0
- package/dist/types/platforms/vrp/index.d.ts +83 -0
- package/dist/types/platforms/vrp/render.d.ts +96 -0
- package/dist/types/schema/common.d.ts +12 -6
- package/dist/types/schema/index.d.ts +1 -0
- package/dist/types/schema/interfaces.d.ts +14 -6
- package/dist/types/schema/policy.d.ts +18 -10
- package/dist/types/schema/routing.d.ts +14 -1
- package/dist/types/schema/system.d.ts +16 -6
- package/dist/types/schema/time-zones.d.ts +2 -0
- package/dist/types/transport/console.d.ts +79 -23
- package/dist/types/transport/path-check.d.ts +32 -0
- package/dist/types/transport/ssh.d.ts +17 -15
- package/package.json +17 -11
- package/src/cli/graph-format.ts +91 -0
- package/src/cli/index.ts +1074 -484
- package/src/cli/new.ts +208 -175
- package/src/cli/rename.ts +97 -91
- package/src/core/address-space.ts +320 -0
- package/src/core/address.ts +202 -0
- package/src/core/cabling.ts +154 -0
- package/src/core/cross-checks.ts +364 -0
- package/src/core/define.ts +26 -3
- package/src/core/project-files.ts +35 -0
- package/src/core/schema-docs.ts +138 -130
- package/src/core/secrets.ts +170 -76
- package/src/core/topology.ts +656 -0
- package/src/core/utils.ts +37 -0
- package/src/core/validator.ts +407 -0
- package/src/helpers/bgp.ts +301 -0
- package/src/helpers/checks.ts +178 -0
- package/src/helpers/exchange.ts +117 -0
- package/src/helpers/filters.ts +107 -0
- package/src/helpers/index.ts +12 -0
- package/src/helpers/route-server.ts +212 -0
- package/src/index.ts +6 -3
- package/src/integrations/librenms.ts +291 -0
- package/src/integrations/netbox.ts +620 -0
- package/src/integrations/peeringdb.ts +173 -0
- package/src/integrations/prometheus.ts +90 -0
- package/src/integrations/registries.ts +25 -0
- package/src/platforms/bgp-wait.ts +41 -0
- package/src/platforms/catalog.ts +69 -0
- package/src/platforms/derive.ts +117 -0
- package/src/{adapters/devices → platforms}/fortios/TRAPS.md +6 -0
- package/src/platforms/fortios/firewall.ts +377 -0
- package/src/platforms/fortios/index.ts +1060 -0
- package/src/platforms/fortios/names.ts +130 -0
- package/src/platforms/fortios/plan.ts +929 -0
- package/src/platforms/fortios/render.ts +779 -0
- package/src/platforms/fortios/routing.ts +476 -0
- package/src/platforms/fortios/tree.ts +129 -0
- package/src/platforms/index.ts +36 -0
- package/src/{adapters/devices → platforms}/junos/TRAPS.md +8 -0
- package/src/platforms/junos/bgp.ts +293 -0
- package/src/platforms/junos/index.ts +1006 -0
- package/src/platforms/junos/render.ts +967 -0
- package/src/platforms/line-diff.ts +244 -0
- package/src/platforms/platform.ts +122 -0
- package/src/platforms/raisecom-ros/TRAPS.md +40 -0
- package/src/platforms/raisecom-ros/index.ts +731 -0
- package/src/platforms/raisecom-ros/render.ts +328 -0
- package/src/{adapters/devices → platforms}/routeros/TRAPS.md +16 -2
- package/src/platforms/routeros/export.ts +342 -0
- package/src/platforms/routeros/index.ts +636 -0
- package/src/{adapters/devices → platforms}/routeros/models.ts +2 -0
- package/src/platforms/routeros/plan.ts +444 -0
- package/src/platforms/routeros/render.ts +1483 -0
- package/src/platforms/vrp/TRAPS.md +45 -0
- package/src/platforms/vrp/index.ts +652 -0
- package/src/platforms/vrp/render.ts +615 -0
- package/src/schema/common.ts +15 -6
- package/src/schema/index.ts +1 -0
- package/src/schema/interfaces.ts +15 -5
- package/src/schema/policy.ts +22 -10
- package/src/schema/routing.ts +16 -1
- package/src/schema/system.ts +16 -6
- package/src/schema/time-zones.ts +482 -0
- package/src/studio/data.ts +172 -168
- package/src/studio/git.ts +95 -90
- package/src/studio/public/app.js +161 -150
- package/src/studio/public/compare.js +219 -212
- package/src/studio/public/diff.js +77 -75
- package/src/studio/public/dom.js +118 -108
- package/src/studio/public/evaluate.js +584 -545
- package/src/studio/public/export.js +120 -118
- package/src/studio/public/graph.js +1343 -1266
- package/src/studio/public/net.js +115 -109
- package/src/studio/public/tables.js +1135 -1083
- package/src/studio/public/tools.js +561 -529
- package/src/studio/server.ts +202 -196
- package/src/transport/console.ts +363 -271
- package/src/transport/path-check.ts +91 -0
- package/src/transport/ssh.ts +98 -94
- package/templates/colocation/checks.ts +11 -6
- package/templates/colocation/edge-01.ts +9 -9
- package/templates/colocation/routing.ts +2 -2
- package/templates/colocation/tenancy.ts +3 -3
- package/templates/colocation/tor-01.ts +3 -3
- package/templates/edge-router/checks.ts +4 -4
- package/templates/edge-router/edge-01.ts +5 -5
- package/templates/edge-router/routing.ts +2 -2
- package/templates/project/AGENTS.md +5 -1
- package/templates/single-site/checks.ts +2 -2
- package/dist/chunks/index-47debt16.js +0 -956
- package/dist/chunks/index-v8zgr7wm.js +0 -128
- package/dist/chunks/new-ny89s7y7.js +0 -166
- package/dist/chunks/server-tjbb3rqc.js +0 -251
- package/dist/presets/index.js +0 -394
- package/dist/types/adapters/devices/catalog.d.ts +0 -86
- package/dist/types/adapters/devices/derive.d.ts +0 -7
- package/dist/types/adapters/devices/fortios/firewall.d.ts +0 -23
- package/dist/types/adapters/devices/fortios/index.d.ts +0 -58
- package/dist/types/adapters/devices/fortios/names.d.ts +0 -48
- package/dist/types/adapters/devices/fortios/plan.d.ts +0 -28
- package/dist/types/adapters/devices/fortios/render.d.ts +0 -38
- package/dist/types/adapters/devices/fortios/routing.d.ts +0 -32
- package/dist/types/adapters/devices/fortios/tree.d.ts +0 -33
- package/dist/types/adapters/devices/index.d.ts +0 -3
- package/dist/types/adapters/devices/junos/bgp.d.ts +0 -11
- package/dist/types/adapters/devices/junos/index.d.ts +0 -42
- package/dist/types/adapters/devices/junos/render.d.ts +0 -52
- package/dist/types/adapters/devices/lines.d.ts +0 -56
- package/dist/types/adapters/devices/raisecom-ros/index.d.ts +0 -28
- package/dist/types/adapters/devices/routeros/export.d.ts +0 -39
- package/dist/types/adapters/devices/routeros/index.d.ts +0 -30
- package/dist/types/adapters/devices/routeros/plan.d.ts +0 -4
- package/dist/types/adapters/devices/routeros/render.d.ts +0 -100
- package/dist/types/adapters/devices/types.d.ts +0 -40
- package/dist/types/adapters/devices/vrp/index.d.ts +0 -27
- package/dist/types/adapters/registries/index.d.ts +0 -3
- package/dist/types/adapters/registries/librenms.d.ts +0 -15
- package/dist/types/adapters/registries/peeringdb.d.ts +0 -16
- package/dist/types/adapters/registries/prometheus.d.ts +0 -16
- package/dist/types/core/across.d.ts +0 -4
- package/dist/types/core/addr.d.ts +0 -34
- package/dist/types/core/files.d.ts +0 -6
- package/dist/types/core/merge.d.ts +0 -4
- package/dist/types/core/time.d.ts +0 -2
- package/dist/types/core/validate.d.ts +0 -2
- package/dist/types/presets/index.d.ts +0 -183
- package/src/adapters/devices/catalog.ts +0 -41
- package/src/adapters/devices/derive.ts +0 -59
- package/src/adapters/devices/fortios/firewall.ts +0 -362
- package/src/adapters/devices/fortios/index.ts +0 -923
- package/src/adapters/devices/fortios/names.ts +0 -115
- package/src/adapters/devices/fortios/plan.ts +0 -888
- package/src/adapters/devices/fortios/render.ts +0 -768
- package/src/adapters/devices/fortios/routing.ts +0 -444
- package/src/adapters/devices/fortios/tree.ts +0 -121
- package/src/adapters/devices/index.ts +0 -9
- package/src/adapters/devices/junos/bgp.ts +0 -269
- package/src/adapters/devices/junos/index.ts +0 -862
- package/src/adapters/devices/junos/render.ts +0 -872
- package/src/adapters/devices/lines.ts +0 -212
- package/src/adapters/devices/raisecom-ros/TRAPS.md +0 -26
- package/src/adapters/devices/raisecom-ros/index.ts +0 -700
- package/src/adapters/devices/routeros/export.ts +0 -321
- package/src/adapters/devices/routeros/index.ts +0 -346
- package/src/adapters/devices/routeros/plan.ts +0 -398
- package/src/adapters/devices/routeros/render.ts +0 -1490
- package/src/adapters/devices/types.ts +0 -38
- package/src/adapters/devices/vrp/TRAPS.md +0 -26
- package/src/adapters/devices/vrp/index.ts +0 -865
- package/src/adapters/registries/index.ts +0 -19
- package/src/adapters/registries/librenms.ts +0 -92
- package/src/adapters/registries/peeringdb.ts +0 -169
- package/src/adapters/registries/prometheus.ts +0 -71
- package/src/cli/graph.ts +0 -89
- package/src/core/across.ts +0 -350
- package/src/core/addr.ts +0 -174
- package/src/core/addresses.ts +0 -316
- package/src/core/files.ts +0 -32
- package/src/core/graph.ts +0 -640
- package/src/core/merge.ts +0 -19
- package/src/core/time.ts +0 -15
- package/src/core/validate.ts +0 -348
- package/src/presets/index.ts +0 -579
- /package/dist/types/{adapters/devices → platforms}/fortios/models.d.ts +0 -0
- /package/dist/types/{adapters/devices → platforms}/junos/models.d.ts +0 -0
- /package/dist/types/{adapters/devices → platforms}/raisecom-ros/models.d.ts +0 -0
- /package/dist/types/{adapters/devices → platforms}/vrp/models.d.ts +0 -0
- /package/src/{adapters/devices → platforms}/fortios/models.ts +0 -0
- /package/src/{adapters/devices → platforms}/junos/models.ts +0 -0
- /package/src/{adapters/devices → platforms}/raisecom-ros/models.ts +0 -0
- /package/src/{adapters/devices → platforms}/vrp/models.ts +0 -0
package/README.md
CHANGED
|
@@ -9,16 +9,16 @@ Documentation: [circuit.tako.id](https://circuit.tako.id)
|
|
|
9
9
|
|
|
10
10
|
## What it does
|
|
11
11
|
|
|
12
|
-
- **One file per device.** VLANs, ports, addresses, routing, firewall, users and services
|
|
13
|
-
- **
|
|
14
|
-
- **The file is the whole truth.** A port, user or service the file
|
|
15
|
-
- **See every change first.** `diff` shows it offline, `apply` plans it against the live device, and nothing is sent without `--confirm`. On RouterOS, Junos and FortiOS
|
|
16
|
-
- **History in git.** Each device's last snapshot
|
|
17
|
-
- **
|
|
18
|
-
- **Secrets stay out of the
|
|
19
|
-
- **See the network.**
|
|
20
|
-
- **Keeps the rest
|
|
21
|
-
- **Safe with AI agents.** Every project gets an `AGENTS.md` that
|
|
12
|
+
- **One file per device.** VLANs, ports, addresses, routing, firewall, users and services in TypeScript. Your editor checks every name as you type.
|
|
13
|
+
- **Same words for every vendor.** MikroTik RouterOS 7, Huawei VRP, Raisecom ROS, Juniper Junos and Fortinet FortiOS each get their own commands. Anything a device can't do is an error before anything is sent.
|
|
14
|
+
- **The file is the whole truth.** A port, user or service the file doesn't mention is removed or turned off, so nothing set by hand stays behind.
|
|
15
|
+
- **See every change first.** `diff` shows it offline, `apply` plans it against the live device, and nothing is sent without `--confirm`. On RouterOS, Junos and FortiOS a change undoes itself if Circuit can't log in again afterwards.
|
|
16
|
+
- **History in git.** Each device's last snapshot lives in `.circuit/state/`, so the repo's history is the network's history.
|
|
17
|
+
- **Your own rules.** Checks run on every change; helpers give ready-made filters, BGP policies and checks.
|
|
18
|
+
- **Secrets stay out of the repo.** They come from `.env` or 1Password and never show up in a plan or a snapshot.
|
|
19
|
+
- **See the network.** `circuit studio` draws cables, VLANs, addresses, BGP, OSPF and tunnels in your browser, marks what's broken or differs from the device, and lists everything in tables for people who don't read TypeScript. It can run on a server for the whole team. `circuit graph` prints the drawing as Mermaid, DOT or JSON.
|
|
20
|
+
- **Keeps the rest in step.** Prefix lists from a registry, your PeeringDB record, LibreNMS, NetBox, Prometheus targets, WireGuard client configs, and your BGP communities for a looking glass.
|
|
21
|
+
- **Safe with AI agents.** Every project gets an `AGENTS.md` that says what an agent may run; the last step stays yours.
|
|
22
22
|
|
|
23
23
|
<picture>
|
|
24
24
|
<source media="(prefers-color-scheme: dark)" srcset="docs/public/screenshots/studio-dark.png">
|
|
@@ -44,19 +44,18 @@ npx @takodotid/circuit new # or: pnpm dlx @takodotid/circuit new, bunx @t
|
|
|
44
44
|
|
|
45
45
|
It asks which kind of network you have, creates a project with example devices, and installs Circuit. [Getting started](https://circuit.tako.id/guide/getting-started) walks through the first run.
|
|
46
46
|
|
|
47
|
-
Circuit supports MikroTik RouterOS 7, Huawei VRP, Raisecom ROS, Juniper Junos and Fortinet FortiOS. Releases are on the [releases page](https://github.com/takodotid/circuit/releases), on npm and on GitHub Packages.
|
|
47
|
+
Circuit supports MikroTik RouterOS 7, Huawei VRP V200R005, Raisecom ROS 6.5, Juniper Junos 21 and Fortinet FortiOS 6.2, at the versions on the [platforms page](https://circuit.tako.id/platforms/). Releases are on the [releases page](https://github.com/takodotid/circuit/releases), on npm and on GitHub Packages.
|
|
48
48
|
|
|
49
49
|
## Working on Circuit
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
bun install
|
|
53
|
-
bun run typecheck
|
|
53
|
+
bun run check # everything CI runs: typecheck, tests, format, docs build, Node build
|
|
54
54
|
bun run test # every example and template validates, and plans nothing against its own render
|
|
55
|
-
bun run build # dist/, what Node, npm and pnpm run
|
|
56
55
|
bun run docs:dev # the documentation site, from docs/
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
[Contributing](https://circuit.tako.id/contributing) explains the layout, how to add a platform, and how releases are cut. `AGENTS.md` has the rules for changing the code.
|
|
58
|
+
[Contributing](https://circuit.tako.id/contributing) explains the layout, how to add a platform, and how releases are cut. `AGENTS.md` has the rules for changing the code, for people and AI agents alike; `.claude/skills/` has the step-by-step guides an agent loads, such as adding a device.
|
|
60
59
|
|
|
61
60
|
## License
|
|
62
61
|
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// src/core/utils.ts
|
|
2
|
+
class Utils2 {
|
|
3
|
+
static merge(...records) {
|
|
4
|
+
const result = {};
|
|
5
|
+
for (const record of records) {
|
|
6
|
+
for (const [key, value] of Object.entries(record)) {
|
|
7
|
+
if (key in result)
|
|
8
|
+
throw new Error(`Utils.merge: ${key} is declared twice`);
|
|
9
|
+
result[key] = value;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
static timeZoneOffset(zone) {
|
|
15
|
+
const name = new Intl.DateTimeFormat("en-US", {
|
|
16
|
+
timeZone: zone,
|
|
17
|
+
timeZoneName: "longOffset"
|
|
18
|
+
}).formatToParts(new Date).find((entry) => entry.type === "timeZoneName").value;
|
|
19
|
+
const found = /GMT([+-])(\d{2}):(\d{2})/.exec(name);
|
|
20
|
+
if (!found)
|
|
21
|
+
return 0;
|
|
22
|
+
const [, sign, hours, minutes] = found;
|
|
23
|
+
const sizeInMinutes = Number(hours) * 60 + Number(minutes);
|
|
24
|
+
return sign === "-" ? -sizeInMinutes : sizeInMinutes;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/core/secrets.ts
|
|
29
|
+
import { spawnSync } from "node:child_process";
|
|
30
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
31
|
+
import { join } from "node:path";
|
|
32
|
+
import { parseEnv } from "node:util";
|
|
33
|
+
|
|
34
|
+
class Secrets2 {
|
|
35
|
+
static root = process.cwd();
|
|
36
|
+
static envFile;
|
|
37
|
+
static fromOnePassword = new Map;
|
|
38
|
+
static revealed = new Set;
|
|
39
|
+
static REDACTED = "<redacted>";
|
|
40
|
+
static SHORTEST_DOTENV_VALUE = 6;
|
|
41
|
+
static MARKER = /<secret:([A-Za-z0-9_./:-]+)>/g;
|
|
42
|
+
static useRoot(directory) {
|
|
43
|
+
Secrets2.root = directory;
|
|
44
|
+
Secrets2.envFile = undefined;
|
|
45
|
+
}
|
|
46
|
+
static dotenv() {
|
|
47
|
+
if (Secrets2.envFile)
|
|
48
|
+
return Secrets2.envFile;
|
|
49
|
+
const path = join(Secrets2.root, ".env");
|
|
50
|
+
const text = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
51
|
+
Secrets2.refuseCutValues(text);
|
|
52
|
+
Secrets2.envFile = parseEnv(text);
|
|
53
|
+
return Secrets2.envFile;
|
|
54
|
+
}
|
|
55
|
+
static refuseCutValues(text) {
|
|
56
|
+
for (const line of text.split(/\r?\n/)) {
|
|
57
|
+
const [, name, value] = /^\s*(?:export\s+)?([\w.-]+)\s*=\s*(.*)$/.exec(line) ?? [];
|
|
58
|
+
if (!name || !value || /^['"`]/.test(value) || !/\S#/.test(value))
|
|
59
|
+
continue;
|
|
60
|
+
throw new Error(`.env: the value of ${name} has a # in it, which starts a comment there; put the value in quotes`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static readOnePassword(name, reference) {
|
|
64
|
+
const cached = Secrets2.fromOnePassword.get(reference);
|
|
65
|
+
if (cached !== undefined)
|
|
66
|
+
return cached;
|
|
67
|
+
const result = spawnSync("op", ["read", "--no-newline", reference], { encoding: "utf8" });
|
|
68
|
+
if (result.error)
|
|
69
|
+
throw new Error(`secret ${name} is a 1Password reference, and the 1Password CLI, op, is not installed`);
|
|
70
|
+
if (result.status !== 0) {
|
|
71
|
+
const reason = result.stderr.trim() || `op exited with ${result.status}`;
|
|
72
|
+
throw new Error(`secret ${name}: 1Password could not read ${reference}: ${reason}`);
|
|
73
|
+
}
|
|
74
|
+
const value = result.stdout;
|
|
75
|
+
Secrets2.fromOnePassword.set(reference, value);
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
static isSecret(value) {
|
|
79
|
+
return typeof value === "object" && value !== null && (("secret" in value) || ("secret_file" in value));
|
|
80
|
+
}
|
|
81
|
+
static referenceOf(secret) {
|
|
82
|
+
return "secret" in secret ? secret.secret : `file:${secret.secret_file}`;
|
|
83
|
+
}
|
|
84
|
+
static sourceOf(reference) {
|
|
85
|
+
if (reference.startsWith("file:"))
|
|
86
|
+
return existsSync(join(Secrets2.root, reference.slice("file:".length))) ? "a file" : undefined;
|
|
87
|
+
const fromFile = Secrets2.dotenv()[reference];
|
|
88
|
+
const value = process.env[reference] || fromFile;
|
|
89
|
+
if (!value)
|
|
90
|
+
return;
|
|
91
|
+
const where = process.env[reference] && process.env[reference] !== fromFile ? "the environment" : ".env";
|
|
92
|
+
return value.startsWith("op://") ? `1Password, through ${where}` : where;
|
|
93
|
+
}
|
|
94
|
+
static valueOf(reference) {
|
|
95
|
+
if (reference.startsWith("file:")) {
|
|
96
|
+
const path = reference.slice("file:".length);
|
|
97
|
+
const fullPath = join(Secrets2.root, path);
|
|
98
|
+
if (!existsSync(fullPath))
|
|
99
|
+
throw new Error(`secret file ${path} does not exist`);
|
|
100
|
+
const value = readFileSync(fullPath, "utf8").trimEnd();
|
|
101
|
+
if (!value)
|
|
102
|
+
throw new Error(`secret file ${path} is empty`);
|
|
103
|
+
Secrets2.revealed.add(value);
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
const fromFile = Secrets2.dotenv()[reference];
|
|
107
|
+
const value = process.env[reference] || fromFile;
|
|
108
|
+
if (!value)
|
|
109
|
+
throw new Error(`secret ${reference} is not set in the environment or in .env`);
|
|
110
|
+
const revealed = value.startsWith("op://") ? Secrets2.readOnePassword(reference, value) : value;
|
|
111
|
+
Secrets2.revealed.add(revealed);
|
|
112
|
+
return revealed;
|
|
113
|
+
}
|
|
114
|
+
static reveal(secret) {
|
|
115
|
+
return Secrets2.valueOf(typeof secret === "string" ? secret : Secrets2.referenceOf(secret));
|
|
116
|
+
}
|
|
117
|
+
static referencesIn(value, found = new Set) {
|
|
118
|
+
if (Secrets2.isSecret(value))
|
|
119
|
+
found.add(Secrets2.referenceOf(value));
|
|
120
|
+
else if (Array.isArray(value))
|
|
121
|
+
for (const item of value)
|
|
122
|
+
Secrets2.referencesIn(item, found);
|
|
123
|
+
else if (typeof value === "object" && value !== null)
|
|
124
|
+
for (const item of Object.values(value))
|
|
125
|
+
Secrets2.referencesIn(item, found);
|
|
126
|
+
return found;
|
|
127
|
+
}
|
|
128
|
+
static scrub(text, options = {}) {
|
|
129
|
+
const values = new Set(options.extra ?? []);
|
|
130
|
+
for (const value of Object.values(Secrets2.dotenv())) {
|
|
131
|
+
if (value.length >= Secrets2.SHORTEST_DOTENV_VALUE && !value.startsWith("op://"))
|
|
132
|
+
values.add(value);
|
|
133
|
+
}
|
|
134
|
+
for (const value of Secrets2.revealed)
|
|
135
|
+
values.add(value);
|
|
136
|
+
for (const reference of Secrets2.referencesIn(options.network)) {
|
|
137
|
+
const value = Secrets2.storedValueOf(reference);
|
|
138
|
+
if (value)
|
|
139
|
+
values.add(value);
|
|
140
|
+
}
|
|
141
|
+
const ordered = [...values].filter(Boolean).sort((a, b) => b.length - a.length);
|
|
142
|
+
return ordered.reduce((out, value) => out.split(value).join(Secrets2.REDACTED), text);
|
|
143
|
+
}
|
|
144
|
+
static storedValueOf(reference) {
|
|
145
|
+
if (reference.startsWith("file:")) {
|
|
146
|
+
const path = join(Secrets2.root, reference.slice("file:".length));
|
|
147
|
+
return existsSync(path) ? readFileSync(path, "utf8").trimEnd() : undefined;
|
|
148
|
+
}
|
|
149
|
+
const value = process.env[reference] || Secrets2.dotenv()[reference];
|
|
150
|
+
if (!value?.startsWith("op://"))
|
|
151
|
+
return value;
|
|
152
|
+
return Secrets2.fromOnePassword.get(value);
|
|
153
|
+
}
|
|
154
|
+
static loginOf(device) {
|
|
155
|
+
const user = device.users?.[device.connection.user];
|
|
156
|
+
if (!user)
|
|
157
|
+
throw new Error(`${device.name}: connection user ${device.connection.user} is not one of its users`);
|
|
158
|
+
return {
|
|
159
|
+
...device.connection.host ? { host: device.connection.host } : {},
|
|
160
|
+
port: device.connection.port ?? 22,
|
|
161
|
+
user: device.connection.user,
|
|
162
|
+
password: Secrets2.reveal(user.password),
|
|
163
|
+
...device.connection.console ? { console: device.connection.console } : {}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
static marker(secret) {
|
|
167
|
+
return `<secret:${Secrets2.referenceOf(secret)}>`;
|
|
168
|
+
}
|
|
169
|
+
static substitute(text) {
|
|
170
|
+
return text.replace(Secrets2.MARKER, (_, reference) => Secrets2.valueOf(reference));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export { Utils2, Secrets2 };
|