Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 17, 2025

Notification System for Container Updates

All tasks completed!

Implementation of Discord and Email notifications when containers have updates available:

  • Backend: Create notification models and database schema
    • Add notification settings model
    • Add notification provider enum (Discord, Email)
    • Add notification history/log table
    • Add database migrations
  • Backend: Create notification service
    • Implement Discord webhook notification
    • Implement Email SMTP notification
    • Add notification service with send methods
    • Security hardening: URL validation, email validation, TLS improvements
  • Backend: Integrate notifications with image update service
    • Hook into image update detection flow
    • Send notifications when updates detected
  • Backend: Add notification API handlers
    • Create handler for notification settings CRUD
    • Add test notification endpoint
  • Backend: Wire up services in bootstrap
    • Add notification service to services container
    • Register notification handler routes
  • Frontend: Create notification settings UI
    • Add notifications page under settings
    • Create Discord webhook configuration form
    • Create Email SMTP configuration form
    • Add test notification buttons
  • Frontend: Add notification settings to navigation
  • Documentation: Update with notification configuration
    • Added security warnings for Gmail App Passwords
  • Security: Address CodeQL findings

Security Improvements (Latest Commit)

SSRF Prevention

  • ✅ Added webhook URL validation to ensure URLs point to Discord domains only
  • ✅ Enforced HTTPS for all webhook URLs
  • ✅ Validated webhook URL paths match Discord's API structure
  • ✅ Prevented access to internal/private networks through webhook URLs

Input Validation

  • ✅ Added email address validation using Go's net/mail package
  • ✅ Validated both sender and recipient email addresses
  • ✅ Ensured proper email format before sending

TLS Security

  • ✅ Set minimum TLS version to TLS 1.2
  • ✅ Explicitly disabled insecure TLS certificate verification
  • ✅ Ensured proper certificate validation for SMTP connections

Security Features Summary

  • All sensitive data (webhook URLs, passwords) encrypted before storage
  • Webhook URL validation prevents SSRF attacks
  • Email validation prevents injection attacks
  • TLS 1.2+ enforced for all encrypted connections
  • Proper certificate verification enabled
Original prompt

This section details on the original issue you should resolve

<issue_title>⚡️ Feature: Notification when containers update</issue_title>
<issue_description>### Feature Description

Problem It Solves

Proposed Solution

Alternatives Considered

No response

Additional Context

No response

Would you be willing to work on this feature?

  • Yes, I'd like to implement this feature
  • I could help with parts of this feature
  • No, I'm just suggesting the feature</issue_description>

<agent_instructions>Id like to add discord and email notifications to start but maybe apprise api works? most of this logic should all be in the backend, but the needs to be a frontend ui component to configure as well </agent_instructions>

Comments on the Issue (you are @copilot in this section)

@kmendell > Please include [signal-api](https://github.com/bbernhard/signal-cli-rest-api) support when implementing notifications.

Im not familar with this, But ill take a look, to start it was just going to be email notifciations most likley. </comment_new>

Fixes #147


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Greptile Overview

Updated On: 2025-10-17 19:17:57 UTC

Greptile Summary

This PR implements a comprehensive notification system that sends Discord webhook and email notifications when container image updates are detected. The implementation includes complete backend infrastructure with database models, migrations for both PostgreSQL and SQLite, a notification service with SSRF protection and email validation, API handlers for CRUD operations, and integration with the existing image update service. The frontend adds a new notifications settings page with configuration forms for both Discord and Email providers, complete with test functionality and proper internationalization support.

The system uses encrypted storage for sensitive data like webhook URLs and SMTP passwords, implements security hardening measures including webhook URL validation to prevent SSRF attacks, email address validation using Go's net/mail package, and enforces TLS 1.2+ for SMTP connections. The architecture follows the existing codebase patterns with proper dependency injection, service separation, and environment scoping (though notification handlers don't currently use environment context).

Important Files Changed

Changed Files
Filename Score Overview
backend/internal/services/notification_service.go 4/5 Core notification service with Discord webhook and email functionality, includes security hardening
backend/internal/api/notification_handler.go 3/5 REST API handler for notification settings with environment-scoped routes but unused environment context
backend/internal/services/image_update_service.go 4/5 Integrated notification sending when container updates are detected
frontend/src/routes/settings/notifications/+page.svelte 5/5 Comprehensive notification settings UI with Discord and Email configuration forms
backend/internal/models/notification.go 4/5 Database models for notification settings and logs with proper GORM annotations
backend/internal/utils/notifications/email_util.go 4/5 SMTP client utility with TLS security and email header injection prevention
backend/resources/migrations/postgres/019_add_notifications.up.sql 5/5 PostgreSQL migration creating notification tables with proper indexing
backend/resources/migrations/sqlite/019_add_notifications.up.sql 5/5 SQLite migration creating notification tables with appropriate schema
frontend/messages/en.json 5/5 Added comprehensive localization support for notification system UI
backend/internal/bootstrap/services_bootstrap.go 5/5 Added notification service to dependency injection container
frontend/src/lib/services/notification-service.ts 5/5 Frontend service for notification settings management and testing
docs/NOTIFICATIONS.md 5/5 Comprehensive documentation with security warnings and configuration guide
backend/go.mod 5/5 Added SMTP dependencies for email notification functionality
backend/go.sum 5/5 Updated checksums for new SMTP library dependencies

Confidence score: 4/5

  • This PR introduces a well-architected notification system with good security practices, but has some implementation gaps that could cause issues
  • Score reflects solid overall implementation with security hardening, but points deducted for API handler environment scoping mismatch and potential notification service null checks
  • Pay close attention to backend/internal/api/notification_handler.go for the environment scoping issue and backend/internal/services/image_update_service.go for the notification integration

@Copilot Copilot AI changed the title [WIP] Add notification feature for container updates ⚡️ Add notification system for container updates (Discord & Email) Oct 17, 2025
@Copilot Copilot AI requested a review from kmendell October 17, 2025 04:56
Copilot finished work on behalf of kmendell October 17, 2025 04:56
@kmendell kmendell changed the title ⚡️ Add notification system for container updates (Discord & Email) feat: notification system for container updates (Discord & Email) Oct 17, 2025
@kmendell
Copy link
Member

@copilot fix the codeql errors

- Add webhook URL validation to prevent SSRF attacks
- Validate Discord webhook URLs are HTTPS and point to Discord domains
- Add email address validation using net/mail package
- Improve TLS configuration with MinVersion and explicit InsecureSkipVerify=false
- Ensure proper certificate verification for SMTP TLS connections

Co-authored-by: kmendell <[email protected]>
Copy link
Contributor Author

Copilot AI commented Oct 17, 2025

@copilot fix the codeql errors

Fixed CodeQL security issues in commit fc43077:

Security improvements:

  • Added webhook URL validation to prevent SSRF attacks (validates URLs are HTTPS and point to Discord domains)
  • Added email address validation using Go's net/mail package
  • Improved TLS configuration with MinVersion set to TLS 1.2 and explicit certificate verification
  • Added path validation for Discord webhook URLs

All changes ensure proper input validation and secure network communication.

Copilot finished work on behalf of kmendell October 17, 2025 07:51
@kmendell kmendell marked this pull request as ready for review October 17, 2025 19:17
@kmendell kmendell requested a review from a team as a code owner October 17, 2025 19:17
@kmendell kmendell changed the title feat: notification system for container updates (Discord & Email) feat: notification system for container and image updates Oct 17, 2025
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

22 files reviewed, 12 comments

Edit Code Review Agent Settings | Greptile

notificationService: notificationService,
}

notifications := group.Group("/environments/:id/notifications")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The :id parameter from the environment route is never used in any handler methods, creating inconsistency between the API design and implementation

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/api/notification_handler.go
Line: 21:21

Comment:
**logic:** The `:id` parameter from the environment route is never used in any handler methods, creating inconsistency between the API design and implementation

How can I resolve this? If you propose a fix, please make it concise.

}

func (h *NotificationHandler) GetAllSettings(c *gin.Context) {
settings, err := h.notificationService.GetAllSettings(c.Request.Context())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider extracting environment ID from URL path if notifications should be environment-scoped: envID := c.Param("id")

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/api/notification_handler.go
Line: 33:33

Comment:
**style:** Consider extracting environment ID from URL path if notifications should be environment-scoped: `envID := c.Param("id")`

How can I resolve this? If you propose a fix, please make it concise.


type NotificationSettings struct {
ID uint `json:"id" gorm:"primaryKey"`
Provider string `json:"provider" gorm:"not null;index"`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Provider field should use NotificationProvider type instead of string for better type safety and validation

Context Used: Rule from dashboard - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/models/notification.go
Line: 24:24

Comment:
**style:** Provider field should use NotificationProvider type instead of string for better type safety and validation

**Context Used:** Rule from `dashboard` - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... ([source](https://app.greptile.com/review/custom-context?memory=214b40a8-9695-4738-986d-5949b5d65ff1))

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +265 to +267
if decrypted, err := utils.Decrypt(emailConfig.SMTPPassword); err == nil {
emailConfig.SMTPPassword = decrypted
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: same pattern as webhook URL - silently ignoring password decryption errors could mask configuration problems

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/services/notification_service.go
Line: 265:267

Comment:
**style:** same pattern as webhook URL - silently ignoring password decryption errors could mask configuration problems

How can I resolve this? If you propose a fix, please make it concise.

}

// Authenticate if credentials are provided
if config.SMTPUsername != "" || config.SMTPPassword != "" {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Authentication logic allows empty username with non-empty password, which may not be intended behavior for most SMTP servers

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/utils/notifications/email_util.go
Line: 74:74

Comment:
**logic:** Authentication logic allows empty username with non-empty password, which may not be intended behavior for most SMTP servers

How can I resolve this? If you propose a fix, please make it concise.

// sendHelloCommand sends the HELO/EHLO command to the SMTP server
func sendHelloCommand(client *smtp.Client) error {
// Try to get hostname, use "localhost" as fallback
hostname := "localhost"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Using hardcoded 'localhost' as hostname may cause issues with some SMTP servers that validate HELO hostname

Context Used: Rule from dashboard - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/utils/notifications/email_util.go
Line: 87:87

Comment:
**style:** Using hardcoded 'localhost' as hostname may cause issues with some SMTP servers that validate HELO hostname

**Context Used:** Rule from `dashboard` - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... ([source](https://app.greptile.com/review/custom-context?memory=214b40a8-9695-4738-986d-5949b5d65ff1))

How can I resolve this? If you propose a fix, please make it concise.

}

// Write the email content
_, err = io.Copy(w, strings.NewReader(message))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Using io.Copy with strings.NewReader is less efficient than directly writing the string with w.Write([]byte(message))

Context Used: Rule from dashboard - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/utils/notifications/email_util.go
Line: 130:130

Comment:
**style:** Using `io.Copy` with `strings.NewReader` is less efficient than directly writing the string with `w.Write([]byte(message))`

**Context Used:** Rule from `dashboard` - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... ([source](https://app.greptile.com/review/custom-context?memory=214b40a8-9695-4738-986d-5949b5d65ff1))

How can I resolve this? If you propose a fix, please make it concise.

s = strings.ReplaceAll(s, "\n", "")

// Allow only: letters, numbers, dot, slash, dash, colon, at, underscore
safe := make([]rune, 0, len(s))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Pre-allocating slice with len(s) capacity may be wasteful if many characters are filtered out

Context Used: Rule from dashboard - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/utils/notifications/email_util.go
Line: 159:159

Comment:
**style:** Pre-allocating slice with `len(s)` capacity may be wasteful if many characters are filtered out

**Context Used:** Rule from `dashboard` - GoLang Best Practices

Follow idiomatic Go patterns and conventions
Handle errors explicitly, don’t ... ([source](https://app.greptile.com/review/custom-context?memory=214b40a8-9695-4738-986d-5949b5d65ff1))

How can I resolve this? If you propose a fix, please make it concise.

Copy link

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

Copy link

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

⚡️ Feature: Notification when containers update

2 participants