Skip to content

Sync dev to main#171

Merged
tis24dev merged 41 commits intomainfrom
dev
Mar 11, 2026
Merged

Sync dev to main#171
tis24dev merged 41 commits intomainfrom
dev

Conversation

@tis24dev
Copy link
Owner

@tis24dev tis24dev commented Mar 11, 2026

  • test(orchestrator): maximize coverage for network_apply
  • ci: bump the actions-updates group across 1 directory with 2 updates (ci: bump the actions-updates group across 1 directory with 2 updates #164)
  • backup/pve: clarify datastore skip logs
  • feat(webhook): optional Discord content fallback for embed-only messages
  • Revert "feat(webhook): optional Discord content fallback for embed-only messages"
  • Update go.mod
  • Harden restore decisions against untrusted backup metadata
  • Enforce staged backup checksum verification in restore/decrypt flows
  • fix(orchestrator): preserve staged network symlinks
  • fix(orchestrator): harden restore path validation against broken symlink escapes
  • fix(backup): sanitize datastore and storage path segments
  • fix(io): bound timed fs and input goroutine buildup
  • fix(orchestrator): preserve operational restore errors during path validation
  • Separate PBS override scan roots from real datastore identities.
  • fix(orchestrator): resolve symlinked base dirs before validating relative links
  • fix(safefs): harden timeout test cleanup and limiter capture
  • fix(input): preserve completed inflight reads across retries
  • fix(pbs): disambiguate datastore output keys across CLI and overrides
  • test(input): assert inflight cleanup after completed retry consumption
  • fix(safefs): return TimeoutError when deadline expires before run
  • fix(restore): validate compatibility before full restore fallback
  • fix(orchestrator): bound restore metadata reads
  • fix(orchestrator): validate staged network symlink targets
  • fix(orchestrator): validate symlink targets in firewall staged sync
  • fix(orchestrator): recognize full Proxmox system names
  • fix(orchestrator): validate raw backup checksums during discovery
  • test: add PBS datastore status filename collision regression coverage
  • fix(pbs): always apply datastore path overrides without CLI discovery
  • Normalize safefs deadline handling
  • Surface decompressor close errors during restore archive inspection
  • Fix symlink target rewriting for resolved destination parents
  • Revalidate created overlay symlinks within restore root
  • Normalize trimmed age encryption mode during bundle preparation
  • Use a fresh timeout for rclone checksum inspection
  • fix(orchestrator): fail safety restore on operational symlink validation errors
  • Avoid holding the input state mutex across blocking waits on ctx.Done() and inflight completion.
  • backup: skip relative PBS datastore overrides
  • backup: prefer CLI datastore path when merging inventory
  • fix(orchestrator): bound .sha256 reads during backup discovery
  • fix(orchestrator): surface rclone checksum failures after early close
  • fix(orchestrator): validate prepared archive paths before decrypt/copy

Summary by CodeRabbit

  • New Features

    • Added support for PBS datastore path overrides via environment configuration
    • Enhanced archive integrity verification with checksum validation
    • Added archive analysis for better restore decision-making
  • Improvements

    • Strengthened symlink and path safety during restoration
    • Enhanced network configuration application with improved validation
    • Optimized concurrency handling for user input operations
    • Updated Go toolchain and GitHub Actions dependencies
  • Documentation

    • Updated PBS datastore configuration guidance to clarify override behavior

tis24dev and others added 30 commits February 27, 2026 15:30
- Add network_apply_additional_test.go with extensive tests for rollback (arm/disarm), NIC repair CLI (overrides/conflicts), snapshot IP parsing, command selection, and error paths.
- Use FakeFS/FakeCommandRunner plus PATH stubs to deterministically exercise both success and failure branches.
- Bring network_apply.go coverage to ~99% with no production code changes.
…164)

Bumps the actions-updates group with 2 updates in the / directory: [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) and [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


Updates `goreleaser/goreleaser-action` from 6 to 7
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](goreleaser/goreleaser-action@v6...v7)

Updates `actions/attest-build-provenance` from 3 to 4
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](actions/attest-build-provenance@v3...v4)

