ruborg 0.3.1 → 0.4.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.
data/README.md CHANGED
@@ -17,7 +17,14 @@ A friendly Ruby frontend for [Borg Backup](https://www.borgbackup.org/). Ruborg
17
17
  - 📊 **Logging** - Comprehensive logging with daily rotation
18
18
  - 🗄️ **Multi-Repository** - Manage multiple backup repositories with different sources
19
19
  - 🔄 **Auto-initialization** - Automatically initialize repositories on first use
20
- - **Well-tested** - Comprehensive test suite with RSpec
20
+ e- **Retention Policies** - Configure backup retention (hourly, daily, weekly, monthly, yearly)
21
+ - 🗑️ **Automatic Pruning** - Automatically remove old backups based on retention policies
22
+ - 📁 **Per-File Backup Mode** - NEW! Backup each file as a separate archive with metadata-based retention
23
+ - 🕒 **File Metadata Retention** - NEW! Prune based on file modification time, works even after files are deleted
24
+ - 📋 **Repository Descriptions** - Document each repository's purpose
25
+ - 📈 **Summary View** - Quick overview of all repositories and their configurations
26
+ - 🔧 **Custom Borg Path** - Support for custom Borg executable paths per repository
27
+ - ✅ **Well-tested** - Comprehensive test suite with RSpec (147 tests)
21
28
  - 🔒 **Security-focused** - Path validation, safe YAML loading, command injection protection
22
29
 
23
30
  ## Prerequisites
@@ -66,64 +73,44 @@ gem install ruborg
66
73
 
67
74
  ## Configuration
68
75
 
69
- Ruborg supports two configuration formats: **single repository** (legacy) and **multi-repository** (recommended for complex setups).
76
+ Create your configuration file from the example template:
70
77
 
71
- ### Single Repository Configuration
72
-
73
- ```yaml
74
- # Repository path
75
- repository: /path/to/borg/repository
76
-
77
- # Paths to backup
78
- backup_paths:
79
- - /home/user/documents
80
- - /home/user/projects
81
-
82
- # Exclude patterns
83
- exclude_patterns:
84
- - "*.tmp"
85
- - "*.log"
86
-
87
- # Compression algorithm (lz4, zstd, zlib, lzma, none)
88
- compression: lz4
89
-
90
- # Encryption mode (repokey, keyfile, none)
91
- encryption: repokey
92
-
93
- # Passbolt integration (optional)
94
- passbolt:
95
- resource_id: "your-passbolt-resource-uuid"
96
-
97
- # Auto-initialize repository (optional, default: false)
98
- auto_init: true
99
-
100
- # Log file path (optional, default: ~/.ruborg/logs/ruborg.log)
101
- log_file: /var/log/ruborg.log
102
-
103
- # Borg environment options (optional)
104
- borg_options:
105
- allow_relocated_repo: true # Allow relocated repositories (default: true)
106
- allow_unencrypted_repo: true # Allow unencrypted repositories (default: true)
78
+ ```bash
79
+ cp ruborg.yml.example ruborg.yml
80
+ chmod 600 ruborg.yml # Important: protect your configuration
107
81
  ```
108
82
 
109
- ### Multi-Repository Configuration
110
-
111
- For managing multiple repositories with different sources:
83
+ Then edit `ruborg.yml` with your settings. Ruborg uses a multi-repository YAML configuration format:
112
84
 
113
85
  ```yaml
114
86
  # Global settings (applied to all repositories unless overridden)
115
87
  compression: lz4
116
88
  encryption: repokey
117
89
  auto_init: true
90
+ log_file: /var/log/ruborg.log
91
+
92
+ # Custom Borg executable path (optional)
93
+ # Use this if borg is not in PATH or you want to use a specific version
94
+ # borg_path: /usr/local/bin/borg
95
+
118
96
  passbolt:
119
97
  resource_id: "global-passbolt-id"
120
98
  borg_options:
121
99
  allow_relocated_repo: false
122
100
  allow_unencrypted_repo: false
123
101
 
102
+ # Global retention policy (can be overridden per repository)
103
+ retention:
104
+ keep_hourly: 24 # Keep 24 hourly backups
105
+ keep_daily: 7 # Keep 7 daily backups
106
+ keep_weekly: 4 # Keep 4 weekly backups
107
+ keep_monthly: 6 # Keep 6 monthly backups
108
+ keep_yearly: 1 # Keep 1 yearly backup
109
+
124
110
  # Multiple repositories
125
111
  repositories:
126
112
  - name: documents
113
+ description: "Personal and work documents backup"
127
114
  path: /mnt/backup/documents
128
115
  sources:
129
116
  - name: home-docs
@@ -138,10 +125,18 @@ repositories:
138
125
  - "*.log"
139
126
 
140
127
  - name: databases
128
+ description: "MySQL and PostgreSQL database dumps"
141
129
  path: /mnt/backup/databases
142
130
  # Repository-specific passbolt (overrides global)
143
131
  passbolt:
144
132
  resource_id: "db-specific-passbolt-id"
133
+ # Repository-specific retention (overrides global)
134
+ retention:
135
+ keep_daily: 14
136
+ keep_weekly: 8
137
+ keep_monthly: 12
138
+ # Repository-specific borg executable path (optional)
139
+ # borg_path: /opt/borg-2.0/bin/borg
145
140
  sources:
146
141
  - name: mysql
147
142
  paths:
@@ -149,14 +144,29 @@ repositories:
149
144
  - name: postgres
150
145
  paths:
151
146
  - /var/lib/postgresql/dumps
147
+
148
+ - name: media
149
+ description: "Photos and videos archive"
150
+ path: /mnt/backup/media
151
+ # Override compression for large media files
152
+ compression: lz4
153
+ retention:
154
+ keep_weekly: 2
155
+ keep_monthly: 3
156
+ sources:
157
+ - name: photos
158
+ paths:
159
+ - /home/user/Pictures
152
160
  ```
153
161
 
154
- **Multi-repo benefits:**
155
- - Organize backups by type (documents, databases, media)
156
- - Different encryption keys per repository
157
- - Multiple sources per repository
158
- - Per-source exclude patterns
159
- - Repository-specific settings override global ones
162
+ **Configuration Features:**
163
+ - **Descriptions**: Add `description` field to document each repository's purpose
164
+ - **Global Settings**: Compression, encryption, auto_init, log_file, borg_path, borg_options, and retention apply to all repositories
165
+ - **Per-Repository Overrides**: Any global setting can be overridden at the repository level (including custom borg_path per repository)
166
+ - **Custom Borg Path**: Specify a custom Borg executable path if borg is not in PATH or to use a specific version
167
+ - **Retention Policies**: Define how many backups to keep (hourly, daily, weekly, monthly, yearly)
168
+ - **Multiple Sources**: Each repository can have multiple backup sources with their own exclude patterns
169
+ - **Flexible Organization**: Organize backups by type (documents, databases, media) with different policies
160
170
 
161
171
  ## Usage
162
172
 
@@ -172,22 +182,6 @@ ruborg init /path/to/repository --passbolt-id "resource-uuid"
172
182
 
173
183
  ### Create a Backup
174
184
 
175
- **Single repository:**
176
- ```bash
177
- # Using default configuration (ruborg.yml)
178
- ruborg backup
179
-
180
- # Using custom configuration file
181
- ruborg backup --config /path/to/config.yml
182
-
183
- # With custom archive name
184
- ruborg backup --name "my-backup-2025-10-04"
185
-
186
- # Remove source files after successful backup
187
- ruborg backup --remove-source
188
- ```
189
-
190
- **Multi-repository:**
191
185
  ```bash
192
186
  # Backup specific repository
193
187
  ruborg backup --repository documents
@@ -197,31 +191,82 @@ ruborg backup --all
197
191
 
198
192
  # Backup specific repository with custom name
199
193
  ruborg backup --repository databases --name "db-backup-2025-10-05"
194
+
195
+ # Using custom configuration file
196
+ ruborg backup --config /path/to/config.yml --repository documents
197
+
198
+ # Remove source files after successful backup
199
+ ruborg backup --repository documents --remove-source
200
200
  ```
201
201
 
202
202
  ### List Archives
203
203
 
204
204
  ```bash
205
- ruborg list
205
+ # List archives for a specific repository
206
+ ruborg list --repository documents
206
207
  ```
207
208
 
208
209
  ### Restore from Archive
209
210
 
210
211
  ```bash
211
212
  # Restore entire archive to current directory
212
- ruborg restore archive-name
213
+ ruborg restore archive-name --repository documents
213
214
 
214
215
  # Restore to specific directory
215
- ruborg restore archive-name --destination /path/to/restore
216
+ ruborg restore archive-name --repository documents --destination /path/to/restore
216
217
 
217
218
  # Restore a single file from archive
218
- ruborg restore archive-name --path /path/to/file.txt --destination /new/location
219
+ ruborg restore archive-name --repository documents --path /path/to/file.txt --destination /new/location
219
220
  ```
220
221
 
221
222
  ### View Repository Information
222
223
 
223
224
  ```bash
225
+ # Show summary of all configured repositories
224
226
  ruborg info
227
+
228
+ # View detailed info for a specific repository
229
+ ruborg info --repository documents
230
+ ```
231
+
232
+ The `info` command without `--repository` displays a summary showing:
233
+ - Global configuration settings
234
+ - All configured repositories with their descriptions
235
+ - Retention policies (global and per-repository overrides)
236
+ - Number of sources per repository
237
+
238
+ ### Check Repository Compatibility
239
+
240
+ ```bash
241
+ # Check specific repository compatibility with installed Borg version
242
+ ruborg check --repository documents
243
+
244
+ # Check all repositories
245
+ ruborg check --all
246
+
247
+ # Check with data integrity verification (slower)
248
+ ruborg check --repository documents --verify-data
249
+ ```
250
+
251
+ The `check` command verifies:
252
+ - Installed Borg version
253
+ - Repository format version
254
+ - Compatibility between Borg and repository versions
255
+ - Optionally: Repository data integrity (with `--verify-data`)
256
+
257
+ **Example output:**
258
+ ```
259
+ Borg version: 1.2.8
260
+
261
+ --- Checking repository: documents ---
262
+ Repository version: 1
263
+ ✓ Compatible with Borg 1.2.8
264
+
265
+ --- Checking repository: databases ---
266
+ Repository version: 2
267
+ ✗ INCOMPATIBLE with Borg 1.2.8
268
+ Repository version 2 cannot be read by Borg 1.2.8
269
+ Please upgrade Borg or migrate the repository
225
270
  ```
226
271
 
227
272
  ## Logging
@@ -278,15 +323,17 @@ Ruborg will automatically retrieve the passphrase when performing backup operati
278
323
 
279
324
  ## Auto-initialization
280
325
 
281
- Set `auto_init: true` in your configuration file to automatically initialize the repository on first use:
326
+ Set `auto_init: true` in the global settings or per-repository to automatically initialize repositories on first use:
282
327
 
283
328
  ```yaml
284
- repository: /path/to/borg/repository
285
329
  auto_init: true
286
- passbolt:
287
- resource_id: "your-passbolt-resource-uuid"
288
- backup_paths:
289
- - /path/to/backup
330
+ repositories:
331
+ - name: documents
332
+ path: /path/to/borg/repository
333
+ sources:
334
+ - name: main
335
+ paths:
336
+ - /path/to/backup
290
337
  ```
291
338
 
292
339
  When enabled, ruborg will automatically run `borg init` if the repository doesn't exist when you run `backup`, `list`, or `info` commands. The passphrase will be retrieved from Passbolt if configured.
@@ -323,21 +370,231 @@ See [SECURITY.md](SECURITY.md) for detailed security information and best practi
323
370
  | Command | Description | Options |
324
371
  |---------|-------------|---------|
325
372
  | `init REPOSITORY` | Initialize a new Borg repository | `--passphrase`, `--passbolt-id`, `--log` |
326
- | `backup` | Create a backup using config file | `--config`, `--name`, `--remove-source`, `--repository`, `--all`, `--log` |
373
+ | `backup` | Create a backup using config file | `--config`, `--repository`, `--all`, `--name`, `--remove-source`, `--log` |
327
374
  | `list` | List all archives in repository | `--config`, `--repository`, `--log` |
328
- | `restore ARCHIVE` | Restore files from archive | `--config`, `--destination`, `--path`, `--repository`, `--log` |
375
+ | `restore ARCHIVE` | Restore files from archive | `--config`, `--repository`, `--destination`, `--path`, `--log` |
329
376
  | `info` | Show repository information | `--config`, `--repository`, `--log` |
377
+ | `check` | Check repository integrity and compatibility | `--config`, `--repository`, `--all`, `--verify-data`, `--log` |
330
378
 
331
- ### Global Options
379
+ ### Options
332
380
 
333
381
  - `--config`: Path to configuration file (default: `ruborg.yml`)
334
382
  - `--log`: Path to log file (overrides config, default: `~/.ruborg/logs/ruborg.log`)
335
- - `--repository` / `-r`: Repository name (required for multi-repo configs)
383
+ - `--repository` / `-r`: Repository name (optional for info, required for backup/list/restore/check unless --all)
384
+ - `--all`: Process all repositories (backup and check commands)
385
+ - `--name`: Custom archive name (backup command only)
386
+ - `--remove-source`: Remove source files after successful backup (backup command only)
387
+ - `--destination`: Destination directory for restore (restore command only)
388
+ - `--path`: Specific file or directory to restore (restore command only)
389
+ - `--verify-data`: Run full data integrity check (check command only, slower)
390
+
391
+ ## Retention Policies
336
392
 
337
- ### Multi-Repository Options
393
+ Retention policies define how many backups to keep. You can use **count-based rules**, **time-based rules**, or **both together** for maximum flexibility.
338
394
 
339
- - `--all`: Backup all repositories (multi-repo config only)
340
- - `--repository NAME`: Target specific repository by name
395
+ ### Count-based Retention
396
+
397
+ Keep a specific number of backups for each time interval:
398
+
399
+ ```yaml
400
+ retention:
401
+ keep_hourly: 24 # Keep last 24 hourly backups
402
+ keep_daily: 7 # Keep last 7 daily backups
403
+ keep_weekly: 4 # Keep last 4 weekly backups
404
+ keep_monthly: 6 # Keep last 6 monthly backups
405
+ keep_yearly: 1 # Keep last 1 yearly backup
406
+ ```
407
+
408
+ ### Time-based Retention
409
+
410
+ Keep backups based on time periods:
411
+
412
+ ```yaml
413
+ retention:
414
+ keep_within: "7d" # Keep ALL backups within last 7 days
415
+ keep_last: "30d" # Keep at least one backup from last 30 days
416
+ ```
417
+
418
+ ### Combining Time-based and Count-based Rules
419
+
420
+ **Yes, you can combine both types!** When you use both time-based and count-based rules together, they work **additively** - Borg keeps the **union** of all matching backups.
421
+
422
+ ```yaml
423
+ retention:
424
+ keep_within: "2d" # Keep everything from last 2 days
425
+ keep_daily: 7 # PLUS keep 7 daily backups (goes back ~7 days)
426
+ keep_weekly: 4 # PLUS keep 4 weekly backups (goes back ~4 weeks)
427
+ keep_monthly: 6 # PLUS keep 6 monthly backups (goes back ~6 months)
428
+ ```
429
+
430
+ **How this works:** Borg will keep a backup if it matches **ANY** of these rules:
431
+ - Backup is within the last 2 days, OR
432
+ - Backup is one of the last 7 daily backups, OR
433
+ - Backup is one of the last 4 weekly backups, OR
434
+ - Backup is one of the last 6 monthly backups
435
+
436
+ **Practical example:**
437
+
438
+ ```yaml
439
+ # Database backups - keep recent changes, long-term history
440
+ retention:
441
+ keep_within: "1d" # Everything from last 24 hours (frequent changes)
442
+ keep_daily: 14 # Plus 14 days of daily backups (2 weeks)
443
+ keep_weekly: 8 # Plus 8 weeks of weekly backups (2 months)
444
+ keep_monthly: 12 # Plus 12 months of monthly backups (1 year)
445
+ keep_yearly: 3 # Plus 3 years of yearly backups
446
+ ```
447
+
448
+ This configuration provides:
449
+ - **Maximum detail** for recent backups (last 24 hours - every backup kept)
450
+ - **Daily granularity** for the last 2 weeks
451
+ - **Weekly granularity** for the last 2 months
452
+ - **Monthly granularity** for the last year
453
+ - **Yearly snapshots** for long-term compliance
454
+
455
+ **Time format:** Use suffixes like `d` (days), `w` (weeks), `m` (months), `y` (years). Examples: `7d`, `4w`, `6m`, `1y`
456
+
457
+ **Configuration notes:**
458
+ - Policies can be set globally and overridden per repository
459
+ - All fields are optional - use only what you need
460
+ - `keep_within`: Keeps **all** archives created within the specified time period
461
+ - `keep_last`: Ensures at least one backup from the last specified time period is kept
462
+ - **Rules are additive** - combining rules keeps MORE backups, not fewer
463
+ - Retention settings are displayed in the `ruborg info` summary
464
+
465
+ ### Per-File Backup Mode with File Metadata Retention
466
+
467
+ **NEW:** Ruborg supports a per-file backup mode where each file is backed up as a separate archive. This enables intelligent retention based on **file modification time** rather than backup creation time.
468
+
469
+ **Use Case:** Keep backups of actively modified files while automatically pruning backups of files that haven't been modified recently - even after the source files are deleted.
470
+
471
+ ```yaml
472
+ repositories:
473
+ - name: project-files
474
+ description: "Active project files with metadata-based retention"
475
+ path: /mnt/backup/project-files
476
+ retention_mode: per_file # Enable per-file backup mode
477
+ retention:
478
+ # Prune based on file metadata (modification time) read from archives
479
+ keep_files_modified_within: "30d" # Keep files modified in last 30 days
480
+ # Traditional retention also applies
481
+ keep_daily: 7
482
+ sources:
483
+ - name: projects
484
+ paths:
485
+ - /home/user/projects
486
+ exclude:
487
+ - "*.tmp"
488
+ - "*/.cache/*"
489
+ ```
490
+
491
+ **How it works:**
492
+ - **Per-File Archives**: Each file is backed up as a separate Borg archive
493
+ - **Hash-Based Naming**: Archives are named `repo-{hash}-{timestamp}` (hash uniquely identifies the file path)
494
+ - **Original Path Stored**: The complete original file path is stored in the archive comment
495
+ - **Metadata Preservation**: Borg preserves all file metadata (mtime, size, permissions) in the archive
496
+ - **Smart Pruning**: Retention reads file mtime directly from archives - works even after files are deleted
497
+
498
+ **File Metadata Retention Options:**
499
+ - `keep_files_modified_within`: Keep archives containing files modified within the specified time period
500
+ - Reads mtime from inside the Borg archive
501
+ - Works even if source files are deleted
502
+ - Example: `"30d"` keeps files modified in the last 30 days
503
+
504
+ **Mixed Mode Example:**
505
+ ```yaml
506
+ repositories:
507
+ # Standard mode for full system backups
508
+ - name: system
509
+ path: /mnt/backup/system
510
+ retention_mode: standard # Default: one archive per backup run
511
+ retention:
512
+ keep_daily: 7
513
+ sources:
514
+ - name: etc
515
+ paths:
516
+ - /etc
517
+
518
+ # Per-file mode for active development files
519
+ - name: active-code
520
+ path: /mnt/backup/code
521
+ retention_mode: per_file # One archive per file
522
+ retention:
523
+ keep_files_modified_within: "60d"
524
+ keep_monthly: 12 # Plus monthly snapshots
525
+ sources:
526
+ - name: projects
527
+ paths:
528
+ - /home/user/dev
529
+ ```
530
+
531
+ **Performance Note:** Per-file mode creates many archives (one per file). Borg handles this efficiently due to deduplication, but it's best suited for directories with hundreds to thousands of files rather than millions.
532
+
533
+ **Backup vs Retention:** The per-file `retention_mode` only affects how archives are created and pruned. Traditional backup commands still work normally - you can list, restore, and check per-file archives just like standard archives.
534
+
535
+ ### Automatic Pruning
536
+
537
+ Enable **automatic pruning** to remove old backups after each backup operation:
538
+
539
+ ```yaml
540
+ # Global configuration
541
+ auto_prune: true # Enable automatic pruning for all repositories
542
+ retention:
543
+ keep_daily: 7
544
+ keep_weekly: 4
545
+ keep_monthly: 6
546
+
547
+ repositories:
548
+ - name: documents
549
+ path: /mnt/backup/documents
550
+ sources:
551
+ - name: main
552
+ paths:
553
+ - /home/user/documents
554
+
555
+ - name: databases
556
+ path: /mnt/backup/databases
557
+ auto_prune: true # Override: enable pruning for this repository only
558
+ retention:
559
+ keep_daily: 14 # Override: use different retention policy
560
+ keep_weekly: 8
561
+ keep_monthly: 12
562
+ sources:
563
+ - name: mysql
564
+ paths:
565
+ - /var/lib/mysql/dumps
566
+ ```
567
+
568
+ **How it works:**
569
+ - When `auto_prune: true` is set, Ruborg automatically runs `borg prune` after each successful backup
570
+ - Pruning removes old archives that don't match any retention rule
571
+ - If both global and repository-specific `auto_prune` are set, repository-specific takes precedence
572
+ - Requires a retention policy to be configured (otherwise pruning is skipped)
573
+ - Pruning statistics are displayed after completion
574
+
575
+ **Example output:**
576
+
577
+ ```
578
+ --- Backing up repository: documents ---
579
+ ✓ Backup created: documents-2025-10-06_12-30-45
580
+ Pruning old backups...
581
+ ✓ Pruning completed
582
+ ```
583
+
584
+ **Manual pruning:**
585
+
586
+ If you prefer to prune manually or have `auto_prune: false`, run Borg's prune command directly:
587
+
588
+ ```bash
589
+ # Example: Apply retention policy to a repository
590
+ BORG_PASSPHRASE="your-passphrase" borg prune \
591
+ --keep-hourly=24 \
592
+ --keep-daily=7 \
593
+ --keep-weekly=4 \
594
+ --keep-monthly=6 \
595
+ --keep-yearly=1 \
596
+ /path/to/repository
597
+ ```
341
598
 
342
599
  ## Development
343
600
 
data/Rakefile CHANGED
@@ -5,4 +5,4 @@ require "rspec/core/rake_task"
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- task default: :spec
8
+ task default: :spec
data/SECURITY.md CHANGED
@@ -54,6 +54,18 @@ Ruborg implements several security measures to protect your backup operations:
54
54
  - Allows control over unencrypted repository access via config
55
55
  - Defaults to safe settings while maintaining backward compatibility
56
56
 
57
+ ### 11. Borg Executable Validation
58
+ - Validates that `borg_path` points to an actual executable file
59
+ - Verifies the executable is actually Borg by checking version output
60
+ - Prevents execution of arbitrary binaries specified in config
61
+ - Searches PATH for command-name-only specifications
62
+
63
+ ### 12. Dependency Vulnerability Scanning
64
+ - Uses `bundler-audit` to check for known vulnerabilities
65
+ - Regular database updates ensure latest security advisories
66
+ - Integrated into development workflow
67
+ - Run: `bundle exec bundle-audit check`
68
+
57
69
  ## Security Best Practices
58
70
 
59
71
  ### When Using `--remove-source`
@@ -66,9 +78,27 @@ Ruborg implements several security measures to protect your backup operations:
66
78
  4. **Use absolute paths** in configuration to avoid ambiguity
67
79
 
68
80
  ### Configuration File Security
69
- - Store configuration files with restricted permissions: `chmod 600 ruborg.yml`
81
+
82
+ **CRITICAL**: Always protect your configuration file with restrictive permissions:
83
+
84
+ ```bash
85
+ # Set owner-only read/write permissions
86
+ chmod 600 ruborg.yml
87
+
88
+ # Verify permissions
89
+ ls -l ruborg.yml
90
+ # Should show: -rw------- 1 user user ... ruborg.yml
91
+
92
+ # For shared environments with a backup group
93
+ chmod 640 ruborg.yml
94
+ chown user:backup ruborg.yml
95
+ ```
96
+
97
+ **Additional recommendations:**
70
98
  - Never commit Passbolt resource IDs to public repositories
71
99
  - Use environment variables for sensitive paths when possible
100
+ - Store config files outside web-accessible directories
101
+ - Regularly audit who has access to the config file
72
102
 
73
103
  ### Repository Security
74
104
  - Use encrypted repositories (default: `encryption: repokey`)
@@ -114,7 +144,16 @@ We will respond within 48 hours and work with you to address the issue.
114
144
 
115
145
  ## Security Audit History
116
146
 
117
- - **v0.3.1** (2025-10-05): Comprehensive security hardening
147
+ - **v0.4.0** (2025-10-06): Complete command injection elimination
148
+ - **CRITICAL**: Fixed all remaining command injection vulnerabilities in repository.rb
149
+ - Replaced all backtick execution with Open3.capture3/capture2e methods
150
+ - Added Borg executable validation to prevent arbitrary binary execution
151
+ - Integrated bundler-audit for dependency vulnerability scanning
152
+ - Removed unused env_to_cmd_prefix method
153
+ - Enhanced security documentation with config file permission requirements
154
+ - Zero known vulnerabilities in dependencies
155
+
156
+ - **v0.3.1** (2025-10-05): Initial security hardening
118
157
  - Fixed command injection in Passbolt CLI execution (uses Open3.capture3)
119
158
  - Added path traversal protection for extract operations
120
159
  - Implemented symlink protection for file deletion with --remove-source
data/exe/ruborg CHANGED
@@ -3,4 +3,4 @@
3
3
 
4
4
  require_relative "../lib/ruborg"
5
5
 
6
- Ruborg::CLI.start(ARGV)
6
+ Ruborg::CLI.start(ARGV)