From 65c917240e4b4698d9514c22b7ea0eadacd9664e Mon Sep 17 00:00:00 2001 From: Jack McCracken Date: Wed, 4 May 2022 15:37:38 -0400 Subject: [PATCH 01/10] Add trusted types directive --- .../headers/content_security_policy_config.rb | 2 ++ .../headers/policy_management.rb | 30 ++++++++++++++++++- .../headers/content_security_policy_spec.rb | 14 +++++++++ .../headers/policy_management_spec.rb | 2 ++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/secure_headers/headers/content_security_policy_config.rb b/lib/secure_headers/headers/content_security_policy_config.rb index 3c477161..5d3c7550 100644 --- a/lib/secure_headers/headers/content_security_policy_config.rb +++ b/lib/secure_headers/headers/content_security_policy_config.rb @@ -35,6 +35,7 @@ def initialize(hash) @report_only = nil @report_uri = nil @require_sri_for = nil + @require_trusted_types_for = nil @sandbox = nil @script_nonce = nil @script_src = nil @@ -44,6 +45,7 @@ def initialize(hash) @style_src = nil @style_src_elem = nil @style_src_attr = nil + @trusted_types = nil @worker_src = nil @upgrade_insecure_requests = nil @disable_nonce_backwards_compatibility = nil diff --git a/lib/secure_headers/headers/policy_management.rb b/lib/secure_headers/headers/policy_management.rb index d3ce5702..4c69111f 100644 --- a/lib/secure_headers/headers/policy_management.rb +++ b/lib/secure_headers/headers/policy_management.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "set" +require 'byebug' module SecureHeaders module PolicyManagement @@ -98,7 +99,19 @@ def self.included(base) STYLE_SRC_ATTR ].flatten.freeze - ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0).uniq.sort + # Experimental directives - these vary greatly in support + # See MDN for details. + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types + TRUSTED_TYPES = :trusted_types + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/require-trusted-types-for + REQUIRE_TRUSTED_TYPES_FOR = :require_trusted_types_for + + DIRECTIVES_EXPERIMENTAL = [ + TRUSTED_TYPES, + REQUIRE_TRUSTED_TYPES_FOR, + ].flatten.freeze + + ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0 + DIRECTIVES_EXPERIMENTAL).uniq.sort # Think of default-src and report-uri as the beginning and end respectively, # everything else is in between. @@ -121,6 +134,7 @@ def self.included(base) OBJECT_SRC => :source_list, PLUGIN_TYPES => :media_type_list, REQUIRE_SRI_FOR => :require_sri_for_list, + REQUIRE_TRUSTED_TYPES_FOR => :require_trusted_types_for_list, REPORT_URI => :source_list, PREFETCH_SRC => :source_list, SANDBOX => :sandbox_list, @@ -130,6 +144,7 @@ def self.included(base) STYLE_SRC => :source_list, STYLE_SRC_ELEM => :source_list, STYLE_SRC_ATTR => :source_list, + TRUSTED_TYPES => :source_list, WORKER_SRC => :source_list, UPGRADE_INSECURE_REQUESTS => :boolean, }.freeze @@ -175,6 +190,7 @@ def self.included(base) ].freeze REQUIRE_SRI_FOR_VALUES = Set.new(%w(script style)) + REQUIRE_TRUSTED_TYPES_FOR_VALUES = Set.new(%w(script)) module ClassMethods # Public: generate a header name, value array that is user-agent-aware. @@ -325,6 +341,8 @@ def validate_directive!(directive, value) validate_media_type_expression!(directive, value) when :require_sri_for_list validate_require_sri_source_expression!(directive, value) + when :require_trusted_types_for_list + validate_require_trusted_types_for_source_expression!(directive, value) else raise ContentSecurityPolicyConfigError.new("Unknown directive #{directive}") end @@ -369,6 +387,16 @@ def validate_require_sri_source_expression!(directive, require_sri_for_expressio end end + # Private: validates that a require trusted types for expression: + # 1. is an array of strings + # 2. is a subset of ["script"] + def validate_require_trusted_types_for_source_expression!(directive, require_trusted_types_for_expression) + ensure_array_of_strings!(directive, require_trusted_types_for_expression) + unless require_trusted_types_for_expression.to_set.subset?(REQUIRE_TRUSTED_TYPES_FOR_VALUES) + raise ContentSecurityPolicyConfigError.new(%(require-sri for must be a subset of #{REQUIRE_TRUSTED_TYPES_FOR_VALUES.to_a} but was #{require_trusted_types_for_expression})) + end + end + # Private: validates that a source expression: # 1. is an array of strings # 2. does not contain any deprecated, now invalid values (inline, eval, self, none) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index dbd878a9..ce4256fe 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -146,6 +146,15 @@ module SecureHeaders expect(csp.value).to eq("default-src 'self'; require-sri-for script style") end + it "supports require-trusted-types-for directive" do + csp = ContentSecurityPolicy.new({require_trusted_types_for: %(script)}) + expect(csp.value).to eq("require-trusted-types-for script") + end + + it "does not support style for require-trusted-types-for directive" do + expect { ContentSecurityPolicy.new({require_trusted_types_for: %(script style)}) }.to raise_error(ContentSecurityPolicyConfigError) + end + it "includes prefetch-src" do csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com)) expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com") @@ -185,6 +194,11 @@ module SecureHeaders csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_attr: %w('self')}) expect(csp.value).to eq("style-src 'self'; style-src-attr 'self'") end + + it "supports trusted-types directive" do + csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)}) + expect(csp.value).to eq("trusted-types blahblahpolicy") + end end end end diff --git a/spec/lib/secure_headers/headers/policy_management_spec.rb b/spec/lib/secure_headers/headers/policy_management_spec.rb index 1a9ac4eb..150e0b35 100644 --- a/spec/lib/secure_headers/headers/policy_management_spec.rb +++ b/spec/lib/secure_headers/headers/policy_management_spec.rb @@ -45,6 +45,7 @@ module SecureHeaders plugin_types: %w(application/x-shockwave-flash), prefetch_src: %w(fetch.com), require_sri_for: %w(script style), + require_trusted_types_for: %w(script), script_src: %w('self'), style_src: %w('unsafe-inline'), upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/ @@ -53,6 +54,7 @@ module SecureHeaders script_src_attr: %w(example.com), style_src_elem: %w(example.com), style_src_attr: %w(example.com), + trusted_types: %w(abcpolicy), report_uri: %w(https://example.com/uri-directive), } From e78ae24e2527917079b8bbe2e5972ab37b0ddc04 Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Thu, 12 May 2022 18:34:40 +0000 Subject: [PATCH 02/10] just enough to get the trusted types directive into the csp, I think --- lib/secure_headers/headers/content_security_policy.rb | 10 ++++++++++ lib/secure_headers/headers/policy_management.rb | 7 ++++++- .../headers/content_security_policy_spec.rb | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index 38ac6cc0..6e80272f 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -61,10 +61,20 @@ def build_value build_sandbox_list_directive(directive_name) when :media_type_list build_media_type_list_directive(directive_name) + when :require_trusted_types_for_list + build_trusted_type_list_directive(directive_name) end end.compact.join("; ") end + def build_trusted_type_list_directive(directive) + source_list = @config.directive_value(directive) + if source_list && !source_list.empty? + escaped_source_list = source_list.gsub(/[\n;]/, " ") + [symbol_to_hyphen_case(directive), escaped_source_list].join(" ").strip + end + end + def build_sandbox_list_directive(directive) return unless sandbox_list = @config.directive_value(directive) max_strict_policy = case sandbox_list diff --git a/lib/secure_headers/headers/policy_management.rb b/lib/secure_headers/headers/policy_management.rb index 4c69111f..4c686e74 100644 --- a/lib/secure_headers/headers/policy_management.rb +++ b/lib/secure_headers/headers/policy_management.rb @@ -286,7 +286,8 @@ def list_directive?(directive) source_list?(directive) || sandbox_list?(directive) || media_type_list?(directive) || - require_sri_for_list?(directive) + require_sri_for_list?(directive) || + require_trusted_types_for_list?(directive) end # For each directive in additions that does not exist in the original config, @@ -324,6 +325,10 @@ def require_sri_for_list?(directive) DIRECTIVE_VALUE_TYPES[directive] == :require_sri_for_list end + def require_trusted_types_for_list?(directive) + DIRECTIVE_VALUE_TYPES[directive] == :require_trusted_types_for_list + end + # Private: Validates that the configuration has a valid type, or that it is a valid # source expression. def validate_directive!(directive, value) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index ce4256fe..f6471f43 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -147,8 +147,8 @@ module SecureHeaders end it "supports require-trusted-types-for directive" do - csp = ContentSecurityPolicy.new({require_trusted_types_for: %(script)}) - expect(csp.value).to eq("require-trusted-types-for script") + csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %(script)) + expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script") end it "does not support style for require-trusted-types-for directive" do From 21b2f46cabca53d734659bb2b5d2c4f598d83cef Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Thu, 26 May 2022 13:41:06 +0000 Subject: [PATCH 03/10] fix test syntax --- lib/secure_headers/headers/content_security_policy.rb | 4 +--- lib/secure_headers/headers/policy_management.rb | 2 +- .../secure_headers/headers/content_security_policy_spec.rb | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index 6e80272f..63373dd3 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -53,7 +53,7 @@ def value def build_value directives.map do |directive_name| case DIRECTIVE_VALUE_TYPES[directive_name] - when :source_list, :require_sri_for_list # require_sri is a simple set of strings that don't need to deal with symbol casing + when :source_list, :require_sri_for_list, :require_trusted_types_for_list # require_sri is a simple set of strings that don't need to deal with symbol casing build_source_list_directive(directive_name) when :boolean symbol_to_hyphen_case(directive_name) if @config.directive_value(directive_name) @@ -61,8 +61,6 @@ def build_value build_sandbox_list_directive(directive_name) when :media_type_list build_media_type_list_directive(directive_name) - when :require_trusted_types_for_list - build_trusted_type_list_directive(directive_name) end end.compact.join("; ") end diff --git a/lib/secure_headers/headers/policy_management.rb b/lib/secure_headers/headers/policy_management.rb index 4c686e74..0a92716d 100644 --- a/lib/secure_headers/headers/policy_management.rb +++ b/lib/secure_headers/headers/policy_management.rb @@ -398,7 +398,7 @@ def validate_require_sri_source_expression!(directive, require_sri_for_expressio def validate_require_trusted_types_for_source_expression!(directive, require_trusted_types_for_expression) ensure_array_of_strings!(directive, require_trusted_types_for_expression) unless require_trusted_types_for_expression.to_set.subset?(REQUIRE_TRUSTED_TYPES_FOR_VALUES) - raise ContentSecurityPolicyConfigError.new(%(require-sri for must be a subset of #{REQUIRE_TRUSTED_TYPES_FOR_VALUES.to_a} but was #{require_trusted_types_for_expression})) + raise ContentSecurityPolicyConfigError.new(%(require-trusted-types-for for must be a subset of #{REQUIRE_TRUSTED_TYPES_FOR_VALUES.to_a} but was #{require_trusted_types_for_expression})) end end diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index f6471f43..a190ab97 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -147,7 +147,7 @@ module SecureHeaders end it "supports require-trusted-types-for directive" do - csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %(script)) + csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script)) expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script") end From 79a2b5dce28da0221cdbb244f52e9c7f556d7b8b Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Tue, 7 Jun 2022 17:31:17 +0000 Subject: [PATCH 04/10] remove unused function --- lib/secure_headers/headers/content_security_policy.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index 63373dd3..3c3c0c7e 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -65,14 +65,6 @@ def build_value end.compact.join("; ") end - def build_trusted_type_list_directive(directive) - source_list = @config.directive_value(directive) - if source_list && !source_list.empty? - escaped_source_list = source_list.gsub(/[\n;]/, " ") - [symbol_to_hyphen_case(directive), escaped_source_list].join(" ").strip - end - end - def build_sandbox_list_directive(directive) return unless sandbox_list = @config.directive_value(directive) max_strict_policy = case sandbox_list From f2cc4c9f813f94d205826aa8ac191e0476d0f045 Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Tue, 7 Jun 2022 17:48:00 +0000 Subject: [PATCH 05/10] move trusted types validate config to appropriate test file --- .../secure_headers/headers/content_security_policy_spec.rb | 4 ---- spec/lib/secure_headers/headers/policy_management_spec.rb | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index a190ab97..3e5c609b 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -151,10 +151,6 @@ module SecureHeaders expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script") end - it "does not support style for require-trusted-types-for directive" do - expect { ContentSecurityPolicy.new({require_trusted_types_for: %(script style)}) }.to raise_error(ContentSecurityPolicyConfigError) - end - it "includes prefetch-src" do csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com)) expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com") diff --git a/spec/lib/secure_headers/headers/policy_management_spec.rb b/spec/lib/secure_headers/headers/policy_management_spec.rb index 150e0b35..d9c85279 100644 --- a/spec/lib/secure_headers/headers/policy_management_spec.rb +++ b/spec/lib/secure_headers/headers/policy_management_spec.rb @@ -122,6 +122,12 @@ module SecureHeaders end.to raise_error(ContentSecurityPolicyConfigError) end + it "rejects style for trusted types" do + expect do + ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(style_src: %w('self'), require_trusted_types_for: %w(script style), trusted_types: %w(abcpolicy)))) + end + end + # this is mostly to ensure people don't use the antiquated shorthands common in other configs it "performs light validation on source lists" do expect do From f10a4a4dd0429d02342603f30944bc896000f6f6 Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Wed, 8 Jun 2022 15:08:05 +0000 Subject: [PATCH 06/10] remove debugging in file --- lib/secure_headers/headers/policy_management.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/secure_headers/headers/policy_management.rb b/lib/secure_headers/headers/policy_management.rb index 0a92716d..a4d9635e 100644 --- a/lib/secure_headers/headers/policy_management.rb +++ b/lib/secure_headers/headers/policy_management.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "set" -require 'byebug' module SecureHeaders module PolicyManagement From ba3cf0288dfe4f25fbed639ba28b8701d7dc1a66 Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Wed, 8 Jun 2022 15:10:18 +0000 Subject: [PATCH 07/10] make test match others and add tesfor allow-duplicates --- .../secure_headers/headers/content_security_policy_spec.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index 3e5c609b..c57edca1 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -146,7 +146,7 @@ module SecureHeaders expect(csp.value).to eq("default-src 'self'; require-sri-for script style") end - it "supports require-trusted-types-for directive" do + it "allows style as a require-trusted-types-src" do csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script)) expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script") end @@ -195,6 +195,11 @@ module SecureHeaders csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)}) expect(csp.value).to eq("trusted-types blahblahpolicy") end + + it "allows duplicate policy names in trusted-types directive" do + csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy 'allow-duplicates')}) + expect(csp.value).to eq("trusted-types blahblahpolicy 'allow-duplicates'") + end end end end From 98674532f92a961a82dc99553af24ec6b2a7a63b Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Mon, 27 Jun 2022 13:06:24 -0400 Subject: [PATCH 08/10] Apply suggestions from code review Co-authored-by: Lucas Garron --- lib/secure_headers/headers/content_security_policy.rb | 4 +++- .../secure_headers/headers/content_security_policy_spec.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index 3c3c0c7e..7fc7c186 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -53,7 +53,9 @@ def value def build_value directives.map do |directive_name| case DIRECTIVE_VALUE_TYPES[directive_name] - when :source_list, :require_sri_for_list, :require_trusted_types_for_list # require_sri is a simple set of strings that don't need to deal with symbol casing + when :source_list, + :require_sri_for_list, # require_sri is a simple set of strings that don't need to deal with symbol casing + :require_trusted_types_for_list build_source_list_directive(directive_name) when :boolean symbol_to_hyphen_case(directive_name) if @config.directive_value(directive_name) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index c57edca1..73222a29 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -146,7 +146,7 @@ module SecureHeaders expect(csp.value).to eq("default-src 'self'; require-sri-for script style") end - it "allows style as a require-trusted-types-src" do + it "allows style as a require-trusted-types-for source" do csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script)) expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script") end From 071c580fe60f684dba31c9fc93a1dbe13165c898 Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Mon, 27 Jun 2022 20:48:27 +0000 Subject: [PATCH 09/10] fix whitespace --- lib/secure_headers/headers/content_security_policy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index 7fc7c186..2c9ef501 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -55,7 +55,7 @@ def build_value case DIRECTIVE_VALUE_TYPES[directive_name] when :source_list, :require_sri_for_list, # require_sri is a simple set of strings that don't need to deal with symbol casing - :require_trusted_types_for_list + :require_trusted_types_for_list build_source_list_directive(directive_name) when :boolean symbol_to_hyphen_case(directive_name) if @config.directive_value(directive_name) From f40910c4fe23c6d9398b762ceccafe0e2387bb66 Mon Sep 17 00:00:00 2001 From: Kylie Stradley <4666485+KyFaSt@users.noreply.github.com> Date: Tue, 28 Jun 2022 13:38:40 +0000 Subject: [PATCH 10/10] add test for 'none' trusted type --- .../secure_headers/headers/content_security_policy_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index 73222a29..53f8cfa2 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -196,6 +196,11 @@ module SecureHeaders expect(csp.value).to eq("trusted-types blahblahpolicy") end + it "supports trusted-types directive with 'none'" do + csp = ContentSecurityPolicy.new({trusted_types: %w(none)}) + expect(csp.value).to eq("trusted-types none") + end + it "allows duplicate policy names in trusted-types directive" do csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy 'allow-duplicates')}) expect(csp.value).to eq("trusted-types blahblahpolicy 'allow-duplicates'")