Skip to content

Commit 70424f9

Browse files
authored
Merge pull request #13 from Flowpack/fix-pipeline
Fix pipeline
2 parents 2618eb7 + 5568da2 commit 70424f9

6 files changed

Lines changed: 80 additions & 61 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: CI
22

3-
on: [ push ]
3+
on: [ push, pull_request ]
44

55
jobs:
66
phpunit:

Classes/Helpers/DirectivesNormalizer.php

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
*
1515
* We also cleanup of empty directives and entries here before further processing.
1616
*/
17-
class DirectivesNormalizer
17+
final class DirectivesNormalizer
1818
{
1919
/**
20-
* @param array<string, array<string|int, string|bool>> $directives
20+
* @param array<string, ?array<string|int, string|bool>> $directives
2121
* @return string[][]
2222
* @throws DirectivesNormalizerException
2323
*/
@@ -26,43 +26,50 @@ public static function normalize(array $directives, LoggerInterface $logger): ar
2626
$result = [];
2727
// directives e.g. script-src:
2828
foreach ($directives as $directive => $values) {
29-
if(is_array($values) && sizeof($values) > 0) {
30-
$normalizedValues = [];
31-
$firstKeyType = null;
32-
// values e.g. 'self', 'unsafe-inline' OR key-value pairs e.g. example.com: true
33-
foreach ($values as $key => $value) {
34-
$keyType = gettype($key);
35-
$valueType = gettype($value);
36-
if ($firstKeyType === null) {
37-
$firstKeyType = $keyType;
38-
} else {
39-
if ($keyType !== $firstKeyType) {
40-
// we do not allow mixed key types -> this should be marked as an error in the IDE as well
41-
// as Flow should throw an exception here. But just to be sure, we add this check.
42-
throw new DirectivesNormalizerException('Directives must be defined as a list OR an object.');
43-
}
29+
if (!is_array($values) || count($values) === 0) {
30+
continue;
31+
}
32+
33+
$normalizedValues = [];
34+
$firstKeyType = null;
35+
// values e.g. 'self', 'unsafe-inline' OR key-value pairs e.g. example.com: true
36+
foreach ($values as $key => $value) {
37+
if ($firstKeyType === null) {
38+
$firstKeyType = gettype($key);
39+
} else {
40+
if (gettype($key) !== $firstKeyType) {
41+
// we do not allow mixed key types -> this should be marked as an error in the IDE as well
42+
// as Flow should throw an exception here. But just to be sure, we add this check.
43+
throw new DirectivesNormalizerException(
44+
'Directives must be defined as a list OR an object.'
45+
);
4446
}
47+
}
4548

46-
if($keyType === 'integer' && $valueType === 'string' && !empty($value)) {
47-
// old configuration format using list
48-
$normalizedValues[] = $value;
49-
$logger->warning('Using list format for CSP directives is deprecated and will be removed in future versions. Please use key-value pairs with boolean values instead.');
50-
} elseif($keyType === 'string') {
51-
// new configuration format using key-value pairs
52-
if($valueType === 'boolean') {
53-
if($value === true && !empty($key)) {
54-
$normalizedValues[] = $key;
55-
}
56-
} else {
57-
// We chose a format similar to NodeType constraints yaml configuration.
58-
throw new DirectivesNormalizerException('When using keys in your yaml, the values must be boolean.');
49+
if (is_int($key) && is_string($value) && trim($value) !== '') {
50+
// old configuration format using list
51+
$normalizedValues[] = $value;
52+
$logger->warning(
53+
'Using list format for CSP directives is deprecated and will be removed in future versions. Please use key-value pairs with boolean values instead.'
54+
);
55+
} elseif (is_string($key)) {
56+
// new configuration format using key-value pairs
57+
if (is_bool($value)) {
58+
if ($value === true && trim($key) !== '') {
59+
$normalizedValues[] = $key;
5960
}
61+
continue;
6062
}
63+
64+
// We chose a format similar to NodeType constraints yaml configuration.
65+
throw new DirectivesNormalizerException(
66+
'When using keys in your yaml, the values must be boolean.'
67+
);
6168
}
62-
if(!empty($normalizedValues)) {
63-
// we also clean up empty directives here
64-
$result[$directive] = $normalizedValues;
65-
}
69+
}
70+
if ($normalizedValues !== []) {
71+
// we also clean up empty directives here
72+
$result[$directive] = $normalizedValues;
6673
}
6774
}
6875

Classes/Helpers/TagHelper.php

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class TagHelper
99
public static function tagHasAttribute(
1010
string $tag,
1111
string $name,
12-
string $value = null
12+
?string $value = null
1313
): bool {
1414
$value = (string)$value;
1515
if ($value === '') {
@@ -36,10 +36,10 @@ public static function tagChangeAttributeValue(
3636
return preg_replace_callback(
3737
self::buildMatchAttributeNameWithAnyValueReqex($name),
3838
function ($hits) use ($newValue) {
39-
return $hits["pre"].
40-
$hits["name"].
41-
$hits["glue"].
42-
$newValue.
39+
return $hits["pre"] .
40+
$hits["name"] .
41+
$hits["glue"] .
42+
$newValue .
4343
$hits["post"];
4444
},
4545
$tag
@@ -49,22 +49,22 @@ function ($hits) use ($newValue) {
4949
public static function tagAddAttribute(
5050
string $tag,
5151
string $name,
52-
string $value = null
52+
?string $value = null
5353
): string {
5454
return preg_replace_callback(
5555
self::buildMatchEndOfOpeningTagReqex(),
5656
function ($hits) use ($name, $value) {
5757
if ((string)$value !== '') {
58-
return $hits["start"].
59-
' '.
60-
$name.
61-
'="'.
62-
$value.
63-
'"'.
58+
return $hits["start"] .
59+
' ' .
60+
$name .
61+
'="' .
62+
$value .
63+
'"' .
6464
$hits["end"];
6565
}
6666

67-
return $hits["start"].' '.$name.$hits["end"];
67+
return $hits["start"] . ' ' . $name . $hits["end"];
6868
},
6969
$tag
7070
);
@@ -85,16 +85,16 @@ private static function buildMatchAttributeNameWithAnyValueReqex(string $name):
8585
{
8686
$nameQuoted = self::escapeReqexCharsInString($name);
8787

88-
return '/(?<pre><.*? )(?<name>'.
89-
$nameQuoted.
88+
return '/(?<pre><.*? )(?<name>' .
89+
$nameQuoted .
9090
')(?<glue>=")(?<value>.*?)(?<post>".*?>)/';
9191
}
9292

9393
private static function buildMatchAttributeNameReqex(string $name): string
9494
{
9595
$nameQuoted = self::escapeReqexCharsInString($name);
9696

97-
return '/(?<pre><.*? )(?<name>'.$nameQuoted.')(?<post>.*?>)/';
97+
return '/(?<pre><.*? )(?<name>' . $nameQuoted . ')(?<post>.*?>)/';
9898
}
9999

100100
private static function buildMatchAttributeNameWithSpecificValueReqex(
@@ -104,10 +104,10 @@ private static function buildMatchAttributeNameWithSpecificValueReqex(
104104
$nameQuoted = self::escapeReqexCharsInString($name);
105105
$valueQuoted = self::escapeReqexCharsInString($value);
106106

107-
return '/(?<pre><.*? )(?<name>'.
108-
$nameQuoted.
109-
')(?<glue>=")(?<value>'.
110-
$valueQuoted.
107+
return '/(?<pre><.*? )(?<name>' .
108+
$nameQuoted .
109+
')(?<glue>=")(?<value>' .
110+
$valueQuoted .
111111
')(?<post>".*?>)/';
112112
}
113113
}

Tests/Unit/Factory/PolicyFactoryTest.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Flowpack\ContentSecurityPolicy\Exceptions\InvalidDirectiveException;
88
use Flowpack\ContentSecurityPolicy\Factory\PolicyFactory;
9+
use Flowpack\ContentSecurityPolicy\Helpers\DirectivesNormalizer;
910
use Flowpack\ContentSecurityPolicy\Model\Directive;
1011
use Flowpack\ContentSecurityPolicy\Model\Nonce;
1112
use Flowpack\ContentSecurityPolicy\Model\Policy;
@@ -20,10 +21,12 @@
2021
#[UsesClass(Policy::class)]
2122
#[UsesClass(Directive::class)]
2223
#[UsesClass(InvalidDirectiveException::class)]
24+
#[UsesClass(DirectivesNormalizer::class)]
2325
class PolicyFactoryTest extends TestCase
2426
{
2527
private readonly LoggerInterface&MockObject $loggerMock;
2628
private readonly PolicyFactory $policyFactory;
29+
private readonly ReflectionClass $policyFactoryReflection;
2730

2831
protected function setUp(): void
2932
{
@@ -35,7 +38,10 @@ protected function setUp(): void
3538

3639
$this->policyFactoryReflection = new ReflectionClass($this->policyFactory);
3740
$this->policyFactoryReflection->getProperty('logger')->setValue($this->policyFactory, $this->loggerMock);
38-
$this->policyFactoryReflection->getProperty('throwInvalidDirectiveException')->setValue($this->policyFactory, true);
41+
$this->policyFactoryReflection->getProperty('throwInvalidDirectiveException')->setValue(
42+
$this->policyFactory,
43+
true
44+
);
3945
}
4046

4147
public function testCreateShouldReturnPolicyAndMergeCustomWithDefaultDirective(): void
@@ -116,7 +122,10 @@ public function testCreateShouldFailWithInvalidDirective(): void
116122
public function testCreateShouldLogInvalidDirectiveInProduction(): void
117123
{
118124
$nonceMock = $this->createMock(Nonce::class);
119-
$this->policyFactoryReflection->getProperty('throwInvalidDirectiveException')->setValue($this->policyFactory, false);
125+
$this->policyFactoryReflection->getProperty('throwInvalidDirectiveException')->setValue(
126+
$this->policyFactory,
127+
false
128+
);
120129

121130
$defaultDirective = [
122131
'invalid' => [
@@ -131,7 +140,10 @@ public function testCreateShouldLogInvalidDirectiveInProduction(): void
131140
$this->loggerMock->expects($this->once())->method('critical');
132141
$this->policyFactory->create($nonceMock, $defaultDirective, $customDirective);
133142

134-
$this->policyFactoryReflection->getProperty('throwInvalidDirectiveException')->setValue($this->policyFactory, true);
143+
$this->policyFactoryReflection->getProperty('throwInvalidDirectiveException')->setValue(
144+
$this->policyFactory,
145+
true
146+
);
135147
}
136148

137149
public function testCreateShouldReturnPolicyWithUniqueValues(): void

Tests/Unit/Helpers/DirectivesNormalizerTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
use Psr\Log\LoggerInterface;
1313

1414
#[CoversClass(DirectivesNormalizer::class)]
15+
#[CoversClass(DirectivesNormalizerException::class)]
1516
class DirectivesNormalizerTest extends TestCase
1617
{
1718
private readonly LoggerInterface&MockObject $loggerMock;
19+
1820
protected function setUp(): void
1921
{
2022
parent::setUp();
@@ -167,6 +169,7 @@ public function testConfiguration(): void
167169

168170
self::assertSame($expected, $actual);
169171

172+
// @phpstan-ignore argument.type
170173
$actual = DirectivesNormalizer::normalize([
171174
'base-uri',
172175
'script-src' => [],

Tests/Unit/Model/PolicyTest.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use PHPUnit\Framework\Attributes\CoversClass;
1212
use PHPUnit\Framework\Attributes\UsesClass;
1313
use PHPUnit\Framework\TestCase;
14-
use Psr\Log\LoggerInterface;
1514
use ReflectionClass;
1615

1716
#[CoversClass(Policy::class)]
@@ -26,8 +25,6 @@ protected function setUp(): void
2625
{
2726
parent::setUp();
2827

29-
$this->loggerMock = $this->createMock(LoggerInterface::class);
30-
3128
$this->policy = new Policy();
3229

3330
$this->policyReflection = new ReflectionClass($this->policy);

0 commit comments

Comments
 (0)