---
updated-dependencies:
- dependency-name: goreleaser/goreleaser-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions-updates
- dependency-name: actions/attest-build-provenance
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Make PVE datastore skip messages user-friendly: log disabled storages as SKIP,
offline storages as actionable WARNING, and always emit DEBUG skip details with
active/enabled/status and an explicit reason.
Fix detected datastores report header to match output column order.
Extend unit tests to cover runtime flag parsing and the new skip logging, and
make Makefile coverage targets honor the go.mod toolchain via GOTOOLCHAIN.
Adds per-endpoint opt-in Discord content text (WEBHOOK_<ENDPOINT>_DISCORD_CONTENT_ENABLED/..._DISCORD_CONTENT) to avoid “empty” messages when embeds aren’t rendered. Default remains unchanged (embed-only). Includes 2000-char truncation, docs/template updates, and tests.
Derive restore compatibility, cluster gating, and hostname warnings from archive-backed facts instead of candidate manifest metadata. Add restore archive analysis for internal backup metadata and category-based fallback, update restore planning and compatibility checks to consume trusted decision inputs, and add regression tests covering manifest spoofing for backup type and cluster mode.
Require checksum verification for staged backup archives before any restore or decrypt operation proceeds. Add strict SHA256 parsing and normalization, enforce checksum source agreement between sidecar and manifest metadata, reject raw backup candidates with no verifiable integrity source, centralize shared prepare-path verification for bundle and raw inputs, preserve source artifact checksum separately from the prepared plain archive checksum, and update regression tests to cover missing, mismatched, and legacy checksum scenarios.
Use Lstat in network staged apply so symlink entries are handled as symlinks instead of being dereferenced and copied as regular file contents. Reject symlinked staged network directories, extend the FS abstraction with Lstat, and add regression tests covering preserved symlinks and invalid symlinked stage roots.
…ink escapes

Replace the restore path safety checks with a shared FS-aware resolver that walks paths component by component using Lstat and Readlink, correctly handling missing tails and rejecting intermediate symlink escapes. Apply the new validation to regular restore, safety restore, symlink and hardlink handling, and add regression tests for broken escaping symlinks, symlink loops, and symlinked restore roots.
Introduce a shared path-safe key for PBS datastore names and PVE storage names when building collector output paths, preventing path traversal and filename collisions from raw config values. Keep raw names unchanged in metadata and command invocations, update all affected PBS/PVE collector call sites, and add regression tests covering unsafe names while preserving the existing layout for already-safe names.
Prevent unbounded goroutine accumulation in timeout/cancel wrappers by limiting in-flight safefs operations and reusing a single in-flight read per reader/file descriptor in the input package. Keep public APIs unchanged, preserve current timeout semantics, and add regression coverage for limiter saturation, repeated timeouts, and race-safe cleanup of timed operations.
…lidation

Teach the restore path resolver to distinguish security violations from local operational failures, so only real root-escape conditions are reported as illegal paths. Keep broken-symlink and traversal hardening intact, allow in-root permission and ENOTDIR failures to surface through the normal restore flow, and add regression tests covering the new security vs operational error classification.
- add explicit PBS datastore metadata for source, CLI identity and output key
- derive stable path-based output keys for PBS_DATASTORE_PATH overrides
- keep existing output names for real CLI-discovered PBS datastores
- skip datastore show/status CLI calls for override-only entries
- use filesystem-only namespace discovery for override paths
- keep PXAR outputs isolated for colliding override basenames
- preserve distinct override entries in PBS datastore inventory
- exclude override-only inventory entries from datastore.cfg fallback restore
- add regression coverage for basename collisions and restore safety
- update PBS_DATASTORE_PATH documentation to reflect scan-root semantics
…tive links

resolvePathRelativeToBaseWithinRootFS now canonicalizes baseDir by resolving existing symlinks before validating relative link targets. This closes the bypass where an archive could create an apparently harmless parent symlink and then install a relative symlink that escapes destRoot once materialized by the kernel.
Make safefs timeout tests failure-safe by draining blocked workers from cleanup and separating worker cleanup from global state restore. Also capture limiter and fs operation hooks locally in runLimited/Stat/ReadDir/Statfs to avoid races with global resets while async work is still in flight.
Keep completed in-flight line and password reads attached to their state until
a caller consumes the buffered result, instead of clearing the inflight state
from the producer goroutine.

