@takodotid/circuit 0.34.2 → 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.
Files changed (240) hide show
  1. package/README.md +13 -14
  2. package/dist/chunks/index-20kcjxjg.js +174 -0
  3. package/dist/chunks/index-2r4bbhac.js +977 -0
  4. package/dist/chunks/index-n7w3tg5y.js +149 -0
  5. package/dist/chunks/new-w3zys5y4.js +172 -0
  6. package/dist/chunks/server-gzsf5me5.js +259 -0
  7. package/dist/cli/index.js +11347 -9018
  8. package/dist/helpers/index.js +594 -0
  9. package/dist/index.js +9 -28
  10. package/dist/types/core/{addresses.d.ts → address-space.d.ts} +23 -7
  11. package/dist/types/core/address.d.ts +44 -0
  12. package/dist/types/core/cabling.d.ts +41 -0
  13. package/dist/types/core/cross-checks.d.ts +28 -0
  14. package/dist/types/core/define.d.ts +25 -3
  15. package/dist/types/core/project-files.d.ts +12 -0
  16. package/dist/types/core/schema-docs.d.ts +13 -4
  17. package/dist/types/core/secrets.d.ts +62 -21
  18. package/dist/types/core/{graph.d.ts → topology.d.ts} +32 -12
  19. package/dist/types/core/utils.d.ts +8 -0
  20. package/dist/types/core/validator.d.ts +19 -0
  21. package/dist/types/helpers/bgp.d.ts +97 -0
  22. package/dist/types/helpers/checks.d.ts +32 -0
  23. package/dist/types/helpers/exchange.d.ts +49 -0
  24. package/dist/types/helpers/filters.d.ts +51 -0
  25. package/dist/types/helpers/index.d.ts +10 -0
  26. package/dist/types/helpers/route-server.d.ts +52 -0
  27. package/dist/types/index.d.ts +5 -3
  28. package/dist/types/integrations/librenms.d.ts +60 -0
  29. package/dist/types/integrations/netbox.d.ts +89 -0
  30. package/dist/types/integrations/peeringdb.d.ts +24 -0
  31. package/dist/types/integrations/prometheus.d.ts +24 -0
  32. package/dist/types/integrations/registries.d.ts +8 -0
  33. package/dist/types/platforms/bgp-wait.d.ts +18 -0
  34. package/dist/types/platforms/catalog.d.ts +109 -0
  35. package/dist/types/platforms/derive.d.ts +17 -0
  36. package/dist/types/platforms/fortios/firewall.d.ts +45 -0
  37. package/dist/types/platforms/fortios/index.d.ts +134 -0
  38. package/dist/types/platforms/fortios/names.d.ts +52 -0
  39. package/dist/types/platforms/fortios/plan.d.ts +104 -0
  40. package/dist/types/platforms/fortios/render.d.ts +75 -0
  41. package/dist/types/platforms/fortios/routing.d.ts +56 -0
  42. package/dist/types/platforms/fortios/tree.d.ts +37 -0
  43. package/dist/types/platforms/index.d.ts +13 -0
  44. package/dist/types/platforms/junos/bgp.d.ts +44 -0
  45. package/dist/types/platforms/junos/index.d.ts +114 -0
  46. package/dist/types/platforms/junos/render.d.ts +154 -0
  47. package/dist/types/platforms/line-diff.d.ts +67 -0
  48. package/dist/types/platforms/platform.d.ts +120 -0
  49. package/dist/types/platforms/raisecom-ros/index.d.ts +71 -0
  50. package/dist/types/platforms/raisecom-ros/render.d.ts +41 -0
  51. package/dist/types/platforms/routeros/export.d.ts +59 -0
  52. package/dist/types/platforms/routeros/index.d.ts +96 -0
  53. package/dist/types/{adapters/devices → platforms}/routeros/models.d.ts +4 -0
  54. package/dist/types/platforms/routeros/plan.d.ts +54 -0
  55. package/dist/types/platforms/routeros/render.d.ts +240 -0
  56. package/dist/types/platforms/vrp/index.d.ts +83 -0
  57. package/dist/types/platforms/vrp/render.d.ts +96 -0
  58. package/dist/types/schema/common.d.ts +12 -6
  59. package/dist/types/schema/index.d.ts +1 -0
  60. package/dist/types/schema/interfaces.d.ts +14 -6
  61. package/dist/types/schema/policy.d.ts +18 -10
  62. package/dist/types/schema/routing.d.ts +14 -1
  63. package/dist/types/schema/system.d.ts +16 -6
  64. package/dist/types/schema/time-zones.d.ts +2 -0
  65. package/dist/types/transport/console.d.ts +79 -23
  66. package/dist/types/transport/path-check.d.ts +32 -0
  67. package/dist/types/transport/ssh.d.ts +17 -15
  68. package/package.json +17 -11
  69. package/src/cli/graph-format.ts +91 -0
  70. package/src/cli/index.ts +1074 -484
  71. package/src/cli/new.ts +208 -175
  72. package/src/cli/rename.ts +97 -91
  73. package/src/core/address-space.ts +320 -0
  74. package/src/core/address.ts +202 -0
  75. package/src/core/cabling.ts +154 -0
  76. package/src/core/cross-checks.ts +364 -0
  77. package/src/core/define.ts +26 -3
  78. package/src/core/project-files.ts +35 -0
  79. package/src/core/schema-docs.ts +138 -130
  80. package/src/core/secrets.ts +170 -76
  81. package/src/core/topology.ts +656 -0
  82. package/src/core/utils.ts +37 -0
  83. package/src/core/validator.ts +407 -0
  84. package/src/helpers/bgp.ts +301 -0
  85. package/src/helpers/checks.ts +178 -0
  86. package/src/helpers/exchange.ts +117 -0
  87. package/src/helpers/filters.ts +107 -0
  88. package/src/helpers/index.ts +12 -0
  89. package/src/helpers/route-server.ts +212 -0
  90. package/src/index.ts +6 -3
  91. package/src/integrations/librenms.ts +291 -0
  92. package/src/integrations/netbox.ts +620 -0
  93. package/src/integrations/peeringdb.ts +173 -0
  94. package/src/integrations/prometheus.ts +90 -0
  95. package/src/integrations/registries.ts +25 -0
  96. package/src/platforms/bgp-wait.ts +41 -0
  97. package/src/platforms/catalog.ts +69 -0
  98. package/src/platforms/derive.ts +117 -0
  99. package/src/{adapters/devices → platforms}/fortios/TRAPS.md +6 -0
  100. package/src/platforms/fortios/firewall.ts +377 -0
  101. package/src/platforms/fortios/index.ts +1060 -0
  102. package/src/platforms/fortios/names.ts +130 -0
  103. package/src/platforms/fortios/plan.ts +929 -0
  104. package/src/platforms/fortios/render.ts +779 -0
  105. package/src/platforms/fortios/routing.ts +476 -0
  106. package/src/platforms/fortios/tree.ts +129 -0
  107. package/src/platforms/index.ts +36 -0
  108. package/src/{adapters/devices → platforms}/junos/TRAPS.md +8 -0
  109. package/src/platforms/junos/bgp.ts +293 -0
  110. package/src/platforms/junos/index.ts +1006 -0
  111. package/src/platforms/junos/render.ts +967 -0
  112. package/src/platforms/line-diff.ts +244 -0
  113. package/src/platforms/platform.ts +122 -0
  114. package/src/platforms/raisecom-ros/TRAPS.md +40 -0
  115. package/src/platforms/raisecom-ros/index.ts +731 -0
  116. package/src/platforms/raisecom-ros/render.ts +328 -0
  117. package/src/{adapters/devices → platforms}/routeros/TRAPS.md +16 -2
  118. package/src/platforms/routeros/export.ts +342 -0
  119. package/src/platforms/routeros/index.ts +636 -0
  120. package/src/{adapters/devices → platforms}/routeros/models.ts +2 -0
  121. package/src/platforms/routeros/plan.ts +444 -0
  122. package/src/platforms/routeros/render.ts +1483 -0
  123. package/src/platforms/vrp/TRAPS.md +45 -0
  124. package/src/platforms/vrp/index.ts +652 -0
  125. package/src/platforms/vrp/render.ts +615 -0
  126. package/src/schema/common.ts +15 -6
  127. package/src/schema/index.ts +1 -0
  128. package/src/schema/interfaces.ts +15 -5
  129. package/src/schema/policy.ts +22 -10
  130. package/src/schema/routing.ts +16 -1
  131. package/src/schema/system.ts +16 -6
  132. package/src/schema/time-zones.ts +482 -0
  133. package/src/studio/data.ts +172 -168
  134. package/src/studio/git.ts +95 -90
  135. package/src/studio/public/app.js +161 -150
  136. package/src/studio/public/compare.js +219 -212
  137. package/src/studio/public/diff.js +77 -75
  138. package/src/studio/public/dom.js +118 -108
  139. package/src/studio/public/evaluate.js +584 -545
  140. package/src/studio/public/export.js +120 -118
  141. package/src/studio/public/graph.js +1343 -1266
  142. package/src/studio/public/net.js +115 -109
  143. package/src/studio/public/tables.js +1135 -1083
  144. package/src/studio/public/tools.js +561 -529
  145. package/src/studio/server.ts +202 -196
  146. package/src/transport/console.ts +363 -271
  147. package/src/transport/path-check.ts +91 -0
  148. package/src/transport/ssh.ts +98 -94
  149. package/templates/colocation/checks.ts +11 -6
  150. package/templates/colocation/edge-01.ts +9 -9
  151. package/templates/colocation/routing.ts +2 -2
  152. package/templates/colocation/tenancy.ts +3 -3
  153. package/templates/colocation/tor-01.ts +3 -3
  154. package/templates/edge-router/checks.ts +4 -4
  155. package/templates/edge-router/edge-01.ts +5 -5
  156. package/templates/edge-router/routing.ts +2 -2
  157. package/templates/project/AGENTS.md +5 -1
  158. package/templates/single-site/checks.ts +2 -2
  159. package/dist/chunks/index-47debt16.js +0 -956
  160. package/dist/chunks/index-v8zgr7wm.js +0 -128
  161. package/dist/chunks/new-ny89s7y7.js +0 -166
  162. package/dist/chunks/server-tjbb3rqc.js +0 -251
  163. package/dist/presets/index.js +0 -394
  164. package/dist/types/adapters/devices/catalog.d.ts +0 -86
  165. package/dist/types/adapters/devices/derive.d.ts +0 -7
  166. package/dist/types/adapters/devices/fortios/firewall.d.ts +0 -23
  167. package/dist/types/adapters/devices/fortios/index.d.ts +0 -58
  168. package/dist/types/adapters/devices/fortios/names.d.ts +0 -48
  169. package/dist/types/adapters/devices/fortios/plan.d.ts +0 -28
  170. package/dist/types/adapters/devices/fortios/render.d.ts +0 -38
  171. package/dist/types/adapters/devices/fortios/routing.d.ts +0 -32
  172. package/dist/types/adapters/devices/fortios/tree.d.ts +0 -33
  173. package/dist/types/adapters/devices/index.d.ts +0 -3
  174. package/dist/types/adapters/devices/junos/bgp.d.ts +0 -11
  175. package/dist/types/adapters/devices/junos/index.d.ts +0 -42
  176. package/dist/types/adapters/devices/junos/render.d.ts +0 -52
  177. package/dist/types/adapters/devices/lines.d.ts +0 -56
  178. package/dist/types/adapters/devices/raisecom-ros/index.d.ts +0 -28
  179. package/dist/types/adapters/devices/routeros/export.d.ts +0 -39
  180. package/dist/types/adapters/devices/routeros/index.d.ts +0 -30
  181. package/dist/types/adapters/devices/routeros/plan.d.ts +0 -4
  182. package/dist/types/adapters/devices/routeros/render.d.ts +0 -100
  183. package/dist/types/adapters/devices/types.d.ts +0 -40
  184. package/dist/types/adapters/devices/vrp/index.d.ts +0 -27
  185. package/dist/types/adapters/registries/index.d.ts +0 -3
  186. package/dist/types/adapters/registries/librenms.d.ts +0 -15
  187. package/dist/types/adapters/registries/peeringdb.d.ts +0 -16
  188. package/dist/types/adapters/registries/prometheus.d.ts +0 -16
  189. package/dist/types/core/across.d.ts +0 -4
  190. package/dist/types/core/addr.d.ts +0 -34
  191. package/dist/types/core/files.d.ts +0 -6
  192. package/dist/types/core/merge.d.ts +0 -4
  193. package/dist/types/core/time.d.ts +0 -2
  194. package/dist/types/core/validate.d.ts +0 -2
  195. package/dist/types/presets/index.d.ts +0 -183
  196. package/src/adapters/devices/catalog.ts +0 -41
  197. package/src/adapters/devices/derive.ts +0 -59
  198. package/src/adapters/devices/fortios/firewall.ts +0 -362
  199. package/src/adapters/devices/fortios/index.ts +0 -923
  200. package/src/adapters/devices/fortios/names.ts +0 -115
  201. package/src/adapters/devices/fortios/plan.ts +0 -888
  202. package/src/adapters/devices/fortios/render.ts +0 -768
  203. package/src/adapters/devices/fortios/routing.ts +0 -444
  204. package/src/adapters/devices/fortios/tree.ts +0 -121
  205. package/src/adapters/devices/index.ts +0 -9
  206. package/src/adapters/devices/junos/bgp.ts +0 -269
  207. package/src/adapters/devices/junos/index.ts +0 -862
  208. package/src/adapters/devices/junos/render.ts +0 -872
  209. package/src/adapters/devices/lines.ts +0 -212
  210. package/src/adapters/devices/raisecom-ros/TRAPS.md +0 -25
  211. package/src/adapters/devices/raisecom-ros/index.ts +0 -693
  212. package/src/adapters/devices/routeros/export.ts +0 -321
  213. package/src/adapters/devices/routeros/index.ts +0 -346
  214. package/src/adapters/devices/routeros/plan.ts +0 -398
  215. package/src/adapters/devices/routeros/render.ts +0 -1490
  216. package/src/adapters/devices/types.ts +0 -38
  217. package/src/adapters/devices/vrp/TRAPS.md +0 -26
  218. package/src/adapters/devices/vrp/index.ts +0 -865
  219. package/src/adapters/registries/index.ts +0 -19
  220. package/src/adapters/registries/librenms.ts +0 -92
  221. package/src/adapters/registries/peeringdb.ts +0 -169
  222. package/src/adapters/registries/prometheus.ts +0 -71
  223. package/src/cli/graph.ts +0 -89
  224. package/src/core/across.ts +0 -350
  225. package/src/core/addr.ts +0 -174
  226. package/src/core/addresses.ts +0 -316
  227. package/src/core/files.ts +0 -32
  228. package/src/core/graph.ts +0 -640
  229. package/src/core/merge.ts +0 -19
  230. package/src/core/time.ts +0 -15
  231. package/src/core/validate.ts +0 -348
  232. package/src/presets/index.ts +0 -579
  233. /package/dist/types/{adapters/devices → platforms}/fortios/models.d.ts +0 -0
  234. /package/dist/types/{adapters/devices → platforms}/junos/models.d.ts +0 -0
  235. /package/dist/types/{adapters/devices → platforms}/raisecom-ros/models.d.ts +0 -0
  236. /package/dist/types/{adapters/devices → platforms}/vrp/models.d.ts +0 -0
  237. /package/src/{adapters/devices → platforms}/fortios/models.ts +0 -0
  238. /package/src/{adapters/devices → platforms}/junos/models.ts +0 -0
  239. /package/src/{adapters/devices → platforms}/raisecom-ros/models.ts +0 -0
  240. /package/src/{adapters/devices → platforms}/vrp/models.ts +0 -0
@@ -0,0 +1,52 @@
1
+ import type { Family, IPv4, IPv6, Prefix } from "../schema";
2
+ import type { ExchangeMember } from "./exchange";
3
+ /** A route server on an exchange's peering LAN: a server running BIRD 2 or OpenBGPD that passes every member's routes to every other member. */
4
+ export type RouteServer = {
5
+ /** Its name, such as `rs1`, written at the top of its config. */
6
+ name: string;
7
+ /** Its own AS. Members peer with it, but it never adds itself to a path, so members see each other's paths as they were sent. */
8
+ asn: number;
9
+ /** Its BGP router ID, an IPv4 address of the server. Its address on the peering LAN is the usual pick. */
10
+ router_id: IPv4;
11
+ /** Its IPv4 address on the peering LAN. Every member with an IPv4 address gets an IPv4 session from it. */
12
+ ipv4?: IPv4;
13
+ /** Its IPv6 address on the peering LAN. Every member with an IPv6 address gets an IPv6 session from it. */
14
+ ipv6?: IPv6;
15
+ };
16
+ /** A route server's config, written from an exchange's member list. Circuit writes the file; it never logs in to the server. */
17
+ export declare class RouteServerConfig {
18
+ /** The shortest and longest prefix a member may send, by family. */
19
+ static readonly LENGTHS: Readonly<Record<Family, {
20
+ shortest: number;
21
+ longest: number;
22
+ }>>;
23
+ /** The rules a route must pass, the same in every config. */
24
+ private static readonly RULES;
25
+ /**
26
+ * The BIRD 2 config of one route server: one session per member and family, each passing on only the routes the member may send.
27
+ *
28
+ * Throws when the server has no address on the peering LAN, has one outside it, or two members would get sessions of one name.
29
+ */
30
+ static bird(server: RouteServer, lan: {
31
+ ipv4?: Prefix;
32
+ ipv6?: Prefix;
33
+ }, members: readonly ExchangeMember[]): string;
34
+ /**
35
+ * The OpenBGPD config (`bgpd.conf`) of one route server: one session per member and family, in one group per family, and filter rules that pass on only the routes each member may send.
36
+ *
37
+ * Throws when the server has no address on the peering LAN, or has one outside it.
38
+ */
39
+ static openbgpd(server: RouteServer, lan: {
40
+ ipv4?: Prefix;
41
+ ipv6?: Prefix;
42
+ }, members: readonly ExchangeMember[]): string;
43
+ /** The families the server has an address in, each checked to be inside the peering LAN. */
44
+ private static families;
45
+ /** A BIRD symbol: letters, digits and underscores, starting with a letter. */
46
+ private static protocolName;
47
+ /** A member's name and AS, safe inside double quotes. */
48
+ private static description;
49
+ private static birdSession;
50
+ /** One family's sessions: a group holding every member with an address in that family. */
51
+ private static openbgpdGroup;
52
+ }
@@ -1,6 +1,8 @@
1
1
  export { defineDevice, defineNetwork, secret, secretFile } from "./core/define";
