Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove parameters that conflict with security schemas #166

3 changes: 2 additions & 1 deletion lib/rspec/openapi/result_recorder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def record_results!
config_file = File.join(File.dirname(path), RSpec::OpenAPI.config_filename)
begin
require config_file if File.exist?(config_file)
rescue => e
rescue StandardError => e
puts "WARNING: Unable to load #{config_file}: #{e}"
end

Expand All @@ -32,6 +32,7 @@ def record_results!
RSpec::OpenAPI::SchemaCleaner.cleanup!(spec, new_from_zero)
RSpec::OpenAPI::ComponentsUpdater.update!(spec, new_from_zero)
RSpec::OpenAPI::SchemaCleaner.cleanup_empty_required_array!(spec)
RSpec::OpenAPI::SchemaCleaner.cleanup_conflicting_security_parameters!(spec)
RSpec::OpenAPI::SchemaSorter.deep_sort!(spec)
end
end
Expand Down
23 changes: 23 additions & 0 deletions lib/rspec/openapi/schema_cleaner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@
base
end

def cleanup_conflicting_security_parameters!(base)
Fixed Show fixed Hide fixed
security_schemes = base.dig('components', 'securitySchemes') || {}
paths_to_parameters = RSpec::OpenAPI::HashHelper.matched_paths_deeply_nested(base, 'paths', 'security')

paths_to_parameters.each do |path|
parent = base.dig(*path.take(path.length - 1))

security_schemes_for_parent = security_schemes.select do |security_scheme_name, _security_scheme|
parent.dig('security', 0).keys.include?(security_scheme_name)
end

security_schemes_for_parent.each_value do |security_scheme|
next unless parent['parameters']

parent['parameters'].reject! do |parameter|
parameter['in'] == security_scheme['in'] && # same location (ie. header)
parameter['name'] == security_scheme['name'] # same name (ie. AUTHORIZATION)
end
parent.delete('parameters') if parent['parameters'].empty?
end
end
end

def cleanup_empty_required_array!(base)
paths_to_objects = [
*RSpec::OpenAPI::HashHelper.matched_paths_deeply_nested(base, 'components.schemas', 'properties'),
Expand Down
15 changes: 15 additions & 0 deletions spec/rails/app/controllers/secret_items_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class SecretItemsController < ApplicationController
before_action :authenticate_api_key!

def index
render json: { items: ['secrets'] }
end

private

def authenticate_api_key!
if request.env['Secret-Key'] != '42'
head :unauthorized
end
end
end
2 changes: 2 additions & 0 deletions spec/rails/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@
end

get '/test_block' => ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['A TEST']] }

get '/secret_items' => 'secret_items#index'
end
end
21 changes: 21 additions & 0 deletions spec/requests/rails_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
},
}

RSpec::OpenAPI.security_schemes = {
SecretApiKeyAuth: {
type: 'apiKey',
in: 'header',
name: 'Secret-Key',
},
}

RSpec.describe 'Tables', type: :request do
describe '#index' do
context it 'returns a list of tables' do
Expand Down Expand Up @@ -198,6 +206,19 @@
end
end

RSpec.describe 'SecretKey securityScheme',
type: :request,
openapi: { security: [{ 'SecretApiKeyAuth' => [] }] } do
describe '#secret_items' do
it 'authorizes with secret key' do
get '/secret_items',
headers: {
'Secret-Key' => '42',
}
end
end
end

RSpec.describe 'Extra routes', type: :request do
describe '#test_block' do
it 'returns the block content' do
Expand Down
Loading