This fixes the race where a read could complete after a timeout, be cleaned up
before the next retry started, and leave the completed input unreachable.
Add deterministic tests for both retry-while-pending and completion-before-retry
cases to lock the behavior down.
Add a PBS-specific output-key resolver to guarantee stable, unique datastore filenames and directories across auto-detected datastores and PBS_DATASTORE_PATH overrides. This fixes real collisions between CLI datastore names and path-derived override keys, makes pbsDatastore.pathKey() source-aware when OutputKey is unset, and keeps inventory output_key values aligned with the actual files written by PBS collectors. Includes regression tests for CLI-vs-override collisions, override fallback behavior, and inventory consistency.
The new tests verify that line and password inflight reads remain attached
after timeout until the completed result is reused, and that state.inflight
is cleared immediately after that consumer receives the result.
update runLimited to re-check ctx.Err() after effectiveTimeout()
avoid calling run() when effectiveTimeout() returns 0 because the context deadline already elapsed
preserve the no-timeout path only for genuinely disabled timeouts
add a regression test for the expired-deadline edge case in internal/safefs
When restore archive analysis fails in the UI workflow, do not jump
immediately to full restore.
Build a best-effort RestoreDecisionInfo from the manifest, run the
existing compatibility check first, and only then fall back to
runFullRestoreWithUI.
Also add a regression test covering the analysis-error path to ensure
the compatibility warning is still shown before the full restore
fallback executes.
Reject oversized backup_metadata.txt entries during restore archive inspection by reading through a fixed limit before parsing. This prevents unbounded memory allocation from crafted archives and ensures truncated metadata caused by limit overflow is treated as invalid rather than partially trusted. Add regression tests covering oversized metadata rejection and the public restore analysis path.
Validate symlink targets during staged network apply before recreating them
under the destination tree. Reuse the existing path-security resolver to
ensure targets stay within the allowed destination root, rewrite safe
absolute targets to relative links, and reject absolute or relative targets
that escape the subtree. Add regression tests for safe rewrites and escaping
symlink targets.
Validate symlink targets in syncDirExact before recreating them under the
destination subtree. Reuse the existing path-security resolver to ensure
firewall and SDN staged symlinks stay within the allowed destination root,
rewrite safe absolute targets to relative links, and reject absolute or
relative targets that escape the subtree. Add regression tests for safe
rewrites and escaping symlink targets.
Verify and fix parseSystemTypeString in compatibility.go.

The parser now recognizes space-separated and full-name variants such as
"Proxmox VE", "Proxmox Backup", and "Proxmox Backup Server", in addition
to the existing acronym and hyphenated forms.

Add regression tests to ensure these values map correctly to
SystemTypePVE and SystemTypePBS.
Validate and normalize manifest and sidecar SHA256 values before
accepting local or rclone raw backup candidates.

Reject candidates when the manifest checksum is malformed, the .sha256
sidecar cannot be parsed, or both checksum sources disagree. Persist the
normalized checksum and its source on the candidate so downstream staged
integrity verification only works with pre-validated values.

