diff --git a/.env.test b/.env.test
new file mode 100644
index 00000000..9ef2c8a0
--- /dev/null
+++ b/.env.test
@@ -0,0 +1,4 @@
+APP_HOST=canine.example.com
+OMNIAUTH_GITHUB_WEBHOOK_SECRET=1234567890
+OMNIAUTH_GITHUB_PUBLIC_KEY=1234567890
+OMNIAUTH_GITHUB_PRIVATE_KEY=1234567890
diff --git a/.gitignore b/.gitignore
index 1a2d2ceb..c16b10cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@
# Ignore all environment files (except templates).
/.env*
!/.env*.erb
+!/.env.test
# Ignore all logfiles and tempfiles.
/log/*
diff --git a/app/controllers/inbound_webhooks/application_controller.rb b/app/controllers/inbound_webhooks/application_controller.rb
new file mode 100644
index 00000000..d2b75572
--- /dev/null
+++ b/app/controllers/inbound_webhooks/application_controller.rb
@@ -0,0 +1,9 @@
+module InboundWebhooks
+ class ApplicationController < ActionController::API
+ private
+
+ def payload
+ @payload ||= request.form_data? ? request.request_parameters.to_json : request.raw_post
+ end
+ end
+end
diff --git a/app/controllers/inbound_webhooks/github_controller.rb b/app/controllers/inbound_webhooks/github_controller.rb
new file mode 100644
index 00000000..3b396d5c
--- /dev/null
+++ b/app/controllers/inbound_webhooks/github_controller.rb
@@ -0,0 +1,29 @@
+module InboundWebhooks
+ class GithubController < ApplicationController
+ before_action :verify_event
+
+ def create
+ # Save webhook to database
+ record = InboundWebhook.create(body: payload)
+
+ # Queue webhook for processing
+ InboundWebhooks::GithubJob.perform_later(record)
+
+ # Tell service we received the webhook successfully
+ head :ok
+ end
+
+ private
+
+ def verify_event
+ payload = request.body.read
+ # TODO: Verify the event was sent from the service
+ # Render `head :bad_request` if verification fails
+ secret = ENV["OMNIAUTH_GITHUB_WEBHOOK_SECRET"]
+ signature = "sha256=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, payload)
+ unless Rack::Utils.secure_compare(signature, request.headers["HTTP_X_HUB_SIGNATURE_256"])
+ head :bad_request
+ end
+ end
+ end
+end
diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb
index 25046f2f..bd527963 100644
--- a/app/controllers/users/omniauth_callbacks_controller.rb
+++ b/app/controllers/users/omniauth_callbacks_controller.rb
@@ -1,7 +1,7 @@
module Users
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
- before_action :set_service, except: [:failure]
- before_action :set_user, except: [:failure]
+ before_action :set_service, except: [ :failure ]
+ before_action :set_user, except: [ :failure ]
attr_reader :service, :user
@@ -40,7 +40,7 @@ module Users
end
def auth
- request.env['omniauth.auth']
+ request.env["omniauth.auth"]
end
def set_service
@@ -68,17 +68,16 @@ module Users
uid: auth.uid,
expires_at: expires_at,
access_token: auth.credentials.token,
- access_token_secret: auth.credentials.secret,
+ access_token_secret: auth.credentials.secret
}
end
def create_user
User.create(
email: auth.info.email,
- #name: auth.info.name,
- password: Devise.friendly_token[0,20]
+ # name: auth.info.name,
+ password: Devise.friendly_token[0, 20]
)
end
-
end
end
diff --git a/app/models/inbound_webook.rb b/app/models/inbound_webook.rb
new file mode 100644
index 00000000..4b47c826
--- /dev/null
+++ b/app/models/inbound_webook.rb
@@ -0,0 +1,20 @@
+# == Schema Information
+#
+# Table name: inbound_webooks
+#
+# id :bigint not null, primary key
+# body :text
+# status :integer default("pending")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+class InboundWebook < ApplicationRecord
+ cattr_accessor :incinerate_after, default: 7.days
+ enum status: %i[pending processing processed failed]
+
+ after_update_commit :incinerate_later, if: -> { status_previously_changed? && processed? }
+
+ def incinerate_later
+ InboundWebhooks::IncinerationJob.set(wait: incinerate_after).perform_later(self)
+ end
+end
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb
index 96a94124..4fc43f92 100644
--- a/app/views/devise/shared/_links.html.erb
+++ b/app/views/devise/shared/_links.html.erb
@@ -18,8 +18,6 @@
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
<% end %>
-<%- if devise_mapping.omniauthable? %>
- <%- resource_class.omniauth_providers.each do |provider| %>
- <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %>
- <% end %>
+<%- resource_class.omniauth_providers.each do |provider| %>
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %>
<% end %>
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 2ccfc37e..db08d27f 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -24,7 +24,7 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
- config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
+ config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
@@ -36,7 +36,7 @@ Devise.setup do |config|
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
# available as additional gems.
- require 'devise/orm/active_record'
+ require "devise/orm/active_record"
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating a user. The default is
@@ -58,12 +58,12 @@ Devise.setup do |config|
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
- config.case_insensitive_keys = [:email]
+ config.case_insensitive_keys = [ :email ]
# Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or
# modifying a user and when used to authenticate or find a user. Default is :email.
- config.strip_whitespace_keys = [:email]
+ config.strip_whitespace_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# It can be set to an array that will enable params authentication only for the
@@ -97,7 +97,7 @@ Devise.setup do |config|
# Notice that if you are skipping storage for all authentication paths, you
# may want to disable generating routes to Devise's sessions controller by
# passing skip: :sessions to `devise_for` in your config/routes.rb
- config.skip_session_storage = [:http_auth]
+ config.skip_session_storage = [ :http_auth ]
# By default, Devise cleans up the CSRF token on authentication to
# avoid CSRF token fixation attacks. This means that, when using AJAX
@@ -271,14 +271,8 @@ Devise.setup do |config|
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
- # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
-
- env_creds = Rails.application.credentials[Rails.env.to_sym] || {}
- %i{ facebook twitter github }.each do |provider|
- if options = env_creds[provider]
- config.omniauth provider, options[:app_id], options[:app_secret], options.fetch(:options, {})
- end
- end
+ # TODO (chris): add digital ocean?
+ config.omniauth :github, ENV["OMNIAUTH_GITHUB_PRIVATE_KEY"], ENV["OMNIAUTH_GITHUB_PRIVATE_KEY"], scope: "user,repo,write:packages", webhook_secret: ENV["OMNIAUTH_GITHUB_WEBHOOK_SECRET"]
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
diff --git a/db/migrate/20240925230423_create_inbound_webooks.rb b/db/migrate/20240925230423_create_inbound_webooks.rb
new file mode 100644
index 00000000..07fd1e3f
--- /dev/null
+++ b/db/migrate/20240925230423_create_inbound_webooks.rb
@@ -0,0 +1,9 @@
+class CreateInboundWebooks < ActiveRecord::Migration[7.2]
+ def change
+ create_table :inbound_webooks do |t|
+ t.text :body
+ t.integer :status, default: 0
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 863fdc53..6e163876 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.2].define(version: 2024_09_25_222027) do
+ActiveRecord::Schema[7.2].define(version: 2024_09_25_230423) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -143,6 +143,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_222027) do
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
end
+ create_table "inbound_webooks", force: :cascade do |t|
+ t.text "body"
+ t.integer "status", default: 0
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "log_outputs", force: :cascade do |t|
t.bigint "loggable_id", null: false
t.string "loggable_type", null: false
diff --git a/test/fixtures/inbound_webooks.yml b/test/fixtures/inbound_webooks.yml
new file mode 100644
index 00000000..b01c658f
--- /dev/null
+++ b/test/fixtures/inbound_webooks.yml
@@ -0,0 +1,20 @@
+# == Schema Information
+#
+# Table name: inbound_webooks
+#
+# id :bigint not null, primary key
+# body :text
+# status :integer default("pending")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the "{}" from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+#
+one: {}
+# column: value
+#
+two: {}
+# column: value
diff --git a/test/models/inbound_webook_test.rb b/test/models/inbound_webook_test.rb
new file mode 100644
index 00000000..014b8243
--- /dev/null
+++ b/test/models/inbound_webook_test.rb
@@ -0,0 +1,17 @@
+# == Schema Information
+#
+# Table name: inbound_webooks
+#
+# id :bigint not null, primary key
+# body :text
+# status :integer default("pending")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+require "test_helper"
+
+class InboundWebookTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end