@highstate/common 0.9.15 → 0.9.16

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 (34) hide show
  1. package/dist/chunk-HZBJ6LLS.js +1057 -0
  2. package/dist/chunk-HZBJ6LLS.js.map +1 -0
  3. package/dist/highstate.manifest.json +9 -9
  4. package/dist/index.js +2 -50
  5. package/dist/index.js.map +1 -1
  6. package/dist/units/dns/record-set/index.js +4 -6
  7. package/dist/units/dns/record-set/index.js.map +1 -1
  8. package/dist/units/existing-server/index.js +7 -13
  9. package/dist/units/existing-server/index.js.map +1 -1
  10. package/dist/units/network/l3-endpoint/index.js +6 -9
  11. package/dist/units/network/l3-endpoint/index.js.map +1 -1
  12. package/dist/units/network/l4-endpoint/index.js +6 -9
  13. package/dist/units/network/l4-endpoint/index.js.map +1 -1
  14. package/dist/units/script/index.js +6 -9
  15. package/dist/units/script/index.js.map +1 -1
  16. package/dist/units/server-dns/index.js +7 -11
  17. package/dist/units/server-dns/index.js.map +1 -1
  18. package/dist/units/server-patch/index.js +7 -11
  19. package/dist/units/server-patch/index.js.map +1 -1
  20. package/dist/units/ssh/key-pair/index.js +18 -12
  21. package/dist/units/ssh/key-pair/index.js.map +1 -1
  22. package/package.json +20 -6
  23. package/src/shared/command.ts +19 -9
  24. package/src/shared/files.ts +730 -0
  25. package/src/shared/index.ts +1 -0
  26. package/src/shared/network.ts +88 -1
  27. package/src/shared/ssh.ts +36 -18
  28. package/src/units/existing-server/index.ts +1 -1
  29. package/src/units/remote-folder/index.ts +0 -0
  30. package/src/units/server-dns/index.ts +1 -1
  31. package/src/units/server-patch/index.ts +1 -1
  32. package/src/units/ssh/key-pair/index.ts +12 -2
  33. package/dist/chunk-NISDP46H.js +0 -546
  34. package/dist/chunk-NISDP46H.js.map +0 -1
@@ -3,3 +3,4 @@ export * from "./dns"
3
3
  export * from "./passwords"
4
4
  export * from "./ssh"
5
5
  export * from "./network"
6
+ export * from "./files"
@@ -19,6 +19,13 @@ export type InputL3Endpoint = network.L3Endpoint | string
19
19
  */
20
20
  export type InputL4Endpoint = network.L4Endpoint | string
21
21
 
22
+ /**
23
+ * The L7 endpoint for some service.
24
+ *
25
+ * The format is: `appProtocol://endpoint[:port][/resource]`
26
+ */
27
+ export type InputL7Endpoint = network.L7Endpoint | string
28
+
22
29
  /**
23
30
  * Stringifies a L3 endpoint object into a string.
24
31
  *
@@ -40,7 +47,6 @@ export function l3EndpointToString(l3Endpoint: network.L3Endpoint): string {
40
47
  * Stringifies a L4 endpoint object into a string.
41
48
  *
42
49
  * @param l4Endpoint The L4 endpoint object to stringify.
43
- *
44
50
  * @returns The string representation of the L4 endpoint.
45
51
  */
