rds_ssm_connect 1.7.14 → 1.7.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.
@@ -0,0 +1,186 @@
1
+ name: Update Homebrew Tap
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ update-tap:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Get version
12
+ id: version
13
+ run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
14
+
15
+ - name: Download release assets
16
+ env:
17
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18
+ run: |
19
+ VERSION=${{ steps.version.outputs.VERSION }}
20
+ gh release download "v${VERSION}" -R yarka-guru/connection_app \
21
+ -p "RDS.SSM.Connect_${VERSION}_aarch64.dmg" \
22
+ -p "RDS.SSM.Connect_${VERSION}_x64.dmg" \
23
+ -p "RDS.SSM.Connect_${VERSION}_amd64.deb" \
24
+ -p "RDS.SSM.Connect_${VERSION}_arm64.deb"
25
+
26
+ - name: Compute SHA256 hashes
27
+ id: hashes
28
+ run: |
29
+ VERSION=${{ steps.version.outputs.VERSION }}
30
+ echo "ARM_DMG_SHA=$(sha256sum RDS.SSM.Connect_${VERSION}_aarch64.dmg | cut -d' ' -f1)" >> $GITHUB_OUTPUT
31
+ echo "X64_DMG_SHA=$(sha256sum RDS.SSM.Connect_${VERSION}_x64.dmg | cut -d' ' -f1)" >> $GITHUB_OUTPUT
32
+ echo "AMD64_DEB_SHA=$(sha256sum RDS.SSM.Connect_${VERSION}_amd64.deb | cut -d' ' -f1)" >> $GITHUB_OUTPUT
33
+ echo "ARM64_DEB_SHA=$(sha256sum RDS.SSM.Connect_${VERSION}_arm64.deb | cut -d' ' -f1)" >> $GITHUB_OUTPUT
34
+
35
+ - name: Checkout Homebrew tap
36
+ uses: actions/checkout@v4
37
+ with:
38
+ repository: yarka-guru/homebrew-tap
39
+ token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
40
+ path: homebrew-tap
41
+
42
+ - name: Update Cask formula
43
+ run: |
44
+ VERSION=${{ steps.version.outputs.VERSION }}
45
+ cat > homebrew-tap/Casks/rds-ssm-connect.rb << CASK
46
+ cask "rds-ssm-connect" do
47
+ version "${VERSION}"
48
+
49
+ on_arm do
50
+ sha256 "${{ steps.hashes.outputs.ARM_DMG_SHA }}"
51
+ url "https://github.com/yarka-guru/connection_app/releases/download/v#{version}/RDS.SSM.Connect_#{version}_aarch64.dmg"
52
+ end
53
+
54
+ on_intel do
55
+ sha256 "${{ steps.hashes.outputs.X64_DMG_SHA }}"
56
+ url "https://github.com/yarka-guru/connection_app/releases/download/v#{version}/RDS.SSM.Connect_#{version}_x64.dmg"
57
+ end
58
+
59
+ name "RDS SSM Connect"
60
+ desc "Secure database tunneling via AWS SSM"
61
+ homepage "https://github.com/yarka-guru/connection_app"
62
+
63
+ depends_on macos: ">= :monterey"
64
+ depends_on formula: "aws-vault"
65
+ depends_on formula: "awscli"
66
+
67
+ app "RDS SSM Connect.app"
68
+
69
+ caveats <<~EOS
70
+ You also need the AWS Session Manager Plugin:
71
+ brew install --cask session-manager-plugin
72
+
73
+ Ensure your AWS profiles are configured in ~/.aws/config
74
+ EOS
75
+
76
+ zap trash: [
77
+ "~/Library/Application Support/com.rds-ssm-connect.desktop",
78
+ "~/Library/Caches/com.rds-ssm-connect.desktop",
79
+ ]
80
+ end
81
+ CASK
82
+
83
+ - name: Update Linux formula
84
+ run: |
85
+ VERSION=${{ steps.version.outputs.VERSION }}
86
+ cat > homebrew-tap/Formula/rds-ssm-connect.rb << FORMULA
87
+ class RdsSsmConnect < Formula
88
+ desc "Secure database tunneling via AWS SSM"
89
+ homepage "https://github.com/yarka-guru/connection_app"
90
+ version "${VERSION}"
91
+ license "MIT"
92
+
93
+ on_linux do
94
+ on_intel do
95
+ url "https://github.com/yarka-guru/connection_app/releases/download/v#{version}/RDS.SSM.Connect_#{version}_amd64.deb"
96
+ sha256 "${{ steps.hashes.outputs.AMD64_DEB_SHA }}"
97
+ end
98
+ on_arm do
99
+ url "https://github.com/yarka-guru/connection_app/releases/download/v#{version}/RDS.SSM.Connect_#{version}_arm64.deb"
100
+ sha256 "${{ steps.hashes.outputs.ARM64_DEB_SHA }}"
101
+ end
102
+ end
103
+
104
+ depends_on "awscli"
105
+ depends_on "aws-vault"
106
+
107
+ def install
108
+ system "ar", "x", cached_download
109
+ mkdir_p "extract"
110
+ system "tar", "xf", Dir["data.tar.*"].first, "-C", "extract"
111
+
112
+ bin.install Dir["extract/usr/bin/*"]
113
+ share.install Dir["extract/usr/share/*"] if Dir.exist?("extract/usr/share")
114
+ end
115
+
116
+ def caveats
117
+ <<~EOS
118
+ You also need the AWS Session Manager Plugin:
119
+ https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html
120
+
121
+ Ensure your AWS profiles are configured in ~/.aws/config
122
+
123
+ On macOS, install the desktop app instead:
124
+ brew install --cask rds-ssm-connect
125
+ EOS
126
+ end
127
+ end
128
+ FORMULA
129
+
130
+ - name: Update README
131
+ run: |
132
+ VERSION=${{ steps.version.outputs.VERSION }}
133
+ cat > homebrew-tap/README.md << 'README'
134
+ # Homebrew Tap for RDS SSM Connect
135
+
136
+ Secure database tunneling via AWS SSM.
137
+
138
+ ## Installation
139
+
140
+ ### macOS (Desktop App)
141
+
142
+ ```bash
143
+ brew tap yarka-guru/tap
144
+ brew install --cask rds-ssm-connect
145
+ ```
146
+
147
+ ### Linux (x86_64 / ARM64)
148
+
149
+ ```bash
150
+ brew tap yarka-guru/tap
151
+ brew install rds-ssm-connect
152
+ ```
153
+
154
+ ## Direct Downloads
155
+
156
+ Download installers directly from [GitHub Releases](https://github.com/yarka-guru/connection_app/releases/latest):
157
+
158
+ | Platform | Format |
159
+ |----------|--------|
160
+ | macOS (Apple Silicon) | `.dmg` |
161
+ | macOS (Intel) | `.dmg` |
162
+ | Linux (x86_64) | `.deb`, `.rpm`, `.AppImage` |
163
+ | Linux (ARM64) | `.deb`, `.AppImage` |
164
+ | Windows | `.exe` (NSIS), `.msi` |
165
+
166
+ ## Updating
167
+
168
+ ```bash
169
+ brew update
170
+ brew upgrade --cask rds-ssm-connect # macOS
171
+ brew upgrade rds-ssm-connect # Linux
172
+ ```
173
+ README
174
+
175
+ - name: Commit and push
176
+ working-directory: homebrew-tap
177
+ run: |
178
+ git config user.name "github-actions[bot]"
179
+ git config user.email "github-actions[bot]@users.noreply.github.com"
180
+ git add -A
181
+ if git diff --cached --quiet; then
182
+ echo "No changes to commit"
183
+ else
184
+ git commit -m "Update to v${{ steps.version.outputs.VERSION }}"
185
+ git push
186
+ fi
package/connect.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { exec } from 'node:child_process'
3
+ import { exec, spawn, spawnSync } from 'node:child_process'
4
4
  import { EventEmitter } from 'node:events'
5
5
  import fs from 'node:fs/promises'
6
6
  import net from 'node:net'
@@ -14,7 +14,7 @@ import {
14
14
  } from './configLoader.js'
15
15
 
16
16
  // Package info for version checking
17
- const packageJson = { name: 'rds_ssm_connect', version: '1.7.14' }
17
+ const packageJson = { name: 'rds_ssm_connect', version: '1.7.15' }
18
18
 
19
19
  const execAsync = promisify(exec)
20
20
 
@@ -83,20 +83,63 @@ async function checkForUpdates() {
83
83
  // Store active child processes for cleanup
84
84
  let activeChildProcesses = []
85
85
 
86
+ // Recursively collect all descendant PIDs of a process via pgrep.
87
+ function getDescendantPids(pid) {
88
+ const descendants = []
89
+ try {
90
+ const { stdout } = spawnSync('pgrep', ['-P', String(pid)], {
91
+ encoding: 'utf-8',
92
+ timeout: 3000,
93
+ })
94
+ if (stdout) {
95
+ const children = stdout.trim().split('\n').filter(Boolean).map(Number)
96
+ for (const childPid of children) {
97
+ descendants.push(childPid, ...getDescendantPids(childPid))
98
+ }
99
+ }
100
+ } catch (_err) {
101
+ // pgrep not available or timed out
102
+ }
103
+ return descendants
104
+ }
105
+
106
+ // Kill entire process tree: shell → aws-vault → aws → session-manager-plugin.
107
+ // Uses three strategies because descendants may escape to different process
108
+ // groups (aws-vault / AWS CLI behavior on macOS).
109
+ function killProcessTree(child) {
110
+ if (!child || !child.pid) return
111
+ const rootPid = child.pid
112
+
113
+ // Walk the tree to find every descendant PID
114
+ const descendants = getDescendantPids(rootPid)
115
+ const allPids = [rootPid, ...descendants]
116
+
117
+ // Strategy 1: Process group kill (fast, atomic — works when all share PGID)
118
+ try { process.kill(-rootPid, 'SIGTERM') } catch (_err) {}
119
+
120
+ // Strategy 2: Individual SIGTERM (handles descendants in different groups)
121
+ for (const pid of allPids) {
122
+ try { process.kill(pid, 'SIGTERM') } catch (_err) {}
123
+ }
124
+
125
+ // Strategy 3: SIGKILL survivors (cannot be caught or ignored)
126
+ for (const pid of allPids) {
127
+ try { process.kill(pid, 'SIGKILL') } catch (_err) {}
128
+ }
129
+ }
130
+
86
131
  // Handle graceful shutdown
87
132
  function setupProcessCleanup() {
88
- const cleanup = () => {
133
+ const killAll = () => {
89
134
  activeChildProcesses.forEach((child) => {
90
- if (child && !child.killed) {
91
- child.kill('SIGTERM')
92
- }
135
+ killProcessTree(child)
93
136
  })
94
- process.exit(0)
137
+ activeChildProcesses = []
95
138
  }
96
139
 
97
- process.on('SIGINT', cleanup)
98
- process.on('SIGTERM', cleanup)
99
- process.on('exit', cleanup)
140
+ process.on('SIGINT', () => { killAll(); process.exit(0) })
141
+ process.on('SIGTERM', () => { killAll(); process.exit(0) })
142
+ process.on('exit', killAll)
100
143
  }
101
144
 
102
145
  async function readAwsConfig() {
@@ -251,6 +294,7 @@ async function handleTargetNotConnectedError(
251
294
  region,
252
295
  retryCount,
253
296
  maxRetries,
297
+ onChild,
254
298
  ) {
255
299
  // Terminate the disconnected instance
256
300
  await terminateBastionInstance(ENV, instanceId, region)
@@ -270,6 +314,7 @@ async function handleTargetNotConnectedError(
270
314
  region,
271
315
  retryCount + 1,
272
316
  maxRetries,
317
+ onChild,
273
318
  )
274
319
  }
275
320
 
@@ -282,7 +327,11 @@ function executePortForwardingCommand(
282
327
  region,
283
328
  ) {
284
329
  const portForwardingCommand = `aws-vault exec ${ENV} -- aws ssm start-session --region ${region} --target ${instanceId} --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters "host=${rdsEndpoint},portNumber='${remotePort}',localPortNumber='${portNumber}'" --cli-connect-timeout 0`
285
- const child = exec(portForwardingCommand)
330
+ const child = spawn(portForwardingCommand, {
331
+ shell: true,
332
+ detached: true,
333
+ stdio: ['ignore', 'pipe', 'pipe'],
334
+ })
286
335
 
287
336
  // Register child process for cleanup
288
337
  activeChildProcesses.push(child)
@@ -299,6 +348,7 @@ async function startPortForwardingWithConfig(
299
348
  region,
300
349
  retryCount = 0,
301
350
  maxRetries = RETRY_CONFIG.PORT_FORWARDING_MAX_RETRIES,
351
+ onChild,
302
352
  ) {
303
353
  return new Promise((resolve, reject) => {
304
354
  const child = executePortForwardingCommand(
@@ -309,6 +359,11 @@ async function startPortForwardingWithConfig(
309
359
  remotePort,
310
360
  region,
311
361
  )
362
+ // Notify caller of the new child (used for per-connection tracking).
363
+ // If the connection was already disconnected, the callback kills this
364
+ // child immediately so it doesn't linger as an orphan.
365
+ if (onChild) onChild(child)
366
+
312
367
  const sessionState = monitorPortForwardingSession(child)
313
368
 
314
369
  child.on('close', async (code) => {
@@ -331,6 +386,7 @@ async function startPortForwardingWithConfig(
331
386
  region,
332
387
  retryCount,
333
388
  maxRetries,
389
+ onChild,
334
390
  )
335
391
  resolve()
336
392
  } else if (code !== 0) {
@@ -543,6 +599,18 @@ async function connect(projectKey, profile, options = {}) {
543
599
 
544
600
  let manualDisconnect = false
545
601
  let stopKeepalive = null
602
+ let currentChild = null // per-connection child tracking
603
+
604
+ // Called whenever a new child process is spawned for this connection.
605
+ // If disconnect() was already called, kills the child immediately so
606
+ // it doesn't linger as an orphan during retry chains.
607
+ const onChild = (child) => {
608
+ currentChild = child
609
+ if (manualDisconnect) {
610
+ killProcessTree(child)
611
+ activeChildProcesses = activeChildProcesses.filter((p) => p !== child)
612
+ }
613
+ }
546
614
 
547
615
  // Emit status updates
548
616
  const emit = (event, data) => {
@@ -600,6 +668,7 @@ async function connect(projectKey, profile, options = {}) {
600
668
  region,
601
669
  0,
602
670
  RETRY_CONFIG.PORT_FORWARDING_MAX_RETRIES,
671
+ onChild,
603
672
  )
604
673
 
605
674
  // Session ended — clean up keepalive
@@ -672,13 +741,12 @@ async function connect(projectKey, profile, options = {}) {
672
741
  disconnect: () => {
673
742
  manualDisconnect = true
674
743
  stopKeepalive?.()
675
- // Kill all active child processes
676
- activeChildProcesses.forEach((child) => {
677
- if (child && !child.killed) {
678
- child.kill('SIGTERM')
679
- }
680
- })
681
- activeChildProcesses = []
744
+ // Kill only THIS connection's child process group
745
+ if (currentChild) {
746
+ killProcessTree(currentChild)
747
+ activeChildProcesses = activeChildProcesses.filter((p) => p !== currentChild)
748
+ currentChild = null
749
+ }
682
750
  },
683
751
  waitForClose: () => portForwardingPromise,
684
752
  }
package/gui-adapter.js CHANGED
@@ -253,19 +253,19 @@ async function handleCommand(command) {
253
253
  }
254
254
  }
255
255
 
256
- // Handle process signals for cleanup
257
- function setupCleanup() {
258
- const cleanup = () => {
259
- for (const [_connId, connection] of activeConnections) {
260
- connection.disconnect()
261
- }
262
- activeConnections.clear()
263
- process.exit(0)
256
+ // Disconnect all active connections (idempotent — safe to call multiple times)
257
+ function disconnectAll() {
258
+ for (const [_connId, connection] of activeConnections) {
259
+ connection.disconnect()
264
260
  }
261
+ activeConnections.clear()
262
+ }
265
263
 
266
- process.on('SIGINT', cleanup)
267
- process.on('SIGTERM', cleanup)
268
- process.on('exit', cleanup)
264
+ // Handle process signals for cleanup
265
+ function setupCleanup() {
266
+ process.on('SIGINT', () => { disconnectAll(); process.exit(0) })
267
+ process.on('SIGTERM', () => { disconnectAll(); process.exit(0) })
268
+ process.on('exit', disconnectAll)
269
269
  }
270
270
 
271
271
  // Main entry point
@@ -294,10 +294,7 @@ async function main() {
294
294
  })
295
295
 
296
296
  rl.on('close', () => {
297
- for (const [_connId, connection] of activeConnections) {
298
- connection.disconnect()
299
- }
300
- activeConnections.clear()
297
+ disconnectAll()
301
298
  process.exit(0)
302
299
  })
303
300
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rds_ssm_connect",
3
- "version": "1.7.14",
3
+ "version": "1.7.16",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
package/src/App.svelte CHANGED
@@ -57,6 +57,15 @@ function handleGlobalKeydown(e) {
57
57
  e.preventDefault()
58
58
  showSettings = !showSettings
59
59
  }
60
+ // Ctrl+Q (Linux) / Cmd+Q fallback → quit app
61
+ if ((e.metaKey || e.ctrlKey) && e.key === 'q') {
62
+ e.preventDefault()
63
+ if (activeConnections.length > 0) {
64
+ showCloseConfirm = true
65
+ } else {
66
+ invoke?.('quit_app').catch(() => appWindow?.destroy())
67
+ }
68
+ }
60
69
  }
61
70
 
62
71
  onMount(() => {
@@ -103,11 +112,13 @@ async function initApp() {
103
112
  return
104
113
  }
105
114
 
106
- // Intercept window close — prompt if there are active connections
115
+ // Intercept window close — prompt if active connections, otherwise quit cleanly
107
116
  unlistenCloseRequested = await appWindow.onCloseRequested(async (event) => {
117
+ event.preventDefault()
108
118
  if (activeConnections.length > 0) {
109
- event.preventDefault()
110
119
  showCloseConfirm = true
120
+ } else {
121
+ try { await invoke('quit_app') } catch (_err) { appWindow?.destroy() }
111
122
  }
112
123
  })
113
124
 
@@ -182,7 +193,12 @@ async function confirmClose() {
182
193
  } catch (_err) {
183
194
  // Best-effort disconnect before closing
184
195
  }
185
- await invoke('quit_app')
196
+ try {
197
+ await invoke('quit_app')
198
+ } catch (_err) {
199
+ // If quit_app fails, force close via window API
200
+ appWindow?.close()
201
+ }
186
202
  }
187
203
 
188
204
  function cancelClose() {
@@ -428,8 +444,10 @@ async function handleInstallUpdate() {
428
444
 
429
445
  try {
430
446
  await invoke('install_update')
431
- statusMessage = 'Update installed! Restart to apply.'
432
- // The app will restart automatically after install
447
+ // App should auto-restart and never reach here, but just in case:
448
+ isUpdating = false
449
+ showUpdateBanner = false
450
+ statusMessage = 'Update installed successfully.'
433
451
  } catch (err) {
434
452
  errorMessage = `Update failed: ${err}`
435
453
  isUpdating = false
@@ -149,7 +149,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
149
149
  dependencies = [
150
150
  "proc-macro2",
151
151
  "quote",
152
- "syn 2.0.114",
152
+ "syn 2.0.115",
153
153
  ]
154
154
 
155
155
  [[package]]
@@ -184,7 +184,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
184
184
  dependencies = [
185
185
  "proc-macro2",
186
186
  "quote",
187
- "syn 2.0.114",
187
+ "syn 2.0.115",
188
188
  ]
189
189
 
190
190
  [[package]]
@@ -392,7 +392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
392
392
  checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
393
393
  dependencies = [
394
394
  "serde",
395
- "toml 0.9.11+spec-1.1.0",
395
+ "toml 0.9.12+spec-1.1.0",
396
396
  ]
397
397
 
398
398
  [[package]]
@@ -602,7 +602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
602
602
  checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
603
603
  dependencies = [
604
604
  "quote",
605
- "syn 2.0.114",
605
+ "syn 2.0.115",
606
606
  ]
607
607
 
608
608
  [[package]]
@@ -612,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
612
612
  checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
613
613
  dependencies = [
614
614
  "quote",
615
- "syn 2.0.114",
615
+ "syn 2.0.115",
616
616
  ]
617
617
 
618
618
  [[package]]
@@ -636,7 +636,7 @@ dependencies = [
636
636
  "proc-macro2",
637
637
  "quote",
638
638
  "strsim",
639
- "syn 2.0.114",
639
+ "syn 2.0.115",
640
640
  ]
641
641
 
642
642
  [[package]]
@@ -647,14 +647,14 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
647
647
  dependencies = [
648
648
  "darling_core",
649
649
  "quote",
650
- "syn 2.0.114",
650
+ "syn 2.0.115",
651
651
  ]
652
652
 
653
653
  [[package]]
654
654
  name = "deranged"
655
- version = "0.5.5"
655
+ version = "0.5.6"
656
656
  source = "registry+https://github.com/rust-lang/crates.io-index"
657
- checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
657
+ checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4"
658
658
  dependencies = [
659
659
  "powerfmt",
660
660
  "serde_core",
@@ -668,7 +668,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
668
668
  dependencies = [
669
669
  "proc-macro2",
670
670
  "quote",
671
- "syn 2.0.114",
671
+ "syn 2.0.115",
672
672
  ]
673
673
 
674
674
  [[package]]
@@ -681,7 +681,7 @@ dependencies = [
681
681
  "proc-macro2",
682
682
  "quote",
683
683
  "rustc_version",
684
- "syn 2.0.114",
684
+ "syn 2.0.115",
685
685
  ]
686
686
 
687
687
  [[package]]
@@ -739,7 +739,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
739
739
  dependencies = [
740
740
  "proc-macro2",
741
741
  "quote",
742
- "syn 2.0.114",
742
+ "syn 2.0.115",
743
743
  ]
744
744
 
745
745
  [[package]]
@@ -762,7 +762,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
762
762
  dependencies = [
763
763
  "proc-macro2",
764
764
  "quote",
765
- "syn 2.0.114",
765
+ "syn 2.0.115",
766
766
  ]
767
767
 
768
768
  [[package]]
@@ -810,7 +810,7 @@ dependencies = [
810
810
  "cc",
811
811
  "memchr",
812
812
  "rustc_version",
813
- "toml 0.9.11+spec-1.1.0",
813
+ "toml 0.9.12+spec-1.1.0",
814
814
  "vswhom",
815
815
  "winreg",
816
816
  ]
@@ -854,7 +854,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
854
854
  dependencies = [
855
855
  "proc-macro2",
856
856
  "quote",
857
- "syn 2.0.114",
857
+ "syn 2.0.115",
858
858
  ]
859
859
 
860
860
  [[package]]
@@ -996,7 +996,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
996
996
  dependencies = [
997
997
  "proc-macro2",
998
998
  "quote",
999
- "syn 2.0.114",
999
+ "syn 2.0.115",
1000
1000
  ]
1001
1001
 
1002
1002
  [[package]]
@@ -1083,7 +1083,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
1083
1083
  dependencies = [
1084
1084
  "proc-macro2",
1085
1085
  "quote",
1086
- "syn 2.0.114",
1086
+ "syn 2.0.115",
1087
1087
  ]
1088
1088
 
1089
1089
  [[package]]
@@ -1346,7 +1346,7 @@ dependencies = [
1346
1346
  "proc-macro-error",
1347
1347
  "proc-macro2",
1348
1348
  "quote",
1349
- "syn 2.0.114",
1349
+ "syn 2.0.115",
1350
1350
  ]
1351
1351
 
1352
1352
  [[package]]
@@ -1425,7 +1425,7 @@ dependencies = [
1425
1425
  "proc-macro-error",
1426
1426
  "proc-macro2",
1427
1427
  "quote",
1428
- "syn 2.0.114",
1428
+ "syn 2.0.115",
1429
1429
  ]
1430
1430
 
1431
1431
  [[package]]
@@ -2003,7 +2003,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
2003
2003
  dependencies = [
2004
2004
  "bitflags 2.10.0",
2005
2005
  "libc",
2006
- "redox_syscall 0.7.0",
2006
+ "redox_syscall 0.7.1",
2007
2007
  ]
2008
2008
 
2009
2009
  [[package]]
@@ -2061,7 +2061,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
2061
2061
  dependencies = [
2062
2062
  "proc-macro2",
2063
2063
  "quote",
2064
- "syn 2.0.114",
2064
+ "syn 2.0.115",
2065
2065
  ]
2066
2066
 
2067
2067
  [[package]]
@@ -2232,7 +2232,7 @@ dependencies = [
2232
2232
  "proc-macro-crate 3.4.0",
2233
2233
  "proc-macro2",
2234
2234
  "quote",
2235
- "syn 2.0.114",
2235
+ "syn 2.0.115",
2236
2236
  ]
2237
2237
 
2238
2238
  [[package]]
@@ -2500,7 +2500,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
2500
2500
  dependencies = [
2501
2501
  "proc-macro2",
2502
2502
  "quote",
2503
- "syn 2.0.114",
2503
+ "syn 2.0.115",
2504
2504
  ]
2505
2505
 
2506
2506
  [[package]]
@@ -2737,7 +2737,7 @@ dependencies = [
2737
2737
  "phf_shared 0.11.3",
2738
2738
  "proc-macro2",
2739
2739
  "quote",
2740
- "syn 2.0.114",
2740
+ "syn 2.0.115",
2741
2741
  ]
2742
2742
 
2743
2743
  [[package]]
@@ -2873,7 +2873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2873
2873
  checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
2874
2874
  dependencies = [
2875
2875
  "proc-macro2",
2876
- "syn 2.0.114",
2876
+ "syn 2.0.115",
2877
2877
  ]
2878
2878
 
2879
2879
  [[package]]
@@ -3057,7 +3057,7 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
3057
3057
 
3058
3058
  [[package]]
3059
3059
  name = "rds-ssm-connect"
3060
- version = "1.7.14"
3060
+ version = "1.7.16"
3061
3061
  dependencies = [
3062
3062
  "reqwest 0.12.28",
3063
3063
  "semver",
@@ -3085,9 +3085,9 @@ dependencies = [
3085
3085
 
3086
3086
  [[package]]
3087
3087
  name = "redox_syscall"
3088
- version = "0.7.0"
3088
+ version = "0.7.1"
3089
3089
  source = "registry+https://github.com/rust-lang/crates.io-index"
3090
- checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
3090
+ checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b"
3091
3091
  dependencies = [
3092
3092
  "bitflags 2.10.0",
3093
3093
  ]
@@ -3120,7 +3120,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
3120
3120
  dependencies = [
3121
3121
  "proc-macro2",
3122
3122
  "quote",
3123
- "syn 2.0.114",
3123
+ "syn 2.0.115",
3124
3124
  ]
3125
3125
 
3126
3126
  [[package]]
@@ -3418,7 +3418,7 @@ dependencies = [
3418
3418
  "proc-macro2",
3419
3419
  "quote",
3420
3420
  "serde_derive_internals",
3421
- "syn 2.0.114",
3421
+ "syn 2.0.115",
3422
3422
  ]
3423
3423
 
3424
3424
  [[package]]
@@ -3530,7 +3530,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
3530
3530
  dependencies = [
3531
3531
  "proc-macro2",
3532
3532
  "quote",
3533
- "syn 2.0.114",
3533
+ "syn 2.0.115",
3534
3534
  ]
3535
3535
 
3536
3536
  [[package]]
@@ -3541,7 +3541,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
3541
3541
  dependencies = [
3542
3542
  "proc-macro2",
3543
3543
  "quote",
3544
- "syn 2.0.114",
3544
+ "syn 2.0.115",
3545
3545
  ]
3546
3546
 
3547
3547
  [[package]]
@@ -3565,7 +3565,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
3565
3565
  dependencies = [
3566
3566
  "proc-macro2",
3567
3567
  "quote",
3568
- "syn 2.0.114",
3568
+ "syn 2.0.115",
3569
3569
  ]
3570
3570
 
3571
3571
  [[package]]
@@ -3626,7 +3626,7 @@ dependencies = [
3626
3626
  "darling",
3627
3627
  "proc-macro2",
3628
3628
  "quote",
3629
- "syn 2.0.114",
3629
+ "syn 2.0.115",
3630
3630
  ]
3631
3631
 
3632
3632
  [[package]]
@@ -3648,7 +3648,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
3648
3648
  dependencies = [
3649
3649
  "proc-macro2",
3650
3650
  "quote",
3651
- "syn 2.0.114",
3651
+ "syn 2.0.115",
3652
3652
  ]
3653
3653
 
3654
3654
  [[package]]
@@ -3875,9 +3875,9 @@ dependencies = [
3875
3875
 
3876
3876
  [[package]]
3877
3877
  name = "syn"
3878
- version = "2.0.114"
3878
+ version = "2.0.115"
3879
3879
  source = "registry+https://github.com/rust-lang/crates.io-index"
3880
- checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
3880
+ checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12"
3881
3881
  dependencies = [
3882
3882
  "proc-macro2",
3883
3883
  "quote",
@@ -3901,7 +3901,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
3901
3901
  dependencies = [
3902
3902
  "proc-macro2",
3903
3903
  "quote",
3904
- "syn 2.0.114",
3904
+ "syn 2.0.115",
3905
3905
  ]
3906
3906
 
3907
3907
  [[package]]
@@ -3986,7 +3986,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
3986
3986
  dependencies = [
3987
3987
  "proc-macro2",
3988
3988
  "quote",
3989
- "syn 2.0.114",
3989
+ "syn 2.0.115",
3990
3990
  ]
3991
3991
 
3992
3992
  [[package]]
@@ -4075,7 +4075,7 @@ dependencies = [
4075
4075
  "serde_json",
4076
4076
  "tauri-utils",
4077
4077
  "tauri-winres",
4078
- "toml 0.9.11+spec-1.1.0",
4078
+ "toml 0.9.12+spec-1.1.0",
4079
4079
  "walkdir",
4080
4080
  ]
4081
4081
 
@@ -4097,7 +4097,7 @@ dependencies = [
4097
4097
  "serde",
4098
4098
  "serde_json",
4099
4099
  "sha2",
4100
- "syn 2.0.114",
4100
+ "syn 2.0.115",
4101
4101
  "tauri-utils",
4102
4102
  "thiserror 2.0.18",
4103
4103
  "time",
@@ -4115,7 +4115,7 @@ dependencies = [
4115
4115
  "heck 0.5.0",
4116
4116
  "proc-macro2",
4117
4117
  "quote",
4118
- "syn 2.0.114",
4118
+ "syn 2.0.115",
4119
4119
  "tauri-codegen",
4120
4120
  "tauri-utils",
4121
4121
  ]
@@ -4133,7 +4133,7 @@ dependencies = [
4133
4133
  "serde",
4134
4134
  "serde_json",
4135
4135
  "tauri-utils",
4136
- "toml 0.9.11+spec-1.1.0",
4136
+ "toml 0.9.12+spec-1.1.0",
4137
4137
  "walkdir",
4138
4138
  ]
4139
4139
 
@@ -4312,7 +4312,7 @@ dependencies = [
4312
4312
  "serde_with",
4313
4313
  "swift-rs",
4314
4314
  "thiserror 2.0.18",
4315
- "toml 0.9.11+spec-1.1.0",
4315
+ "toml 0.9.12+spec-1.1.0",
4316
4316
  "url",
4317
4317
  "urlpattern",
4318
4318
  "uuid",
@@ -4327,7 +4327,7 @@ checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0"
4327
4327
  dependencies = [
4328
4328
  "dunce",
4329
4329
  "embed-resource",
4330
- "toml 0.9.11+spec-1.1.0",
4330
+ "toml 0.9.12+spec-1.1.0",
4331
4331
  ]
4332
4332
 
4333
4333
  [[package]]
@@ -4380,7 +4380,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
4380
4380
  dependencies = [
4381
4381
  "proc-macro2",
4382
4382
  "quote",
4383
- "syn 2.0.114",
4383
+ "syn 2.0.115",
4384
4384
  ]
4385
4385
 
4386
4386
  [[package]]
@@ -4391,7 +4391,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
4391
4391
  dependencies = [
4392
4392
  "proc-macro2",
4393
4393
  "quote",
4394
- "syn 2.0.114",
4394
+ "syn 2.0.115",
4395
4395
  ]
4396
4396
 
4397
4397
  [[package]]
@@ -4458,7 +4458,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
4458
4458
  dependencies = [
4459
4459
  "proc-macro2",
4460
4460
  "quote",
4461
- "syn 2.0.114",
4461
+ "syn 2.0.115",
4462
4462
  ]
4463
4463
 
4464
4464
  [[package]]
@@ -4508,9 +4508,9 @@ dependencies = [
4508
4508
 
4509
4509
  [[package]]
4510
4510
  name = "toml"
4511
- version = "0.9.11+spec-1.1.0"
4511
+ version = "0.9.12+spec-1.1.0"
4512
4512
  source = "registry+https://github.com/rust-lang/crates.io-index"
4513
- checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
4513
+ checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
4514
4514
  dependencies = [
4515
4515
  "indexmap 2.13.0",
4516
4516
  "serde_core",
@@ -4577,9 +4577,9 @@ dependencies = [
4577
4577
 
4578
4578
  [[package]]
4579
4579
  name = "toml_parser"
4580
- version = "1.0.6+spec-1.1.0"
4580
+ version = "1.0.7+spec-1.1.0"
4581
4581
  source = "registry+https://github.com/rust-lang/crates.io-index"
4582
- checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
4582
+ checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
4583
4583
  dependencies = [
4584
4584
  "winnow 0.7.14",
4585
4585
  ]
@@ -4654,7 +4654,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
4654
4654
  dependencies = [
4655
4655
  "proc-macro2",
4656
4656
  "quote",
4657
- "syn 2.0.114",
4657
+ "syn 2.0.115",
4658
4658
  ]
4659
4659
 
4660
4660
  [[package]]
@@ -4964,7 +4964,7 @@ dependencies = [
4964
4964
  "bumpalo",
4965
4965
  "proc-macro2",
4966
4966
  "quote",
4967
- "syn 2.0.114",
4967
+ "syn 2.0.115",
4968
4968
  "wasm-bindgen-shared",
4969
4969
  ]
4970
4970
 
@@ -5109,7 +5109,7 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54"
5109
5109
  dependencies = [
5110
5110
  "proc-macro2",
5111
5111
  "quote",
5112
- "syn 2.0.114",
5112
+ "syn 2.0.115",
5113
5113
  ]
5114
5114
 
5115
5115
  [[package]]
@@ -5236,7 +5236,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
5236
5236
  dependencies = [
5237
5237
  "proc-macro2",
5238
5238
  "quote",
5239
- "syn 2.0.114",
5239
+ "syn 2.0.115",
5240
5240
  ]
5241
5241
 
5242
5242
  [[package]]
@@ -5247,7 +5247,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
5247
5247
  dependencies = [
5248
5248
  "proc-macro2",
5249
5249
  "quote",
5250
- "syn 2.0.114",
5250
+ "syn 2.0.115",
5251
5251
  ]
5252
5252
 
5253
5253
  [[package]]
@@ -5626,7 +5626,7 @@ dependencies = [
5626
5626
  "heck 0.5.0",
5627
5627
  "indexmap 2.13.0",
5628
5628
  "prettyplease",
5629
- "syn 2.0.114",
5629
+ "syn 2.0.115",
5630
5630
  "wasm-metadata",
5631
5631
  "wit-bindgen-core",
5632
5632
  "wit-component",
@@ -5642,7 +5642,7 @@ dependencies = [
5642
5642
  "prettyplease",
5643
5643
  "proc-macro2",
5644
5644
  "quote",
5645
- "syn 2.0.114",
5645
+ "syn 2.0.115",
5646
5646
  "wit-bindgen-core",
5647
5647
  "wit-bindgen-rust",
5648
5648
  ]
@@ -5785,7 +5785,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
5785
5785
  dependencies = [
5786
5786
  "proc-macro2",
5787
5787
  "quote",
5788
- "syn 2.0.114",
5788
+ "syn 2.0.115",
5789
5789
  "synstructure",
5790
5790
  ]
5791
5791
 
@@ -5833,7 +5833,7 @@ dependencies = [
5833
5833
  "proc-macro-crate 3.4.0",
5834
5834
  "proc-macro2",
5835
5835
  "quote",
5836
- "syn 2.0.114",
5836
+ "syn 2.0.115",
5837
5837
  "zbus_names",
5838
5838
  "zvariant",
5839
5839
  "zvariant_utils",
@@ -5867,7 +5867,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
5867
5867
  dependencies = [
5868
5868
  "proc-macro2",
5869
5869
  "quote",
5870
- "syn 2.0.114",
5870
+ "syn 2.0.115",
5871
5871
  ]
5872
5872
 
5873
5873
  [[package]]
@@ -5887,7 +5887,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
5887
5887
  dependencies = [
5888
5888
  "proc-macro2",
5889
5889
  "quote",
5890
- "syn 2.0.114",
5890
+ "syn 2.0.115",
5891
5891
  "synstructure",
5892
5892
  ]
5893
5893
 
@@ -5927,7 +5927,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
5927
5927
  dependencies = [
5928
5928
  "proc-macro2",
5929
5929
  "quote",
5930
- "syn 2.0.114",
5930
+ "syn 2.0.115",
5931
5931
  ]
5932
5932
 
5933
5933
  [[package]]
@@ -5944,9 +5944,9 @@ dependencies = [
5944
5944
 
5945
5945
  [[package]]
5946
5946
  name = "zmij"
5947
- version = "1.0.20"
5947
+ version = "1.0.21"
5948
5948
  source = "registry+https://github.com/rust-lang/crates.io-index"
5949
- checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7"
5949
+ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
5950
5950
 
5951
5951
  [[package]]
5952
5952
  name = "zvariant"
@@ -5971,7 +5971,7 @@ dependencies = [
5971
5971
  "proc-macro-crate 3.4.0",
5972
5972
  "proc-macro2",
5973
5973
  "quote",
5974
- "syn 2.0.114",
5974
+ "syn 2.0.115",
5975
5975
  "zvariant_utils",
5976
5976
  ]
5977
5977
 
@@ -5984,6 +5984,6 @@ dependencies = [
5984
5984
  "proc-macro2",
5985
5985
  "quote",
5986
5986
  "serde",
5987
- "syn 2.0.114",
5987
+ "syn 2.0.115",
5988
5988
  "winnow 0.7.14",
5989
5989
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rds-ssm-connect"
3
- version = "1.7.14"
3
+ version = "1.7.16"
4
4
  description = "Secure RDS connections through AWS SSM"
5
5
  authors = ["Iaroslav Pyrogov"]
6
6
  edition = "2024"
@@ -818,6 +818,8 @@ async fn install_update(app_handle: AppHandle) -> Result<(), String> {
818
818
  .await
819
819
  .map_err(|e| format!("Failed to download/install update: {}", e))?;
820
820
 
821
+ app_handle.restart();
822
+
821
823
  Ok(())
822
824
  }
823
825
 
@@ -836,7 +838,31 @@ async fn open_url(app_handle: AppHandle, url: String) -> Result<(), String> {
836
838
  }
837
839
 
838
840
  #[tauri::command]
839
- async fn quit_app(app_handle: AppHandle) -> Result<(), String> {
841
+ async fn quit_app(
842
+ app_handle: AppHandle,
843
+ state: tauri::State<'_, Arc<TokioMutex<SidecarState>>>,
844
+ ) -> Result<(), String> {
845
+ // Take the sidecar child out (releases the lock before sleeping)
846
+ let child_to_kill = {
847
+ let mut guard = state.lock().await;
848
+ guard.child.take()
849
+ };
850
+
851
+ if let Some(child) = child_to_kill {
852
+ // Send SIGTERM first so the sidecar's cleanup handlers fire
853
+ // (disconnects all connections and kills process trees)
854
+ let pid = child.pid();
855
+ let _ = std::process::Command::new("kill")
856
+ .args(["-TERM", &pid.to_string()])
857
+ .status();
858
+
859
+ // Brief wait for graceful shutdown
860
+ tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
861
+
862
+ // Force-kill if still alive
863
+ let _ = child.kill();
864
+ }
865
+
840
866
  app_handle.exit(0);
841
867
  Ok(())
842
868
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://schema.tauri.app/config/2",
3
3
  "productName": "RDS SSM Connect",
4
- "version": "1.7.14",
4
+ "version": "1.7.16",
5
5
  "identifier": "com.rds-ssm-connect.desktop",
6
6
  "build": {
7
7
  "beforeDevCommand": "npm run dev:vite",