Skip to content

Stabilize notifier dispatch, CI, and cleanup refinements#216

Merged
tis24dev merged 12 commits into
mainfrom
dev
May 18, 2026
Merged

Stabilize notifier dispatch, CI, and cleanup refinements#216
tis24dev merged 12 commits into
mainfrom
dev

Conversation

@tis24dev
Copy link
Copy Markdown
Owner

@tis24dev tis24dev commented May 18, 2026

Summary by CodeRabbit

  • New Features

    • Email delivery method now supports additional alias values (proxmox, proxmox-notifications, proxmox-mail-forward) for PMF delivery.
    • Notifications now snapshot and report consistent backup issue counts at dispatch time.
  • Bug Fixes

    • Fixed configuration wizard to properly exit when preserving existing settings.
    • Improved exit code and issue aggregation logic for dry-run backups.
  • Tests

    • Added comprehensive notification dispatch and early error handling test coverage.
  • Chores

    • Updated Go module dependencies.
    • Updated GitHub Actions workflow versions for improved security.

Review Change Stack

Greptile Summary

This PR fixes per-notifier error/warning count drift in the dispatch chain by introducing a pre-notification snapshot (startNotificationGroupsnapshotPreNotificationIssues) taken once before all notifiers run, and removing the per-call log-file re-parsing from convertBackupStatsToNotificationData. It also cleans up dead code, deduplicates template sanitization, and bumps CI actions and Go module dependencies.

  • Notification boundary (extensions.go, notification_adapter.go): Issue counts and log categories are now snapshotted immediately before dispatch via refreshLogIssuesFromFile(true) and stored on BackupStats.LogCategories; each notifier reads the frozen snapshot instead of re-parsing the log, so warnings emitted by an earlier notifier in the chain cannot inflate the counts seen by later ones.
  • Exit-code logic (applyIssueExitCode): Extracted into a standalone function that preserves domain-specific failure codes (e.g. ExitStorageError) and only promotes ExitSuccess/ExitGenericError — a deliberate improvement over the old unconditional switch.
  • Dry-run path (backup_run_phases.go): finalizeBackupStats now delegates issue-count finalization exclusively to finalizeDryRunIssueStats for dry-run; the non-dry-run path relies entirely on the notification-boundary snapshot, eliminating the double-parse that existed before.

Confidence Score: 5/5

Safe to merge; all changed paths are well-tested and the notification snapshot design is consistent end-to-end.

The core bug fix (count drift across notifiers) is correctly implemented: a single snapshot replaces per-notifier log re-parsing, and the new tests cover both the snapshot invariant and the applyIssueExitCode logic exhaustively. The dry-run and failure paths each still set their own exit codes before the notification phase, so no execution path is left with an uninitialized ExitCode. The remaining changes (dead-code removal, duplicate sanitization call, switch refactors, dependency bumps) are straightforward and low-risk.

No files require special attention; extensions.go and notification_adapter.go carry the heaviest logic change but are covered by targeted regression tests.

Important Files Changed

