@marcusrbrown/infra 0.9.17 → 0.10.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.
@@ -0,0 +1,78 @@
1
+ import type {goke} from 'goke'
2
+ import type {ActionCtx} from '../../lib/action-ctx'
3
+
4
+ import {z} from 'zod'
5
+
6
+ import {validateVpnHost} from './host'
7
+ import {getVpnWgStatus, type SpawnFn} from './shared'
8
+
9
+ export {getVpnStatusSummary} from './shared'
10
+
11
+ declare const process: {
12
+ env: Record<string, string | undefined>
13
+ exitCode?: number
14
+ }
15
+
16
+ // ─── Action (exported for direct testing) ────────────────────────────────────
17
+
18
+ export async function vpnStatusAction(
19
+ options: {key?: string | undefined},
20
+ ctx: ActionCtx,
21
+ spawn?: SpawnFn,
22
+ ): Promise<void> {
23
+ const hostEnvKey = options.key ?? 'VPN_HOST'
24
+ const host = process.env[hostEnvKey]
25
+
26
+ if (!host) {
27
+ ctx.console.error(`VPN host not set. Export ${hostEnvKey} or pass --key <env-name> pointing to a set variable.`)
28
+ ctx.process.exit(1)
29
+ return
30
+ }
31
+
32
+ try {
33
+ validateVpnHost(host)
34
+ } catch (error) {
35
+ ctx.console.error(error instanceof Error ? error.message : String(error))
36
+ ctx.process.exit(1)
37
+ return
38
+ }
39
+
40
+ ctx.console.log('VPN status')
41
+ ctx.console.log('')
42
+
43
+ const result = await getVpnWgStatus(host, spawn)
44
+
45
+ if (!result.ok && !result.wgShow) {
46
+ ctx.console.error(`Error: ${result.error ?? 'Unknown error'}`)
47
+ ctx.process.exit(1)
48
+ return
49
+ }
50
+
51
+ const wgShow = result.wgShow
52
+
53
+ if (wgShow?.serverPublicKey) {
54
+ ctx.console.log(`Server public key: ${wgShow.serverPublicKey}`)
55
+ }
56
+
57
+ ctx.console.log(`Peers: ${wgShow?.peerCount ?? 0}`)
58
+ ctx.console.log('')
59
+
60
+ if (result.ok && wgShow?.interfaceUp) {
61
+ ctx.console.log('Status: OK')
62
+ } else {
63
+ ctx.console.log('Status: DEGRADED (WireGuard interface not up)')
64
+ ctx.process.exit(1)
65
+ }
66
+ }
67
+
68
+ // ─── Command registration ─────────────────────────────────────────────────────
69
+
70
+ export function registerVpnStatus(cli: ReturnType<typeof goke>): void {
71
+ cli
72
+ .command('vpn status', 'Show operational health of the VPN box via SSH and wg show.')
73
+ .option(
74
+ '--key [key]',
75
+ z.string().describe('Environment variable name holding the SSH host. Falls back to VPN_HOST when omitted.'),
76
+ )
77
+ .action((options, ctx) => vpnStatusAction(options, ctx))
78
+ }
@@ -11,7 +11,7 @@ const ALLOWED_SHELL_SCRIPTS = new Set(['apps/keeweb/deploy.sh'])
11
11
  // MCP drift-guard: sensitive tool set (two-layer security model)
12
12
  // ---------------------------------------------------------------------------
13
13
  //
14
- // These 6 commands are source-gated: they are NOT in MCP_ALLOWLIST and are
14
+ // These commands are source-gated: they are NOT in MCP_ALLOWLIST and are
15
15
  // therefore never registered as MCP tools. They remain CLI-only.
16
16
  //
17
17
  // WHY each is source-gated (primary layer — MCP_ALLOWLIST exclusion):
@@ -21,6 +21,11 @@ const ALLOWED_SHELL_SCRIPTS = new Set(['apps/keeweb/deploy.sh'])
21
21
  // gateway backup — secret-bearing: writes CA private key material to a tarball
22
22
  // cliproxy keys list — secret-disclosing: prints live bearer tokens in plaintext
23
23
  // cliproxy config get — secret-disclosing: dumps management config incl. management key
24
+ // vpn deploy — mutating: deploys WireGuard config to live VPN box
25
+ // vpn logs — sensitive: streams journalctl logs that may reveal peer IPs/traffic
26
+ // vpn client add — mutating: generates keypair + appends peer + triggers redeploy
27
+ // vpn client list — sensitive: lists peer public keys and tunnel IPs
28
+ // vpn client remove — mutating: removes peer + triggers redeploy
24
29
  //
25
30
  // Defense-in-depth (secondary layer — opencode.jsonc `permission: deny`):
26
31
  // Even if MCP_ALLOWLIST were mistakenly re-expanded, opencode's native tool
@@ -37,6 +42,12 @@ const SENSITIVE_MCP_COMMANDS: readonly string[] = [
37
42
  'gateway backup',
38
43
  'cliproxy keys list',
39
44
  'cliproxy config get',
45
+ // VPN: mutating / sensitive / log-streaming — CLI-only
46
+ 'vpn deploy',
47
+ 'vpn logs',
48
+ 'vpn client add',
49
+ 'vpn client list',
50
+ 'vpn client remove',
40
51
  ]
41
52
 
42
53
  // Accepted version-comment forms on SHA-pinned `uses:` lines:
@@ -26,3 +26,21 @@ metrics.fro.bot ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy
26
26
  |1|8o6qExp0klmE80pMU2CYvmbGqSQ=|064FdS/NWWEIU7EjmGBCwCek+DE= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICRCMPA99bZJ1w+QdZPrTzLK06LF7t91tb0GbKfBkA72
