ruborg 0.7.1 → 0.7.4

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: 5b1659a54e64ed15742467c6e95ea96fd311f0332e2fafdee7e560cec5c2385c
4
- data.tar.gz: ec49de1e1231ad2bd189e08aedb70d22ec10f4f322f1b4690c9c3ec41be590bb
3
+ metadata.gz: 8b7697818fdf4537e02f840cb2f30c71cc3cbd6bbfc8cb8b72fe4bba7908deac
4
+ data.tar.gz: 2c509aec3d6586f7f3ea85aa84a621516e8ea73cd191ff325f8c33f056eb5a15
5
5
  SHA512:
6
- metadata.gz: '0593d8521ab13110b3fefe00b9a1bc3cd6a8c28ffa70e93dda6e3bfa6b763f0562abd564af25a14c5619b2fe7dabb7ef76ffbe1341c6dcdb4dcac7efbb7be847'
7
- data.tar.gz: 9486465c9803962569b5f376556efafa8147d72a294e9a6e3137d29e67c9664b212bed69addc0bab0ad434ddc5f42416e3aa7426087bbf4dd7c9a4ce2c71192f
6
+ metadata.gz: 711e51216fcc8e7522d32567f4a1759dccadb2d9691599b6408eb2f46187586dca3e837b45f7a7044a15117747b3a39ff5b083254ada2fd64f8e88f1c01e9f22
7
+ data.tar.gz: d7d2a732e8fbf38b33a2a5b39d35a820b98f22d3515656663c4e64fc8b589ca7ad5f49441e00f0b117118b04fe13c6ca036c28bcc6109b387a67275b5b8e7d1d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.4] - 2025-10-09
11
+
12
+ ### Fixed
13
+ - **Passbolt Error Reporting**: Enhanced error handling for Passbolt CLI failures
14
+ - Now captures and logs stderr from Passbolt CLI commands
15
+ - Error messages include actual Passbolt CLI output for easier debugging
16
+ - Improved error logging with detailed failure context
17
+
18
+ ### Changed
19
+ - **Passbolt Environment Variables**: Passbolt env vars now explicitly passed to subprocess
20
+ - Preserves `PASSBOLT_SERVER_ADDRESS`, `PASSBOLT_USER_PRIVATE_KEY_FILE`, `PASSBOLT_USER_PASSWORD`
21
+ - Also preserves `PASSBOLT_GPG_HOME` and `PASSBOLT_CONFIG`
22
+ - Ensures Passbolt CLI has access to required configuration when run by Ruborg
23
+
24
+ ## [0.7.3] - 2025-10-09
25
+
26
+ ### Changed
27
+ - **Smart Remove-Source for Skipped Files**: Skipped files (unchanged, already backed up) are now deleted when `--remove-source` is used
28
+ - Previously: Only newly backed-up files were deleted, skipped files remained
29
+ - Now: Both backed-up AND skipped files are deleted (they're all safely backed up)
30
+ - Rationale: If a file is skipped because it's already in an archive (verified by hash), it's safe to delete
31
+ - Makes `--remove-source` behavior consistent: "delete everything that's safely backed up"
32
+
33
+ ### Technical Details
34
+ - Per-file mode verifies files are safely backed up before skipping (path + size + SHA256 hash match)
35
+ - Skipped files are deleted immediately after verification (lib/ruborg/backup.rb:102)
36
+ - Test updated to verify skipped files are deleted (spec/ruborg/per_file_backup_spec.rb:518)
37
+
38
+ ## [0.7.2] - 2025-10-09
39
+
40
+ ### Fixed
41
+ - **Per-File Remove Source Behavior**: Files are now deleted immediately after each successful backup in per-file mode
42
+ - Previously deleted entire source paths at the end (dangerous - could delete unchanged files)
43
+ - Now deletes only successfully backed-up files, one at a time
44
+ - Skipped files (unchanged) are never deleted
45
+ - Matches the per-file philosophy: individual file handling throughout the backup process
46
+
47
+ ### Added
48
+ - **Test Coverage**: Added 2 new RSpec tests verifying per-file remove-source behavior
49
+ - Tests immediate file deletion after backup
50
+ - Tests that skipped files are not deleted
51
+
10
52
  ## [0.7.1] - 2025-10-08
11
53
 
12
54
  ### Added
data/README.md CHANGED
@@ -25,7 +25,7 @@ A friendly Ruby frontend for [Borg Backup](https://www.borgbackup.org/). Ruborg
25
25
  - 📈 **Summary View** - Quick overview of all repositories and their configurations
26
26
  - 🔧 **Custom Borg Path** - Support for custom Borg executable paths per repository
27
27
  - 🏠 **Hostname Validation** - NEW! Restrict backups to specific hosts (global or per-repository)
28
- - ✅ **Well-tested** - Comprehensive test suite with RSpec (286+ examples)
28
+ - ✅ **Well-tested** - Comprehensive test suite with RSpec (288+ examples)
29
29
  - 🔒 **Security-focused** - Path validation, safe YAML loading, command injection protection
30
30
 
31
31
  ## Prerequisites
data/lib/ruborg/backup.rb CHANGED
@@ -91,12 +91,16 @@ module Ruborg
91
91
  stored_hash = stored_info[:hash]
92
92
 
93
93
  if current_hash == stored_hash
94
- # Content truly unchanged
94
+ # Content truly unchanged - file is already safely backed up
95
95
  puts " - Archive already exists (file unchanged)"
96
96
  @logger&.info(
97
97
  "[#{@repo_name}] Skipped #{file_path} - archive #{archive_name} already exists (file unchanged)"
98
98
  )
99
99
  skipped_count += 1
100
+
101
+ # If remove_source is enabled, delete the file (it's already safely backed up)
102
+ remove_single_file(file_path) if remove_source
103
+
100
104
  next
101
105
  else
102
106
  # Size same but content changed (rare: edited + truncated/padded to same size)
@@ -131,6 +135,9 @@ module Ruborg
131
135
  # Log successful action with details
132
136
  @logger&.info("[#{@repo_name}] Archived #{file_path} in archive #{archive_name}")
133
137
  backed_up_count += 1
138
+
139
+ # Remove source file immediately after successful backup in per-file mode
140
+ remove_single_file(file_path) if remove_source
134
141
  end
135
142
  # rubocop:enable Metrics/BlockLength
136
143
 
@@ -139,9 +146,6 @@ module Ruborg
139
146
  else
140
147
  puts "✓ Per-file backup completed: #{backed_up_count} file(s) backed up"
141
148
  end
142
-
143
- # NOTE: remove_source handled per file after successful backup
144
- remove_source_files if remove_source
145
149
  end
146
150
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/BlockNesting
147
151
 
@@ -333,6 +337,34 @@ module Ruborg
333
337
  result
334
338
  end
335
339
 
340
+ def remove_single_file(file_path)
341
+ require "fileutils"
342
+
343
+ # Resolve symlinks and validate path
344
+ begin
345
+ real_path = File.realpath(file_path)
346
+ rescue Errno::ENOENT
347
+ # File doesn't exist (already deleted?), skip
348
+ @logger&.warn("Source file does not exist, skipping: #{file_path}")
349
+ return
350
+ end
351
+
352
+ # Security check: ensure file still exists
353
+ unless File.exist?(real_path)
354
+ @logger&.warn("Source file no longer exists, skipping: #{real_path}")
355
+ return
356
+ end
357
+
358
+ # Additional safety: don't delete system files
359
+ if real_path == "/" || real_path.start_with?("/bin", "/sbin", "/usr", "/etc", "/sys", "/proc")
360
+ @logger&.error("Refusing to delete system path: #{real_path}")
361
+ raise BorgError, "Refusing to delete system path: #{real_path}"
362
+ end
363
+
364
+ @logger&.info("Removing file: #{real_path}")
365
+ FileUtils.rm(real_path)
366
+ end
367
+
336
368
  def remove_source_files
337
369
  require "fileutils"
338
370
 
@@ -17,11 +17,12 @@ module Ruborg
17
17
  @logger&.info("Retrieving password from Passbolt (resource_id: #{@resource_id})")
18
18
 
19
19
  cmd = ["passbolt", "get", "resource", "--id", @resource_id, "--json"]
20
- output, status = execute_command(cmd)
20
+ output, status, error_msg = execute_command(cmd)
21
21
 
22
22
  unless status
23
23
  @logger&.error("Failed to retrieve password from Passbolt for resource #{@resource_id}")
24
- raise PassboltError, "Failed to retrieve password from Passbolt"
24
+ error_detail = error_msg ? ": #{error_msg}" : ""
25
+ raise PassboltError, "Failed to retrieve password from Passbolt#{error_detail}"
25
26
  end
26
27
 
27
28
  @logger&.info("Successfully retrieved password from Passbolt")
@@ -38,8 +39,29 @@ module Ruborg
38
39
 
39
40
  def execute_command(cmd)
40
41
  require "open3"
41
- stdout, _, status = Open3.capture3(*cmd)
42
- [stdout, status.success?]
42
+
43
+ # Preserve Passbolt environment variables
44
+ env = {}
45
+ %w[
46
+ PASSBOLT_SERVER_ADDRESS
47
+ PASSBOLT_USER_PRIVATE_KEY_FILE
48
+ PASSBOLT_USER_PASSWORD
49
+ PASSBOLT_GPG_HOME
50
+ PASSBOLT_CONFIG
51
+ ].each do |var|
52
+ env[var] = ENV[var] if ENV[var]
53
+ end
54
+
55
+ stdout, stderr, status = Open3.capture3(env, *cmd)
56
+
57
+ # Log stderr if command failed
58
+ error_msg = nil
59
+ if !status.success? && !stderr.strip.empty?
60
+ error_msg = stderr.strip
61
+ @logger&.error("Passbolt CLI error: #{error_msg}")
62
+ end
63
+
64
+ [stdout, status.success?, error_msg]
43
65
  end
44
66
 
45
67
  def parse_password(json_output)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruborg
4
- VERSION = "0.7.1"
4
+ VERSION = "0.7.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruborg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michail Pantelelis