@takodotid/circuit 0.43.1 → 1.0.0-rc.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/README.md +115 -37
- package/package.json +21 -58
- package/src/checks/across.ts +402 -0
- package/src/checks/built-in.ts +256 -0
- package/src/checks/device.ts +436 -0
- package/src/checks/index.ts +53 -0
- package/src/cli/advisories.ts +108 -0
- package/src/cli/app.ts +71 -0
- package/src/cli/editor-types.generated.ts +30 -0
- package/src/cli/editor-types.ts +69 -0
- package/src/cli/format.ts +124 -0
- package/src/cli/git-hooks.ts +79 -0
- package/src/cli/index.ts +350 -1170
- package/src/cli/migrate.ts +554 -0
- package/src/cli/project-commands.ts +656 -0
- package/src/cli/releases.ts +374 -0
- package/src/cli/remember.ts +339 -0
- package/src/cli/rename.ts +27 -33
- package/src/cli/secrets-password.ts +60 -0
- package/src/cli/secrets.ts +258 -0
- package/src/cli/setup.ts +300 -0
- package/src/cli/signing.ts +23 -0
- package/src/cli/text-editor.ts +268 -0
- package/src/cli/ui.ts +298 -0
- package/src/cli/version.ts +2 -0
- package/src/cli/versions.ts +158 -0
- package/src/config/address.ts +102 -0
- package/src/config/circuit.d.ts +30 -0
- package/src/config/common.ts +65 -0
- package/src/config/communities.ts +479 -0
- package/src/config/define.ts +684 -0
- package/src/config/device.ts +164 -0
- package/src/config/firewall.ts +150 -0
- package/src/config/index.ts +22 -0
- package/src/{schema → config}/interfaces.ts +121 -85
- package/src/config/keys.ts +434 -0
- package/src/config/management.ts +61 -0
- package/src/config/merge.ts +335 -0
- package/src/config/models.ts +70 -0
- package/src/config/monitoring.ts +64 -0
- package/src/config/network.ts +180 -0
- package/src/config/presets.ts +149 -0
- package/src/config/routing.ts +401 -0
- package/src/config/services.ts +51 -0
- package/src/config/switching.ts +84 -0
- package/src/config/system.ts +103 -0
- package/src/{schema → config}/time-zones.ts +1 -1
- package/src/core/address.ts +1 -1
- package/src/core/cabling.ts +8 -43
- package/src/core/graph.ts +40 -0
- package/src/{integrations → core}/registries.ts +5 -3
- package/src/core/secrets-file.ts +539 -0
- package/src/core/secrets.ts +83 -64
- package/src/core/topology.ts +103 -146
- package/src/core/utils.ts +12 -1
- package/src/model.ts +83 -0
- package/src/platforms/derive.ts +64 -37
- package/src/platforms/finding.ts +9 -0
- package/src/platforms/fortios/firewall.ts +76 -64
- package/src/platforms/fortios/index.ts +189 -125
- package/src/platforms/fortios/names.ts +51 -18
- package/src/platforms/fortios/render.ts +69 -62
- package/src/platforms/fortios/routing.ts +89 -58
- package/src/platforms/fortios/vdoms.ts +47 -16
- package/src/platforms/junos/TRAPS.md +2 -2
- package/src/platforms/junos/bgp.ts +63 -42
- package/src/platforms/junos/index.ts +122 -89
- package/src/platforms/junos/render.ts +139 -104
- package/src/platforms/platform.ts +10 -8
- package/src/platforms/raisecom-ros/TRAPS.md +1 -1
- package/src/platforms/raisecom-ros/index.ts +89 -70
- package/src/platforms/raisecom-ros/render.ts +49 -45
- package/src/platforms/routeros/TRAPS.md +3 -3
- package/src/platforms/routeros/index.ts +121 -60
- package/src/platforms/routeros/render.ts +214 -195
- package/src/platforms/vrp/TRAPS.md +1 -1
- package/src/platforms/vrp/index.ts +74 -50
- package/src/platforms/vrp/render.ts +67 -56
- package/src/project/project.ts +725 -0
- package/src/studio/app/env.d.ts +9 -0
- package/src/studio/app/index.html +18 -0
- package/src/studio/app/src/App.vue +95 -0
- package/src/studio/app/src/components/AddressesView.vue +38 -0
- package/src/studio/app/src/components/CablesView.vue +29 -0
- package/src/studio/app/src/components/CompareView.vue +160 -0
- package/src/studio/app/src/components/DataTable.vue +49 -0
- package/src/studio/app/src/components/DeviceView.vue +237 -0
- package/src/studio/app/src/components/DevicesView.vue +32 -0
- package/src/studio/app/src/components/Faceplate.vue +75 -0
- package/src/studio/app/src/components/GraphView.vue +282 -0
- package/src/studio/app/src/components/LineDiff.vue +24 -0
- package/src/studio/app/src/components/ProblemsView.vue +42 -0
- package/src/studio/app/src/components/SearchView.vue +72 -0
- package/src/studio/app/src/components/SecretsView.vue +112 -0
- package/src/studio/app/src/components/SessionsView.vue +35 -0
- package/src/studio/app/src/components/Settings.vue +95 -0
- package/src/studio/app/src/components/ToolsView.vue +118 -0
- package/src/studio/app/src/components/VlansView.vue +50 -0
- package/src/studio/app/src/lib/csv.ts +19 -0
- package/src/studio/{public/diff.js → app/src/lib/diff.ts} +40 -35
- package/src/studio/app/src/lib/format.ts +38 -0
- package/src/studio/app/src/lib/net.ts +68 -0
- package/src/studio/app/src/lib/secrets-crypto.ts +35 -0
- package/src/studio/app/src/lib/store.ts +71 -0
- package/src/studio/app/src/lib/tools.ts +217 -0
- package/src/studio/app/src/main.ts +9 -0
- package/src/studio/{public → app/src}/style.css +14 -4
- package/src/studio/app/tsconfig.json +17 -0
- package/src/studio/app/vite.config.ts +16 -0
- package/src/studio/assets.generated.ts +3 -0
- package/src/studio/data.ts +96 -188
- package/src/studio/git.ts +27 -43
- package/src/studio/server.ts +196 -107
- package/src/studio/types.ts +141 -0
- package/src/transport/console.ts +3 -3
- package/src/transport/ssh.ts +1 -1
- package/dist/chunks/index-3b343xva.js +0 -177
- package/dist/chunks/index-6wb41q67.js +0 -62
- package/dist/chunks/index-n7w3tg5y.js +0 -149
- package/dist/chunks/index-yzw86rc8.js +0 -921
- package/dist/chunks/new-w3zys5y4.js +0 -172
- package/dist/chunks/server-cxr9ynxc.js +0 -259
- package/dist/cli/index.js +0 -12922
- package/dist/helpers/index.js +0 -881
- package/dist/index.js +0 -28
- package/dist/types/core/address-space.d.ts +0 -62
- package/dist/types/core/address.d.ts +0 -44
- package/dist/types/core/cabling.d.ts +0 -41
- package/dist/types/core/cross-checks.d.ts +0 -28
- package/dist/types/core/define.d.ts +0 -79
- package/dist/types/core/project-files.d.ts +0 -12
- package/dist/types/core/schema-docs.d.ts +0 -25
- package/dist/types/core/secrets.d.ts +0 -62
- package/dist/types/core/topology.d.ts +0 -96
- package/dist/types/core/utils.d.ts +0 -10
- package/dist/types/core/validator.d.ts +0 -23
- package/dist/types/helpers/bgp.d.ts +0 -195
- package/dist/types/helpers/cables.d.ts +0 -69
- package/dist/types/helpers/checks.d.ts +0 -36
- package/dist/types/helpers/exchange.d.ts +0 -55
- package/dist/types/helpers/filters.d.ts +0 -51
- package/dist/types/helpers/index.d.ts +0 -14
- package/dist/types/helpers/route-server.d.ts +0 -52
- package/dist/types/helpers/upstreams.d.ts +0 -192
- package/dist/types/index.d.ts +0 -10
- package/dist/types/integrations/librenms.d.ts +0 -60
- package/dist/types/integrations/netbox.d.ts +0 -89
- package/dist/types/integrations/peeringdb.d.ts +0 -24
- package/dist/types/integrations/prometheus.d.ts +0 -24
- package/dist/types/integrations/registries.d.ts +0 -8
- package/dist/types/platforms/bgp-wait.d.ts +0 -24
- package/dist/types/platforms/catalog.d.ts +0 -109
- package/dist/types/platforms/derive.d.ts +0 -17
- package/dist/types/platforms/fortios/firewall.d.ts +0 -47
- package/dist/types/platforms/fortios/index.d.ts +0 -140
- package/dist/types/platforms/fortios/models.d.ts +0 -14
- package/dist/types/platforms/fortios/names.d.ts +0 -52
- package/dist/types/platforms/fortios/plan.d.ts +0 -114
- package/dist/types/platforms/fortios/render.d.ts +0 -77
- package/dist/types/platforms/fortios/routing.d.ts +0 -56
- package/dist/types/platforms/fortios/tree.d.ts +0 -37
- package/dist/types/platforms/fortios/vdoms.d.ts +0 -50
- package/dist/types/platforms/index.d.ts +0 -13
- package/dist/types/platforms/junos/bgp.d.ts +0 -44
- package/dist/types/platforms/junos/index.d.ts +0 -114
- package/dist/types/platforms/junos/models.d.ts +0 -14
- package/dist/types/platforms/junos/render.d.ts +0 -154
- package/dist/types/platforms/line-diff.d.ts +0 -67
- package/dist/types/platforms/platform.d.ts +0 -135
- package/dist/types/platforms/raisecom-ros/index.d.ts +0 -71
- package/dist/types/platforms/raisecom-ros/models.d.ts +0 -14
- package/dist/types/platforms/raisecom-ros/render.d.ts +0 -41
- package/dist/types/platforms/routeros/export.d.ts +0 -59
- package/dist/types/platforms/routeros/index.d.ts +0 -116
- package/dist/types/platforms/routeros/models.d.ts +0 -18
- package/dist/types/platforms/routeros/plan.d.ts +0 -58
- package/dist/types/platforms/routeros/render.d.ts +0 -250
- package/dist/types/platforms/vrp/index.d.ts +0 -83
- package/dist/types/platforms/vrp/models.d.ts +0 -12
- package/dist/types/platforms/vrp/render.d.ts +0 -96
- package/dist/types/schema/common.d.ts +0 -30
- package/dist/types/schema/device.d.ts +0 -126
- package/dist/types/schema/firewall.d.ts +0 -131
- package/dist/types/schema/index.d.ts +0 -8
- package/dist/types/schema/interfaces.d.ts +0 -205
- package/dist/types/schema/policy.d.ts +0 -107
- package/dist/types/schema/routing.d.ts +0 -161
- package/dist/types/schema/system.d.ts +0 -198
- package/dist/types/schema/time-zones.d.ts +0 -2
- package/dist/types/transport/console.d.ts +0 -115
- package/dist/types/transport/path-check.d.ts +0 -32
- package/dist/types/transport/ssh.d.ts +0 -27
- package/src/cli/graph-format.ts +0 -91
- package/src/cli/new.ts +0 -234
- package/src/core/address-space.ts +0 -320
- package/src/core/cross-checks.ts +0 -369
- package/src/core/define.ts +0 -124
- package/src/core/project-files.ts +0 -35
- package/src/core/schema-docs.ts +0 -174
- package/src/core/validator.ts +0 -508
- package/src/helpers/bgp.ts +0 -473
- package/src/helpers/cables.ts +0 -74
- package/src/helpers/checks.ts +0 -201
- package/src/helpers/exchange.ts +0 -123
- package/src/helpers/filters.ts +0 -107
- package/src/helpers/index.ts +0 -25
- package/src/helpers/route-server.ts +0 -212
- package/src/helpers/upstreams.ts +0 -369
- package/src/index.ts +0 -13
- package/src/integrations/librenms.ts +0 -291
- package/src/integrations/netbox.ts +0 -620
- package/src/integrations/peeringdb.ts +0 -173
- package/src/integrations/prometheus.ts +0 -90
- package/src/schema/common.ts +0 -41
- package/src/schema/device.ts +0 -145
- package/src/schema/firewall.ts +0 -140
- package/src/schema/index.ts +0 -8
- package/src/schema/policy.ts +0 -115
- package/src/schema/routing.ts +0 -173
- package/src/schema/system.ts +0 -203
- package/src/studio/public/app.js +0 -186
- package/src/studio/public/compare.js +0 -250
- package/src/studio/public/dom.js +0 -138
- package/src/studio/public/evaluate.js +0 -687
- package/src/studio/public/export.js +0 -130
- package/src/studio/public/graph.js +0 -1541
- package/src/studio/public/index.html +0 -83
- package/src/studio/public/net.js +0 -134
- package/src/studio/public/tables.js +0 -1289
- package/src/studio/public/tools.js +0 -610
- package/templates/colocation/checks.ts +0 -53
- package/templates/colocation/circuit.config.ts +0 -9
- package/templates/colocation/edge-01.ts +0 -133
- package/templates/colocation/routing.ts +0 -13
- package/templates/colocation/tenancy.ts +0 -76
- package/templates/colocation/tenants/acme.ts +0 -19
- package/templates/colocation/tenants/index.ts +0 -6
- package/templates/colocation/tor-01.ts +0 -33
- package/templates/edge-router/checks.ts +0 -20
- package/templates/edge-router/circuit.config.ts +0 -8
- package/templates/edge-router/edge-01.ts +0 -110
- package/templates/edge-router/routing.ts +0 -13
- package/templates/project/AGENTS.md +0 -51
- package/templates/project/CLAUDE.md +0 -1
- package/templates/project/README.md +0 -16
- package/templates/project/gitignore +0 -5
- package/templates/project/tsconfig.json +0 -13
- package/templates/single-site/checks.ts +0 -26
- package/templates/single-site/circuit.config.ts +0 -8
- package/templates/single-site/router.ts +0 -86
- package/templates/single-site/site.ts +0 -18
- package/templates/single-site/switch.ts +0 -34
- /package/src/studio/{public → app/public}/favicon.svg +0 -0
- /package/src/studio/{public → app/public}/special-gothic-latin-ext.woff2 +0 -0
- /package/src/studio/{public → app/public}/special-gothic-latin.woff2 +0 -0
- /package/src/studio/{public → app/public}/special-gothic-license.txt +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Layer 2 shared by ports: `switching.vlans`, `.stp`, `.lldp`, `.acls`.
|
|
2
|
+
|
|
3
|
+
import type { Family, Named, OneOrMore, Ordered, Prefix, Rate } from "./common";
|
|
4
|
+
import type { Ports, Protocol } from "./firewall";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A VLAN. Its key in `switching.vlans` is its name. `Untrusted` is whether the network turns on the check `untrusted_vlans`, which
|
|
8
|
+
* `untrusted` needs.
|
|
9
|
+
*/
|
|
10
|
+
export type Vlan<Untrusted extends boolean = true> = {
|
|
11
|
+
/** The VLAN's number on the wire, 1 to 4094. Two VLANs on a device never share one. */
|
|
12
|
+
id: number;
|
|
13
|
+
/** What the VLAN is for. Dropped on a platform where a VLAN is only its number (Raisecom, FortiOS), so a device takes a VLAN whole wherever it runs. */
|
|
14
|
+
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The VLAN carries traffic straight from outside: a transit, an exchange, an ISP handoff, or such a one's native VLAN. Only Circuit
|
|
17
|
+
* reads it, for the check `untrusted_vlans`; the device never sees it. Write it on every device that declares the VLAN. Allowed only
|
|
18
|
+
* when the network's `circuit()` turns on `untrusted_vlans`: an error in the editor, and `circuit validate` stops.
|
|
19
|
+
*/
|
|
20
|
+
untrusted?: Untrusted extends true ? true : "allowed only when circuit.ts turns on the check untrusted_vlans";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Which packets an ACL rule applies to. All must be true.
|
|
25
|
+
*
|
|
26
|
+
* `vlan`, `src` and `dst` each take a list. Where the platform has no list, Circuit writes one rule per combination: the VLAN
|
|
27
|
+
* outermost, then `src`, then `dst`.
|
|
28
|
+
*/
|
|
29
|
+
export type AclMatch<V extends string> = {
|
|
30
|
+
/** Only packets of this family. */
|
|
31
|
+
family?: Family;
|
|
32
|
+
/** IP protocol. */
|
|
33
|
+
protocol?: Protocol;
|
|
34
|
+
/** Source prefix, or any of several. */
|
|
35
|
+
src?: OneOrMore<Prefix>;
|
|
36
|
+
/** Destination prefix, or any of several. */
|
|
37
|
+
dst?: OneOrMore<Prefix>;
|
|
38
|
+
/** Source port, or any of several. */
|
|
39
|
+
src_port?: Ports;
|
|
40
|
+
/** Destination port, or any of several. */
|
|
41
|
+
dst_port?: Ports;
|
|
42
|
+
/** One of `switching.vlans`, or any of several: only packets in this VLAN. */
|
|
43
|
+
vlan?: OneOrMore<V>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A stateless rule evaluated in hardware where traffic arrives, before routing, the condition first:
|
|
48
|
+
* `{ if: { vlan: "ix", src: "10.0.0.0/8" }, then: "drop" }`. No `if`: every packet.
|
|
49
|
+
*/
|
|
50
|
+
export type AclRule<V extends string> = {
|
|
51
|
+
/** Shown beside the rule on the device. */
|
|
52
|
+
description?: string;
|
|
53
|
+
/** Which packets the rule applies to. Every packet when absent. */
|
|
54
|
+
if?: AclMatch<V>;
|
|
55
|
+
/** What happens to a matching packet. */
|
|
56
|
+
then: "accept" | "drop";
|
|
57
|
+
/** Accepted traffic above this rate is dropped. On RouterOS it did not limit traffic the CPU routes; see its TRAPS.md. */
|
|
58
|
+
rate?: Rate;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** Spanning tree on every switched port. A port may override it. */
|
|
62
|
+
export type Stp = {
|
|
63
|
+
/** Which variant runs. RSTP when absent. */
|
|
64
|
+
mode?: "stp" | "rstp" | "mstp";
|
|
65
|
+
/** Bridge priority, 0 to 61440 in steps of 4096. Lower wins the root election. */
|
|
66
|
+
priority?: number;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** Layer 2 that the ports share. `V` is the device's VLAN names, `A` its ACL names, `I` its ports and interfaces. `Untrusted` is whether the network turns on `untrusted_vlans`. */
|
|
70
|
+
export type Switching<V extends string, A extends string, I extends string, Untrusted extends boolean = true> = {
|
|
71
|
+
/** VLANs, keyed by name. A port, a LAG or a VLAN interface names one of these. */
|
|
72
|
+
vlans?: Named<V, Vlan<Untrusted>>;
|
|
73
|
+
/** Spanning tree on every switched port. A port may override it. */
|
|
74
|
+
stp?: Stp;
|
|
75
|
+
/** Advertise and learn neighbors with LLDP on every port (`true`), or only on the interfaces listed. A port may override it. */
|
|
76
|
+
lldp?:
|
|
77
|
+
| true
|
|
78
|
+
| {
|
|
79
|
+
/** Some of the device's ports and interfaces. */
|
|
80
|
+
interfaces: readonly I[];
|
|
81
|
+
};
|
|
82
|
+
/** Hardware ACLs, keyed by name, applied to a port with `ingress_acl`. Each is rules in order, written whole in one place: the first runs first. */
|
|
83
|
+
acls?: Named<A, Ordered<AclRule<NoInfer<V>>>>;
|
|
84
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// The box itself: `system.timezone`, `.banner`, `.release_channel`, `.ip_stack`, `.alarms`, `.dns`, `.ntp`, `.logging`, `.hardware_offload`, `.users`, `.certificates`, `.vdoms`.
|
|
2
|
+
|
|
3
|
+
import type { IP, Named, Secret, Severity } from "./common";
|
|
4
|
+
import type { StaticRoute } from "./routing";
|
|
5
|
+
import type { TimeZone } from "./time-zones";
|
|
6
|
+
|
|
7
|
+
/** A software release track, as RouterOS names them. `long-term` changes least; `development` is the newest and least tested. */
|
|
8
|
+
export type ReleaseChannel = "long-term" | "stable" | "testing" | "development";
|
|
9
|
+
|
|
10
|
+
/** How bad an alarm is, most severe first, as ITU-T X.733 ranks them. */
|
|
11
|
+
export type AlarmSeverity = "critical" | "major" | "minor" | "warning";
|
|
12
|
+
|
|
13
|
+
/** A login on the device. */
|
|
14
|
+
export type User = {
|
|
15
|
+
/** What the user may do. */
|
|
16
|
+
role: "admin" | "operator" | "read-only";
|
|
17
|
+
/** The login password. */
|
|
18
|
+
password: Secret;
|
|
19
|
+
/** Who the account is for. */
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Public keys accepted instead of the password over SSH. */
|
|
22
|
+
ssh_keys?: readonly string[];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** A certificate the device presents or trusts. */
|
|
26
|
+
export type Certificate = {
|
|
27
|
+
/** The certificate, a PEM file (`.pem` or `.crt`): a path from the project root. Public, so it is kept in the repository. */
|
|
28
|
+
certificate_file: string;
|
|
29
|
+
/** Its private key: a PEM file through `secretFile`, or PEM base64-encoded as one line through `secret`. A certificate the device only trusts, such as a CA, has none. */
|
|
30
|
+
private_key?: Secret;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Virtual domains, on FortiOS: the device's own traffic kept apart from the traffic it routes. Everything is in `root` when absent.
|
|
35
|
+
*
|
|
36
|
+
* Multi-VDOM mode is turned on by hand, not by a plan: it moves the whole configuration into `root` and ends every session.
|
|
37
|
+
*/
|
|
38
|
+
export type Vdoms<I extends string> = {
|
|
39
|
+
/** A VDOM for the device's own traffic: FortiGuard, NTP, DNS and logging leave from it, by its own routes, so they never follow the routed traffic's default route. Everything not listed here stays in `root`. */
|
|
40
|
+
management: {
|
|
41
|
+
/** Its name, such as `mgmt`. Not `root`. */
|
|
42
|
+
name: string;
|
|
43
|
+
/** Some of the device's ports and interfaces: the ones in it. A LAG's member ports go with the LAG. */
|
|
44
|
+
interfaces: readonly I[];
|
|
45
|
+
/** Its static routes, such as its own default route. */
|
|
46
|
+
static_routes?: readonly StaticRoute<I, never, never>[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Device-wide settings: the box itself. `U` is the device's user names, `C` its certificate names, `I` its ports and interfaces. */
|
|
51
|
+
export type System<U extends string, C extends string, I extends string> = {
|
|
52
|
+
/** IANA zone, for example `Asia/Jakarta`. The editor suggests every name. UTC when absent. */
|
|
53
|
+
timezone?: TimeZone;
|
|
54
|
+
/** Shown at login. */
|
|
55
|
+
banner?: string;
|
|
56
|
+
/** Software release track the device updates from. `stable` when absent. */
|
|
57
|
+
release_channel?: ReleaseChannel;
|
|
58
|
+
/** Host behaviour of the IP stack. */
|
|
59
|
+
ip_stack?: {
|
|
60
|
+
/** Send ICMP redirects. Off when absent. */
|
|
61
|
+
icmp_redirects?: boolean;
|
|
62
|
+
/** Answer a TCP SYN flood with SYN cookies. Off when absent. */
|
|
63
|
+
syn_cookies?: boolean;
|
|
64
|
+
};
|
|
65
|
+
/** Alarms raised at another severity than the platform's own, keyed by the alarm's name as the platform spells it, such as `hwOpticalUnAuthorized` on VRP. */
|
|
66
|
+
alarms?: Record<
|
|
67
|
+
string,
|
|
68
|
+
{
|
|
69
|
+
/** The severity it is raised at. */
|
|
70
|
+
severity: AlarmSeverity;
|
|
71
|
+
}
|
|
72
|
+
>;
|
|
73
|
+
/** Resolvers the device uses. Answering others is `services.dns_server`. */
|
|
74
|
+
dns?: {
|
|
75
|
+
/** Resolvers, in order of preference. */
|
|
76
|
+
servers: readonly IP[];
|
|
77
|
+
};
|
|
78
|
+
/** How the device keeps time. Answering others is `services.ntp_server`. */
|
|
79
|
+
ntp?: {
|
|
80
|
+
/** Time sources, by address (alone or with its length) or name, in order of preference. */
|
|
81
|
+
servers: readonly string[];
|
|
82
|
+
};
|
|
83
|
+
/** Log messages kept on the device itself. Sending them to collectors is `monitoring.syslog`. */
|
|
84
|
+
logging?: {
|
|
85
|
+
/** Kept on the device's own storage, from `level` up. */
|
|
86
|
+
local?: {
|
|
87
|
+
/** The least severe message kept. */
|
|
88
|
+
level: Severity;
|
|
89
|
+
/** How many rotated files to keep. */
|
|
90
|
+
files?: number;
|
|
91
|
+
/** Lines in each file before it rotates. */
|
|
92
|
+
lines_per_file?: number;
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
/** Forward in hardware where the platform can. An interface may override it. */
|
|
96
|
+
hardware_offload?: boolean;
|
|
97
|
+
/** Logins, keyed by user name. Users not listed are removed. */
|
|
98
|
+
users?: Named<U, User>;
|
|
99
|
+
/** Certificates the device presents or trusts, keyed by name. `management.https` and `management.api_tls` name one. */
|
|
100
|
+
certificates?: Named<C, Certificate>;
|
|
101
|
+
/** Virtual domains, on FortiOS only: a management VDOM apart from the routed traffic. */
|
|
102
|
+
vdoms?: Vdoms<I>;
|
|
103
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Every IANA time zone name Circuit knows, copied from Circuit 0.43 (`src/schema/time-zones.ts`, generated from the runtime).
|
|
2
2
|
|
|
3
3
|
/** An IANA time zone name, such as `Asia/Jakarta`, or `UTC`. */
|
|
4
4
|
export type TimeZone =
|
package/src/core/address.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Address arithmetic for both families. Addresses are parsed to bigint so v4 and v6 share one code path.
|
|
2
2
|
|
|
3
|
-
import type { Family, IP, IPv4, IPv6, Prefix } from "../
|
|
3
|
+
import type { Family, IP, IPv4, IPv6, Prefix } from "../model";
|
|
4
4
|
|
|
5
5
|
/** Address helpers, for checks of your own. */
|
|
6
6
|
export class Address {
|
package/src/core/cabling.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
// The cabling as LLDP sees it, compared with what `link` says. `
|
|
1
|
+
// The cabling as LLDP sees it, compared with what `link` says. `diff` and `apply` read a device's LLDP neighbors while they are connected, and warn where they disagree.
|
|
2
2
|
|
|
3
|
-
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { join } from "node:path";
|
|
5
3
|
import { Catalog } from "../platforms/catalog";
|
|
6
|
-
import type { Device } from "../
|
|
7
|
-
import type { Finding } from "
|
|
4
|
+
import type { Device } from "../model";
|
|
5
|
+
import type { Finding } from "../platforms/finding";
|
|
8
6
|
|
|
9
7
|
/** A device one of our ports sees at the far end of its cable, over LLDP. */
|
|
10
8
|
export type Neighbor = {
|
|
@@ -17,50 +15,17 @@ export type Neighbor = {
|
|
|
17
15
|
};
|
|
18
16
|
|
|
19
17
|
export class Cabling {
|
|
20
|
-
/** The end of a state file that holds a device's LLDP neighbors, beside its config. */
|
|
21
|
-
static readonly SUFFIX = ".lldp.json";
|
|
22
|
-
|
|
23
|
-
/** The file a device's neighbors are saved in. */
|
|
24
|
-
static path(stateDirectory: string, device: string): string {
|
|
25
|
-
return join(stateDirectory, device + Cabling.SUFFIX);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Save what a device sees, sorted, so a file changes only when a neighbor does. */
|
|
29
|
-
static save(stateDirectory: string, device: string, neighbors: readonly Neighbor[]): void {
|
|
30
|
-
const sorted = [...neighbors].sort((a, b) => Cabling.order(a).localeCompare(Cabling.order(b)));
|
|
31
|
-
const tidy = sorted.map(({ port, system, remote_port }) => ({ port, system, remote_port }));
|
|
32
|
-
|
|
33
|
-
writeFileSync(Cabling.path(stateDirectory, device), JSON.stringify(tidy, null, 4) + "\n");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Forget what a device saw, when its neighbors could not be read this time. */
|
|
37
|
-
static forget(stateDirectory: string, device: string): void {
|
|
38
|
-
rmSync(Cabling.path(stateDirectory, device), { force: true });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** What a device saw at its last snapshot, or undefined when its neighbors were never read. */
|
|
42
|
-
static load(stateDirectory: string, device: string): Neighbor[] | undefined {
|
|
43
|
-
const path = Cabling.path(stateDirectory, device);
|
|
44
|
-
if (!existsSync(path)) return undefined;
|
|
45
|
-
|
|
46
|
-
return JSON.parse(readFileSync(path, "utf8")) as Neighbor[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private static order(neighbor: Neighbor): string {
|
|
50
|
-
return `${neighbor.port} ${neighbor.system} ${neighbor.remote_port}`;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
18
|
/** The device runs LLDP somewhere: on every port, on the interfaces it lists, or on a port that turns it on. */
|
|
54
19
|
static runsAnywhere(device: Device): boolean {
|
|
55
|
-
return Boolean(device.lldp) || Object.values(device.
|
|
20
|
+
return Boolean(device.switching?.lldp) || Object.values(device.interfaces?.ethernet ?? {}).some((port) => port?.lldp === true);
|
|
56
21
|
}
|
|
57
22
|
|
|
58
23
|
/** The port runs LLDP, by the port's own `lldp`, or else the device's. */
|
|
59
24
|
static runsOn(device: Device, port: string): boolean {
|
|
60
|
-
const own = device.
|
|
25
|
+
const own = device.interfaces?.ethernet?.[port]?.lldp;
|
|
61
26
|
if (own !== undefined) return own;
|
|
62
27
|
|
|
63
|
-
const lldp = device.lldp;
|
|
28
|
+
const lldp = device.switching?.lldp;
|
|
64
29
|
return lldp === true || (typeof lldp === "object" && (lldp.interfaces as readonly string[]).includes(port));
|
|
65
30
|
}
|
|
66
31
|
|
|
@@ -77,14 +42,14 @@ export class Cabling {
|
|
|
77
42
|
if (!seen) continue;
|
|
78
43
|
|
|
79
44
|
const warn = (message: string) => findings.push({ level: "warning", device: device.name, message });
|
|
80
|
-
const linked = Object.entries(device.
|
|
45
|
+
const linked = Object.entries(device.interfaces?.ethernet ?? {}).filter(([, port]) => port?.link);
|
|
81
46
|
const ports = new Set([...linked.map(([name]) => name), ...seen.map((neighbor) => neighbor.port)]);
|
|
82
47
|
|
|
83
48
|
for (const port of ports) {
|
|
84
49
|
if (!Cabling.runsOn(device, port)) continue;
|
|
85
50
|
|
|
86
51
|
const here = seen.filter((neighbor) => neighbor.port === port);
|
|
87
|
-
const link = device.
|
|
52
|
+
const link = device.interfaces?.ethernet?.[port]?.link;
|
|
88
53
|
|
|
89
54
|
if (!link) {
|
|
90
55
|
for (const neighbor of here) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// The network as a graph: the shapes `Topology` draws, without its code, so Studio's page can share them.
|
|
2
|
+
|
|
3
|
+
/** One view of the network. Every edge belongs to one. */
|
|
4
|
+
export type Layer = "l1" | "l2" | "l3" | "bgp" | "ospf" | "tunnels";
|
|
5
|
+
|
|
6
|
+
/** One of our devices, a segment several of them share, or something outside the network. */
|
|
7
|
+
export type GraphNode = {
|
|
8
|
+
/** Unique among the nodes, such as `device:edge-01` or `as:64501`. */
|
|
9
|
+
id: string;
|
|
10
|
+
kind: "device" | "segment" | "outside";
|
|
11
|
+
/** A word or two, drawn on the node. */
|
|
12
|
+
label: string;
|
|
13
|
+
/** One fact per line, for a closer look. */
|
|
14
|
+
detail: string[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** A VLAN a cable carries. */
|
|
18
|
+
export type CarriedVlan = {
|
|
19
|
+
name: string;
|
|
20
|
+
id: number;
|
|
21
|
+
/** Carried without a tag: the access VLAN, or a trunk's native VLAN. */
|
|
22
|
+
untagged: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type GraphEdge = {
|
|
26
|
+
layer: Layer;
|
|
27
|
+
/** Node ids. */
|
|
28
|
+
from: string;
|
|
29
|
+
to: string;
|
|
30
|
+
/** A few words, drawn on the edge. */
|
|
31
|
+
label: string;
|
|
32
|
+
/** One fact per line, for a closer look. */
|
|
33
|
+
detail: string[];
|
|
34
|
+
/** Only one end declares it: the far device does not declare the cable, session or tunnel back. */
|
|
35
|
+
oneSided?: true;
|
|
36
|
+
/** On `l2`, the VLANs the cable carries. */
|
|
37
|
+
vlans?: CarriedVlan[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type Graph = { nodes: GraphNode[]; edges: GraphEdge[] };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
// Registries
|
|
1
|
+
// Registries Circuit reads prefix sets from.
|
|
2
2
|
|
|
3
|
-
import type { Family } from "../
|
|
4
|
-
|
|
3
|
+
import type { Family } from "../model";
|
|
4
|
+
|
|
5
|
+
/** A registry Circuit fetches prefixes from. */
|
|
6
|
+
export type Registry = "ripe-stat";
|
|
5
7
|
|
|
6
8
|
export class Registries {
|
|
7
9
|
/** The prefixes of one family a registry gives for a query. */
|