Remove deprecated code

This commit is contained in:
Fabien Potencier
2026-06-08 12:53:32 +02:00
parent 4530a4837a
commit c2c949d5bc
6 changed files with 13 additions and 80 deletions
+1
View File
@@ -1,5 +1,6 @@
# 4.0.0 (2026-XX-XX)
* Add the `isAlwaysAllowedInSandbox()` method to `Twig\TwigCallableInterface` and `Twig\TokenParser\TokenParserInterface`
* Remove the `Twig\Sandbox\SourcePolicyInterface` interface and the corresponding argument of `Twig\Extension\SandboxExtension::__construct()`
* Enforce the `parent`, `block`, and `attribute` functions against the sandbox `allowedFunctions` allow-list
-17
View File
@@ -46,26 +46,9 @@ allowed and will generate a ``\Twig\Sandbox\SecurityError`` exception.
Note that native array-like classes (like ``ArrayObject``) are always
allowed, you don't need to configure them.
.. caution::
The ``extends`` and ``use`` tags, as well as the ``parent``, ``block``, and
``attribute`` functions are always allowed in a sandboxed template. That
behavior will change in 4.0 where they will need to be explicitly allowed
like any other tag or function. To opt-in to the 4.0 behavior now (so they
need to be allow-listed or get rejected), enable strict mode on the
security policy::
$policy->setStrict(true);
Marking Filters, Functions, and Tags as Always Allowed
------------------------------------------------------
.. versionadded:: 3.28
The ``always_allowed_in_sandbox`` option for filters and functions, and
the ``isAlwaysAllowedInSandbox()`` method for token parsers, were added in
Twig 3.28.
Some filters, functions, and tags are inherently safe and should always be
usable in sandboxed templates without forcing every policy to allow-list them.
Mark such callables by setting the ``always_allowed_in_sandbox`` option to
+5 -22
View File
@@ -28,8 +28,6 @@ use Twig\Node\Expression\Variable\ContextVariable;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Node\Nodes;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigCallableInterface;
use Twig\Util\CallableParameters;
/**
@@ -211,7 +209,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
return false;
}
return self::isAlwaysAllowedInSandbox($parser);
return $parser->isAlwaysAllowedInSandbox();
}
private function isFilterAlwaysAllowedInSandbox(Environment $env, FilterExpression $node): bool
@@ -222,7 +220,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
return false;
}
return self::isAlwaysAllowedInSandbox($filter);
return $filter->isAlwaysAllowedInSandbox();
}
private function isFunctionAlwaysAllowedInSandbox(Environment $env, FunctionExpression $node): bool
@@ -233,7 +231,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
return false;
}
return self::isAlwaysAllowedInSandbox($function);
return $function->isAlwaysAllowedInSandbox();
}
private function isSandboxedFunctionAlwaysAllowedInSandbox(Environment $env, Node $node, string $name): bool
@@ -244,7 +242,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
return false;
}
return self::isAlwaysAllowedInSandbox($function);
return $function->isAlwaysAllowedInSandbox();
}
private function isFunctionNameAlwaysAllowedInSandbox(Environment $env, string $name): bool
@@ -253,22 +251,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
return false;
}
return self::isAlwaysAllowedInSandbox($function);
}
/**
* @param TwigCallableInterface|TokenParserInterface $subject
*/
private static function isAlwaysAllowedInSandbox($subject): bool
{
if (method_exists($subject, 'isAlwaysAllowedInSandbox')) {
return $subject->isAlwaysAllowedInSandbox();
}
$interface = $subject instanceof TokenParserInterface ? TokenParserInterface::class : TwigCallableInterface::class;
trigger_deprecation('twig/twig', '3.28', 'Not implementing the "isAlwaysAllowedInSandbox()" method in "%s" is deprecated. This method will be part of the "%s" interface in 4.0.', $subject::class, $interface);
return false;
return $function->isAlwaysAllowedInSandbox();
}
public function getPriority(): int
+5 -2
View File
@@ -20,8 +20,6 @@ use Twig\Token;
* Interface implemented by token parsers.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @method bool isAlwaysAllowedInSandbox() Whether the tag is always allowed in sandbox mode, even when not explicitly allow-listed. Not implementing this method is deprecated since Twig 3.28, it will be required in 4.0.
*/
interface TokenParserInterface
{
@@ -41,4 +39,9 @@ interface TokenParserInterface
* Gets the tag name associated with this token parser.
*/
public function getTag(): string;
/**
* Whether the tag is always allowed in sandbox mode, even when not explicitly allow-listed.
*/
public function isAlwaysAllowedInSandbox(): bool;
}
+2 -3
View File
@@ -13,9 +13,6 @@ namespace Twig;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @method bool needsIsSandboxed() Whether the callable needs the current sandbox state passed as an argument. Not implementing this method is deprecated since Twig 3.25, it will be required in 4.0.
* @method bool isAlwaysAllowedInSandbox() Whether the callable is always allowed in sandbox mode, even when not explicitly allow-listed. Not implementing this method is deprecated since Twig 3.28, it will be required in 4.0.
*/
interface TwigCallableInterface extends \Stringable
{
@@ -40,6 +37,8 @@ interface TwigCallableInterface extends \Stringable
public function needsIsSandboxed(): bool;
public function isAlwaysAllowedInSandbox(): bool;
public function withDynamicArguments(string $name, string $dynamicName, array $arguments): self;
public function getArguments(): array;
-36
View File
@@ -21,7 +21,6 @@ namespace Twig\Tests\Extension;
*/
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
use PHPUnit\Framework\TestCase;
use Twig\Environment;
use Twig\Error\RuntimeError;
@@ -44,7 +43,6 @@ use Twig\Sandbox\SecurityPolicy;
use Twig\Source;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
@@ -1550,18 +1548,6 @@ EOF
$this->expectExceptionMessage('Calling "__tostring" method on a "'.FooObject::class.'" object is not allowed');
$twig->load('index')->render(['obj' => new FooObject()]);
}
#[IgnoreDeprecations]
public function testCustomTokenParserWithoutIsAlwaysAllowedInSandboxTriggersDeprecation()
{
$twig = $this->getEnvironment(true, [], ['index' => '{% legacy_tag %}'], tags: ['legacy_tag']);
$twig->addTokenParser(new LegacyTokenParserWithoutIsAlwaysAllowedInSandbox());
$this->expectUserDeprecationMessage(\sprintf('Since twig/twig 3.28: Not implementing the "isAlwaysAllowedInSandbox()" method in "%s" is deprecated. This method will be part of the "Twig\TokenParser\TokenParserInterface" interface in 4.0.', LegacyTokenParserWithoutIsAlwaysAllowedInSandbox::class));
// tag is allow-listed, so the render itself succeeds; the deprecation fires from the sandbox visitor while compiling
$this->assertSame('', $twig->load('index')->render([]));
}
}
class ParentClass
@@ -1744,25 +1730,3 @@ class GatedSandboxTokenParser extends AbstractTokenParser
return 'gated_tag';
}
}
class LegacyTokenParserWithoutIsAlwaysAllowedInSandbox implements TokenParserInterface
{
private Parser $parser;
public function setParser(Parser $parser): void
{
$this->parser = $parser;
}
public function parse(Token $token): Node
{
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new TextNode('', $token->getLine());
}
public function getTag(): string
{
return 'legacy_tag';
}
}