messhy 0.9.0 → 0.9.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14432b60b44c17938ab995bb9e9ca0a360f1381bbfe4f746e3bcc6a07be2e658
4
- data.tar.gz: d98203d9b327d971f61e81022611e0f54d9e08673d381ae57fa27b58a55dabeb
3
+ metadata.gz: fd61d3c3a60ea6d3f5decc20c10c17168607ff1e752e688ad0aec6f22c37be79
4
+ data.tar.gz: b6552633a9762e716b3bee6380c318eecefd8e3280fb44a100bd921f4c82c816
5
5
  SHA512:
6
- metadata.gz: c8db3c1b1b7f71680e565c0373b463f4c749d4be645a90f587970a8955ef95d1684dffe2bf46d4cbbaf4de763e4d21482ed7c9e8aa72d4a64c56190c1076038b
7
- data.tar.gz: 2e59b8e950931e8f27a4f004a5e9e381176ced1cb670fd16f03045ea4ee0856a2f81e577a5fc07fc5b535d4bd45218989db72b896ec0ab18cfe003af864517aa
6
+ metadata.gz: c2a44398671a4801cab1170cc5889ac55c4da1ffa1005422664d8b783ee30933eca79c30ccdd2b905b36cc7c82b9049ae97fec9ddc61fd11e42611682dd92ac1
7
+ data.tar.gz: e159a7b8575b572f348d10867a6ff3797bc765d87552b134eb8ea1d2a910359a24b54b7e66023633bac4725af5adaf846558b1c998429e1c4b7a06546fb63ad0
data/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.1] - 2026-09-02
11
+
12
+ ### Fixed
13
+
14
+ - Preserve live peers outside the source-owned mesh during reconciliation.
15
+ Exact-source pruning is available only through the explicit `--prune` option.
16
+
10
17
  ## [0.9.0] - 2026-09-02
11
18
 
12
19
  ### Added
data/README.md CHANGED
@@ -178,8 +178,11 @@ messhy reconcile --environment=production
178
178
  `import-keys` writes the same mode-`0600` local secret files as initial setup
179
179
  and never prints key material. `reconcile` validates each candidate config,
180
180
  applies active peer changes with `wg syncconf`, and restores the previous config
181
- if a live sync fails. Set `ssh_known_hosts_file` to a reviewed file when the
182
- mesh should not depend on the operator's global SSH configuration.
181
+ if a live sync fails. Existing peers outside the source configuration are
182
+ preserved by default so another system can own adjacent mesh members. Pass
183
+ `--prune` only when the source configuration should remove those peers. Set
184
+ `ssh_known_hosts_file` to a reviewed file when the mesh should not depend on
185
+ the operator's global SSH configuration.
183
186
 
184
187
  ### Status & Monitoring
185
188
 
data/lib/messhy/cli.rb CHANGED
@@ -28,9 +28,10 @@ module Messhy
28
28
 
29
29
  desc 'reconcile', 'Apply mesh changes without restarting active WireGuard interfaces'
30
30
  option :dry_run, type: :boolean, default: false
31
+ option :prune, type: :boolean, default: false, desc: 'Remove live peers absent from the source configuration'
31
32
  def reconcile
32
33
  config = load_config
33
- Installer.new(config, dry_run: options[:dry_run]).reconcile
34
+ Installer.new(config, dry_run: options[:dry_run], prune: options[:prune]).reconcile
34
35
  rescue SSHKit::Runner::ExecuteError => e
35
36
  handle_ssh_error(e, config)
36
37
  end
@@ -9,11 +9,12 @@ require 'base64'
9
9
  module Messhy
10
10
  # rubocop:disable Metrics/ClassLength
11
11
  class Installer
12
- attr_reader :config, :dry_run, :ssh_executor
12
+ attr_reader :config, :dry_run, :prune, :ssh_executor
13
13
 
14
- def initialize(config, dry_run: false, ssh_executor: SSHExecutor.new(config))
14
+ def initialize(config, dry_run: false, prune: false, ssh_executor: SSHExecutor.new(config))
15
15
  @config = config
16
16
  @dry_run = dry_run
17
+ @prune = prune
17
18
  @ssh_executor = ssh_executor
18
19
  @node_keys = load_existing_keys
19
20
  @psk_map = load_existing_psks
@@ -52,6 +53,7 @@ module Messhy
52
53
  if dry_run
53
54
  puts " [DRY RUN] Would reconcile #{node_name}"
54
55
  else
56
+ config_content = preserve_unmanaged_peers(node_name, config_content) unless prune
55
57
  ssh_executor.reconcile_config(node_name, config_content)
56
58
  puts " ✓ Reconciled #{node_name}"
57
59
  end
@@ -179,6 +181,12 @@ module Messhy
179
181
 
180
182
  private
181
183
 
184
+ def preserve_unmanaged_peers(node_name, config_content)
185
+ current = WireguardConfig.parse(ssh_executor.read_wireguard_config(node_name))
186
+ managed_peer_names = config.node_names - [node_name]
187
+ current.preserve_unmanaged_peers_in(config_content, managed_peer_names: managed_peer_names)
188
+ end
189
+
182
190
  def validate_imported_address!(node_name, node_config, snapshot)
183
191
  address = snapshot.interface['Address'].to_s.split('/').first
184
192
  return if address == node_config['mesh_ip']
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Messhy
4
- VERSION = '0.9.0'
4
+ VERSION = '0.9.1'
5
5
  end
@@ -36,5 +36,33 @@ module Messhy
36
36
 
37
37
  self
38
38
  end
39
+
40
+ def preserve_unmanaged_peers_in(candidate_content, managed_peer_names:)
41
+ candidate = self.class.parse(candidate_content)
42
+ candidate_public_keys = candidate.peers.filter_map { |peer| peer['PublicKey'] }
43
+ managed_peer_names = managed_peer_names.to_set
44
+
45
+ unmanaged_peers = peers.reject do |peer|
46
+ managed_peer_names.include?(peer['Name']) || candidate_public_keys.include?(peer['PublicKey'])
47
+ end
48
+
49
+ return candidate_content if unmanaged_peers.empty?
50
+
51
+ [candidate_content.rstrip, *unmanaged_peers.map { |peer| render_peer(peer) }, ''].join("\n\n")
52
+ end
53
+
54
+ private
55
+
56
+ def render_peer(peer)
57
+ lines = []
58
+ lines << "# Peer: #{peer['Name']}" if peer['Name']
59
+ lines << '[Peer]'
60
+ peer.each do |key, value|
61
+ next if key == 'Name'
62
+
63
+ lines << "#{key} = #{value}"
64
+ end
65
+ lines.join("\n")
66
+ end
39
67
  end
40
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: messhy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - BoringCache