@highstate/common 0.14.2 → 0.16.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 (91) hide show
  1. package/dist/{chunk-WFWXDYUX.js → chunk-X5BK6JSN.js} +877 -194
  2. package/dist/chunk-X5BK6JSN.js.map +1 -0
  3. package/dist/highstate.manifest.json +12 -2
  4. package/dist/index.js +1 -1
  5. package/dist/units/databases/etcd-patch/index.js +20 -0
  6. package/dist/units/databases/etcd-patch/index.js.map +1 -0
  7. package/dist/units/databases/existing-etcd/index.js +14 -0
  8. package/dist/units/databases/existing-etcd/index.js.map +1 -0
  9. package/dist/units/databases/existing-mariadb/index.js +2 -2
  10. package/dist/units/databases/existing-mariadb/index.js.map +1 -1
  11. package/dist/units/databases/existing-mongodb/index.js +2 -2
  12. package/dist/units/databases/existing-mongodb/index.js.map +1 -1
  13. package/dist/units/databases/existing-postgresql/index.js +2 -2
  14. package/dist/units/databases/existing-postgresql/index.js.map +1 -1
  15. package/dist/units/databases/existing-redis/index.js +2 -2
  16. package/dist/units/databases/existing-redis/index.js.map +1 -1
  17. package/dist/units/databases/existing-s3/index.js +18 -0
  18. package/dist/units/databases/existing-s3/index.js.map +1 -0
  19. package/dist/units/databases/mariadb-patch/index.js +24 -0
  20. package/dist/units/databases/mariadb-patch/index.js.map +1 -0
  21. package/dist/units/databases/mongodb-patch/index.js +24 -0
  22. package/dist/units/databases/mongodb-patch/index.js.map +1 -0
  23. package/dist/units/databases/postgresql-patch/index.js +24 -0
  24. package/dist/units/databases/postgresql-patch/index.js.map +1 -0
  25. package/dist/units/databases/redis-patch/index.js +27 -0
  26. package/dist/units/databases/redis-patch/index.js.map +1 -0
  27. package/dist/units/databases/s3-patch/index.js +25 -0
  28. package/dist/units/databases/s3-patch/index.js.map +1 -0
  29. package/dist/units/dns/record-set/index.js +14 -20
  30. package/dist/units/dns/record-set/index.js.map +1 -1
  31. package/dist/units/existing-server/index.js +3 -4
  32. package/dist/units/existing-server/index.js.map +1 -1
  33. package/dist/units/network/address-space/index.js +20 -0
  34. package/dist/units/network/address-space/index.js.map +1 -0
  35. package/dist/units/network/endpoint-filter/index.js +15 -0
  36. package/dist/units/network/endpoint-filter/index.js.map +1 -0
  37. package/dist/units/network/l3-endpoint/index.js +2 -2
  38. package/dist/units/network/l3-endpoint/index.js.map +1 -1
  39. package/dist/units/network/l4-endpoint/index.js +2 -2
  40. package/dist/units/network/l4-endpoint/index.js.map +1 -1
  41. package/dist/units/network/l7-endpoint/index.js +12 -0
  42. package/dist/units/network/l7-endpoint/index.js.map +1 -0
  43. package/dist/units/script/index.js +1 -1
  44. package/dist/units/server-patch/index.js +9 -12
  45. package/dist/units/server-patch/index.js.map +1 -1
  46. package/dist/units/ssh/key-pair/index.js +1 -1
  47. package/package.json +64 -10
  48. package/src/shared/command.ts +1 -1
  49. package/src/shared/dns.ts +11 -93
  50. package/src/shared/files.ts +3 -3
  51. package/src/shared/impl-ref.ts +4 -0
  52. package/src/shared/index.ts +2 -0
  53. package/src/shared/network/address-space.spec.ts +114 -0
  54. package/src/shared/network/address-space.ts +364 -0
  55. package/src/shared/network/address.spec.ts +109 -0
  56. package/src/shared/network/address.ts +119 -0
  57. package/src/shared/network/endpoints.spec.ts +249 -0
  58. package/src/shared/network/endpoints.ts +608 -0
  59. package/src/shared/network/index.ts +4 -0
  60. package/src/shared/network/ip.ts +236 -0
  61. package/src/shared/network/subnet.spec.ts +62 -0
  62. package/src/shared/network/subnet.ts +137 -0
  63. package/src/shared/ssh.ts +1 -1
  64. package/src/shared/tls.ts +21 -5
  65. package/src/shared/utils.ts +93 -0
  66. package/src/units/databases/etcd-patch/index.ts +23 -0
  67. package/src/units/databases/existing-etcd/index.ts +11 -0
  68. package/src/units/databases/existing-mariadb/index.ts +1 -1
  69. package/src/units/databases/existing-mongodb/index.ts +1 -1
  70. package/src/units/databases/existing-postgresql/index.ts +1 -1
  71. package/src/units/databases/existing-redis/index.ts +1 -1
  72. package/src/units/databases/existing-s3/index.ts +1 -1
  73. package/src/units/databases/mariadb-patch/index.ts +27 -0
  74. package/src/units/databases/mongodb-patch/index.ts +27 -0
  75. package/src/units/databases/postgresql-patch/index.ts +27 -0
  76. package/src/units/databases/redis-patch/index.ts +32 -0
  77. package/src/units/databases/s3-patch/index.ts +28 -0
  78. package/src/units/dns/record-set/index.ts +15 -20
  79. package/src/units/existing-server/index.ts +3 -4
  80. package/src/units/network/address-space/index.ts +20 -0
  81. package/src/units/network/endpoint-filter/index.ts +5 -5
  82. package/src/units/network/l3-endpoint/index.ts +2 -2
  83. package/src/units/network/l4-endpoint/index.ts +2 -2
  84. package/src/units/network/l7-endpoint/index.ts +2 -2
  85. package/src/units/remote-file/index.ts +12 -5
  86. package/src/units/server-patch/index.ts +10 -13
  87. package/dist/chunk-WFWXDYUX.js.map +0 -1
  88. package/dist/units/server-dns/index.js +0 -26
  89. package/dist/units/server-dns/index.js.map +0 -1
  90. package/src/shared/network.ts +0 -413
  91. package/src/units/server-dns/index.ts +0 -26
