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 +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +1 -1
- data/lib/ruborg/backup.rb +36 -4
- data/lib/ruborg/passbolt.rb +26 -4
- data/lib/ruborg/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8b7697818fdf4537e02f840cb2f30c71cc3cbd6bbfc8cb8b72fe4bba7908deac
|
|
4
|
+
data.tar.gz: 2c509aec3d6586f7f3ea85aa84a621516e8ea73cd191ff325f8c33f056eb5a15
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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 (
|
|
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
|
|
data/lib/ruborg/passbolt.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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)
|
data/lib/ruborg/version.rb
CHANGED