Skip to content

Commit

Permalink
Adds cloudflare webhook adapter. (#117)
Browse files Browse the repository at this point in the history
* Adds cloudflare webhook adapter.

* Dont test against rails master
  • Loading branch information
armiiller authored Mar 18, 2024
1 parent b1b3b99 commit e48b73b
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 6 deletions.
6 changes: 0 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ jobs:
ruby: ['2.7', '3.0', '3.1']
gemfile:
- rails_7
- rails_master
exclude:
- gemfile: rails_master
ruby: 2.7
- gemfile: rails_master
ruby: 3.0
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
BUNDLE_PATH_RELATIVE_TO_CWD: true
Expand Down
75 changes: 75 additions & 0 deletions app/models/pager_tree/integrations/cloudflare/v3.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module PagerTree::Integrations
class Cloudflare::V3 < Integration
OPTIONS = [
{key: :webhook_secret, type: :string, default: nil}
]
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"

after_initialize do
self.option_webhook_secret ||= nil
end

def adapter_should_block_incoming?(request)
self.option_webhook_secret.present? && (request.headers["cf-webhook-auth"] != self.option_webhook_secret)
end

def adapter_supports_incoming?
true
end

def adapter_supports_outgoing?
false
end

def adapter_incoming_can_defer?
true
end

def adapter_thirdparty_id
@adapter_thirdparty_id ||= SecureRandom.uuid
end

def adapter_action
:create
end

def adapter_process_create
Alert.new(
title: _title,
description: _description,
thirdparty_id: adapter_thirdparty_id,
dedup_keys: [],
additional_data: _additional_datums
)
end

private

def _title
adapter_incoming_request_params.dig("text")&.truncate(70) || "CF Event #{adapter_incoming_request_params.dig("text")&.titleize}"
end

def _description
ActionController::Base.helpers.simple_format(adapter_incoming_request_params.dig("text"))
end

def _additional_datums
timestamp = begin
Time.at(adapter_incoming_request_params.dig("ts")).utc.to_datetime
rescue
nil
end

datums = []
datums << AdditionalDatum.new(format: "text", label: "Account Name", value: adapter_incoming_request_params.dig("data", "account_name"))
datums << AdditionalDatum.new(format: "text", label: "Zone Name", value: adapter_incoming_request_params.dig("data", "zone_name"))
datums << AdditionalDatum.new(format: "link", label: "Dashboard Link", value: adapter_incoming_request_params.dig("data", "dashboard_link"))
datums << AdditionalDatum.new(format: "datetime", label: "Timestamp", value: timestamp)
datums << AdditionalDatum.new(format: "text", label: "Alert Type", value: adapter_incoming_request_params.dig("alert_type"))
datums << AdditionalDatum.new(format: "text", label: "Account ID", value: adapter_incoming_request_params.dig("account_id"))
datums << AdditionalDatum.new(format: "text", label: "Policy ID", value: adapter_incoming_request_params.dig("policy_id"))

datums.filter { |datum| datum.value.present? }
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="form-group">
<%= form.label :option_webhook_secret %>
<%= form.text_field :option_webhook_secret, class: "form-control" %>
<p class="form-hint"><%== t(".option_webhook_secret_hint_html") %></p>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="sm:col-span-2">
<dt class="text-sm font-medium text-gray-500">
<%= t("activerecord.attributes.pager_tree/integrations/cloudflare/v3.option_webhook_secret") %>
</dt>
<dd class="mt-1 text-sm text-gray-900">
<div class="flex items-center gap-2">
<p class="text-sm truncate">
<%= mask integration.option_webhook_secret %>
</p>
</div>
</dd>
</div>
6 changes: 6 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ en:
option_alert_handoff_hint_html: "Send when the alert has been handed off"
option_template_hint_html: "A handlebars template describing the body that should be posted. See <a href='https://pagertree.com/docs/integration-guides/outgoing-webhook#custom-format' target='_blank'>docs</a> for details."
option_send_linked_hint_html: "Send linked data (source, source_log, user, team)"
cloudflare:
v3:
form_options:
option_webhook_secret_hint_html: "Cloudflare Webhook Secret"
email:
v3:
form_options:
Expand Down Expand Up @@ -133,6 +137,8 @@ en:
option_outgoing_rules: "Outgoing Rules"
"pager_tree/integrations/apex_ping/v3":
option_api_key: "API Key"
"pager_tree/integrations/cloudflare/v3":
option_webhook_secret: "Webhook Secret"
"pager_tree/integrations/email/v3":
option_allow_spam: "Allow Spam"
option_dedup_threads: "Dedup Threads"
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/pager_tree/integrations/integrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ azure_monitor_v3:
type: "PagerTree::Integrations::AzureMonitor::V3"
# options: no_options

cloudflare_v3:
type: "PagerTree::Integrations::Cloudflare::V3"
options:
webhook_secret: "abc123"

cronitor_v3:
type: "PagerTree::Integrations::Cronitor::V3"
# options: no_options
Expand Down
74 changes: 74 additions & 0 deletions test/models/pager_tree/integrations/cloudflare/v3_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require "test_helper"

module PagerTree::Integrations
class Cloudflare::V3Test < ActiveSupport::TestCase
include Integrateable

setup do
@integration = pager_tree_integrations_integrations(:cloudflare_v3)

@create_request = {
name: "Testing Webhook",
text: "Requests to the following zone(s) have been failing for at least 5 minutes: zone-name",
data: {
unreachable_zones: [
{
zone_name: "zone-name",
host: ""
}
]
},
ts: 1710782148,
account_id: "abc123",
policy_id: "def456",
alert_type: "real_origin_monitoring"
}.with_indifferent_access
end

test "sanity" do
assert @integration.adapter_supports_incoming?
assert @integration.adapter_incoming_can_defer?
assert_not @integration.adapter_supports_outgoing?
assert @integration.adapter_show_alerts?
assert @integration.adapter_show_logs?
assert_not @integration.adapter_show_outgoing_webhook_delivery?
end

test "adapter_actions" do
@integration.adapter_incoming_request_params = @create_request
assert_equal :create, @integration.adapter_action
end

test "adapter_thirdparty_id" do
@integration.adapter_incoming_request_params = @create_request
assert @integration.adapter_thirdparty_id.present?
end

test "adapter_process_create" do
@integration.adapter_incoming_request_params = @create_request

true_alert = Alert.new(
title: "Requests to the following zone(s) have been failing for at least 5 ...",
description: ActionController::Base.helpers.simple_format(@create_request["text"]),
urgency: nil,
thirdparty_id: @integration.adapter_thirdparty_id,
dedup_keys: [],
additional_data: [
AdditionalDatum.new(format: "datetime", label: "Timestamp", value: Time.at(1710782148).utc.to_datetime),
AdditionalDatum.new(format: "text", label: "Alert Type", value: "real_origin_monitoring"),
AdditionalDatum.new(format: "text", label: "Account ID", value: "abc123"),
AdditionalDatum.new(format: "text", label: "Policy ID", value: "def456")
]
)

assert_equal true_alert.to_json, @integration.adapter_process_create.to_json
end

test "blocking_incoming" do
@blocked_request = @create_request.deep_dup
@integration.option_webhook_secret = "abc123"
assert @integration.adapter_should_block_incoming?(OpenStruct.new({headers: {"cf-webhook-auth" => ""}}))
assert_not @integration.adapter_should_block_incoming?(OpenStruct.new({headers: {"cf-webhook-auth" => "abc123"}}))
end
end
end

0 comments on commit e48b73b

Please sign in to comment.