Skip to content

Commit eb8ca3b

Browse files
committed
Remove deprecated code
1 parent 46a1107 commit eb8ca3b

14 files changed

Lines changed: 54 additions & 223 deletions

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
* Always allow printing a `Markup` object in a sandbox, whatever the security policy is
55
* Remove the `Twig\Sandbox\SourcePolicyInterface` interface and the corresponding argument of `Twig\Extension\SandboxExtension::__construct()`
66
* Enforce the `parent`, `block`, and `attribute` functions against the sandbox `allowedFunctions` allow-list
7+
* Enforce tests against the sandbox `allowedTests` allow-list and add the `$allowedTests` argument to `Twig\Sandbox\SecurityPolicy::__construct()`
8+
* Add a fourth `array $tests` argument to `Twig\Sandbox\SecurityPolicyInterface::checkSecurity()`
9+
* Throw a `SyntaxError` when an `extends`, `use`, or `macro` tag is not at the root of a template
710

811
# 4.0.0 alpha 1 (2026-05-17)
912

doc/sandbox.rst

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,10 @@ Everything else won't be allowed and will generate a
4242

4343
.. note::
4444

45-
The ``allowedTests`` argument is available since Twig 3.28 (in earlier
46-
versions all tests were always allowed). Most built-in tests (``empty``,
47-
``defined``, ``even``, ``same as``, ``iterable``, etc.) are always allowed
48-
and do not need to be listed. Only custom tests and the built-in
49-
``constant`` test must be allow-listed like filters and functions.
45+
Most built-in tests (``empty``, ``defined``, ``even``, ``same as``,
46+
``iterable``, etc.) are always allowed and do not need to be listed. Only
47+
custom tests and the built-in ``constant`` test must be allow-listed like
48+
filters and functions.
5049

5150
.. note::
5251

@@ -149,12 +148,11 @@ iterated items). That transitive behavior is documented separately under
149148
the sandbox model. The criteria above are about what the item itself
150149
exposes, not about how its arguments behave.
151150

152-
Built-ins That Will Be Always Allowed in 4.0
153-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151+
Built-ins That Are Always Allowed
152+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154153

155-
The following Twig built-ins meet the criteria above and will have the
156-
``always_allowed_in_sandbox`` flag set in Twig 4.0. They still need to be
157-
explicitly allow-listed in 3.x.
154+
The following Twig built-ins meet the criteria above and have the
155+
``always_allowed_in_sandbox`` flag set, so they never need to be allow-listed.
158156

159157
* Tags: ``apply``, ``block``, ``do``, ``for``, ``guard``, ``if``, ``macro``,
160158
``set``, ``types``, ``with``.
@@ -165,18 +163,14 @@ explicitly allow-listed in 3.x.
165163
``title``, ``trim``, ``upper``, ``url_encode``.
166164
* Functions: ``cycle``, ``max``, ``min``.
167165

168-
When upgrading to 4.0, you can drop these names from your ``SecurityPolicy``
169-
allow-lists. Leaving them in is harmless: listing a name that is always
170-
allowed has no effect.
166+
Listing one of these names in your ``SecurityPolicy`` is harmless: it has no
167+
effect.
171168

172169
The corresponding built-in tests (``defined``, ``divisible by``, ``empty``,
173170
``even``, ``iterable``, ``mapping``, ``none``, ``null``, ``odd``, ``same as``,
174-
``sequence``, ``true``) are **already** flagged as always allowed since Twig
175-
3.28, so they never need to be allow-listed. This is safe because tests were
176-
never enforced by the sandbox before 3.28: flagging them keeps existing
177-
templates working unchanged. The ``constant`` test is the exception: it reaches
178-
into the PHP runtime, so it is not always allowed and must be allow-listed (it
179-
is still implicitly allowed in 3.x with a deprecation, and rejected in 4.0).
171+
``sequence``, ``true``) are also always allowed, so they never need to be
172+
allow-listed. The ``constant`` test is the exception: it reaches into the PHP
173+
runtime, so it is not always allowed and must be allow-listed.
180174

181175
Enabling the Sandbox
182176
--------------------

phpstan-baseline.neon

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
parameters:
22
ignoreErrors:
3-
- # The "$tests" parameter is documented now and will be part of the signature in 4.0
4-
message: '#^PHPDoc tag @param references unknown parameter\: \$tests$#'
5-
identifier: parameter.notFound
6-
count: 1
7-
path: src/Sandbox/SecurityPolicyInterface.php
8-
9-
103
- # 2 parameters will be required
114
message: '#^Method Twig\\Node\\IncludeNode\:\:addGetTemplate\(\) invoked with 2 parameters, 1 required\.$#'
125
identifier: arguments.count

src/Extension/SandboxExtension.php

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,29 +65,11 @@ public function getSecurityPolicy(): SecurityPolicyInterface
6565
return $this->policy;
6666
}
6767

