diff --git a/.github/psalm/cache/.gitignore b/.github/psalm/cache/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/.github/psalm/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/.github/psalm/psalm.baseline.xml b/.github/psalm/psalm.baseline.xml new file mode 100644 index 0000000000..f74693accd --- /dev/null +++ b/.github/psalm/psalm.baseline.xml @@ -0,0 +1,3 @@ + + + diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml new file mode 100644 index 0000000000..11027c374e --- /dev/null +++ b/.github/workflows/psalm.yml @@ -0,0 +1,97 @@ +name: Static analysis + +on: + pull_request: ~ + +jobs: + psalm: + name: Psalm + runs-on: Ubuntu-20.04 + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.0' + extensions: "json,memcached,mongodb,redis,xsl,ldap,dom" + ini-values: "memory_limit=-1" + coverage: none + + - name: Checkout PR + uses: actions/checkout@v2 + with: + path: pr + + - name: Checkout base + uses: actions/checkout@v2 + with: + ref: ${{ github.base_ref }} + path: base + + - name: Configure composer + run: | + cd base + COMPOSER_HOME="$(composer config home)" + ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV + + - name: Determine composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: composer-${{ github.base_ref }} + restore-keys: composer- + + - name: Install Psalm + run: | + composer require psalm/phar + cp ./vendor/bin/psalm.phar base/psalm.phar + cp ./vendor/bin/psalm.phar pr/psalm.phar + + - name: Install dependencies for base + run: | + cd base + echo "::group::modify composer.json" + composer remove symfony/phpunit-bridge --no-interaction --no-update + composer require --no-update phpunit/phpunit php-http/discovery psr/event-dispatcher + echo "::endgroup::" + echo "::group::composer update" + composer update --no-progress --ansi + echo "::endgroup::" + + - name: Generate Psalm baseline + run: | + cd base + ./psalm.phar --set-baseline=.github/psalm/psalm.baseline.xml --no-progress + + - name: Copy baseline + run: | + cp base/.github/psalm/psalm.baseline.xml pr/.github/psalm/psalm.baseline.xml + + - name: Install dependencies for PR + run: | + cd pr + echo "::group::modify composer.json" + composer remove symfony/phpunit-bridge --no-interaction --no-update + composer require --no-update phpunit/phpunit php-http/discovery psr/event-dispatcher + echo "::endgroup::" + echo "::group::composer update" + composer update --no-progress --ansi + echo "::endgroup::" + + - name: Cache Psalm + uses: actions/cache@v2 + with: + path: pr/.github/psalm/cache/ + key: psalm-${{ github.base_ref }} + restore-keys: psalm- + + - name: Psalm + run: | + cd pr + ./psalm.phar --version + ./psalm.phar --output-format=github --no-progress diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000000..3f12f1331c --- /dev/null +++ b/psalm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index bb34d724b3..b96521f754 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -389,6 +389,9 @@ class NativeSessionStorage implements SessionStorageInterface $this->emulateSameSite = $value; continue; } + if ('cookie_secure' === $key && 'auto' === $value) { + continue; + } ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value); } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/SessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/SessionListener.php index e982a795b2..93bbb2f117 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/SessionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/SessionListener.php @@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; /** * Sets the session in the request. @@ -33,10 +34,12 @@ class SessionListener extends AbstractSessionListener parent::__construct($container, $debug); } - protected function getSession(): ?SessionInterface + public function onKernelRequest(GetResponseEvent $event) { - if (!$this->container->has('session')) { - return null; + parent::onKernelRequest($event); + + if (!$event->isMasterRequest() || !$this->container->has('session')) { + return; } if ($this->container->has('session_storage') @@ -46,6 +49,13 @@ class SessionListener extends AbstractSessionListener ) { $storage->setOptions(['cookie_secure' => true]); } + } + + protected function getSession(): ?SessionInterface + { + if (!$this->container->has('session')) { + return null; + } return $this->container->get('session'); } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php index 8530494354..ac6175d98f 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php @@ -62,7 +62,7 @@ class SessionListenerTest extends TestCase $listener = new SessionListener($container); $event = $this->createMock(RequestEvent::class); - $event->expects($this->once())->method('isMasterRequest')->willReturn(true); + $event->expects($this->exactly(2))->method('isMasterRequest')->willReturn(true); $event->expects($this->once())->method('getRequest')->willReturn($request); $listener->onKernelRequest($event); @@ -206,12 +206,16 @@ class SessionListenerTest extends TestCase $listener = new SessionListener($container); $listener->onKernelRequest($event); + // storage->setOptions() should have been called already + $container->set('session_storage', null); + $sessionStorage = null; + $subRequest = $masterRequest->duplicate(); // at this point both master and subrequest have a closure to build the session $masterRequest->getSession(); - // calling the factory on the subRequest should not trigger a second call to storage->sesOptions() + // calling the factory on the subRequest should not trigger a second call to storage->setOptions() $subRequest->getSession(); }