Bug 38365: Add application/reports+json as accepted Content-Type
report-to directive uses application/reports+json To test: 1. prove t/db_dependent/api/v1/public/csp_reports.t Signed-off-by: David Cook <dcook@prosentient.com.au> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
This commit is contained in:
parent
a472e6354a
commit
d3d0592eb7
|
|
@ -49,7 +49,7 @@ sub add {
|
|||
my $report = $c->req->json;
|
||||
|
||||
# CSP reports come wrapped in a 'csp-report' key
|
||||
my $csp_report = $report->{'csp-report'} // $report;
|
||||
my $csp_report = $report->{'csp-report'} // $report->{'body'} // $report;
|
||||
|
||||
my $logger = Koha::Logger->get( { interface => 'csp' } );
|
||||
|
||||
|
|
|
|||
|
|
@ -4,61 +4,57 @@ description: |
|
|||
A Content-Security-Policy violation report as sent by browsers.
|
||||
See https://www.w3.org/TR/CSP3/#violation-reports for specification.
|
||||
properties:
|
||||
csp-report:
|
||||
type: object
|
||||
description: The CSP violation report object
|
||||
properties:
|
||||
document-uri:
|
||||
type: string
|
||||
description: The URI of the document where the violation occurred
|
||||
maxLength: 200
|
||||
referrer:
|
||||
type: string
|
||||
description: The referrer of the document where the violation occurred
|
||||
maxLength: 200
|
||||
violated-directive:
|
||||
type: string
|
||||
description: The directive that was violated (e.g., "script-src 'self'")
|
||||
maxLength: 100
|
||||
effective-directive:
|
||||
type: string
|
||||
description: The effective directive that was violated
|
||||
maxLength: 100
|
||||
original-policy:
|
||||
type: string
|
||||
description: The original CSP policy as specified in the header
|
||||
maxLength: 400
|
||||
disposition:
|
||||
type: string
|
||||
description: Either "enforce" or "report" depending on CSP mode
|
||||
enum:
|
||||
- enforce
|
||||
- report
|
||||
blocked-uri:
|
||||
type: string
|
||||
description: The URI of the resource that was blocked
|
||||
maxLength: 200
|
||||
line-number:
|
||||
type: integer
|
||||
description: Line number in the document where the violation occurred
|
||||
minimum: 0
|
||||
maximum: 999999
|
||||
column-number:
|
||||
type: integer
|
||||
description: Column number where the violation occurred
|
||||
minimum: 0
|
||||
maximum: 999999
|
||||
source-file:
|
||||
type: string
|
||||
description: The URI of the script where the violation occurred
|
||||
maxLength: 200
|
||||
status-code:
|
||||
type: integer
|
||||
description: HTTP status code of the document
|
||||
minimum: 0
|
||||
maximum: 999
|
||||
script-sample:
|
||||
type: string
|
||||
description: First 40 characters of the inline script that caused the violation
|
||||
maxLength: 41
|
||||
additionalProperties: true
|
||||
document-uri:
|
||||
type: string
|
||||
description: The URI of the document where the violation occurred
|
||||
maxLength: 200
|
||||
referrer:
|
||||
type: string
|
||||
description: The referrer of the document where the violation occurred
|
||||
maxLength: 200
|
||||
violated-directive:
|
||||
type: string
|
||||
description: The directive that was violated (e.g., "script-src 'self'")
|
||||
maxLength: 100
|
||||
effective-directive:
|
||||
type: string
|
||||
description: The effective directive that was violated
|
||||
maxLength: 100
|
||||
original-policy:
|
||||
type: string
|
||||
description: The original CSP policy as specified in the header
|
||||
maxLength: 400
|
||||
disposition:
|
||||
type: string
|
||||
description: Either "enforce" or "report" depending on CSP mode
|
||||
enum:
|
||||
- enforce
|
||||
- report
|
||||
blocked-uri:
|
||||
type: string
|
||||
description: The URI of the resource that was blocked
|
||||
maxLength: 200
|
||||
line-number:
|
||||
type: integer
|
||||
description: Line number in the document where the violation occurred
|
||||
minimum: 0
|
||||
maximum: 999999
|
||||
column-number:
|
||||
type: integer
|
||||
description: Column number where the violation occurred
|
||||
minimum: 0
|
||||
maximum: 999999
|
||||
source-file:
|
||||
type: string
|
||||
description: The URI of the script where the violation occurred
|
||||
maxLength: 200
|
||||
status-code:
|
||||
type: integer
|
||||
description: HTTP status code of the document
|
||||
minimum: 0
|
||||
maximum: 999
|
||||
script-sample:
|
||||
type: string
|
||||
description: First 40 characters of the inline script that caused the violation
|
||||
maxLength: 41
|
||||
additionalProperties: true
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
type: object
|
||||
description: |
|
||||
A Content-Security-Policy violation report as sent by browsers.
|
||||
See https://www.w3.org/TR/CSP3/#violation-reports for specification.
|
||||
properties:
|
||||
csp-report:
|
||||
$ref: "csp_report.yaml"
|
||||
body:
|
||||
$ref: "csp_report.yaml"
|
||||
user_agent:
|
||||
type: string
|
||||
maxLength: 300
|
||||
destination:
|
||||
type: string
|
||||
maxLength: 200
|
||||
url:
|
||||
type: string
|
||||
maxLength: 200
|
||||
timestamp:
|
||||
type: string
|
||||
maxLength: 50
|
||||
attempts:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 99
|
||||
additionalProperties: true
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
consumes:
|
||||
- application/csp-report
|
||||
- application/json
|
||||
- application/reports+json
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
|
|
@ -25,7 +26,7 @@
|
|||
description: CSP violation report
|
||||
required: true
|
||||
schema:
|
||||
$ref: "../swagger.yaml#/definitions/csp_report"
|
||||
$ref: "../swagger.yaml#/definitions/csp_report_uri_to"
|
||||
responses:
|
||||
"204":
|
||||
description: Report received successfully
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ definitions:
|
|||
$ref: ./definitions/city.yaml
|
||||
csp_report:
|
||||
$ref: ./definitions/csp_report.yaml
|
||||
csp_report_uri_to:
|
||||
$ref: ./definitions/csp_report_uri_to.yaml
|
||||
credit:
|
||||
$ref: ./definitions/credit.yaml
|
||||
debit:
|
||||
|
|
|
|||
|
|
@ -36,146 +36,171 @@ t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
|
|||
|
||||
subtest 'add() tests' => sub {
|
||||
|
||||
plan tests => 15;
|
||||
plan tests => 2;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
# Test with standard CSP report format
|
||||
my $csp_report = {
|
||||
'csp-report' => {
|
||||
'document-uri' => 'https://library.example.org/cgi-bin/koha/opac-main.pl',
|
||||
'referrer' => '',
|
||||
'violated-directive' => "script-src 'self' 'nonce-abc123'",
|
||||
'effective-directive' => 'script-src',
|
||||
'original-policy' => "default-src 'self'; script-src 'self' 'nonce-abc123'",
|
||||
'disposition' => 'enforce',
|
||||
'blocked-uri' => 'inline',
|
||||
'line-number' => 42,
|
||||
'column-number' => 10,
|
||||
'source-file' => 'https://library.example.org/cgi-bin/koah/opac-main.pl',
|
||||
'status-code' => 200,
|
||||
}
|
||||
};
|
||||
foreach my $csp_report_type ( 'report-uri', 'report-to' ) {
|
||||
subtest "Test $csp_report_type" => sub {
|
||||
plan tests => 15;
|
||||
my $content_type = $csp_report_type eq 'report-to' ? 'application/csp-report' : 'application/reports+json';
|
||||
|
||||
$csp_report->{'csp-report'}->{'line-number'} = 99999999999999999;
|
||||
# Test with standard CSP report-uri format
|
||||
my $csp_report = {
|
||||
'csp-report' => {
|
||||
'document-uri' => 'https://library.example.org/cgi-bin/koha/opac-main.pl',
|
||||
'referrer' => '',
|
||||
'violated-directive' => "script-src 'self' 'nonce-abc123'",
|
||||
'effective-directive' => 'script-src',
|
||||
'original-policy' => "default-src 'self'; script-src 'self' 'nonce-abc123'",
|
||||
'disposition' => 'enforce',
|
||||
'blocked-uri' => 'inline',
|
||||
'line-number' => 42,
|
||||
'column-number' => 10,
|
||||
'source-file' => 'https://library.example.org/cgi-bin/koah/opac-main.pl',
|
||||
'status-code' => 200,
|
||||
}
|
||||
};
|
||||
if ( $csp_report_type eq 'report-to' ) {
|
||||
$csp_report->{'body'} = delete $csp_report->{'csp-report'};
|
||||
$csp_report->{'age'} = 1;
|
||||
$csp_report->{'type'} = 'csp-violation';
|
||||
$csp_report->{'url'} = 'https://library.example.org/cgi-bin/koha/opac-main.pl';
|
||||
$csp_report->{'user_agent'} = 'Test::Mojo';
|
||||
}
|
||||
|
||||
# Too large integers should be rejected
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of line-number exceeding maximum value' );
|
||||
my $csp_report_body_key = $csp_report_type eq 'report-uri' ? 'csp-report' : 'body';
|
||||
|
||||
$csp_report->{'csp-report'}->{'line-number'} = -1;
|
||||
$csp_report->{$csp_report_body_key}->{'line-number'} = 99999999999999999;
|
||||
|
||||
# Too small integers should be rejected
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of line-number not reaching minimum value' );
|
||||
$csp_report->{'csp-report'}->{'line-number'} = 42;
|
||||
# Too large integers should be rejected
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of line-number exceeding maximum value' );
|
||||
|
||||
$csp_report->{'csp-report'}->{'disposition'} = 'this is not okay';
|
||||
$csp_report->{$csp_report_body_key}->{'line-number'} = -1;
|
||||
|
||||
# Enum values should be confirmed
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of disposition is not either "enforce" nor "report"' );
|
||||
$csp_report->{'csp-report'}->{'disposition'} = 'enforce';
|
||||
# Too small integers should be rejected
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of line-number not reaching minimum value' );
|
||||
$csp_report->{$csp_report_body_key}->{'line-number'} = 42;
|
||||
|
||||
$csp_report->{'csp-report'}->{'script-sample'} =
|
||||
'this is way too long script sample. a maximum of only 40 characters is allowed';
|
||||
$csp_report->{$csp_report_body_key}->{'disposition'} = 'this is not okay';
|
||||
|
||||
# Too long strings should be rejected
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of script-sample exceeding maximum length' );
|
||||
$csp_report->{'csp-report'}->{'script-sample'} = 'console.log("hi");';
|
||||
# Enum values should be confirmed
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is(
|
||||
400,
|
||||
'CSP report rejected (400) because of disposition is not either "enforce" nor "report"'
|
||||
);
|
||||
$csp_report->{$csp_report_body_key}->{'disposition'} = 'enforce';
|
||||
|
||||
# Anonymous request should work (browsers send these without auth)
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted' );
|
||||
$csp_report->{$csp_report_body_key}->{'script-sample'} =
|
||||
'this is way too long script sample. a maximum of only 40 characters is allowed';
|
||||
|
||||
# Test with application/json content type (also valid)
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/json' } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted with application/json content type' );
|
||||
# Too long strings should be rejected
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 400, 'CSP report rejected (400) because of script-sample exceeding maximum length' );
|
||||
$csp_report->{$csp_report_body_key}->{'script-sample'} = 'console.log("hi");';
|
||||
|
||||
# Test with minimal report
|
||||
my $minimal_report = {
|
||||
'csp-report' => {
|
||||
'document-uri' => 'https://library.example.org/',
|
||||
'violated-directive' => 'script-src',
|
||||
'blocked-uri' => 'https://evil.example.com/script.js',
|
||||
}
|
||||
};
|
||||
# Anonymous request should work (browsers send these without auth)
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted' );
|
||||
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => json => $minimal_report )
|
||||
->status_is( 204, 'Minimal CSP report accepted' );
|
||||
# Test with application/json content type (also valid)
|
||||
$t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted with application/json content type' );
|
||||
|
||||
subtest 'make sure log entries are being written' => sub {
|
||||
plan tests => 17;
|
||||
# Test with minimal report
|
||||
my $minimal_report = {
|
||||
'csp-report' => {
|
||||
'document-uri' => 'https://library.example.org/',
|
||||
'violated-directive' => 'script-src',
|
||||
'blocked-uri' => 'https://evil.example.com/script.js',
|
||||
}
|
||||
};
|
||||
if ( $csp_report_type eq 'report-to' ) {
|
||||
$minimal_report->{'body'} = delete $minimal_report->{'csp-report'};
|
||||
$minimal_report->{'age'} = 1;
|
||||
$minimal_report->{'type'} = 'csp-violation';
|
||||
$minimal_report->{'url'} = 'https://library.example.org/cgi-bin/koha/opac-main.pl';
|
||||
$minimal_report->{'user_agent'} = 'Test::Mojo';
|
||||
}
|
||||
|
||||
my $log4perl_conf_file = C4::Context->config('intranetdir') . '/etc/log4perl.conf';
|
||||
open my $fh, '<:encoding(UTF-8)', $log4perl_conf_file or do {
|
||||
carp "Cannot read $log4perl_conf_file: $!";
|
||||
return;
|
||||
};
|
||||
my $log4perl_conf_content = "";
|
||||
while (<$fh>) {
|
||||
my $line = $_;
|
||||
next unless $line =~ /^(log4perl.logger.(plack-)?csp)|(log4perl.appender.(PLACK)?CSP)/;
|
||||
$log4perl_conf_content .= "$line";
|
||||
}
|
||||
close $fh;
|
||||
like( $log4perl_conf_content, qr/__LOG_DIR__\/csp-violations\.log/, 'csp-violations.log is defined' );
|
||||
like(
|
||||
$log4perl_conf_content, qr/__LOG_DIR__\/plack-csp-violations\.log/,
|
||||
'plack-csp-violations.log is defined'
|
||||
);
|
||||
like(
|
||||
$log4perl_conf_content, qr/log4perl.appender.CSP=Log::Log4perl::Appender::File/,
|
||||
'CSP: File appender exists'
|
||||
);
|
||||
like(
|
||||
$log4perl_conf_content, qr/log4perl.appender.PLACKCSP=Log::Log4perl::Appender::File/,
|
||||
'PLACKCSP: File appender exists'
|
||||
);
|
||||
$log4perl_conf_content =~ s/Log::Log4perl::Appender::File/Log::Log4perl::Appender::TestBuffer/g;
|
||||
Log::Log4perl::init( \$log4perl_conf_content );
|
||||
my $appenders = Log::Log4perl->appenders;
|
||||
my $appender = Log::Log4perl->appenders->{CSP};
|
||||
my $appenderplack = Log::Log4perl->appenders->{PLACKCSP};
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $minimal_report )
|
||||
->status_is( 204, 'Minimal CSP report accepted' );
|
||||
|
||||
is( $appender->buffer, '', 'Nothing in log buffer yet' );
|
||||
is( $appenderplack->buffer, '', 'Nothing in plack log buffer yet' );
|
||||
subtest 'make sure log entries are being written' => sub {
|
||||
plan tests => 17;
|
||||
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted' );
|
||||
my $log4perl_conf_file = C4::Context->config('intranetdir') . '/etc/log4perl.conf';
|
||||
open my $fh, '<:encoding(UTF-8)', $log4perl_conf_file or do {
|
||||
carp "Cannot read $log4perl_conf_file: $!";
|
||||
return;
|
||||
};
|
||||
my $log4perl_conf_content = "";
|
||||
while (<$fh>) {
|
||||
my $line = $_;
|
||||
next unless $line =~ /^(log4perl.logger.(plack-)?csp)|(log4perl.appender.(PLACK)?CSP)/;
|
||||
$log4perl_conf_content .= "$line";
|
||||
}
|
||||
close $fh;
|
||||
like( $log4perl_conf_content, qr/__LOG_DIR__\/csp-violations\.log/, 'csp-violations.log is defined' );
|
||||
like(
|
||||
$log4perl_conf_content, qr/__LOG_DIR__\/plack-csp-violations\.log/,
|
||||
'plack-csp-violations.log is defined'
|
||||
);
|
||||
like(
|
||||
$log4perl_conf_content, qr/log4perl.appender.CSP=Log::Log4perl::Appender::File/,
|
||||
'CSP: File appender exists'
|
||||
);
|
||||
like(
|
||||
$log4perl_conf_content, qr/log4perl.appender.PLACKCSP=Log::Log4perl::Appender::File/,
|
||||
'PLACKCSP: File appender exists'
|
||||
);
|
||||
$log4perl_conf_content =~ s/Log::Log4perl::Appender::File/Log::Log4perl::Appender::TestBuffer/g;
|
||||
Log::Log4perl::init( \$log4perl_conf_content );
|
||||
my $appenders = Log::Log4perl->appenders;
|
||||
my $appender = Log::Log4perl->appenders->{CSP};
|
||||
my $appenderplack = Log::Log4perl->appenders->{PLACKCSP};
|
||||
|
||||
my $expected_log_entry = sprintf(
|
||||
"CSP violation: '%s' blocked '%s' on page '%s'%s",
|
||||
$csp_report->{'csp-report'}->{'violated-directive'},
|
||||
$csp_report->{'csp-report'}->{'blocked-uri'},
|
||||
$csp_report->{'csp-report'}->{'document-uri'},
|
||||
' at '
|
||||
. $csp_report->{'csp-report'}->{'source-file'} . ':'
|
||||
. $csp_report->{'csp-report'}->{'line-number'} . ':'
|
||||
. $csp_report->{'csp-report'}->{'column-number'}
|
||||
);
|
||||
is( $appender->buffer, '', 'Nothing in log buffer yet' );
|
||||
is( $appenderplack->buffer, '', 'Nothing in plack log buffer yet' );
|
||||
|
||||
like(
|
||||
$appender->buffer, qr/$expected_log_entry/
|
||||
, 'Log contains expected log entry'
|
||||
);
|
||||
is( $appenderplack->buffer, '', 'Nothing in plack log buffer yet' );
|
||||
$appender->clear();
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted' );
|
||||
|
||||
$ENV{'plack.is.enabled.for.this.test'} = 1; # tricking C4::Context->psgi_env
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted' );
|
||||
like(
|
||||
$appenderplack->buffer, qr/$expected_log_entry/
|
||||
, 'Plack log contains expected log entry'
|
||||
);
|
||||
is( $appender->buffer, '', 'Nothing in log buffer yet' );
|
||||
my $expected_log_entry = sprintf(
|
||||
"CSP violation: '%s' blocked '%s' on page '%s'%s",
|
||||
$csp_report->{$csp_report_body_key}->{'violated-directive'},
|
||||
$csp_report->{$csp_report_body_key}->{'blocked-uri'},
|
||||
$csp_report->{$csp_report_body_key}->{'document-uri'},
|
||||
' at '
|
||||
. $csp_report->{$csp_report_body_key}->{'source-file'} . ':'
|
||||
. $csp_report->{$csp_report_body_key}->{'line-number'} . ':'
|
||||
. $csp_report->{$csp_report_body_key}->{'column-number'}
|
||||
);
|
||||
|
||||
Log::Log4perl::init(
|
||||
\<<"HERE"
|
||||
like(
|
||||
$appender->buffer, qr/$expected_log_entry/
|
||||
, 'Log contains expected log entry'
|
||||
);
|
||||
is( $appenderplack->buffer, '', 'Nothing in plack log buffer yet' );
|
||||
$appender->clear();
|
||||
|
||||
$ENV{'plack.is.enabled.for.this.test'} = 1; # tricking C4::Context->psgi_env
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report accepted' );
|
||||
like(
|
||||
$appenderplack->buffer, qr/$expected_log_entry/
|
||||
, 'Plack log contains expected log entry'
|
||||
);
|
||||
is( $appender->buffer, '', 'Nothing in log buffer yet' );
|
||||
|
||||
Log::Log4perl::init(
|
||||
\<<"HERE"
|
||||
log4perl.logger.api = WARN, API
|
||||
log4perl.appender.API=Log::Log4perl::Appender::TestBuffer
|
||||
log4perl.appender.API.mode=append
|
||||
|
|
@ -183,14 +208,20 @@ log4perl.appender.API.layout=PatternLayout
|
|||
log4perl.appender.API.layout.ConversionPattern=[%d] [%p] %m %l%n
|
||||
log4perl.appender.API.utf8=1
|
||||
HERE
|
||||
);
|
||||
$appender = Log::Log4perl->appenders()->{API};
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report returns 204 even when no CSP loggers are defined' );
|
||||
is( $appender->buffer, '', 'Nothing in the only defined log buffer, because it is unrelated to CSP' );
|
||||
);
|
||||
$appender = Log::Log4perl->appenders()->{API};
|
||||
$t->post_ok(
|
||||
'/api/v1/public/csp-reports' => { 'Content-Type' => $content_type } => json => $csp_report )
|
||||
->status_is( 204, 'CSP report returns 204 even when no CSP loggers are defined' );
|
||||
is( $appender->buffer, '', 'Nothing in the only defined log buffer, because it is unrelated to CSP' );
|
||||
|
||||
};
|
||||
# clear buffers
|
||||
$appender->clear();
|
||||
$appenderplack->clear();
|
||||
delete $ENV{'plack.is.enabled.for.this.test'};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue