discourse/spec/requests/default_headers_spec.rb
Kelv 0d90f6e3c3
FIX: cross origin opener policy should apply to public error responses (#31559)
In some error paths, headers that were set earlier can get overwritten
(e.g. `Cross-Origin-Opener-Policy`) by middleware such as
ActionDispatch::ShowExceptions.

This PR sets the `Cross-Origin-Opener-Policy` header to the value of the
SiteSetting `cross_origin_opener_policy_header` if it's missing and if
the response is for HTML.

In future, this DefaultHeaders middleware can be used to set other
default headers that relate to security or other purposes.

### Testing
<img width="631" alt="test"
src="https://github.com/user-attachments/assets/05106a40-2bc7-435d-91a2-4dd2a098f349"
/>
2025-03-03 17:04:24 +08:00

50 lines
1.7 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe Middleware::DefaultHeaders do
context "when a public exception(like RoutingError) is raised" do
context "when requesting an HTML page" do
let(:html_path) { "/nonexistent" }
it "sets the Cross-Origin-Opener-Policy header" do
SiteSetting.bootstrap_error_pages = true
get html_path # triggers a RoutingError, handled by the exceptions_app
expect(response.headers).to have_key("Cross-Origin-Opener-Policy")
expect(response.headers["Cross-Origin-Opener-Policy"]).to eq("same-origin-allow-popups")
end
end
context "when requesting a JSON response for an invalid URL" do
let(:json_path) { "/nonexistent.json" }
it "does not include the Cross-Origin-Opener-Policy header" do
SiteSetting.bootstrap_error_pages = true
SiteSetting.cross_origin_opener_policy_header = "same-origin"
get json_path
expect(response.headers["Cross-Origin-Opener-Policy"]).to be_nil
end
end
end
context "when a rescued exception is raised" do
before do
@old_logger = Rails.logger
@logs = StringIO.new
Rails.logger = Logger.new(@logs)
end
after { Rails.logger = @old_logger }
it "should not raise a 500 (nor should it log a warning) for bad params" do
bad_str = (+"d\xDE").force_encoding("utf-8")
expect(bad_str.valid_encoding?).to eq(false)
get "/latest", params: { test: bad_str }
log = @logs.string
expect(log).not_to include("exception app middleware")
expect(response.status).to eq(400)
expect(response.headers).to have_key("Cross-Origin-Opener-Policy")
expect(response.headers["Cross-Origin-Opener-Policy"]).to eq("same-origin-allow-popups")
end
end
end