Addresses errcheck, gosec, revive, staticcheck, and unused findings
across the codebase (unchecked error returns, unsafe file inclusion
warnings on operator/test-controlled paths, missing package comments,
unused parameters, deprecated API usage). Also fixes two suppression
comments that were silently no-ops due to wrong syntax (#nosec needs
a leading '#', nolint reasons need '//' not '--').
With the backlog clear, drop continue-on-error from the CI lint job
per the plan left in b4b4806.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Copy discipline for notifications: the store, the queue, workers, and
API callers each own clones; no notification object is shared across
goroutines (races previously flagged by -race between workers mutating
Status/RetryCount and handlers JSON-encoding the same pointer).
- Retry progress derives from QueueMessage.Attempt so it survives
requeues; exponential backoff (1s base, 30s cap) honors the documented
queue.retry_backoff setting instead of hammering failing providers in a
tight loop; shutdown abandons pending backoff waits cleanly.
- Stop() cancels a service-lifetime context so idle workers blocked in
Dequeue exit immediately instead of waiting out their poll timeout.
- LocalQueue no longer holds its mutex while sending on the queue
channel (Enqueue/Nack) — with a full buffer this deadlocked the entire
worker pool, since draining requires the same mutex.
- Tenant scoping: notifications are stamped with the caller's ClientID;
non-admin clients can only read/cancel/retry their own (cross-tenant
access reports not-found to avoid leaking existence).
- Sentinel errors ErrNotificationNotFound/ErrNotificationAlreadySent.
- New race, backoff, and tenant-scoping test suites.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Guard against nil result before accessing result.Error in processNotification,
and add NtfyNotifier.Validate override so DefaultTopic is considered before
rejecting notifications with zero recipients.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use typed context key for auth context to prevent collisions (auth.go)
- Eliminate nested locking in CheckRateLimit to prevent potential deadlock (auth.go)
- Add 1MB request body size limit middleware to prevent DoS (router.go)
- Return proper gRPC status codes instead of nil errors on failures (handler.go)
- Use key name instead of raw API key in admin URL paths to prevent secret leakage (keys.go, router.go, keystore_db.go, keystore_hybrid.go)
- Enforce RBAC authorization in service Send/SendBatch for both REST and gRPC (service.go)
- Pin runtime Docker image to alpine:3.21 for reproducible builds (Dockerfile)
- Enable readOnlyRootFilesystem with /tmp emptyDir in k8s deployment (deployment.yaml)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive improvements across REST and gRPC APIs:
- Add structured logging for all notification operations
- Implement HTML email support with multipart/alternative MIME
- Add CC and BCC recipient support for email notifications
- Add GetNotifiers endpoint to query available notifier configurations
- Support configurable From name in SMTP configuration
- Auto-detect content type (text vs HTML) in notification bodies
- Improve error handling and validation across all endpoints
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>