Add coverage for local and rclone discovery, malformed and conflicting
checksums, and reuse of the candidate integrity expectation during
staged verification.
Adds a regression test for collectPBSCommands() covering colliding PBS datastore output keys. The test verifies that assignUniquePBSDatastoreOutputKeys() disambiguates colliding datastore status filenames and that two distinct datastore_*_status.json files are written with the correct datastore-specific content.
Make PBS datastore enumeration best-effort in getDatastoreList so configured PBSDatastorePaths overrides are still appended when proxmox-backup-manager is missing, the datastore list command fails, or its JSON output is invalid. Preserve context cancellation as a fatal error, keep unique output key assignment, and add regression tests for missing CLI, command failure, and parse failure fallback cases.
Add focused safefs tests for expired-deadline paths and make deadline-driven context cancellations consistently map to ErrTimeout/TimeoutError in runLimited and operationLimiter.acquire. This fixes inconsistent timeout classification where some context deadline expirations returned context.DeadlineExceeded instead of the safefs timeout sentinel, while preserving context.Canceled behavior.
Make restore archive inspection fail when the decompression reader reports an error on Close, instead of silently accepting the archive as valid. This updates inspectRestoreArchiveContents to preserve existing inspect errors while surfacing deferred decompressor failures, and adds targeted tests covering both close-error propagation and error-precedence behavior.
tis24dev added 11 commits March 11, 2026 11:32
Update overlay symlink validation to rewrite absolute targets relative to the resolved destination parent instead of the lexical parent path. This fixes incorrect rewritten targets when the destination's parent directory is itself a symlink, and adds a regression test covering the symlinked-parent case.
Add post-creation symlink verification for network overlay and firewall sync paths, mirroring the existing restore symlink safety model. The new check reads back each created symlink, ensures its effective target still resolves within the destination root, removes the link on validation failure, and adds regression tests covering readback failures and post-create escape scenarios.
Trim manifest EncryptionMode before lowercasing in preparePlainBundleCommon so values like " age " still trigger decryption. This aligns decryption behavior with statusFromManifest and adds a regression test proving whitespace-padded age mode is decrypted instead of being misclassified as plain.
Stop reusing the raw-item metadata context for checksum probing in discoverRcloneBackups. The checksum fetch now gets its own per-command timeout budget, matching the documented RCLONE_TIMEOUT_CONNECTION behavior, and a regression test covers the case where a slow metadata read previously left too little time for the checksum fetch.
…ion errors

Distinguish path-security errors from operational failures during safety-backup symlink restore. Keep the existing warning-and-skip behavior for symlink targets that escape the restore root, but propagate non-security errors from resolvePathRelativeToBaseWithinRootFS so restore failures are reported instead of silently dropping symlinks. Add tests covering operational failures before and after symlink creation.
…() and inflight completion.

- lock only to create/read the current inflight operation
- release the mutex before waiting on cancellation or read completion
- re-acquire the mutex only to clear state.inflight if it still matches
  the captured inflight
- store completed line/password results on the inflight state and use done
  as a broadcast completion signal for concurrent waiters
- add regression tests for concurrent cancelled callers and preserve
  existing retry/inflight reuse behavior
Reject relative PBS_DATASTORE_PATH values when building the datastore list.
normalizePBSDatastorePath only cleans input, so relative paths could previously
be accepted as overrides.

Keep the existing override naming, output key, and deduplication logic for valid
absolute paths, and log a warning when skipping an invalid relative override.

Add a regression test covering relative PBS_DATASTORE_PATH entries.
Fix PBS datastore inventory merge so the runtime CLI path overrides datastore.cfg for the same datastore identity. Add a regression test covering config-vs-CLI path precedence during merge.
Replace unbounded checksum sidecar reads in backup discovery with bounded
streaming reads for both local files and rclone sources.

- cap checksum input to 4 KiB before parsing
- remove full-file ReadFile / CombinedOutput usage on .sha256 paths
- return clear errors for oversized or empty checksum files
- preserve compatibility with valid bounded checksum files without trailing newline
- add coverage for local and rclone oversized / bounded-input cases
Only ignore `rclone cat` wait errors when stdout was closed early after
reading a valid first checksum line and stderr is empty.

This prevents genuine rclone failures from being masked when the checksum
is read successfully but the command still exits non-zero with an error
message. Add a regression test for a fake rclone that prints a valid
checksum line and then exits with code 1.
Validate the staged archive path against the manifest encryption mode in
preparePlainBundleCommon before deriving the plain archive output path.

This rejects inconsistent inputs where `EncryptionMode=age` does not have
a `.age` archive suffix, or where a non-age archive still ends with
`.age`. It also ensures decryption never runs with identical input and
output paths by generating a unique output name when needed.

Add regression coverage for both mode/suffix mismatch cases and the
unique-path fallback for age archives.
@github-actions
Copy link

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 2 package(s) with unknown licenses.
See the Details below.

License Issues

.github/workflows/release.yml

PackageVersionLicenseIssue Type
actions/attest-build-provenance4.*.*NullUnknown License
goreleaser/goreleaser-action7.*.*NullUnknown License
Allowed Licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, LicenseRef-scancode-google-patent-license-golang

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/attest-build-provenance 4.*.* UnknownUnknown
actions/goreleaser/goreleaser-action 7.*.* 🟢 5
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Maintained🟢 1016 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Code-Review🟢 3Found 5/16 approved changesets -- score normalized to 3
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Security-Policy⚠️ 0security policy file not detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
Pinned-Dependencies🟢 5dependency not pinned by hash detected -- score normalized to 5