Filename Overview
internal/orchestrator/extensions.go Core notification-boundary refactor: adds startNotificationGroup, snapshotPreNotificationIssues, refreshLogIssuesFromFile, and applyIssueExitCode to snapshot issue counts once before dispatching all notifiers.
internal/orchestrator/notification_adapter.go Removes per-notifier log file re-parsing; notification data now reads from pre-snapshotted stats.ErrorCount, stats.WarningCount, and a shallow-copied stats.LogCategories — the direct fix for count drift.
internal/orchestrator/backup_run_phases.go finalizeBackupStats now only calls finalizeDryRunIssueStats for dry-run; non-dry-run issue counts and exit code are exclusively set by startNotificationGroup at dispatch time.
internal/orchestrator/additional_helpers_test.go Adds stubNotifierChannel fields and warningStorageTarget, plus TestDispatchPostBackupSnapshotsIssuesImmediatelyBeforeNotifications verifying the pre-notification snapshot holds across all notifiers.
internal/orchestrator/extensions_additional_test.go Adds TestApplyIssueExitCode (covering nil, 7 cases) and TestDispatchEarlyErrorNotificationPreservesSyntheticIssueWithLogFile ensuring synthetic counts survive a log-file-present early-error path.
cmd/proxsave/runtime_helpers.go Converts execInfo and execInfoOnce from value types to pointers so tests can replace them atomically without copying; getExecInfo dereferences before returning to preserve the existing value-return contract.
cmd/proxsave/install.go Removes the duplicate config.RemoveRuntimeDerivedEnvKeys call that executed redundantly before writeConfigFile; the call at line 492 (just before writeConfigFile) is the authoritative one.
internal/orchestrator/mount_guard.go Removes the ensureGuardTargetUnmounted wrapper that did nothing but delegate to isMounted with the same signature; guardMountPoint now calls isMounted directly.
internal/orchestrator/notification_adapter_test.go Rewrites TestConvertBackupStatsUsesLogCountsAndCompressionFallback to validate snapshot propagation and adds TestConvertBackupStatsDoesNotRereadLogFile as a regression guard against per-notifier re-parsing.
internal/notify/email.go Refactors two switch-without-expression blocks to typed switch statements for clarity; functionally equivalent.

Sequence Diagram

sequenceDiagram
    participant O as Orchestrator
    participant FAS as finalizeBackupStats
    participant SNG as startNotificationGroup
    participant SPNI as snapshotPreNotificationIssues
    participant AEC as applyIssueExitCode
    participant DN as dispatchNotifications
    participant NA as NotificationAdapter
    participant N1 as Notifier 1
    participant N2 as Notifier 2

    O->>FAS: finalizeBackupStats(run)
    alt dry-run
        FAS->>FAS: finalizeDryRunIssueStats(stats)
    else non-dry-run
        FAS->>FAS: set Duration only
    end

    O->>SNG: startNotificationGroup(ctx, stats)
    SNG->>SPNI: snapshotPreNotificationIssues(stats)
    SPNI->>SPNI: "refreshLogIssuesFromFile(includeCategories=true)"
    SPNI-->>SNG: snapshot frozen on stats
    SNG->>AEC: applyIssueExitCode(stats)
    SNG->>DN: dispatchNotifications(ctx, stats)

    DN->>N1: Notify(ctx, stats)
    N1->>NA: convertBackupStatsToNotificationData(stats)
    NA->>NA: reads frozen counts, copies LogCategories
    NA-->>N1: NotificationData
    N1-->>DN: done

    DN->>N2: Notify(ctx, stats)
    N2->>NA: convertBackupStatsToNotificationData(stats)
    NA->>NA: same frozen counts
    NA-->>N2: NotificationData
    N2-->>DN: done
Loading

Reviews (2): Last reviewed commit: "Clarify issue exit code policy" | Re-trigger Greptile

tis24dev and others added 10 commits May 13, 2026 22:07
Updates golang.org/x/crypto, x/term, x/text and the dependency-review/setup-node Actions with regenerated checksums
Use a plain channel receive when draining the tar writer goroutine after compressor start failure
Store exec info cache state behind pointers so tests can override and restore it without copying sync.Once
Call isMounted directly from guardMountPoint and remove the pass-through helper with misleading unmount wording
Keep runtime-derived env key removal only at the final write point in the install config flow
* Fix per-notifier error/warning count drift in dispatch chain

Snapshot ErrorCount, WarningCount and LogCategories into BackupStats once
at backup completion (finalizeBackupStats / parseFailedBackupLogCounts)
and have convertBackupStatsToNotificationData read them as-is. Re-parsing
the log file per-notifier was over-counting warnings emitted by earlier
notifiers in the dispatch chain, so e.g. Pushover reported 5 warnings
while Email reported 0 on the same run.