46
52
  export function l4EndpointToString(l4Endpoint: network.L4Endpoint): string {
@@ -51,6 +57,37 @@ export function l4EndpointToString(l4Endpoint: network.L4Endpoint): string {
51
57
  return `${l3EndpointToString(l4Endpoint)}:${l4Endpoint.port}`
52
58
  }
53
59
 
60
+ /**
61
+ * Stringifies a L4 endpoint object into a string with protocol.
62
+ *
63
+ * @param l4Endpoint The L4 endpoint object to stringify.
64
+ * @returns The string representation of the L4 endpoint with protocol.
65
+ */
66
+ export function l4EndpointWithProtocolToString(l4Endpoint: network.L4Endpoint): string {
67
+ const protocol = `${l4Endpoint.protocol}://`
68
+
69
+ return `${protocol}${l4EndpointToString(l4Endpoint)}`
70
+ }
71
+
72
+ /**
73
+ * Stringifies a L7 endpoint object into a string.
74
+ *
75
+ * The format is: `appProtocol://endpoint[:port][/resource]`
76
+ * @param l7Endpoint The L7 endpoint object to stringify.
77
+ * @returns The string representation of the L7 endpoint.
78
+ */
79
+ export function l7EndpointToString(l7Endpoint: network.L7Endpoint): string {
80
+ const protocol = `${l7Endpoint.appProtocol}://`
81
+
82
+ let endpoint = l4EndpointToString(l7Endpoint)
83
+
84
+ if (l7Endpoint.resource) {
85
+ endpoint += `/${l7Endpoint.resource}`
86
+ }
87
+
88
+ return `${protocol}${endpoint}`
89
+ }
90
+
54
91
  /**
55
92
  * Stringifies a L3 or L4 endpoint object into a string.
56
93
  *
@@ -68,6 +105,9 @@ export function l34EndpointToString(l34Endpoint: network.L34Endpoint): string {
68
105
  const L34_ENDPOINT_RE =
69
106
  /^(?:(?<protocol>[a-z]+):\/\/)?(?:(?:\[?(?<ipv6>[0-9A-Fa-f:]+)\]?)|(?<ipv4>(?:\d{1,3}\.){3}\d{1,3})|(?<hostname>[a-zA-Z0-9-*]+(?:\.[a-zA-Z0-9-*]+)*))(?::(?<port>\d{1,5}))?$/
70
107
 
108
+ const L7_ENDPOINT_RE =
109
+ /^(?<appProtocol>[a-z]+):\/\/(?:(?:\[?(?<ipv6>[0-9A-Fa-f:]+)\]?)|(?<ipv4>(?:\d{1,3}\.){3}\d{1,3})|(?<hostname>[a-zA-Z0-9-*]+(?:\.[a-zA-Z0-9-*]+)*))(?::(?<port>\d{1,5}))?(?:\/(?<resource>.*))?$/
110
+
71
111
  /**
72
112
  * Parses a L3 or L4 endpoint from a string.
73
113
  *
@@ -275,6 +315,53 @@ export function l3EndpointToCidr(l3Endpoint: network.L3Endpoint): string {
275
315
  }
276
316
  }
277
317
 
318
+ const udpAppProtocols = ["dns", "dhcp"]
319
+
320
+ /**
321
+ * Parses a L7 endpoint from a string.
322
+ *
323
+ * The format is: `appProtocol://endpoint[:port][/resource]`
324
+ *
325
+ * @param l7Endpoint The L7 endpoint string to parse.
326
+ * @returns The parsed L7 endpoint object.
327
+ */
328
+ export function parseL7Endpoint(l7Endpoint: InputL7Endpoint): network.L7Endpoint {
329
+ if (typeof l7Endpoint === "object") {
330
+ return l7Endpoint
331
+ }
332
+
333
+ const match = l7Endpoint.match(L7_ENDPOINT_RE)
334
+ if (!match) {
335
+ throw new Error(`Invalid L7 endpoint: "${l7Endpoint}"`)
336
+ }
337
+
338
+ const { appProtocol, ipv6, ipv4, hostname, port, resource } = match.groups!
339
+
340
+ let visibility: network.EndpointVisibility = "public"
341
+
342
+ if (ipv4 && IPV4_PRIVATE_REGEX.test(ipv4)) {
343
+ visibility = "external"
344
+ } else if (ipv6 && IPV6_PRIVATE_REGEX.test(ipv6)) {
345
+ visibility = "external"
346
+ }
347
+
348
+ return {
349
+ type: ipv6 ? "ipv6" : ipv4 ? "ipv4" : "hostname",
350
+ visibility,
351
+ address: ipv6 || ipv4,
352
+ hostname: hostname,
353
+
354
+ // Default port for L7 endpoints (TODO: add more specific defaults for common protocols)
355
+ port: port ? parseInt(port, 10) : 443,
356
+
357
+ // L7 endpoints typically use TCP, but can also use UDP for specific protocols
358
+ protocol: udpAppProtocols.includes(appProtocol) ? "udp" : "tcp",
359
+
360
+ appProtocol,
361
+ resource: resource || "",
362
+ } as network.L7Endpoint
363
+ }
364
+
278
365
  /**
279
366
  * Updates the endpoints based on the given mode.
280
367
  *
package/src/shared/ssh.ts CHANGED
@@ -40,24 +40,41 @@ export function createSshTerminal(
40
40
 
41
41
  return {
42
42
  name: "ssh",
43
- title: "Shell",
44
- description: "Connect to the server via SSH",
45
- icon: "gg:remote",
46
43
 
47
- image: images["terminal-ssh"].image,
48
- command,
49
-
50
- files: {
51
- "/password": credentials.password,
52
-
53
- "/private_key": {
54
- content: credentials.keyPair?.privateKey,
55
- mode: 0o600,
56
- },
44
+ meta: {
45
+ title: "Shell",
46
+ description: "Connect to the server via SSH",
47
+ icon: "gg:remote",
48
+ },
57
49
 
58
- "/known_hosts": {
59
- content: `${l3EndpointToString(endpoint)} ${credentials.hostKey}`,
60
- mode: 0o644,
50
+ spec: {
51
+ image: images["terminal-ssh"].image,
52
+ command,
53
+
54
+ files: {
55
+ "/password": credentials.password,
56
+
57
+ "/private_key": credentials.keyPair?.privateKey && {
58
+ content: {
59
+ type: "embedded",
60
+ value: credentials.keyPair?.privateKey,
61
+ },
62
+ meta: {
63
+ name: "private_key",
64
+ mode: 0o600,
65
+ },
66
+ },
67
+
68
+ "/known_hosts": {
69
+ content: {
70
+ type: "embedded",
71
+ value: `${l3EndpointToString(endpoint)} ${credentials.hostKey}`,
72
+ },
73
+ meta: {
74
+ name: "known_hosts",
75
+ mode: 0o644,
76
+ },
77
+ },
61
78
  },
62
79
  },
63
80
  } satisfies InstanceTerminal
@@ -77,13 +94,13 @@ export function privateKeyToKeyPair(privateKeyString: Input<string>): Output<ssh
77
94
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
78
95
  const privKey = privateKeyStruct.keys[0].privKey.privKey as Uint8Array
79
96
 
80
- const { fingerprint, publicKey, privateKey } = getKeys(privKey.slice(0, 32))
97
+ const { fingerprint, publicKey } = getKeys(privKey.slice(0, 32))
81
98
 
82
99
  return output({
83
100
  type: "ed25519" as const,
84
101
  fingerprint,
85
102
  publicKey,
86
- privateKey: secret(privateKey),
103
+ privateKey: secret(privateKeyString),
87
104
  })
88
105
  })
89
106
  }
@@ -136,6 +153,7 @@ export function createServerEntity(
136
153
 
137
154
  const command = new local.Command("check-ssh", {
138
155
  create: `nc -zv ${l3EndpointToString(endpoint)} ${sshPort} && echo "up" || echo "down"`,
156
+ triggers: [Date.now()],
139
157
  })
140
158
 
141
159
  return command.stdout.apply(result => {
@@ -25,7 +25,7 @@ export default outputs({
25
25
  server,
26
26
  endpoints: server.endpoints,
27
27
 
28
- $status: {
28
+ $statusFields: {
29
29
  hostname: server.hostname,
30
30
  endpoints: server.endpoints.apply(endpoints => endpoints.map(l3EndpointToString)),
31
31
  },
File without changes
@@ -20,7 +20,7 @@ export default outputs({
20
20
 
21
21
  endpoints,
22
22
 
23
- $status: {
23
+ $statusFields: {
24
24
  endpoints: endpoints.map(l3EndpointToString),
25
25
  },
26
26
  })
@@ -19,7 +19,7 @@ export default outputs({
19
19
 
20
20
  endpoints,
21
21
 
22
- $status: {
22
+ $statusFields: {
23
23
  endpoints: endpoints.map(l3EndpointToString),
24
24
  },
25
25
  })
@@ -2,14 +2,24 @@ import { ssh } from "@highstate/library"
2
2
  import { forUnit, getOrCreateSecret } from "@highstate/pulumi"
3
3
  import { generatePrivateKey, privateKeyToKeyPair } from "../../../shared"
4
4
 
5
- const { secrets, outputs } = forUnit(ssh.keyPair)
5
+ const { name, secrets, outputs } = forUnit(ssh.keyPair)
6
6
 
7
7
  const privateKey = getOrCreateSecret(secrets, "privateKey", generatePrivateKey)
8
8
  const keyPair = privateKeyToKeyPair(privateKey)
9
9
 
10
10
  export default outputs({
11
11
  keyPair: privateKeyToKeyPair(privateKey),
12
- $status: {
12
+ publicKeyFile: {
13
+ meta: {
14
+ name: `${name}.pub`,
15
+ mode: 0o644,
16
+ },
17
+ content: {
18
+ type: "embedded",
19
+ value: keyPair.publicKey,
20
+ },
21
+ },
22
+ $statusFields: {
13
23
  fingerprint: keyPair.fingerprint,
14
24
  publicKey: keyPair.publicKey,
15
25
  },