Scanned Files

  • .github/workflows/release.yml

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1300aad3-cb12-45ef-ae41-4cae50bf3f19

📥 Commits

Reviewing files that changed from the base of the PR and between b7d9670 and e752f47.

📒 Files selected for processing (66)
  • .github/workflows/release.yml
  • Makefile
  • docs/CONFIGURATION.md
  • docs/RESTORE_GUIDE.md
  • go.mod
  • internal/backup/checksum.go
  • internal/backup/checksum_legacy_test.go
  • internal/backup/checksum_test.go
  • internal/backup/collector.go
  • internal/backup/collector_helpers_extra_test.go
  • internal/backup/collector_pbs.go
  • internal/backup/collector_pbs_commands_coverage_test.go
  • internal/backup/collector_pbs_datastore.go
  • internal/backup/collector_pbs_datastore_inventory.go
  • internal/backup/collector_pbs_datastore_inventory_test.go
  • internal/backup/collector_pbs_extra_test.go
  • internal/backup/collector_pbs_test.go
  • internal/backup/collector_pve.go
  • internal/backup/collector_pve_parse_test.go
  • internal/backup/collector_pve_test.go
  • internal/config/templates/backup.env
  • internal/input/input.go
  • internal/input/input_test.go
  • internal/orchestrator/backup_safety.go
  • internal/orchestrator/backup_safety_test.go
  • internal/orchestrator/backup_sources.go
  • internal/orchestrator/backup_sources_test.go
  • internal/orchestrator/compatibility.go
  • internal/orchestrator/compatibility_test.go
  • internal/orchestrator/decrypt.go
  • internal/orchestrator/decrypt_integrity.go
  • internal/orchestrator/decrypt_integrity_test.go
  • internal/orchestrator/decrypt_integrity_test_helpers_test.go
  • internal/orchestrator/decrypt_prepare_common.go
  • internal/orchestrator/decrypt_test.go
  • internal/orchestrator/decrypt_tui.go
  • internal/orchestrator/decrypt_tui_test.go
  • internal/orchestrator/decrypt_workflow_test.go
  • internal/orchestrator/decrypt_workflow_ui.go
  • internal/orchestrator/deps.go
  • internal/orchestrator/deps_test.go
  • internal/orchestrator/network_apply_additional_test.go
  • internal/orchestrator/network_staged_apply.go
  • internal/orchestrator/network_staged_apply_test.go
  • internal/orchestrator/path_security.go
  • internal/orchestrator/path_security_test.go
  • internal/orchestrator/pbs_staged_apply.go
  • internal/orchestrator/pbs_staged_apply_additional_test.go
  • internal/orchestrator/restore.go
  • internal/orchestrator/restore_decision.go
  • internal/orchestrator/restore_decision_test.go
  • internal/orchestrator/restore_errors_test.go
  • internal/orchestrator/restore_firewall.go
  • internal/orchestrator/restore_firewall_additional_test.go
  • internal/orchestrator/restore_plan.go
  • internal/orchestrator/restore_plan_test.go
  • internal/orchestrator/restore_test.go
  • internal/orchestrator/restore_workflow_decision_test.go
  • internal/orchestrator/restore_workflow_more_test.go
  • internal/orchestrator/restore_workflow_ui.go
  • internal/orchestrator/restore_workflow_ui_helpers_test.go
  • internal/orchestrator/selective.go
  • internal/pbs/namespaces.go
  • internal/pbs/namespaces_test.go
  • internal/safefs/safefs.go
  • internal/safefs/safefs_test.go

📝 Walkthrough

Walkthrough

This pull request introduces comprehensive enhancements for backup collection, restoration, and integrity verification. Key additions include PBS datastore override support with deterministic output keying, path security validation for restore operations, archive integrity verification, restore decision logic based on archive analysis, improved checksum normalization, concurrency improvements for input handling and filesystem operations, and network configuration enhancements. The changes span collection, restoration, path safety, and orchestration layers.