* Place issue snapshot at notification boundary

* Align exit code with notification snapshot

---------

Co-authored-by: tis24dev <github@tis24.it>
…dates group (#214)

ci: bump github/codeql-action in the actions-updates group

Bumps the actions-updates group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 4.35.4 to 4.35.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@68bde55...9e0d7b8)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

📝 Walkthrough

Walkthrough

The PR introduces a structured pre-notification snapshot system for backup statistics, capturing error/warning counts and log categories at a well-defined point before notification dispatch. This prevents inconsistent re-parsing of log files across multiple notifiers. Supporting changes include exec-info caching refactoring, config wizard early-exit logic, and routine dependency updates.

Changes

Backup Stats Log Issue Snapshot System

Layer / File(s) Summary
LogCategories field addition to BackupStats
internal/orchestrator/orchestrator.go
BackupStats struct is extended with a new LogCategories []notify.LogCategory field to store snapshot log-category metadata alongside existing error/warning counts.
Issue snapshot capture and exit-code normalization helpers
internal/orchestrator/extensions.go
New startNotificationGroup entry point and helper functions (snapshotPreNotificationIssues, refreshLogIssuesFromFile, applyIssueExitCode) capture log-derived counts/categories into BackupStats and normalize exit codes before notifications dispatch.
Backup phase log finalization refactored to use snapshot helpers
internal/orchestrator/backup_run_phases.go, internal/orchestrator/backup_run_helpers.go
finalizeBackupStats and parseFailedBackupLogCounts now delegate log issue extraction to the centralized refreshLogIssuesFromFile and applyIssueExitCode helpers.
Notification conversion uses pre-snapshotted issue counts
internal/orchestrator/notification_adapter.go, internal/orchestrator/notification_adapter_test.go
convertBackupStatsToNotificationData stops re-parsing the log file and instead consumes pre-snapshotted ErrorCount/WarningCount/LogCategories from BackupStats, ensuring all notifiers observe consistent totals. Tests verify snapshot propagation and prevent log re-reading.
Test helpers and observability for snapshot timing
internal/orchestrator/additional_helpers_test.go, internal/orchestrator/extensions_additional_test.go
stubNotifierChannel is extended to record snapshot data; new tests verify that pre-notification snapshots are captured and observed consistently by multiple notifiers.

Exec Info Pointer-Based Caching

Layer / File(s) Summary
Global execInfo and execInfoOnce pointer conversion
cmd/proxsave/runtime_helpers.go, cmd/proxsave/base_dir_test.go
Global executable-detection cache storage is changed from value types to pointers, allowing test-time reset via pointer assignment.

Config Wizard Early Exit

Layer / File(s) Summary
Skip wizard when skipConfigWizard flag is set
cmd/proxsave/install.go
runConfigWizardCLI returns immediately when the configuration should be preserved, preventing interactive configuration steps.

Minor Refactoring and Documentation

Layer / File(s) Summary
Email delivery method switch refactoring
internal/notify/email.go, docs/CONFIGURATION.md
EmailNotifier.Send delivery-method conditionals are refactored to switch directly on config.DeliveryMethod. Documentation is updated to describe PMF delivery method aliases (proxmox, proxmox-notifications, proxmox-mail-forward).
Test cleanup helper pattern updates
internal/orchestrator/encryption_exported_test.go
Age setup wizard tests are updated to use t.Cleanup for stdin fixture closure with error reporting via t.Errorf.
Code simplifications
internal/orchestrator/mount_guard.go, internal/backup/archiver.go
Unused ensureGuardTargetUnmounted helper is removed; error-channel drain is simplified to a bare receive statement.
Test formatting and alignment
internal/orchestrator/pbs_api_apply_test.go
Whitespace and column alignment adjusted in struct field and error-map entries without changing test logic.

Dependency Version Updates