27
27
  |1|1nwXP2iRwBq0GXyE94EXYJuaUCQ=|Wxoe6EvzjZbk02Hr4mx1YZOciUM= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCma/Y9qRPlZ8v1wnQQBfwghQ0XbtSMn7QHVgIFGBjbO+Xqim7Lv9EArn58HIVACsZKMD0e9T90r70TDXYTWuZ6+RQ2x2soE6DcG/T/2wyan40hVtXLSCg8hx9DNjLR3RBwkiJcbdrYCqpDmi4kOuJAJ+b5JxUhJAkdF5M9xhUko59HtUm5I/j1T2Df60+7CdKMGZKMrCRios/q4lvgImuWS3aZuNQNuJiv6rfhX7L9LqezlJUgw1AbOzaqPXbZ9xpzt8yklGZQNa5I/CS6pEgn4/SKiRsetpgd4SCB9UuCR7ia/M0VU8itNPMZY11Pi+YwJKfJVZDtS+OSFkFxea8B1MyxDZkvOwnzYVx9xG6W48Oi06x4pQgJcqq5V52xM4upSlVtws5gTLNm/3KaJZ3kb7IK4HnTEUQrz/UShtyP1crsqwj5eoDnvcUfaMHx/YC/7LlQFp8AO8W/KEYWzlycJpZLqPrO/gqoiR0AG9NMP0SSRaD7M2pcQ4tKM1xyopE=
28
28
  |1|lwRlQiSSd0h7iti76fvRXTtbkSw=|D//yCCMd1iZftlbjJ0NhKCCf5/8= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOm6bQkB9dGaPJAVbk9IrVxZSM0KrkUikv8JgVrW0iJMKorJ233GaK03n2/5cuAJ/D3z6nN/pF6QGApWfm6s/JA=
29
+
30
+ # wg-egress static IP (52.208.116.13)
31
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
32
+ 52.208.116.13 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILA4LGgnvBjq/yoOKLjzFefGzo9gAspxwfbY8aACj/3q
33
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
34
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
35
+ 52.208.116.13 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCOSk8SjUJHwOzUbb/R0XWu2h/BmtPjDsbzkGZIryUZ00OBeSb2V70BHVagC41BH7XEfMT5jxFJKIAHx4iqcdjrjUfR+lTIJVdHjDpCHLxzKBRQsE9uLPkSoz+DR2Y9mg8tkBXWc2rol+SqjnOWkGsavJey7+bZwEadFPBCwJnCSkn+iIdu6BO2e0X8wvpLC+ThhWXPu8tUiPY5rPgDXtCzj5rROCL79Vh5HcWONmoOzTAnaH6WMlLedX37xM4Vayl62MKyFIQE7Pw/zg2l5StEzIvQjornMs09unFlZnWYla3+T3vwTaqh6B4sbdM332+Rxw0FoHb99xgWqHpk5BnZe6Dc+l6ZHVY6p8j1CSa3/8JMGzr62/OlYfnIOwW3HvHG8R6jmi++LlmfeGmUDOypl9yfAVNPRazEVXq+eWC1helxoRBvkabwpAAKg3aihQDxLPfEi1q8qYORzb/ZAU8z8HqBAfDD6wIjacq1HCUKhZA3QN+E2skjD+IdsVx4FF0=
36
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
37
+ 52.208.116.13 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ5sx3iCboYm5TahbLThB4fWbnz391FDUFcRg+CfvXRCKHAuL8RTdkUaWK3OaFA4Xu1+37B0k3RYfbsBZ6vg6So=
38
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
39
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
40
+ |1|j1LnSfd4ntnFE7CxqDqu6aaQWLo=|A8bf0bH74R6KoEHVjeDDemArv9A= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ5sx3iCboYm5TahbLThB4fWbnz391FDUFcRg+CfvXRCKHAuL8RTdkUaWK3OaFA4Xu1+37B0k3RYfbsBZ6vg6So=
41
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
42
+ |1|4GGoI+hl2sBnBBkgwvuNYyDWsVs=|M6RYPIm/v9wCDInvvra6yLcQneY= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCOSk8SjUJHwOzUbb/R0XWu2h/BmtPjDsbzkGZIryUZ00OBeSb2V70BHVagC41BH7XEfMT5jxFJKIAHx4iqcdjrjUfR+lTIJVdHjDpCHLxzKBRQsE9uLPkSoz+DR2Y9mg8tkBXWc2rol+SqjnOWkGsavJey7+bZwEadFPBCwJnCSkn+iIdu6BO2e0X8wvpLC+ThhWXPu8tUiPY5rPgDXtCzj5rROCL79Vh5HcWONmoOzTAnaH6WMlLedX37xM4Vayl62MKyFIQE7Pw/zg2l5StEzIvQjornMs09unFlZnWYla3+T3vwTaqh6B4sbdM332+Rxw0FoHb99xgWqHpk5BnZe6Dc+l6ZHVY6p8j1CSa3/8JMGzr62/OlYfnIOwW3HvHG8R6jmi++LlmfeGmUDOypl9yfAVNPRazEVXq+eWC1helxoRBvkabwpAAKg3aihQDxLPfEi1q8qYORzb/ZAU8z8HqBAfDD6wIjacq1HCUKhZA3QN+E2skjD+IdsVx4FF0=
43
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
44
+ |1|6g8lttzHI3BCW6rIf1/Bteo1KcM=|bNbGP2QK2pUdPmhplw6eVzspe5g= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILA4LGgnvBjq/yoOKLjzFefGzo9gAspxwfbY8aACj/3q
45
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
46
+ # 52.208.116.13:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15