Changes

Cohort / File(s) Summary
PBS Datastore Support
internal/backup/collector_pbs.go, internal/backup/collector_pbs_datastore.go, internal/backup/collector_pbs_datastore_inventory.go, internal/backup/collector_pbs_datastore_inventory_test.go, internal/backup/collector_pbs_commands_coverage_test.go, internal/backup/collector_pbs_extra_test.go, internal/backup/collector_pbs_test.go, internal/orchestrator/pbs_staged_apply.go, internal/orchestrator/pbs_staged_apply_additional_test.go
Introduces PBS datastore overrides via PBS_DATASTORE_PATH, output key generation with collision handling, path normalization, and origin tracking (CLI vs override). Extends inventory definitions with Origin, CLIName, and OutputKey fields. Updates merge logic and parsing to handle overrides separately. Tests validate override handling, collision disambiguation, and filter override entries during restore.
Path Security & Resolution
internal/orchestrator/path_security.go, internal/orchestrator/path_security_test.go, internal/orchestrator/backup_safety.go, internal/orchestrator/backup_safety_test.go, internal/orchestrator/restore.go, internal/orchestrator/restore_test.go, internal/orchestrator/restore_firewall.go, internal/orchestrator/restore_firewall_additional_test.go, internal/orchestrator/network_staged_apply.go, internal/orchestrator/network_staged_apply_test.go, internal/orchestrator/deps.go, internal/orchestrator/deps_test.go
Centralizes path resolution with symlink-aware traversal, escape detection, and root confinement. Adds Lstat method to FS interface. Implements root-restricted directory/file/symlink overlays. Validates symlink targets within destination roots and post-creation. Tests cover escape prevention, broken intermediate symlinks, and readback validation.
Checksum Normalization & Integrity
internal/backup/checksum.go, internal/backup/checksum_legacy_test.go, internal/backup/checksum_test.go, internal/backup/collector.go, internal/backup/collector_pve.go, internal/backup/collector_pve_parse_test.go, internal/backup/collector_pve_test.go, internal/orchestrator/decrypt_integrity.go, internal/orchestrator/decrypt_integrity_test.go, internal/orchestrator/decrypt_integrity_test_helpers_test.go, internal/orchestrator/backup_sources.go, internal/orchestrator/backup_sources_test.go
Adds NormalizeChecksum and ParseChecksumData helpers for SHA256 validation. Implements collectorPathKey for filesystem-safe keying with hash-based disambiguation. Adds integrity verification flow for backup candidates with bounded checksum file reading. Introduces stagedIntegrityExpectation and resolution logic. Tests validate normalization, parsing, path safety, and integrity workflows.
Restore Decision & Archive Analysis
internal/orchestrator/restore_decision.go, internal/orchestrator/restore_decision_test.go, internal/orchestrator/restore_workflow_ui.go, internal/orchestrator/restore_workflow_decision_test.go, internal/orchestrator/restore_workflow_more_test.go, internal/orchestrator/selective.go, internal/orchestrator/compatibility.go, internal/orchestrator/compatibility_test.go, internal/orchestrator/restore_plan.go, internal/orchestrator/restore_plan_test.go
Introduces archive analysis and restore decision framework: analyzes tar contents for categories and metadata (BackupType, ClusterPayload, Hostname). Updates compatibility checks to use archive payload instead of manifest. Changes PlanRestore to accept clusterBackup boolean. Refactors AnalyzeBackupCategories to delegate to new unified AnalyzeRestoreArchive. Tests cover metadata parsing, category detection, and workflow integration.
Decrypt & Bundle Preparation
internal/orchestrator/decrypt.go, internal/orchestrator/decrypt_prepare_common.go, internal/orchestrator/decrypt_tui.go, internal/orchestrator/decrypt_workflow_ui.go, internal/orchestrator/decrypt_test.go, internal/orchestrator/decrypt_tui_test.go, internal/orchestrator/decrypt_workflow_test.go
Extracts common bundle preparation logic into preparePlainBundleCommon with integrity verification, path resolution, and manifest updating. TUI and UI variants delegate to common path with appropriate decryption callbacks. Adds checksum computation helpers. Tests use dynamic checksum generation and cover plain/age-encrypted paths.
Network Operations
internal/orchestrator/network_apply_additional_test.go
Introduces comprehensive test suite for network apply/rollback functionality, including rollback lifecycle, NIC naming repair, network configuration application, SSH detection, and error handling. Tests use fake filesystem, command runners, and time mocks.
Input Concurrency
internal/input/input.go, internal/input/input_test.go
Replaces single-goroutine reads with per-reader inflight coordination using line/password state caches. Adds cancellation semantics and context deadline handling. Introduces ReadLineWithContext and ReadPasswordWithContext loops for inflight operation reuse. Tests verify concurrent cancellation, timeout reuse, and deadline propagation.
Filesystem Operation Limiting
internal/safefs/safefs.go, internal/safefs/safefs_test.go
Introduces global operation limiter to bound concurrent filesystem operations. Adds ErrTimeout and TimeoutError types. Reworks Stat, ReadDir, Statfs to execute under limiter with deadline handling. Tests cover deadline expiration, limiter capacity enforcement, and context cancellation propagation.
PBS Namespace Discovery
internal/pbs/namespaces.go, internal/pbs/namespaces_test.go
Adds public DiscoverNamespacesFromFilesystem wrapper around internal filesystem-based discovery. Test validates namespace discovery from directory structure.
Configuration & Build
.github/workflows/release.yml, Makefile, go.mod, internal/config/templates/backup.env, docs/CONFIGURATION.md, docs/RESTORE_GUIDE.md
Bumps GoReleaser to v7, Attest Build Provenance to v4, and Go toolchain to 1.25.8. Introduces automatic toolchain selection in Makefile via GOTOOLCHAIN environment variable. Updates PBS_DATASTORE_PATH documentation to clarify filesystem scan roots and path-derived output keys. Adds restore guide notes on override behavior.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Analyzer as Archive Analyzer
    participant Tar as Tar Reader
    participant Decision as Restore Decision

    App->>Analyzer: AnalyzeRestoreArchive(archivePath)
    Analyzer->>Tar: Open & decompress archive
    Tar->>Tar: Read tar entries & collect paths
    Tar->>Tar: Parse restore decision metadata
    Analyzer->>Decision: buildRestoreDecisionInfo(metadata, categories)
    Decision->>Decision: detectBackupTypeFromCategories()
    Analyzer-->>App: RestoreDecisionInfo{BackupType, ClusterPayload, Hostname}