2
- export { merge } from "./core/merge";
3
- export type { Check, Community, Finding, Network } from "./core/define";
2
+ export { Utils } from "./core/utils";
3
+ export type { Check, Community, Finding, NetBoxDevice, Network } from "./core/define";
4
4
  export type * from "./schema";
5
5
  /** Address helpers, for checks of your own. */
6
- export { contains, familyOf, host, isAddress, isCidr, isGlobal, network as prefixOf } from "./core/addr";
6
+ export { Address } from "./core/address";
7
+ /** Secrets, for tools of your own: a secret's value, text with every secret hidden, and how Circuit logs in to a device. */
8
+ export { Secrets } from "./core/secrets";
@@ -0,0 +1,60 @@
1
+ import type { Network } from "../core/define";
2
+ import type { Device } from "../schema";
3
+ /** A device LibreNMS monitors whose settings differ from its config. */
4
+ export type LibreNmsChange = {
5
+ device: Device;
6
+ /** LibreNMS's id for it. */
7
+ id: number;
8
+ /** What differs, in words: `name`, `SNMP credentials` or `location`. Never a secret's value. */
9
+ what: string[];
10
+ /** What is sent: LibreNMS's field names and their values. */
11
+ fields: Record<string, string>;
12
+ };
13
+ /** A device group for one site, to make or whose devices change. */
14
+ export type LibreNmsGroup = {
15
+ /** The site's name, which is the group's. */
16
+ name: string;
17
+ /** LibreNMS has no group of this name yet. */
18
+ create: boolean;
19
+ /** Devices at the site that are not in the group. */
20
+ add: Device[];
21
+ /** Devices in the group that the config puts at another site. */
22
+ remove: Device[];
23
+ };
24
+ /** What `librenms` would do. */
25
+ export type LibreNmsPlan = {
26
+ /** Devices to add. */
27
+ additions: Device[];
28
+ /** Devices to change. */
29
+ changes: LibreNmsChange[];
30
+ /** Site groups to make or change. Empty when the network has no `site`. */
31
+ groups: LibreNmsGroup[];
32
+ /** Devices that cannot be added: their config turns SNMP off. */
33
+ withoutSnmp: Device[];
34
+ /** Hostnames LibreNMS holds that no device in the config has. */
35
+ unknown: string[];
36
+ /** Site groups LibreNMS holds as dynamic groups, which Circuit cannot fill, so leaves alone. */
37
+ dynamicGroups: string[];
38
+ /** LibreNMS's id for each device it monitors, by hostname. */
39
+ ids: ReadonlyMap<string, number>;
40
+ };
41
+ export declare class LibreNms {
42
+ /** LibreNMS's names for the algorithms. */
43
+ private static readonly AUTH;
44
+ private static readonly PRIVACY;
45
+ /** Compare the config with what LibreNMS monitors. A device is known to LibreNMS by its management address. */
46
+ static plan(network: Network): Promise<LibreNmsPlan>;
47
+ /** How many changes a plan holds. */
48
+ static count(plan: LibreNmsPlan): number;
49
+ /** Add each device, change each that differs, then make and fill the site groups. */
50
+ static send(network: Network, plan: LibreNmsPlan): Promise<void>;
51
+ /** What differs between a device's config and LibreNMS's record of it: its name, SNMP credentials and location. */
52
+ private static changeOf;
53
+ /** A static group for each site, with the devices at it. Only groups named after a site are read or changed. */
54
+ private static groupsOf;
55
+ private static settingsOf;
56
+ /** One request. LibreNMS answers a list with nothing in it with 404, so `emptyOn404` reads that as an empty answer. */
57
+ private static call;
58
+ /** How LibreNMS polls a device: its first SNMP version 3 user, or else its version 2c community. */
59
+ private static credentials;
60
+ }
@@ -0,0 +1,89 @@
1
+ import type { Network } from "../core/define";
2
+ /** Each kind of object Circuit writes, in the order they are made: each refers only to kinds before it, or waits for the next pass. */
3
+ export type NetBoxKind = "tag" | "site" | "manufacturer" | "platform" | "device-type" | "role" | "vrf" | "vlan" | "device" | "interface" | "prefix" | "ip-range" | "ip" | "cable";
4
+ /** One object to make, change or delete. */
5
+ export type NetBoxChange = {
6
+ kind: NetBoxKind;
7
+ /** Where NetBox keeps it, such as `dcim/devices`. */
8
+ path: string;
9
+ /** How Circuit knows it, built from its own fields, such as `edge-01/sfp28-1` for an interface. */
10
+ key: string;
11
+ /** What is sent. References to other objects are filled in with their ids when sent. */
12
+ fields: Record<string, unknown>;
13
+ /** NetBox's id, for an object that exists. */
14
+ id?: number;
15
+ /** For a change, each field that differs, as `field: before to after`. */
16
+ diff: string[];
17
+ };
18
+ /** What `circuit netbox` would do. */
19
+ export type NetBoxPlan = {
20
+ creates: NetBoxChange[];
21
+ updates: NetBoxChange[];
22
+ deletes: NetBoxChange[];
23
+ /** Objects NetBox holds without the tag that Circuit would otherwise make or change. Circuit refers to them and leaves them as they are. */
24
+ leftAlone: string[];
25
+ };
26
+ export declare class NetBox {
27
+ private readonly network;
28
+ /** The tag on everything Circuit makes. */
29
+ static readonly TAG = "circuit";
30
+ /** How many rounds `send` takes at most: a field that refers to an object made in the same round, such as a device's primary address, is set in the next. */
31
+ private static readonly PASSES;
32
+ /** Where each kind is kept, and how an object NetBox answers with is known by its key. */
33
+ private static readonly KINDS;
34
+ private static readonly ORDER;
35
+ /** Fields sent when an object is made and never compared after: its tags, which people may add to, and a cable's ends, which its key already holds. */
36
+ private static readonly CREATE_ONLY;
37
+ /** Fields that hold an address, compared in one spelling. */
38
+ private static readonly ADDRESS_FIELDS;
39
+ /** Who makes the hardware each platform runs on: the config names the platform, not the vendor. */
40
+ private static readonly VENDORS;
41
+ /** NetBox's type for a port, by the speed class in Circuit's port name. */
42
+ private static readonly PORT_TYPES;
43
+ /** NetBox's type for every interface that is not a port. */
44
+ private static readonly INTERFACE_TYPES;
45
+ /** A port's fixed speed in kbit/s, as NetBox counts it. */
46
+ private static readonly SPEEDS;
47
+ private readonly base;
48
+ private readonly headers;
49
+ /** Every object the config asks for, by kind and key. */
50
+ private readonly wanted;
51
+ /** NetBox's id for each object it holds, by kind and key. */
52
+ private readonly ids;
53
+ constructor(network: Network);
54
+ /** Compare the config with what NetBox holds. Reads NetBox only. */
55
+ plan(): Promise<NetBoxPlan>;
56
+ /** Send the plan, then plan again and send what is left, until NetBox matches or `PASSES` rounds are done. Returns what is left. */
57
+ send(plan: NetBoxPlan): Promise<NetBoxPlan>;
58
+ /** How many changes a plan holds. */
59
+ static count(plan: NetBoxPlan): number;
60
+ private apply;
61
+ /** Declare an object. The first declaration of a key wins; a later one only fills fields still empty. */
62
+ private want;
63
+ /** A device, its place, VLANs, VRFs, ports, interfaces, addresses and cables. */
64
+ private wantDevice;
65
+ /** A prefix for each subnet an interface is on, and a container for each prefix the network originates in BGP. */
66
+ private wantPrefixes;
67
+ /** Addresses Circuit knows that sit on no interface of ours, as `circuit addresses` lists them: peers, next hops, reservations, VRRP, and DHCP pools as ranges. */
68
+ private wantUnassigned;
69
+ /** A value with every reference replaced by its id, or by `<kind key>` while the object does not exist. */
70
+ private resolve;
71
+ /** The fields NetBox can take now. A reference to an object not made yet waits for the next round. */
72
+ private sendable;
73
+ private call;
74
+ /** Every object of a kind, page by page. */
75
+ private list;
76
+ /** NetBox's answer in the shape Circuit sends: a nested object as its id, a choice as its value, a cable end as its type and id, an address in one spelling. */
77
+ private static normalize;
78
+ private static isTagged;
79
+ /** A port's name on the device, such as `sfp28-1` for `25g-1`, as NetBox shows it. An interface keeps its name from the config. */
80
+ private static interfaceName;
81
+ private static prefixKey;
82
+ /** ` on <device>/<interface>` for an address on an interface, or nothing. */
83
+ private static assignedTo;
84
+ /** One end of a cable, as `<device>/<interface>`, or by its type and id when it is not an interface. */
85
+ private static endOf;
86
+ private static idKey;
87
+ /** A name as NetBox's slugs write it: `Core switch` to `core-switch`. */
88
+ private static slug;
89
+ }
@@ -0,0 +1,24 @@
1
+ import type { Network } from "../core/define";
2
+ /** A change to send. `id` is set when the record exists and is updated in place. */
3
+ export type PeeringDbChange = {
4
+ summary: string;
5
+ id?: number;
6
+ body: Record<string, unknown>;
7
+ };
8
+ export type PeeringDbPlan = {
9
+ changes: PeeringDbChange[];
10
+ /** Records PeeringDB holds that the config does not. */
11
+ unknown: string[];
12
+ };
13
+ export declare class PeeringDb {
14
+ private static readonly API;
15
+ /** What would change at PeeringDB. Reads the public API; needs no key. */
16
+ static plan(network: Network): Promise<PeeringDbPlan>;
17
+ /** Send the changes, with the network's API key. */
18
+ static send(network: Network, changes: PeeringDbChange[]): Promise<void>;
19
+ private static addressesOf;
20
+ /** Whether the device peers with a route server on this interface's subnets. */
21
+ private static peersWithRouteServer;
22
+ /** Every exchange presence the config declares with a PeeringDB exchange LAN. */
23
+ private static wanted;
24
+ }
@@ -0,0 +1,24 @@
1
+ import type { Network } from "../core/define";
2
+ import type { Device } from "../schema";
3
+ export type PrometheusTarget = {
4
+ targets: string[];
5
+ labels: Record<string, string>;
6
+ };
7
+ export declare class Prometheus {
8
+ /** snmp_exporter's names for the algorithms. */
9
+ private static readonly AUTH;
10
+ private static readonly PRIVACY;
11
+ private static readonly AUTHS_HEADER;
12
+ /** The targets, and the devices left out because their config turns SNMP off. */
13
+ static targets(network: Network): {
14
+ targets: PrometheusTarget[];
15
+ withoutSnmp: Device[];
16
+ };
17
+ /** The `auths` section, as YAML, and what the operator must still fill in by hand. */
18
+ static snmpExporterAuths(network: Network): {
19
+ yaml: string;
20
+ notes: string[];
21
+ };
22
+ /** A password as snmp_exporter reads it from its environment, or a note when the secret is a file, which it cannot read. */
23
+ private static fromEnvironment;
24
+ }
@@ -0,0 +1,8 @@
1
+ import type { Family } from "../schema";
2
+ import type { Registry } from "../schema/policy";
3
+ export declare class Registries {
4
+ /** The prefixes of one family a registry gives for a query. */
5
+ static prefixes(name: Registry, query: string, family: Family): Promise<string[]>;
6
+ /** Prefixes an origin AS announces, from RIPEstat. */
7
+ private static ripeStat;
8
+ }
@@ -0,0 +1,18 @@
1
+ import type { BgpSession } from "./platform";
2
+ /** How long to wait, and how often to read again, both in seconds. */
3
+ export type WaitLimits = {
4
+ seconds: number;
5
+ every: number;
6
+ };
7
+ export declare class BgpWait {
8
+ /** `circuit bgp --wait` reads the sessions again every 15 seconds, for at most 600 seconds unless `--max` says otherwise. */
9
+ static readonly COMMAND: WaitLimits;
10
+ /**
11
+ * After an apply, the sessions established before have 180 seconds to be established again, read every 10 seconds. A session reset by a change opens again when one side retries; three minutes leaves room for a slow peer without holding the apply up for long. A session that never went down is seen at the first read, so a healthy apply does not wait.
12
+ */
13
+ static readonly AFTER_APPLY: WaitLimits;
14
+ /** Read the sessions until `enough` holds or time runs out, and give the last read. `waiting` is told of each read that fell short, before the pause. */
15
+ static until(read: () => Promise<BgpSession[]>, enough: (sessions: BgpSession[]) => boolean, limits: WaitLimits, waiting?: (sessions: BgpSession[]) => void): Promise<BgpSession[]>;
16
+ /** How many of these sessions are established. */
17
+ static upCount(sessions: readonly BgpSession[]): number;
18
+ }
@@ -0,0 +1,109 @@
1
+ /** What a model's hardware holds, where a real device held less than its datasheet lists. `validate` checks a config against it. */
2
+ export type ModelLimits = {
3
+ /** The most member ports one LAG may have. More is an error. */
4
+ lag_members?: number;
5
+ /** About how many switch rules the switch chip held. More is a warning: a rule the chip cannot hold is invalid, and so is every rule after it, without a log line. */
6
+ switch_rules?: number;
7
+ /** How many distinct port ranges the switch rules held. More is a warning, for the same reason. */
8
+ switch_port_ranges?: number;
9
+ };
10
+ /** One hardware model: its ports per speed class, how the platform spells a port, and what its hardware holds. */
11
+ export type ModelSpec = {
12
+ ports: Readonly<Record<string, number>>;
13
+ spelling: Readonly<Record<string, string>>;
14
+ limits?: ModelLimits;
15
+ };
16
+ export declare class Catalog {
17
+ static readonly MODELS: {
18
+ readonly routeros: {
19
+ readonly "CCR2216-1G-12XS-2XQ": {
20
+ readonly ports: {
21
+ readonly "100g": 2;
22
+ readonly "25g": 12;
23
+ readonly "1g": 1;
24
+ };
25
+ readonly spelling: {
26
+ readonly "100g": "qsfp28-{n}-1";
27
+ readonly "25g": "sfp28-{n}";
28
+ readonly "1g": "ether{n}";
29
+ };
30
+ readonly limits: {
31
+ readonly lag_members: 8;
32
+ readonly switch_port_ranges: 5;
33
+ };
34
+ };
35
+ };
36
+ readonly vrp: {
37
+ readonly "CE6855-48S6Q-HI": {
38
+ readonly ports: {
39
+ readonly "10g": 48;
40
+ readonly "40g": 6;
41
+ };
42
+ readonly spelling: {
43
+ readonly "10g": "10GE1/0/{n}";
44
+ readonly "40g": "40GE1/0/{n}";
45
+ };
46
+ };
47
+ };
48
+ readonly "raisecom-ros": {
49
+ readonly "RAX721-C-6C48": {
50
+ readonly ports: {
51
+ readonly "100g": 6;
52
+ readonly "25g": 24;
53
+ readonly "10g": 24;
54
+ };
55
+ readonly spelling: {
56
+ readonly "100g": "hundredgige 1/1/{n}";
57
+ readonly "25g": "twenty-fivegige 1/2/{n}";
58
+ readonly "10g": "tengigabitethernet 1/3/{n}";
59
+ };
60
+ };
61
+ };
62
+ readonly junos: {
63
+ readonly "QFX5100-48S-6Q": {
64
+ readonly ports: {
65
+ readonly "40g": 6;
66
+ readonly "10g": 48;
67
+ readonly "1g": 2;
68
+ };
69
+ readonly spelling: {
70
+ readonly "40g": "et-0/0/{n+47}";
71
+ readonly "10g": "xe-0/0/{n-1}";
72
+ readonly "1g": "em{n-1}";
73
+ };
74
+ };
75
+ };
76
+ readonly fortios: {
77
+ readonly "FG-3700D": {
78
+ readonly ports: {
79
+ readonly "40g": 4;
80
+ readonly "10g": 28;
81
+ readonly "1g": 2;
82
+ };
83
+ readonly spelling: {
84
+ readonly "40g": "port{n}";
85
+ readonly "10g": "port{n+4}";
86
+ readonly "1g": "mgmt{n}";
87
+ };
88
+ };
89
+ };
90
+ };
91
+ /** Every port a model has, in order. */
92
+ static ports(platform: string, model: string): string[];
93
+ /** What the model's hardware holds. Empty for a model with no known limits, or a model the catalog does not have. */
94
+ static limits(platform: string, model: string): ModelLimits;
95
+ /** The platform's own name for a port. */
96
+ static spell(platform: string, model: string, port: string): string;
97
+ }
98
+ export type Models = typeof Catalog.MODELS;
99
+ export type PlatformName = keyof Models;
100
+ export type ModelName<Pl extends PlatformName> = keyof Models[Pl] & string;
101
+ type Upto<N extends number, A extends unknown[] = [], R = never> = A["length"] extends N ? R : Upto<N, [...A, 0], R | `${[...A, 0]["length"]}`>;
102
+ type PortsOf<Pl extends PlatformName, M extends ModelName<Pl>> = Models[Pl][M] extends {
103
+ ports: infer P;
104
+ } ? P : never;
105
+ /** `10g-1` to `10g-48` on a model with 48 10G ports. */
106
+ export type PortName<Pl extends PlatformName, M extends ModelName<Pl>> = {
107
+ [S in keyof PortsOf<Pl, M>]: `${S & string}-${Upto<PortsOf<Pl, M>[S] & number>}`;
108
+ }[keyof PortsOf<Pl, M>];
109
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { Device } from "../schema";
2
+ /** A feature a platform renders once proved on one of its devices. */
3
+ export type ProvedFeature = "bfd-timers" | "static-route-bfd" | "multihop-bfd" | "alarm-severity" | "mac-limit" | "ethertype-filter";
4
+ export declare class Derive {
5
+ /** Each LAG's number: its own `id`, or its position among the device's LAGs. */
6
+ static lagIds(device: Device): Map<string, number>;
7
+ /** The IPv4 networks of a port's or an interface's addresses. */
8
+ static ipv4Networks(device: Device, iface: string): string[];
9
+ /** Fields a platform renders only once they are proved on one of its devices. */
10
+ private static readonly UNPROVED_PORT_FIELDS;
11
+ /** Fields a platform refuses until it has proved them on a device. A platform names the ones it has proved, and the rest are refused. */
12
+ static unproved(device: Device, proved?: readonly ProvedFeature[]): string[];
13
+ /** Services the switch platforms run. Each takes its sources from `management.allow`, on the protocol's own port. */
14
+ private static readonly SWITCH_SERVICES;
15
+ /** Fields neither switch platform, VRP nor Raisecom ROS, expresses: a service's own sources or port, a user's description or keys, the IP stack's host settings, a point-to-point address, and offload per interface. `ownSources` names the services a platform gives their own sources. */
16
+ static switchUnsupported(device: Device, ownSources?: readonly ("ssh" | "telnet" | "snmp")[]): string[];
17
+ }
@@ -0,0 +1,45 @@
1
+ import type { AclRule, Device, Family, FilterMatch, FilterRule, NatRule, Ports, Protocol } from "../../schema";
2
+ import { FortiOsBlock } from "./tree";
3
+ export declare class FortiOsFirewall {
4
+ /** IP protocol numbers, for a protocol the platform names only by number. */
5
+ static readonly PROTOCOL_NUMBER: Record<Protocol, number>;
6
+ /** The device's own services, by the config's name, with the protocol and port each listens on unless the config moves it. */
7
+ private static readonly SERVICES;
8
+ /** Every protocol, as a service of Circuit's own, for a device in transparent mode. */
9
+ static readonly ALL_IN_TRANSPARENT = "circuit-all";
10
+ /** NAT rules of both directions, which central NAT needs turned on. */
11
+ static natRules(device: Device): NatRule<string, string>[];
12
+ /** Which families a rule applies to: its own, its addresses', or both. */
13
+ static familiesOf(device: Device, match: FilterMatch<string, string> | undefined): Family[];
14
+ /** A port or ports as the platform writes them in a service: `22`, `1000-2000`. */
15
+ static portList(ports: Ports | undefined): string[];
16
+ /** The service a rule matches, by name, with what it holds. `ALL` when the rule names no protocol and no port; ports without a protocol are TCP's and UDP's. */
17
+ static serviceOf(match: FilterMatch<string, string> | undefined, family: Family): {
18
+ name: string;
19
+ block?: FortiOsBlock;
20
+ };
21
+ /** A rule the platform keeps without being told: replies to a session it let through, and packets that belong to one, pass on their own. */
22
+ static isImplied(rule: FilterRule<string, string>): boolean;
23
+ /** Packet filtering, who reaches the device, NAT and stateless ACLs. */
24
+ static render(root: FortiOsBlock, device: Device): void;
25
+ /**
26
+ * Who reaches the device's own services: each service with sources to allow accepts them and refuses everyone else, ahead of the input chain. Services sharing their sources share the policies, named after `management.allow` or the service.
27
+ */
28
+ private static management;
29
+ /** The interface a rule names on one side, or `any`, quoted. */
30
+ private static interfaceOf;
31
+ /** A policy for traffic through the device. A rejection answers the sender; the platform's deny is silent otherwise. */
32
+ private static policy;
33
+ /** A local-in policy, for traffic to the device itself. */
34
+ private static localIn;
35
+ /** Source NAT: to the outgoing interface's address, or to a pool of one address. */
36
+ private static sourceNat;
37
+ /** Destination NAT, as a virtual IP: the address it answers on, and the port it forwards when the rule names one. */
38
+ private static destinationNat;
39
+ /**
40
+ * A port's ACL as the platform's stateless ACLs, which only drop: each rule that drops becomes one, of each family it applies to. What no rule drops passes, so the rules that accept after the last drop are already there; `unsupported()` refuses one before a drop.
41
+ */
42
+ private static acls;
43
+ /** Whether a port's ACL drops before it accepts: an accept before a drop is an exception the platform's ACLs cannot hold. */
44
+ static acceptsBeforeDrop(rules: readonly AclRule<string>[]): boolean;
45
+ }
@@ -0,0 +1,134 @@
1
+ import type { Neighbor } from "../../core/cabling";
2
+ import type { Device, Family } from "../../schema";
3
+ import { type ConsoleDialect } from "../../transport/console";
4
+ import { type ApplyOptions, type OsSupport, type Plan, type ReadOptions, type ReadSession, Platform } from "../platform";
5
+ /** What a session reads and writes: an SSH shell, or anything else that streams the CLI. */
6
+ export type Channel = {
7
+ write(data: string): unknown;
8
+ on(event: "data", listener: (chunk: Buffer) => void): unknown;
9
+ on(event: "close", listener: () => void): unknown;
10
+ removeListener(event: "data", listener: (chunk: Buffer) => void): unknown;
11
+ removeListener(event: "close", listener: () => void): unknown;
12
+ };
13
+ /** How a change that could cut access is guarded: the device reloads its saved configuration after `seconds` unless `prove` shows access survived. */
14
+ export type Guard = {
15
+ seconds: number;
16
+ prove: () => Promise<void>;
17
+ };
18
+ /** A CLI over a channel: one line at a time, and what the device printed until its prompt came back. */
19
+ export declare class FortiOsCli {
20
+ private readonly channel;
21
+ private readonly newline;
22
+ /** The prompt at the end of what the device printed, `host # ` or `host (context) # `, or a question it waits on. */
23
+ private static readonly PROMPT;
24
+ static readonly QUESTION: RegExp;
25
+ /** The pre-login banner, which waits for the reader to accept it. */
26
+ static readonly BANNER: RegExp;
27
+ /** The device ended the session and asks for a login again. */
28
+ private static readonly LOGGED_OUT;
29
+ /** The pager the device stops at, and how it erases itself once answered. */
30
+ private static readonly PAGER;
31
+ /** The prompt that ended the last answer, which shows where the session is: `(port1)` inside an entry. */
32
+ prompt: string;
33
+ constructor(channel: Channel, newline?: string);
34
+ /** Wait for the prompt, after logging in. */
35
+ ready(timeout?: number): Promise<void>;
36
+ /** Send one line and return what the device printed after it, without the echo or the prompt. */
37
+ run(line: string, timeout?: number): Promise<string>;
38
+ /** Answer a question the device asked. */
39
+ answer(reply: "y" | "n", timeout?: number): Promise<string>;
40
+ /** What the device prints until its prompt or a question. A session the device ended, or that went silent, fails. */
41
+ private collect;
42
+ }
43
+ export declare class FortiOs extends Platform {
44
+ /** How the FortiOS console asks for a login, and what moves it on from where the last session left it. */
45
+ static readonly CONSOLE: ConsoleDialect;
46
+ /** The release this adapter renders for, and was proved on. */
47
+ private static readonly SUPPORTED;
48
+ /** The longest name the platform takes for an interface, and for an address or service. */
49
+ private static readonly NAME_LENGTH;
50
+ /** Names the platform keeps for interfaces of its own. */
51
+ private static readonly RESERVED_INTERFACES;
52
+ /** What the device prints when it refuses a line. */
53
+ private static readonly REFUSED;
54
+ /** How long a device may take to come back from a reload of its configuration, and how often to try it. */
55
+ private static readonly RELOAD;
56
+ /** Commands that only read: `show`, `get`, a set of `diagnose` and `execute` commands. `diagnose sys session filter` sets only this session's filter; `diagnose sys session clear`, which ends sessions, is not here. `diagnose lldprx` shows what LLDP received. */
57
+ private static readonly READS;
58
+ /** A session filter, which holds only in the shell that set it. */
59
+ private static readonly SESSION_FILTER;
60
+ readonly name = "fortios";
61
+ readonly os: OsSupport;
62
+ readonly extension = ".conf";
63
+ readonly console: ConsoleDialect;
64
+ unsupported(device: Device): string[];
65
+ render(device: Device): string;
66
+ read(device: Device, _network?: readonly Device[], options?: ReadOptions): Promise<string>;
67
+ /** The LLDP neighbors the device received, read with `diagnose lldprx neighbor details`. A port hears LLDP only while it, or the aggregate it is in, has `lldp-reception` on. */
68
+ neighbors(device: Device, _network?: readonly Device[], options?: ReadOptions): Promise<Neighbor[]>;
69
+ /**
70
+ * The neighbors in what `diagnose lldprx neighbor details` prints, one `lldprx.neighbor.<n>.<field>: <value>` line per field: `port.txt` is our port, `port.id.data` the far port and `system.name.data` the far device. Our port is given Circuit's name. A neighbor that sent no system name or port is left out.
71
+ */
72
+ static neighborsOf(text: string, device: Device): Neighbor[];
73
+ plan(desired: string, current: string, options: ApplyOptions): Plan;
74
+ apply(device: Device, network: readonly Device[], changes: Plan, options: ApplyOptions): Promise<void>;
75
+ /** Replace a prefix list `refresh` fetched. It cannot cut access, so it is sent without a guard, and saved as it goes. `purge` asks to confirm, and is answered yes. */
76
+ fill(device: Device, _network: readonly Device[], set: string, family: Family, prefixes: string[]): Promise<void>;
77
+ readOnly(command: string): boolean;
78
+ /** Over SSH, each command runs on its own until a session filter is set. The filter holds only in the shell that set it, so it and every command after it run in one shell. */
79
+ session(device: Device, options?: ReadOptions): Promise<ReadSession>;
80
+ /** The lines that replace a prefix list's entries with what a registry returned: every entry is purged, then each prefix added, matching it and anything more specific. */
81
+ static fillLines(set: string, family: Family, prefixes: string[]): string[];
82
+ /**
83
+ * A line with each secret's value in place, escaped inside its quotes. A certificate's key from a variable is PEM encoded as one line of base64, and is sent as the PEM it holds. A file saved with Windows line endings is sent with plain ones: the CLI takes each carriage return as a line of its own, and refuses the key, `Invalid private key`. A `?`, which the CLI takes as a call for help, is typed literally.
84
+ */
85
+ static withSecrets(line: string): string;
86
+ private static login;
87
+ /** Log out of a console, so no session is left open on it. */
88
+ private static consoleLogout;
89
+ /** Log in on the console and open the CLI. Returns the CLI, a way to log in afresh on the same console, and how to let the console go. */
90
+ private static openConsole;
91
+ /** Log in on the console, open the CLI, and run `work` in it. `work` is also given a way to log in afresh on the same console. */
92
+ private static consoleSession;
93
+ /** Log in, open the CLI, and run `work` in it: through the console when asked, else over SSH. */
94
+ private static withCli;
95
+ /** Refuse a device on a release this adapter was not proved on, before anything is read or sent. */
96
+ private static checkVersion;
97
+ /** Secrets the device prints: a password or an SNMPv3 key as a cipher, a certificate's key encrypted, and the SNMP community in clear. None leave the read. */
98
+ private static scrub;
99
+ /** Every section Circuit manages, as the device holds it, credentials scrubbed. */
100
+ private static readConfig;
101
+ /** Leave every `config` and `edit` level, back to the top prompt. */
102
+ private static leave;
103
+ /** Send the lines that set how the device saves changes. */
104
+ private static saving;
105
+ /**
106
+ * Send a plan line by line, each applied as it arrives. The device is first set to revert what is not saved, so a refused line or a fresh login that fails reloads its saved configuration. Once access is proved the change is saved, and changes save themselves again.
107
+ */
108
+ private static configure;
109
+ /**
110
+ * Once the device is back from a reload, set it to save changes on its own again: the saved configuration still says to revert. Setting it saves what runs, so it is set only once the device says nothing is left to reload; until then the reload is asked for again.
111
+ */
112
+ private static settle;
113
+ private static applyOnce;
114
+ /**
115
+ * What transparent mode, which a bridge needs, leaves out: every address but one IPv4 management address outside the bridges, routing beyond static routes for it, NAT and DHCP. Without a management address the device is reached through its console and answers no service.
116
+ */
117
+ private static transparentGaps;
118
+ private static systemGaps;
119
+ private static managementGaps;
120
+ /** Every name the platform knows a port by. */
121
+ private static portNames;
122
+ private static interfaceGaps;
123
+ /** A port or LAG carries tagged only VLANs that have an interface here, and is the only one carrying each. */
124
+ private static trunkGaps;
125
+ /** Layer 3 settings the platform cannot express on a port or an interface. Only a tunnel takes an address with a peer. */
126
+ private static routedGaps;
127
+ /** An ACL as the platform's, which only drop: every drop comes before any accept, and no rule limits a rate or matches a VLAN. */
128
+ private static aclGaps;
129
+ private static staticGaps;
130
+ private static firewallGaps;
131
+ /** A filter rule the platform cannot express. */
132
+ private static ruleGaps;
133
+ private static serviceGaps;
134
+ }