diff --git a/CHANGELOG b/CHANGELOG index cc000d556..07baad84b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ # 3.26.1 (2026-XX-XX) - * n/a + * Deprecate the `Twig\Sandbox\SourcePolicyInterface` interface with no replacement # 3.26.0 (2026-05-20) diff --git a/doc/deprecated.rst b/doc/deprecated.rst index eb5b51674..5c86b2ad4 100644 --- a/doc/deprecated.rst +++ b/doc/deprecated.rst @@ -304,6 +304,10 @@ Sandbox deprecated as of Twig 3.12. You will need to explicitly allow them if needed in 4.0. +* The ``Twig\Sandbox\SourcePolicyInterface`` interface is deprecated as of Twig + 3.26.1 with no replacement. Passing an instance to the + ``Twig\Extension\SandboxExtension`` constructor triggers a deprecation. + * Deprecate the ``sandbox`` tag, use the ``sandboxed`` option of the ``include`` function instead: diff --git a/src/Extension/SandboxExtension.php b/src/Extension/SandboxExtension.php index 52f096702..0f8f1b4c6 100644 --- a/src/Extension/SandboxExtension.php +++ b/src/Extension/SandboxExtension.php @@ -28,6 +28,10 @@ final class SandboxExtension extends AbstractExtension public function __construct(SecurityPolicyInterface $policy, $sandboxed = false, ?SourcePolicyInterface $sourcePolicy = null) { + if (null !== $sourcePolicy) { + trigger_deprecation('twig/twig', '3.26.1', 'The "%s" interface is deprecated with no replacement, do not pass an instance to "%s".', SourcePolicyInterface::class, self::class); + } + $this->policy = $policy; $this->sandboxedGlobally = $sandboxed; $this->sourcePolicy = $sourcePolicy; diff --git a/src/Sandbox/SourcePolicyInterface.php b/src/Sandbox/SourcePolicyInterface.php index b952f1ea6..2daff120c 100644 --- a/src/Sandbox/SourcePolicyInterface.php +++ b/src/Sandbox/SourcePolicyInterface.php @@ -17,6 +17,8 @@ use Twig\Source; * Interface for a class that can optionally enable the sandbox mode based on a template's Twig\Source. * * @author Yaakov Saxon + * + * @deprecated since Twig 3.26.1 with no replacement */ interface SourcePolicyInterface { diff --git a/tests/Extension/SandboxTest.php b/tests/Extension/SandboxTest.php index a5c9dad37..c78bfc6c1 100644 --- a/tests/Extension/SandboxTest.php +++ b/tests/Extension/SandboxTest.php @@ -932,8 +932,13 @@ EOF return $twig; } + /** + * @group legacy + */ public function testSandboxSourcePolicyEnableReturningFalse() { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); + $twig = $this->getEnvironment(false, [], self::$templates, [], [], [], [], [], new class implements SourcePolicyInterface { public function enableSandbox(Source $source): bool { @@ -943,8 +948,13 @@ EOF $this->assertEquals('FOO', $twig->load('1_basic')->render(self::$params)); } + /** + * @group legacy + */ public function testSandboxSourcePolicyEnableReturningTrue() { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); + $twig = $this->getEnvironment(false, [], self::$templates, [], [], [], [], [], new class implements SourcePolicyInterface { public function enableSandbox(Source $source): bool { @@ -955,8 +965,13 @@ EOF $twig->load('1_basic')->render([]); } + /** + * @group legacy + */ public function testSandboxSourcePolicyFalseDoesntOverrideOtherEnables() { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); + $twig = $this->getEnvironment(true, [], self::$templates, [], [], [], [], [], new class implements SourcePolicyInterface { public function enableSandbox(Source $source): bool { @@ -968,10 +983,14 @@ EOF } /** + * @group legacy + * * @dataProvider provideSourcePolicyArrowBlockedTemplates */ public function testSourcePolicyBlocksNonClosureCallableInArrow(string $template) { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); + $sourcePolicy = new class implements SourcePolicyInterface { public function enableSandbox(Source $source): bool { @@ -997,8 +1016,13 @@ EOF yield 'has every' => ['{{ [1,2] has every "is_int" ? "yes" : "no" }}']; } + /** + * @group legacy + */ public function testSourcePolicyAllowsClosureInArrow() { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); + $sourcePolicy = new class implements SourcePolicyInterface { public function enableSandbox(Source $source): bool { @@ -1015,6 +1039,7 @@ EOF */ public function testNonSandboxedSourcePolicyAllowsNonClosureCallable() { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); $this->expectDeprecation('Since twig/twig 3.15: Passing a callable that is not a PHP \Closure as an argument to the "sort" filter is deprecated.'); $sourcePolicy = new class implements SourcePolicyInterface { @@ -1048,8 +1073,13 @@ EOF $this->assertSame('foo:off', $twig->load('index')->render([])); } + /** + * @group legacy + */ public function testNeedsIsSandboxedFilterFollowsSourcePolicy() { + $this->expectDeprecation('Since twig/twig 3.26.1: The "Twig\Sandbox\SourcePolicyInterface" interface is deprecated with no replacement, do not pass an instance to "Twig\Extension\SandboxExtension".'); + $twig = $this->getEnvironment(false, [], [ 'in' => '{{ "foo"|sandbox_aware }}', 'out' => '{{ "foo"|sandbox_aware }}',