mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
fix webhook specs
This commit is contained in:
@@ -75,7 +75,7 @@ module OpenProject
|
||||
# http_options: { open_timeout: 5, read_timeout: 10 }
|
||||
# )
|
||||
def post(url, options = {}, &)
|
||||
super(url, { max_redirects: 0 }.merge(options), &)
|
||||
super(url, { max_redirects: 0, resolver: resolver }.merge(options), &)
|
||||
end
|
||||
|
||||
##
|
||||
|
||||
@@ -53,7 +53,7 @@ module Webhooks
|
||||
def response_attributes(response:, exception:)
|
||||
{
|
||||
response_code: response&.code&.to_i || -1,
|
||||
response_headers: response&.to_hash&.transform_keys { |k| k.underscore.to_sym },
|
||||
response_headers: response&.to_hash&.transform_keys { |k| k.underscore.to_sym }.transform_values(&:first),
|
||||
response_body: response&.body || exception&.message
|
||||
}
|
||||
end
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe AttachmentWebhookJob, :webmock, type: :job do
|
||||
include_context "with ssrf webhook stubs"
|
||||
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:request_url) { "http://example.net/test/42" }
|
||||
shared_let(:project) { create(:project, name: "Foo Bar") }
|
||||
@@ -50,7 +52,7 @@ RSpec.describe AttachmentWebhookJob, :webmock, type: :job do
|
||||
end
|
||||
|
||||
let(:stub) do
|
||||
stub_request(:post, stubbed_url.sub("http://", ""))
|
||||
stub_request(:post, ssrf_resolved_url(stubbed_url))
|
||||
.with(
|
||||
body: hash_including(
|
||||
"action" => event,
|
||||
@@ -59,7 +61,7 @@ RSpec.describe AttachmentWebhookJob, :webmock, type: :job do
|
||||
"id" => attachment.id
|
||||
)
|
||||
),
|
||||
headers: request_headers
|
||||
headers: request_headers.merge(host: "example.net")
|
||||
)
|
||||
.to_return(
|
||||
status: response_code,
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe ProjectWebhookJob, :webmock, type: :job do
|
||||
include_context "with ssrf webhook stubs"
|
||||
|
||||
shared_let(:request_url) { "http://example.net/test/42" }
|
||||
shared_let(:project) { create(:project, name: "Foo Bar") }
|
||||
shared_let(:webhook) { create(:webhook, all_projects: true, url: request_url, secret: nil) }
|
||||
@@ -54,7 +56,7 @@ RSpec.describe ProjectWebhookJob, :webmock, type: :job do
|
||||
end
|
||||
|
||||
let(:stub) do
|
||||
stub_request(:post, stubbed_url.sub("http://", ""))
|
||||
stub_request(:post, ssrf_resolved_url(stubbed_url))
|
||||
.with(
|
||||
body: hash_including(
|
||||
"action" => event,
|
||||
@@ -64,7 +66,7 @@ RSpec.describe ProjectWebhookJob, :webmock, type: :job do
|
||||
**expected_payload
|
||||
)
|
||||
),
|
||||
headers: request_headers
|
||||
headers: request_headers.merge(host: "example.net")
|
||||
)
|
||||
.to_return(
|
||||
status: response_code,
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe TimeEntryWebhookJob, :webmock, type: :job do
|
||||
include_context "with ssrf webhook stubs"
|
||||
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:request_url) { "http://example.net/test/42" }
|
||||
shared_let(:time_entry) { create(:time_entry, hours: 10) }
|
||||
@@ -51,7 +53,7 @@ RSpec.describe TimeEntryWebhookJob, :webmock, type: :job do
|
||||
end
|
||||
|
||||
let(:stub) do
|
||||
stub_request(:post, stubbed_url.sub("http://", ""))
|
||||
stub_request(:post, ssrf_resolved_url(stubbed_url))
|
||||
.with(
|
||||
body: hash_including(
|
||||
"action" => event,
|
||||
@@ -60,7 +62,7 @@ RSpec.describe TimeEntryWebhookJob, :webmock, type: :job do
|
||||
"hours" => "PT10H"
|
||||
)
|
||||
),
|
||||
headers: request_headers
|
||||
headers: request_headers.merge(host: "example.net")
|
||||
)
|
||||
.to_return(
|
||||
status: response_code,
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe WorkPackageCommentWebhookJob, :webmock, type: :model do
|
||||
include_context "with ssrf webhook stubs"
|
||||
|
||||
let(:user) { create(:admin) }
|
||||
let(:request_url) { "http://example.net/test/42" }
|
||||
let(:journal) { work_package.journals.last }
|
||||
@@ -51,7 +53,7 @@ RSpec.describe WorkPackageCommentWebhookJob, :webmock, type: :model do
|
||||
end
|
||||
|
||||
let(:stub) do
|
||||
stub_request(:post, stubbed_url.sub("http://", "")).with(
|
||||
stub_request(:post, ssrf_resolved_url(stubbed_url)).with(
|
||||
body: hash_including(
|
||||
"action" => event_name,
|
||||
"activity" => hash_including(
|
||||
@@ -59,7 +61,7 @@ RSpec.describe WorkPackageCommentWebhookJob, :webmock, type: :model do
|
||||
"comment" => hash_including("raw" => notes)
|
||||
)
|
||||
),
|
||||
headers: request_headers
|
||||
headers: request_headers.merge(host: "example.net")
|
||||
).to_return(
|
||||
status: response_code,
|
||||
body: response_body,
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe WorkPackageWebhookJob, :webmock, type: :model do
|
||||
include_context "with ssrf webhook stubs"
|
||||
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:title) { "Some workpackage subject" }
|
||||
shared_let(:request_url) { "http://example.net/test/42" }
|
||||
@@ -54,7 +56,7 @@ RSpec.describe WorkPackageWebhookJob, :webmock, type: :model do
|
||||
end
|
||||
|
||||
let(:stub) do
|
||||
stub_request(:post, stubbed_url.sub("http://", ""))
|
||||
stub_request(:post, ssrf_resolved_url(stubbed_url))
|
||||
.with(
|
||||
body: hash_including(
|
||||
"action" => event,
|
||||
@@ -63,7 +65,7 @@ RSpec.describe WorkPackageWebhookJob, :webmock, type: :model do
|
||||
"subject" => title
|
||||
)
|
||||
),
|
||||
headers: request_headers
|
||||
headers: request_headers.merge(host: "example.net")
|
||||
)
|
||||
.to_return(
|
||||
status: response_code,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
module WithSsrfWebhookStubsMixin
|
||||
##
|
||||
# A safe public IP returned by the stubbed resolver for any hostname.
|
||||
# It is not in SsrfFilter's private-address blocklist, so SSRF validation passes,
|
||||
# and WebMock stubs using this IP will match the actual Net::HTTP request.
|
||||
SSRF_TEST_IP = "93.184.216.34"
|
||||
|
||||
##
|
||||
# Translates a webhook URL containing a hostname to the IP-based URL that
|
||||
# SsrfFilter will use when making the actual HTTP request. Use this when
|
||||
# setting up WebMock stubs so that they match the resolved request.
|
||||
#
|
||||
# URLs that already contain an IP address are returned unchanged.
|
||||
def ssrf_resolved_url(url)
|
||||
uri = URI.parse(url)
|
||||
return url if [Resolv::IPv4::Regex, Resolv::IPv6::Regex].any? { uri.host.match?(_1) }
|
||||
|
||||
url.sub(uri.host, SSRF_TEST_IP)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_context "with ssrf webhook stubs" do
|
||||
include WithSsrfWebhookStubsMixin
|
||||
|
||||
before do
|
||||
safe_ip = IPAddr.new(WithSsrfWebhookStubsMixin::SSRF_TEST_IP)
|
||||
allow(OpenProject::SsrfProtection).to receive(:resolver).and_return(
|
||||
->(_hostname) { [safe_ip] }
|
||||
)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user