# frozen_string_literal: true RSpec.describe ContentSecurityPolicy::Builder do let(:builder) { described_class.new(base_url: Discourse.base_url) } describe '#<<' do it 'normalizes directive name' do builder << { script_src: ['symbol_underscore'], 'script-src': ['symbol_dash'], 'script_src' => ['string_underscore'], 'script-src' => ['string_dash'], } script_srcs = parse(builder.build)['script-src'] expect(script_srcs).to include(*%w[symbol_underscore symbol_dash string_underscore symbol_underscore]) end it 'rejects invalid directives and ones that are not allowed to be extended' do builder << { invalid_src: ['invalid'], } expect(builder.build).to_not include('invalid') end it 'no-ops on invalid values' do previous = builder.build builder << nil builder << 123 builder << "string" builder << [] builder << {} expect(builder.build).to eq(previous) end end def parse(csp_string) csp_string.split(';').map do |policy| directive, *sources = policy.split [directive, sources] end.to_h end end