Layer / File(s) Summary
GitHub Actions workflow pins
.github/workflows/dependabot-automerge.yml, .github/workflows/dependency-review.yml, .github/workflows/security-ultimate.yml
Action pins for actions/setup-node, actions/dependency-review-action, and github/codeql-action (upload-sarif, init, analyze) are updated to newer commit SHAs.
Go module version updates
go.mod
golang.org/x/crypto, golang.org/x/term, golang.org/x/text, and golang.org/x/sys are bumped to newer patch/minor versions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Possibly related PRs

  • tis24dev/proxsave#212: Updates executable-detection test/implementation plumbing with same pointer-based caching changes to execInfo/execInfoOnce and forceDetectedBaseDirForTest.
  • tis24dev/proxsave#213: Addresses per-notifier error/warning count drift by snapshotting counts in backup finalization and removing log re-parsing during notification conversion—directly overlapping with the main PR's snapshot system implementation.
  • tis24dev/proxsave#179: Modifies runConfigWizardCLI/SkipConfigWizard decision flow in the installer, related to the main PR's config wizard early-exit change.

🐰 A snapshot in time keeps the counts aligned,
No more re-parsing as notifiers wind,
The backup stats bloom with categories in hand,
And consistency spreads throughout all the land! 📊✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Stabilize notifier dispatch, CI, and cleanup refinements' clearly summarizes the main changes: notification stability fixes, CI updates, and code cleanup—all supported by the detailed PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 18, 2026

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
  • ⚠️ 1 package(s) with unknown licenses.
See the Details below.

License Issues

go.mod

PackageVersionLicenseIssue Type
golang.org/x/term0.43.0NullUnknown License
Allowed Licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, LicenseRef-scancode-google-patent-license-golang

OpenSSF Scorecard

PackageVersionScoreDetails
actions/github/codeql-action/analyze 9e0d7b8d25671d64c341c19c0152d693099fb5ba UnknownUnknown
actions/github/codeql-action/init 9e0d7b8d25671d64c341c19c0152d693099fb5ba UnknownUnknown
actions/github/codeql-action/upload-sarif 9e0d7b8d25671d64c341c19c0152d693099fb5ba UnknownUnknown
gomod/golang.org/x/crypto 0.51.0 UnknownUnknown
gomod/golang.org/x/sys 0.44.0 UnknownUnknown
gomod/golang.org/x/term 0.43.0 UnknownUnknown
gomod/golang.org/x/text 0.37.0 UnknownUnknown

Scanned Files

  • .github/workflows/security-ultimate.yml
  • go.mod

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Stabilize notifier dispatch with pre-notification issue snapshot
🐞 Bug fix ✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Fix per-notifier error/warning count drift by snapshotting stats before notification dispatch
• Store exec info behind pointers to enable test overrides without copying sync.Once
• Simplify archiver drain and mount guard logic, remove redundant code
• Update Go module dependencies and GitHub Actions versions
• Add comprehensive test coverage for notification snapshot boundary
Diagram
flowchart LR
  A["Backup Completion"] --> B["finalizeBackupStats"]
  B --> C["Parse Log File"]
  C --> D["Snapshot ErrorCount<br/>WarningCount<br/>LogCategories"]
  D --> E["startNotificationGroup"]
  E --> F["snapshotPreNotificationIssues"]
  F --> G["applyIssueExitCode"]
  G --> H["dispatchNotifications"]
  H --> I["Notifier 1"]
  H --> J["Notifier 2"]
  I --> K["Read Snapshotted Stats"]
  J --> K
  K --> L["Consistent Counts<br/>Across Notifiers"]
Loading

Grey Divider

File Changes

1. internal/orchestrator/extensions.go 🐞 Bug fix +51/-2

Snapshot issues before notification dispatch chain

internal/orchestrator/extensions.go


2. internal/orchestrator/backup_run_phases.go ✨ Enhancement +13/-16

Refactor finalize backup stats with issue snapshot

internal/orchestrator/backup_run_phases.go