68-
public function checkSecurity($tags, $filters, $functions, $tests = [], $source = null): void
68+
public function checkSecurity($tags, $filters, $functions, $tests = [], ?Source $source = null): void
6969
{
70-
// BC: previous signature was checkSecurity($tags, $filters, $functions, ?Source $source = null);
71-
// detect a legacy call where the 4th positional argument was the Source.
72-
if ($tests instanceof Source || (null === $tests && \func_num_args() < 5)) {
73-
trigger_deprecation('twig/twig', '3.28', 'Passing a "Twig\Source" as the 4th argument of "%s()" is deprecated; pass an array of tests instead.', __METHOD__);
74-
$source = $tests;
75-
$tests = [];
76-
}
77-
78-
if (!$this->isSandboxed($source)) {
79-
return;
80-
}
81-
82-
if ((new \ReflectionMethod($this->policy, 'checkSecurity'))->getNumberOfParameters() >= 4) {
70+
if ($this->isSandboxed($source)) {
8371
$this->policy->checkSecurity($tags, $filters, $functions, $tests);
84-
85-
return;
8672
}
87-
88-
trigger_deprecation('twig/twig', '3.28', 'The "%s::checkSecurity()" method will take a 4th "array $tests" argument in 4.0; not declaring it is deprecated.', $this->policy::class);
89-
90-
$this->policy->checkSecurity($tags, $filters, $functions);
9173
}
9274

9375
public function checkMethodAllowed($obj, $method, int $lineno = -1, ?Source $source = null): void

src/Node/CheckSecurityNode.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,8 @@ class CheckSecurityNode extends Node
3131
* @param array<string, int> $usedFunctions
3232
* @param array<string, int> $usedTests
3333
*/
34-
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions, array $usedTests = [])
34+
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions, array $usedTests)
3535
{
36-
if (\func_num_args() < 4) {
37-
trigger_deprecation('twig/twig', '3.28', 'Not passing the "$usedTests" argument to "%s::__construct()" is deprecated; it will be required in 4.0.', static::class);
38-
}
39-
4036
$this->usedFilters = $usedFilters;
4137
$this->usedTags = $usedTags;
4238
$this->usedFunctions = $usedFunctions;

src/NodeVisitor/CorrectnessNodeVisitor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private function checkConfigTag(ConfigNode $node): void
159159
}
160160

161161
if (!isset($this->rootNodes[$node])) {
162-
trigger_deprecation('twig/twig', '3.27', 'Using the "%s" tag outside the root of a template is deprecated in %s at line %d.', $node->getNodeTag(), $node->getSourceContext()->getName(), $node->getTemplateLine());
162+
throw new SyntaxError(\sprintf('The "%s" tag can only be used at the root of a template.', $node->getNodeTag()), $node->getTemplateLine(), $node->getSourceContext());
163163
}
164164
}
165165

src/Sandbox/SecurityPolicy.php

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ final class SecurityPolicy implements SecurityPolicyInterface
4242
* @var string[]
4343
*/
4444
private array $allowedTests;
45-
private bool $strict = false;
4645

4746
public function __construct(array $allowedTags = [], array $allowedFilters = [], array $allowedMethods = [], array $allowedProperties = [], array $allowedFunctions = [], array $allowedTests = [])
4847
{
@@ -100,12 +99,8 @@ public function setStrict(bool $strict): void
10099
{
101100
}
102101

103-
public function checkSecurity($tags, $filters, $functions, array $tests = []): void
102+
public function checkSecurity($tags, $filters, $functions, array $tests): void
104103
{
105-
if (\func_num_args() < 4) {
106-
trigger_deprecation('twig/twig', '3.28', 'Not passing the "$tests" argument to "%s::checkSecurity()" is deprecated; it will be required in 4.0.', static::class);
107-
}
108-
109104
foreach ($tags as $tag) {
110105
if (!\in_array($tag, $this->allowedTags, true)) {
111106
throw new SecurityNotAllowedTagError(\sprintf('Tag "%s" is not allowed.', $tag), $tag);
@@ -126,11 +121,7 @@ public function checkSecurity($tags, $filters, $functions, array $tests = []): v
126121

127122
foreach ($tests as $test) {
128123
if (!\in_array($test, $this->allowedTests, true)) {
129-
if (!$this->strict) {
130-
trigger_deprecation('twig/twig', '3.28', 'The "%s" test is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).', $test);
131-
} else {
132-
throw new SecurityNotAllowedTestError(\sprintf('Test "%s" is not allowed.', $test), $test);
133-
}
124+
throw new SecurityNotAllowedTestError(\sprintf('Test "%s" is not allowed.', $test), $test);
134125
}
135126
}
136127
}

src/Sandbox/SecurityPolicyInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface SecurityPolicyInterface
2626
*
2727
* @throws SecurityError
2828
*/
29-
public function checkSecurity($tags, $filters, $functions/* , array $tests */): void;
29+
public function checkSecurity($tags, $filters, $functions, array $tests): void;
3030

3131
/**
3232
* @param object $obj

0 commit comments

Comments
 (0)