Add Rack::Lint to PermissionsPolicy tests

This adds additional test coverage to PermissionsPolicy::Middleware to
validate that it conforms to the Rack SPEC.

The only changes necessary were to use the appropriate header casing for
Content-Type and Feature-Policy. Since this was the only usage of the
CONTENT_TYPE constant, I opted to remove it, but I can replace it with a
DeprecatedConstantProxy if that's more desirable.
This commit is contained in:
Hartley McGuire 2023-07-26 13:14:24 -04:00
parent 3bdd57fba6
commit 4991525abb
No known key found for this signature in database
GPG Key ID: E823FC1403858A82
3 changed files with 72 additions and 7 deletions

@ -23,13 +23,16 @@ module ActionDispatch # :nodoc:
#
class PermissionsPolicy
class Middleware
CONTENT_TYPE = "Content-Type"
# The Feature-Policy header has been renamed to Permissions-Policy.
# The Permissions-Policy requires a different implementation and isn't
# yet supported by all browsers. To avoid having to rename this
# middleware in the future we use the new name for the middleware but
# keep the old header name and implementation for now.
POLICY = "Feature-Policy"
if Gem::Version.new(Rack::RELEASE) >= Gem::Version.new("3")
POLICY = "feature-policy"
else
POLICY = "Feature-Policy"
end
def initialize(app)
@app = app
@ -56,7 +59,7 @@ def call(env)
private
def html_response?(headers)
if content_type = headers[CONTENT_TYPE]
if content_type = headers[Rack::CONTENT_TYPE]
content_type.include?("html")
end
end

@ -51,6 +51,62 @@ def test_deprecated_directives
end
end
class PermissionsPolicyMiddlewareTest < ActionDispatch::IntegrationTest
APP = ->(env) { [200, {}, []] }
POLICY = ActionDispatch::PermissionsPolicy.new do |p|
p.gyroscope :self
end
class PolicyConfigMiddleware
def initialize(app)
@app = app
end
def call(env)
env["action_dispatch.permissions_policy"] = POLICY
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end
end
test "html requests will set a policy" do
@app = build_app(->(env) { [200, { Rack::CONTENT_TYPE => "text/html" }, []] })
get "/index"
assert_equal "gyroscope 'self'", response.headers[ActionDispatch::PermissionsPolicy::Middleware::POLICY]
end
test "non-html requests will not set a policy" do
@app = build_app(->(env) { [200, { Rack::CONTENT_TYPE => "application/json" }, []] })
get "/index"
assert_nil response.headers[ActionDispatch::PermissionsPolicy::Middleware::POLICY]
end
test "existing policies will not be overwritten" do
@app = build_app(->(env) { [200, { ActionDispatch::PermissionsPolicy::Middleware::POLICY => "gyroscope 'none'" }, []] })
get "/index"
assert_equal "gyroscope 'none'", response.headers[ActionDispatch::PermissionsPolicy::Middleware::POLICY]
end
private
def build_app(app)
PolicyConfigMiddleware.new(
Rack::Lint.new(
ActionDispatch::PermissionsPolicy::Middleware.new(
Rack::Lint.new(app),
),
),
)
end
end
class PermissionsPolicyIntegrationTest < ActionDispatch::IntegrationTest
class PolicyController < ActionController::Base
permissions_policy only: :index do |f|
@ -110,7 +166,9 @@ def call(env)
APP = build_app(ROUTES) do |middleware|
middleware.use PolicyConfigMiddleware
middleware.use Rack::Lint
middleware.use ActionDispatch::PermissionsPolicy::Middleware
middleware.use Rack::Lint
end
def app
@ -202,7 +260,9 @@ def call(env)
APP = build_app(ROUTES) do |middleware|
middleware.use PolicyConfigMiddleware
middleware.use Rack::Lint
middleware.use ActionDispatch::PermissionsPolicy::Middleware
middleware.use Rack::Lint
end
def app

@ -5,6 +5,8 @@
module ApplicationTests
class PermissionsPolicyTest < ActiveSupport::TestCase
POLICY = ActionDispatch::PermissionsPolicy::Middleware::POLICY
include ActiveSupport::Testing::Isolation
include Rack::Test::Methods
@ -34,7 +36,7 @@ def index
app("development")
get "/"
assert_nil last_response.headers["Feature-Policy"]
assert_nil last_response.headers[POLICY]
end
test "global permissions policy in an initializer" do
@ -124,7 +126,7 @@ def index
get "/"
assert_equal 200, last_response.status
assert_nil last_response.headers["Feature-Policy"]
assert_nil last_response.headers[POLICY]
end
test "override permissions policy using different directives in a controller" do
@ -170,7 +172,7 @@ def index
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
app = ->(env) {
[200, { "Content-Type" => "text/html" }, ["<p>Hello, World!</p>"]]
[200, { Rack::CONTENT_TYPE => "text/html" }, ["<p>Hello, World!</p>"]]
}
root to: app
end
@ -185,7 +187,7 @@ def index
private
def assert_policy(expected)
assert_equal 200, last_response.status
assert_equal expected, last_response.headers["Feature-Policy"]
assert_equal expected, last_response.headers[POLICY]
end
end
end