@@ -0,0 +1,249 @@
1
+ import { network } from "@highstate/library"
2
+ import { omit } from "remeda"
3
+ import { describe, expect, it } from "vitest"
4
+ import { addressToCidr, parseAddress } from "./address"
5
+ import {
6
+ endpointToString,
7
+ l3EndpointToCidr,
8
+ l3EndpointToString,
9
+ l4EndpointToFullString,
10
+ l4EndpointToString,
11
+ l7EndpointToString,
12
+ mergeEndpoints,
13
+ parseEndpoint,
14
+ replaceEndpointBase,
15
+ } from "./endpoints"
16
+ import { subnetToString } from "./subnet"
17
+
18
+ describe("endpoints", () => {
19
+ function expectValidDynamic(endpoint: network.L3Endpoint): void {
20
+ expect(endpoint.dynamic).toBeDefined()
21
+ expect(endpoint.dynamic!.type).toBe("static")
22
+
23
+ expect(endpoint.dynamic).toEqual({
24
+ type: "static",
25
+ endpoint: omit(endpoint, ["dynamic"]),
26
+ })
27
+ }
28
+
29
+ it("parses IPv4 L3 endpoint and embeds address entity", () => {
30
+ const endpoint = parseEndpoint("10.0.0.1")
31
+
32
+ expect(endpoint.level).toBe(3)
33
+ expect(endpoint.type).toBe("ipv4")
34
+ expect(endpoint.address?.value).toBe("10.0.0.1")
35
+ expect(addressToCidr(endpoint.address!)).toBe("10.0.0.1/32")
36
+ expect(subnetToString(endpoint.subnet!)).toBe("10.0.0.1/32")
37
+
38
+ expect(l3EndpointToString(endpoint)).toBe("10.0.0.1")
39
+ expect(endpointToString(endpoint)).toBe("10.0.0.1")
40
+ expect(l3EndpointToCidr(endpoint)).toBe("10.0.0.1/32")
41
+
42
+ expect(network.l3EndpointEntity.schema.safeParse(endpoint).success).toBe(true)
43
+ expectValidDynamic(endpoint)
44
+ })
45
+
46
+ it("parses hostname L3 endpoint", () => {
47
+ const endpoint = parseEndpoint("example.com")
48
+
49
+ expect(endpoint.level).toBe(3)
50
+ expect(endpoint.type).toBe("hostname")
51
+ expect(l3EndpointToString(endpoint)).toBe("example.com")
52
+
53
+ expect(network.l3EndpointEntity.schema.safeParse(endpoint).success).toBe(true)
54
+ expectValidDynamic(endpoint)
55
+ })
56
+
57
+ it("parses IPv6 L4 endpoint and formats with brackets", () => {
58
+ const endpoint = parseEndpoint("[2001:db8::1]:6443", 4)
59
+
60
+ expect(endpoint.level).toBe(4)
61
+ expect(endpoint.type).toBe("ipv6")
62
+ expect(endpoint.address?.value).toBe("2001:db8::1")
63
+ expect(endpoint.port).toBe(6443)
64
+
65
+ expect(l4EndpointToString(endpoint)).toBe("[2001:db8::1]:6443")
66
+ expect(l4EndpointToFullString(endpoint)).toBe("tcp://[2001:db8::1]:6443")
67
+
68
+ expect(network.l4EndpointEntity.schema.safeParse(endpoint).success).toBe(true)
69
+ expectValidDynamic(endpoint)
70
+ })
71
+
72
+ it("parses L7 endpoint with app protocol", () => {
73
+ const endpoint = parseEndpoint("https://10.0.0.2:8443/api", 7)
74
+
75
+ expect(endpoint.level).toBe(7)
76
+ expect(endpoint.type).toBe("ipv4")
77
+ expect(endpoint.address?.value).toBe("10.0.0.2")
78
+ expect(endpoint.port).toBe(8443)
79
+ expect(endpoint.protocol).toBe("tcp")
80
+ expect(endpoint.appProtocol).toBe("https")
81
+ expect(endpoint.path).toBe("api")
82
+
83
+ expect(l7EndpointToString(endpoint)).toBe("https://10.0.0.2:8443/api")
84
+
85
+ expect(network.l7EndpointEntity.schema.safeParse(endpoint).success).toBe(true)
86
+ expectValidDynamic(endpoint)
87
+ })
88
+
89
+ it("returns object endpoints as-is", () => {
90
+ const endpoint: network.L3Endpoint = {
91
+ level: 3,
92
+ type: "ipv4",
93
+ address: {
94
+ type: "ipv4",
95
+ value: "10.9.0.1",
96
+ subnet: {
97
+ type: "ipv4",
98
+ baseAddress: "10.9.0.0",
99
+ prefixLength: 24,
100
+ },
101
+ },
102
+ metadata: {},
103
+ dynamic: {
104
+ type: "dynamic",
105
+ implRef: {
106
+ package: "test",
107
+ data: {},
108
+ },
109
+ },
110
+ }
111
+
112
+ const parsed = parseEndpoint(endpoint)
113
+
114
+ expect(parsed).toBe(endpoint)
115
+ expect(parsed.type).toBe("ipv4")
116
+ expect(parsed.subnet).toBeUndefined()
117
+ })
118
+
119
+ it("wraps network.Address input into L3 endpoint without reparsing", () => {
120
+ const address = parseAddress("10.10.0.5/24")
121
+
122
+ const endpoint = parseEndpoint(address)
123
+
124
+ expect(endpoint.level).toBe(3)
125
+ expect(endpoint.type).toBe("ipv4")
126
+ expect(endpoint.address).toBe(address)
127
+ expect(endpoint.subnet).toBe(address.subnet)
128
+ expect(addressToCidr(endpoint.address!)).toBe("10.10.0.5/24")
129
+
130
+ expect(network.l3EndpointEntity.schema.safeParse(endpoint).success).toBe(true)
131
+ expectValidDynamic(endpoint)
132
+ })
133
+
134
+ describe("mergeEndpoints", () => {
135
+ it("merges duplicates by string key and combines metadata", () => {
136
+ const a = parseEndpoint("example.com")
137
+ const b = parseEndpoint("example.com")
138
+
139
+ const merged = mergeEndpoints([
140
+ { ...a, metadata: { "test.one": "a" } },
141
+ { ...b, metadata: { "test.two": 123 } },
142
+ ])
143
+
144
+ expect(merged).toHaveLength(1)
145
+ expect(endpointToString(merged[0]!)).toBe("example.com")
146
+ expect(merged[0]!.metadata).toMatchObject({
147
+ "test.one": "a",
148
+ "test.two": 123,
149
+ })
150
+ })
151
+
152
+ it("lets later endpoints override metadata keys", () => {
153
+ const a = parseEndpoint("example.com")
154
+ const b = parseEndpoint("example.com")
155
+
156
+ const merged = mergeEndpoints([
157
+ { ...a, metadata: { "test.key": "first" } },
158
+ { ...b, metadata: { "test.key": "second" } },
159
+ ])
160
+
161
+ expect(merged).toHaveLength(1)
162
+ expect(merged[0]!.metadata).toMatchObject({ "test.key": "second" })
163
+ })
164
+
165
+ it("does not merge distinct endpoints", () => {
166
+ const merged = mergeEndpoints([parseEndpoint("a.example"), parseEndpoint("b.example")])
167
+
168
+ expect(merged).toHaveLength(2)
169
+ expect(merged.map(endpointToString)).toEqual(["a.example", "b.example"])
170
+ })
171
+
172
+ it("handles missing metadata", () => {
173
+ const a = parseEndpoint("example.com")
174
+ const b = parseEndpoint("example.com")
175
+
176
+ const merged = mergeEndpoints([a, { ...b, metadata: { "test.one": true } }])
177
+
178
+ expect(merged).toHaveLength(1)
179
+ expect(merged[0]!.metadata).toMatchObject({ "test.one": true })
180
+ })
181
+ })
182
+
183
+ describe("replaceEndpointBase", () => {
184
+ it("replaces IP base fields from an L3 IP base and keeps L7 properties", () => {
185
+ const endpoint = parseEndpoint("https://10.0.0.2:8443/api", 7)
186
+ const base = parseEndpoint("10.0.0.9")
187
+
188
+ const replaced = replaceEndpointBase(endpoint, base)
189
+
190
+ expect(replaced.level).toBe(7)
191
+ expect(replaced.type).toBe("ipv4")
192
+ expect(replaced.address?.value).toBe("10.0.0.9")
193
+ expect(replaced.port).toBe(8443)
194
+ expect(replaced.protocol).toBe("tcp")
195
+ expect(replaced.appProtocol).toBe("https")
196
+ expect(replaced.path).toBe("api")
197
+ expect(replaced.metadata?.["iana.scope"]).toBe("private")
198
+
199
+ expectValidDynamic(replaced)
200
+ })
201
+
202
+ it("replaces hostname base from an L3 hostname base and keeps L7 properties", () => {
203
+ const endpoint = parseEndpoint("https://example.com:8443/api", 7)
204
+ const base = parseEndpoint("other.example")
205
+
206
+ const replaced = replaceEndpointBase(endpoint, base)
207
+
208
+ expect(replaced.level).toBe(7)
209
+ expect(replaced.type).toBe("hostname")
210
+ expect(replaced.hostname).toBe("other.example")
211
+ expect(replaced.port).toBe(8443)
212
+ expect(replaced.protocol).toBe("tcp")
213
+ expect(replaced.appProtocol).toBe("https")
214
+ expect(replaced.path).toBe("api")
215
+
216
+ expectValidDynamic(replaced)
217
+ })
218
+
219
+ it("converts hostname endpoint to IP endpoint when base is IP", () => {
220
+ const endpoint = parseEndpoint("https://example.com:8443/api", 7)
221
+ const base = parseEndpoint("10.0.0.9")
222
+
223
+ const replaced = replaceEndpointBase(endpoint, base)
224
+
225
+ expect(replaced.level).toBe(7)
226
+ expect(replaced.type).toBe("ipv4")
227
+ expect(replaced.address?.value).toBe("10.0.0.9")
228
+ expect(replaced.port).toBe(8443)
229
+ expect(replaced.metadata?.["iana.scope"]).toBe("private")
230
+
231
+ expectValidDynamic(replaced)
232
+ })
233
+
234
+ it("converts IPv4 endpoint to IPv6 endpoint when base is IPv6", () => {
235
+ const endpoint = parseEndpoint("10.0.0.1:6443", 4)
236
+ const base = parseEndpoint("2001:db8::2")
237
+
238
+ const replaced = replaceEndpointBase(endpoint, base)
239
+
240
+ expect(replaced.level).toBe(4)
241
+ expect(replaced.type).toBe("ipv6")
242
+ expect(replaced.address?.value).toBe("2001:db8::2")
243
+ expect(replaced.port).toBe(6443)
244
+ expect(replaced.protocol).toBe("tcp")
245
+
246
+ expectValidDynamic(replaced)
247
+ })
248
+ })
249
+ })