The test used a 5ms TTL with a 10ms wall-clock sleep to simulate cache
expiry. On loaded CI runners (Azure eastus), the repull HTTP round-trip
plus disk I/O for Store easily exceeded 5ms, causing the freshly written
cache entry to also appear expired when Load was called immediately after,
producing a spurious 'cache expired' error.
HubCache already exposes a nowFn field for deterministic time injection.
Replace the sleep-based approach with a nowFn that advances the clock 2
hours, making the initial entry appear expired to Apply while keeping the
freshly re-stored entry (retrieved_at ≈ now+2h, TTL=1h) valid for the
final assertion.
Two unit tests cover the code paths introduced when email was registered
as a recognised notification provider type in Stage 2.
- TestSendExternal_EmailProviderSkipsJSONTemplate exercises the goroutine
warn path where an enabled email provider passes isDispatchEnabled but
fails supportsJSONTemplates, producing a warning log without panicking
- TestTestProvider_EmailRejectsJSONTemplateStep asserts TestProvider
returns a clear error for email providers because the JSON template
dispatch path does not apply to email delivery
Patch coverage: 6/6 changed lines covered (100%)
After email was recognised as a supported provider type, the existing
rejection assertion for unsupported types incorrectly included email
in its denial list, causing a nil-dereference panic.
- Remove email from the unsupported-type rejection list and cover it
in the accepted-types path instead
- Correct allFeaturesEnabled fixture to set email flag to true, keeping
the fixture semantically consistent with all other service flags
Add email as a recognized, feature-flagged notification service type.
The flag defaults to false and acts as a dispatch gate alongside the
existing discord, gotify, and webhook notification service flags.
- Add FlagEmailServiceEnabled constant to the notifications feature flag
registry with the canonical key convention
- Register the flag in the handler defaults so it appears in the feature
flags API response with a false default
- Recognise 'email' as a supported notification provider type so that
providers of this type pass the type validation gate
- Gate email dispatch on the new flag in isDispatchEnabled() following
the same pattern as gotify and webhook service flags
- Expand the E2E test fixtures FeatureFlags interface to include the new
flag key so typed fixture objects remain accurate
No email message dispatch is wired in this commit; the flag registration
alone makes the email provider type valid and toggleable.
Remove all deprecated Shoutrrr integration artifacts and dead legacy fallback
code from the notification subsystem.
- Remove legacySendFunc field, ErrLegacyFallbackDisabled error, and
legacyFallbackInvocationError() from notification service
- Delete ShouldUseLegacyFallback() from notification router; simplify
ShouldUseNotify() by removing now-dead providerEngine parameter
- Remove EngineLegacy engine constant; EngineNotifyV1 is the sole engine
- Remove legacy.fallback_enabled feature flag, retiredLegacyFallbackEnvAliases,
and parseFlagBool/resolveRetiredLegacyFallback helpers from flags handler
- Remove orphaned EmailRecipients field from NotificationConfig model
- Delete feature_flags_coverage_v2_test.go (tested only the retired flag path)
- Delete security_notifications_test.go.archived (stale archived file)
- Move FIREFOX_E2E_FIXES_SUMMARY.md to docs/implementation/
- Remove root-level scan artifacts tracked in error; add gitignore patterns to
prevent future tracking of trivy-report.json and related outputs
- Update ARCHITECTURE.instructions.md: Notifications row Shoutrrr → Notify
No functional changes to active notification dispatch or mail delivery.
Three tests broke when the Admin/User/Passthrough privilege model replaced
the old admin/user/guest hierarchy in PR-3.
- user-management: tighten heading locator to name='User Management' to avoid
strict mode violation; the settings layout now renders a second h1
('Settings') alongside the page content heading
- user-lifecycle: update audit trail assertion from 2 to 1; users are now
created with a role in a single API call so the backend does not emit a
user_update audit entry when STEP 2 sends the same role value as creation
- auth-fixtures: replace invalid role='guest' with role='passthrough' in the
guestUser fixture; the 'guest' role was removed in PR-3 and 'passthrough' is
the equivalent lowest-privilege role in the new model
Verified: all three previously-failing tests now pass locally.
The Account.tsx page was removed in PR-2b and replaced by UsersPage.tsx with
a UserDetailModal. Several E2E test sections still referenced UI elements that
only existed in the deleted page, causing CI failures across shards.
- admin-onboarding: update header profile link locator from /settings/account
to /settings/users to match the new navigation target in Layout.tsx
- account-settings: skip five legacy test sections (Profile Management,
Certificate Email, Password Change, API Key Management, Accessibility) that
reference deleted Account.tsx elements (#profile-name, #profile-email,
#useUserEmail, #cert-email) or assume these fields are directly on the page
rather than inside the UserDetailModal
- Each skipped section includes an explanatory comment pointing to the PR-3
'Self-Service Profile via Users Page (F10)' suite as the equivalent coverage
Verified: admin-onboarding 8/8 pass; account-settings 8 pass / 20 skipped
- Implemented middleware to restrict access for passthrough users in management routes.
- Added unit tests for management access requirements based on user roles.
- Updated user model tests to include passthrough role validation.
- Enhanced frontend user management to support passthrough role in invite modal.
- Created end-to-end tests for passthrough user access restrictions and navigation visibility.
- Verified self-service profile management for admins and regular users.
The scheduled CodeQL analysis explicitly passed ref: github.sha, which
is frozen when a cron job is queued, not when it runs. Under load or
during a long queue, the analysis could scan code that is days old,
missing vulnerabilities introduced since the last scheduling window.
Replace with ref: github.ref_name so all trigger types — scheduled,
push, and pull_request — consistently scan the current HEAD of the
branch being processed.