Loading
sequenceDiagram
    participant UI as Restore UI
    participant Decision as Decision Logic
    participant Archive as Archive Analysis
    participant Compat as Compatibility Check

    UI->>Archive: AnalyzeRestoreArchive(archivePath)
    Archive-->>Decision: availableCategories, decisionInfo
    alt Analysis succeeds
        Decision->>Compat: ValidateCompatibility(currentSystem, decisionInfo.BackupType)
    else Analysis fails
        Decision->>Decision: fallbackRestoreDecisionInfoFromManifest(manifest)
    end
    Compat-->>UI: Result (compatible/incompatible)
    UI->>UI: Plan restore using decisionInfo.ClusterPayload
Loading
sequenceDiagram
    participant Client as Restore Client
    participant PathResolver as Path Resolver
    participant FS as Filesystem
    participant Validator as Validator

    Client->>PathResolver: resolvePathWithinRootFS(destRoot, candidate)
    loop Component traversal
        PathResolver->>FS: Lstat(component)
        alt Symlink detected
            FS-->>PathResolver: FileInfo(symlink)
            PathResolver->>FS: Readlink(component)
            FS-->>PathResolver: target
            Validator->>Validator: validateTarget within root
        else Regular file/dir
            FS-->>PathResolver: FileInfo(regular)
        end
    end
    Validator-->>PathResolver: Validated absolute path
    PathResolver-->>Client: Safe path or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 By CodeRabbit's nimble paw,
Archives verified without a flaw,
Paths now safe through symlink's maze,
PBS datastores blaze new ways,
Restore workflows dance with grace,
Integrity checked in every place!

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Comment @coderabbitai help to get the list of available commands and usage tips.

@tis24dev tis24dev merged commit 90dfba1 into main Mar 11, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant