Class: Findbug::AlertChannel

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/findbug/alert_channel.rb

Overview

AlertChannel stores alert channel configurations in the database.

DATABASE SCHEMA

This model expects a table created by the install generator:

create_table :findbug_alert_channels do |t|
  t.string :channel_type, null: false
  t.string :name, null: false
  t.boolean :enabled, default: false
  t.text :config_data
  t.timestamps
end

WHY DB INSTEAD OF INITIALIZER?

Storing alert config in the database lets users create, edit, and manage alert channels from the dashboard UI without code changes or redeployment.

WHY TEXT + SERIALIZE INSTEAD OF JSONB?

ActiveRecord::Encryption works on text columns. We serialize the config hash as JSON and encrypt the entire blob at rest, so webhook URLs and tokens are never stored in plain text.

Constant Summary collapse

CHANNEL_TYPES =

Channel types

%w[email slack discord webhook].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.encryption_available?Boolean

Check if Rails encryption is configured

Returns:

  • (Boolean)


46
47
48
49
50
51
52
# File 'app/models/findbug/alert_channel.rb', line 46

def self.encryption_available?
  return false unless defined?(ActiveRecord::Encryption)

  ActiveRecord::Encryption.config.primary_key.present?
rescue StandardError
  false
end

Instance Method Details

#channel_classObject

Returns the channel class for sending alerts

Maps channel_type to the corresponding Alerts::Channels class.



82
83
84
85
86
87
88
89
# File 'app/models/findbug/alert_channel.rb', line 82

def channel_class
  case channel_type
  when "email"   then Findbug::Alerts::Channels::Email
  when "slack"   then Findbug::Alerts::Channels::Slack
  when "discord" then Findbug::Alerts::Channels::Discord
  when "webhook" then Findbug::Alerts::Channels::Webhook
  end
end

#configObject

Convenience accessor for config



70
71
72
# File 'app/models/findbug/alert_channel.rb', line 70

def config
  config_data || {}
end

#config=(value) ⇒ Object



74
75
76
# File 'app/models/findbug/alert_channel.rb', line 74

def config=(value)
  self.config_data = value
end

#display_typeObject

Human-readable channel type



92
93
94
# File 'app/models/findbug/alert_channel.rb', line 92

def display_type
  channel_type&.titleize
end

#masked_configObject

Returns config with sensitive values masked for display

Shows scheme + host for URLs, masks everything else. Email recipients are shown in full (not sensitive).



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'app/models/findbug/alert_channel.rb', line 101

def masked_config
  masked = {}

  case channel_type
  when "email"
    masked["Recipients"] = Array(config["recipients"]).join(", ").presence || "None"
    masked["From"] = config["from"] || "findbug@localhost"
  when "slack"
    masked["Webhook URL"] = mask_url(config["webhook_url"])
    masked["Channel"] = config["channel"] || "Default"
    masked["Username"] = config["username"] || "Findbug"
  when "discord"
    masked["Webhook URL"] = mask_url(config["webhook_url"])
    masked["Username"] = config["username"] || "Findbug"
  when "webhook"
    masked["URL"] = mask_url(config["url"])
    masked["Method"] = (config["method"] || "POST").upcase
    headers_count = (config["headers"] || {}).size
    masked["Custom Headers"] = "#{headers_count} configured" if headers_count > 0
  end

  masked
end