3. internal/orchestrator/notification_adapter.go 🐞 Bug fix +5/-9

Trust snapshotted stats instead of re-parsing log

internal/orchestrator/notification_adapter.go


View more (19)
4. internal/orchestrator/additional_helpers_test.go 🧪 Tests +98/-2

Add test for notification snapshot boundary

internal/orchestrator/additional_helpers_test.go


5. internal/orchestrator/notification_adapter_test.go 🧪 Tests +57/-19

Update tests to verify snapshot propagation

internal/orchestrator/notification_adapter_test.go


6. internal/orchestrator/extensions_additional_test.go 🧪 Tests +35/-0

Test early error notification with log file

internal/orchestrator/extensions_additional_test.go


7. internal/orchestrator/backup_run_helpers.go ✨ Enhancement +3/-5

Consolidate log issue parsing logic

internal/orchestrator/backup_run_helpers.go


8. internal/orchestrator/orchestrator.go ✨ Enhancement +5/-3

Add LogCategories field to BackupStats

internal/orchestrator/orchestrator.go


9. cmd/proxsave/runtime_helpers.go ✨ Enhancement +5/-4

Store exec info behind pointers for test flexibility

cmd/proxsave/runtime_helpers.go


10. cmd/proxsave/base_dir_test.go 🧪 Tests +2/-2

Update test to use pointer-based exec info

cmd/proxsave/base_dir_test.go


11. cmd/proxsave/install.go 🐞 Bug fix +0/-1

Remove duplicate template sanitization

cmd/proxsave/install.go


12. internal/backup/archiver.go ✨ Enhancement +1/-1

Simplify tar writer drain receive

internal/backup/archiver.go


13. internal/orchestrator/mount_guard.go ✨ Enhancement +1/-9

Remove misleading mount guard status wrapper

internal/orchestrator/mount_guard.go


14. internal/notify/email.go Formatting +4/-4

Simplify switch statement formatting

internal/notify/email.go


15. internal/orchestrator/pbs_api_apply_test.go Formatting +9/-9

Format PBS API apply test alignment

internal/orchestrator/pbs_api_apply_test.go


16. internal/orchestrator/encryption_exported_test.go ✨ Enhancement +10/-2

Use t.Cleanup for file handle management

internal/orchestrator/encryption_exported_test.go


17. go.mod Dependencies +4/-4

Update Go module dependencies

go.mod


18. go.sum Dependencies +8/-8

Update Go module checksums

go.sum


19. .github/workflows/dependabot-automerge.yml Dependencies +1/-1

Update setup-node action version

.github/workflows/dependabot-automerge.yml


20. .github/workflows/dependency-review.yml Dependencies +1/-1

Update dependency-review-action version

.github/workflows/dependency-review.yml


21. .github/workflows/security-ultimate.yml Dependencies +3/-3

Update codeql-action version

.github/workflows/security-ultimate.yml


22. docs/CONFIGURATION.md 📝 Documentation +1/-1

Clarify email delivery method documentation

docs/CONFIGURATION.md


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 18, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Qodo Logo

Comment thread internal/orchestrator/backup_run_phases.go Outdated
Comment thread internal/orchestrator/extensions.go Outdated
Repository owner deleted a comment from coderabbitai Bot May 18, 2026
Repository owner deleted a comment from coderabbitai Bot May 18, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 18, 2026

Codecov Report

❌ Patch coverage is 86.79245% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/orchestrator/backup_run_phases.go 66.66% 3 Missing and 1 partial ⚠️
internal/orchestrator/extensions.go 93.54% 1 Missing and 1 partial ⚠️
internal/notify/email.go 75.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

tis24dev added 2 commits May 19, 2026 00:59
Keep common backup finalization separate from dry-run issue parsing.
Remove dead success handling and cover issue promotion rules.
@tis24dev tis24dev merged commit 24b4c96 into main May 18, 2026
12 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.

2 participants