From 991a5079c5c401db8119a6355fda22f2eb16437b Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 8 Oct 2026 11:20:48 +0200 Subject: [PATCH 01/11] Add support for Mercure 1.0 --- CHANGELOG.md | 17 +++++++ composer.json | 4 +- config/autoload/installer.global.php | 1 + config/autoload/mercure.global.php | 1 + config/params/shlink_dev_env.php.dist | 1 + docs/swagger/definitions/MercureInfo.json | 5 +++ docs/swagger/paths/v2_mercure-info.json | 3 +- module/Core/src/Config/EnvVars.php | 3 ++ module/Core/src/ShortUrl/Entity/ShortUrl.php | 6 ++- ...erBuilderWithCacheDelegatorFactoryTest.php | 4 +- module/Rest/config/dependencies.config.php | 3 +- module/Rest/src/Action/MercureInfoAction.php | 10 +++-- .../test/Action/MercureInfoActionTest.php | 44 +++++++------------ 13 files changed, 62 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 403bb86c..5153f5ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org). +## [Unreleased] +### Added +* [#2671](https://github.com/shlinkio/shlink/issues/2671) Add support for Mercure 1.0. + +### Changed +* *Nothing* + +### Deprecated +* *Nothing* + +### Removed +* *Nothing* + +### Fixed +* *Nothing* + + ## [5.1.7] - 2026-09-21 ### Added * *Nothing* diff --git a/composer.json b/composer.json index e4e95227..a4b6a8d5 100644 --- a/composer.json +++ b/composer.json @@ -42,11 +42,11 @@ "pagerfanta/core": "^3.8", "ramsey/uuid": "^4.9", "shlinkio/doctrine-specification": "^2.3", - "shlinkio/shlink-common": "^9.0.2", + "shlinkio/shlink-common": "dev-main#db84fc4 as 9.1.0", "shlinkio/shlink-config": "^4.1.0", "shlinkio/shlink-event-dispatcher": "^4.4.0", "shlinkio/shlink-importer": "^5.8", - "shlinkio/shlink-installer": "^10.1", + "shlinkio/shlink-installer": "dev-develop#0aff783 as 10.2.0", "shlinkio/shlink-ip-geolocation": "^5.0.0", "shlinkio/shlink-json": "^1.3", "spiral/roadrunner": "^2025.1", diff --git a/config/autoload/installer.global.php b/config/autoload/installer.global.php index 2b80b756..1b822ba7 100644 --- a/config/autoload/installer.global.php +++ b/config/autoload/installer.global.php @@ -40,6 +40,7 @@ return [ Option\Mercure\MercurePublicUrlConfigOption::class, Option\Mercure\MercureInternalUrlConfigOption::class, Option\Mercure\MercureJwtSecretConfigOption::class, + Option\Mercure\MercureVersionConfigOption::class, Option\UrlShortener\GeoLiteLicenseKeyConfigOption::class, Option\UrlShortener\RedirectStatusCodeConfigOption::class, Option\UrlShortener\RedirectCacheLifeTimeConfigOption::class, diff --git a/config/autoload/mercure.global.php b/config/autoload/mercure.global.php index a499c2ae..f6566e90 100644 --- a/config/autoload/mercure.global.php +++ b/config/autoload/mercure.global.php @@ -16,6 +16,7 @@ return [ 'internal_hub_url' => EnvVars::MERCURE_INTERNAL_HUB_URL->loadFromEnv(), 'jwt_secret' => EnvVars::MERCURE_JWT_SECRET->loadFromEnv(), 'jwt_issuer' => 'Shlink', + 'version' => EnvVars::MERCURE_VERSION->loadFromEnv(), ], 'dependencies' => [ diff --git a/config/params/shlink_dev_env.php.dist b/config/params/shlink_dev_env.php.dist index e5dddf35..ff89adfe 100644 --- a/config/params/shlink_dev_env.php.dist +++ b/config/params/shlink_dev_env.php.dist @@ -64,6 +64,7 @@ return [ EnvVars::MERCURE_PUBLIC_HUB_URL->value => 'http://localhost:8002', EnvVars::MERCURE_INTERNAL_HUB_URL->value => 'http://shlink_mercure_proxy', EnvVars::MERCURE_JWT_SECRET->value => 'mercure_jwt_key_long_enough_to_avoid_error', + EnvVars::MERCURE_VERSION->value => 'v1', // RabbitMQ EnvVars::RABBITMQ_ENABLED->value => true, diff --git a/docs/swagger/definitions/MercureInfo.json b/docs/swagger/definitions/MercureInfo.json index ac1f273a..db1781d0 100644 --- a/docs/swagger/definitions/MercureInfo.json +++ b/docs/swagger/definitions/MercureInfo.json @@ -13,6 +13,11 @@ "jwtExpiration": { "type": "string", "description": "The date (in ISO-8601 format) in which the JWT will expire" + }, + "version": { + "type": "string", + "enum": ["v0", "v1"], + "description": "Indicates the version of the mercure hub that has been configured, so that consumers know how to subscribe" } } } diff --git a/docs/swagger/paths/v2_mercure-info.json b/docs/swagger/paths/v2_mercure-info.json index e637ca33..4e2957da 100644 --- a/docs/swagger/paths/v2_mercure-info.json +++ b/docs/swagger/paths/v2_mercure-info.json @@ -27,7 +27,8 @@ "example": { "mercureHubUrl": "https://example.com/.well-known/mercure", "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ", - "jwtExpiration": "2020-04-15T12:18:52+02:00" + "jwtExpiration": "2020-04-15T12:18:52+02:00", + "version": "v1" } } } diff --git a/module/Core/src/Config/EnvVars.php b/module/Core/src/Config/EnvVars.php index f4b71cd5..aa4a9427 100644 --- a/module/Core/src/Config/EnvVars.php +++ b/module/Core/src/Config/EnvVars.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Core\Config; +use Shlinkio\Shlink\Common\Mercure\MercureVersion; use Shlinkio\Shlink\Core\Config\Options\ExtraPathMode; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlMode; @@ -41,6 +42,7 @@ enum EnvVars: string case MERCURE_PUBLIC_HUB_URL = 'MERCURE_PUBLIC_HUB_URL'; case MERCURE_INTERNAL_HUB_URL = 'MERCURE_INTERNAL_HUB_URL'; case MERCURE_JWT_SECRET = 'MERCURE_JWT_SECRET'; + case MERCURE_VERSION = 'MERCURE_VERSION'; case RABBITMQ_ENABLED = 'RABBITMQ_ENABLED'; case RABBITMQ_HOST = 'RABBITMQ_HOST'; case RABBITMQ_PORT = 'RABBITMQ_PORT'; @@ -134,6 +136,7 @@ enum EnvVars: string }, self::DB_USE_ENCRYPTION => false, self::MERCURE_ENABLED => self::MERCURE_PUBLIC_HUB_URL->existsInEnv(), + self::MERCURE_VERSION => MercureVersion::v0->value, self::MERCURE_INTERNAL_HUB_URL => self::MERCURE_PUBLIC_HUB_URL->loadFromEnv(), self::RABBITMQ_ENABLED, self::RABBITMQ_USE_SSL => false, self::RABBITMQ_PORT => 5672, diff --git a/module/Core/src/ShortUrl/Entity/ShortUrl.php b/module/Core/src/ShortUrl/Entity/ShortUrl.php index 187c9d5f..bec3d29b 100644 --- a/module/Core/src/ShortUrl/Entity/ShortUrl.php +++ b/module/Core/src/ShortUrl/Entity/ShortUrl.php @@ -167,8 +167,10 @@ class ShortUrl extends AbstractEntity if ( $this->title === null || $shortUrlEdit->titleWasProvided - || ($this->titleWasAutoResolved - && $shortUrlEdit->titleWasAutoResolved) + || ( + $this->titleWasAutoResolved + && $shortUrlEdit->titleWasAutoResolved + ) ) { $this->title = $shortUrlEdit->title; $this->titleWasAutoResolved = $shortUrlEdit->titleWasAutoResolved; diff --git a/module/Core/test/ObjectMapper/MapperBuilderWithCacheDelegatorFactoryTest.php b/module/Core/test/ObjectMapper/MapperBuilderWithCacheDelegatorFactoryTest.php index 85f8305f..b55df819 100644 --- a/module/Core/test/ObjectMapper/MapperBuilderWithCacheDelegatorFactoryTest.php +++ b/module/Core/test/ObjectMapper/MapperBuilderWithCacheDelegatorFactoryTest.php @@ -42,7 +42,7 @@ class MapperBuilderWithCacheDelegatorFactoryTest extends TestCase { putenv(EnvVars::APP_ENV->value . '=' . $env); - $builder = (new MapperBuilderWithCacheDelegatorFactory())($this->container, '', fn () => $this->baseBuilder); + $builder = new MapperBuilderWithCacheDelegatorFactory()($this->container, '', fn () => $this->baseBuilder); $reflection = new ReflectionObject($builder); /** @var Settings $settings */ $settings = $reflection->getProperty('settings')->getValue($builder); @@ -56,7 +56,7 @@ class MapperBuilderWithCacheDelegatorFactoryTest extends TestCase { putenv(EnvVars::APP_ENV->value . '=prod'); - $builder = (new MapperBuilderWithCacheDelegatorFactory())($this->container, '', fn () => $this->baseBuilder); + $builder = new MapperBuilderWithCacheDelegatorFactory()($this->container, '', fn () => $this->baseBuilder); $reflection = new ReflectionObject($builder); /** @var Settings $settings */ $settings = $reflection->getProperty('settings')->getValue($builder); diff --git a/module/Rest/config/dependencies.config.php b/module/Rest/config/dependencies.config.php index c726b1a0..0086b9f8 100644 --- a/module/Rest/config/dependencies.config.php +++ b/module/Rest/config/dependencies.config.php @@ -12,6 +12,7 @@ use Mezzio\Router\Middleware\ImplicitOptionsMiddleware; use Psr\Log\LoggerInterface; use Shlinkio\Shlink\Common\Doctrine\EntityRepositoryFactory; use Shlinkio\Shlink\Common\Mercure\LcobucciJwtProvider; +use Shlinkio\Shlink\Common\Mercure\MercureOptions; use Shlinkio\Shlink\Core\Config; use Shlinkio\Shlink\Core\Domain\DomainService; use Shlinkio\Shlink\Core\RedirectRule; @@ -68,7 +69,7 @@ return [ ApiKeyService::class => ['em', ApiKeyRepository::class], Action\HealthAction::class => ['em', Config\Options\AppOptions::class], - Action\MercureInfoAction::class => [LcobucciJwtProvider::class, 'config.mercure'], + Action\MercureInfoAction::class => [LcobucciJwtProvider::class, MercureOptions::class], Action\ShortUrl\CreateShortUrlAction::class => [ ShortUrl\UrlShortener::class, ShortUrlDataTransformer::class, diff --git a/module/Rest/src/Action/MercureInfoAction.php b/module/Rest/src/Action/MercureInfoAction.php index 4942731d..ba49ec9b 100644 --- a/module/Rest/src/Action/MercureInfoAction.php +++ b/module/Rest/src/Action/MercureInfoAction.php @@ -9,6 +9,7 @@ use Laminas\Diactoros\Response\JsonResponse; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Shlinkio\Shlink\Common\Mercure\JwtProviderInterface; +use Shlinkio\Shlink\Common\Mercure\MercureOptions; use Shlinkio\Shlink\Rest\Exception\MercureException; use function sprintf; @@ -20,24 +21,25 @@ class MercureInfoAction extends AbstractRestAction public function __construct( private readonly JwtProviderInterface $jwtProvider, - private readonly array $mercureConfig, + private readonly MercureOptions $mercureOptions, ) {} public function handle(ServerRequestInterface $request): ResponseInterface { - $hubUrl = $this->mercureConfig['public_hub_url'] ?? null; + $hubUrl = $this->mercureOptions->publicHubUrl; if ($hubUrl === null) { throw MercureException::mercureNotConfigured(); } - $days = $this->mercureConfig['jwt_days_duration'] ?? 1; - $expiresAt = Chronos::now()->addDays($days); + // Make subscription tokens expire in 1 day + $expiresAt = Chronos::now()->addDays(1); $jwt = $this->jwtProvider->buildSubscriptionToken($expiresAt); return new JsonResponse([ 'mercureHubUrl' => sprintf('%s/.well-known/mercure', $hubUrl), 'token' => $jwt, 'jwtExpiration' => $expiresAt->toAtomString(), + 'version' => $this->mercureOptions->version->value, ]); } } diff --git a/module/Rest/test/Action/MercureInfoActionTest.php b/module/Rest/test/Action/MercureInfoActionTest.php index 841ab933..83596295 100644 --- a/module/Rest/test/Action/MercureInfoActionTest.php +++ b/module/Rest/test/Action/MercureInfoActionTest.php @@ -10,9 +10,12 @@ use Laminas\Diactoros\ServerRequestFactory; use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Shlinkio\Shlink\Common\Mercure\JwtProviderInterface; +use Shlinkio\Shlink\Common\Mercure\MercureOptions; +use Shlinkio\Shlink\Common\Mercure\MercureVersion; use Shlinkio\Shlink\Rest\Action\MercureInfoAction; use Shlinkio\Shlink\Rest\Exception\MercureException; @@ -25,39 +28,29 @@ class MercureInfoActionTest extends TestCase $this->provider = $this->createMock(JwtProviderInterface::class); } - #[Test, DataProvider('provideNoHostConfigs')] - public function throwsExceptionWhenConfigDoesNotHavePublicHost(array $mercureConfig): void + #[Test] + public function throwsExceptionWhenConfigDoesNotHavePublicHost(): void { $this->provider->expects($this->never())->method('buildSubscriptionToken'); - $action = new MercureInfoAction($this->provider, $mercureConfig); + $action = new MercureInfoAction($this->provider, new MercureOptions()); $this->expectException(MercureException::class); $action->handle(ServerRequestFactory::fromGlobals()); } - public static function provideNoHostConfigs(): iterable - { - yield 'host not defined' => [[]]; - yield 'host is null' => [['public_hub_url' => null]]; - } - - public function provideValidConfigs(): iterable - { - yield 'days not defined' => [['public_hub_url' => 'http://foobar.com']]; - yield 'days defined' => [['public_hub_url' => 'http://foobar.com', 'jwt_days_duration' => 20]]; - } - - #[Test, DataProvider('provideDays')] - public function returnsExpectedInfoWhenEverythingIsOk(int|null $days): void + #[Test] + #[TestWith([MercureVersion::v0])] + #[TestWith([MercureVersion::v1])] + public function returnsExpectedInfoWhenEverythingIsOk(MercureVersion $version): void { $this->provider->expects($this->once())->method('buildSubscriptionToken')->willReturn('abc.123'); - $action = new MercureInfoAction($this->provider, [ - 'public_hub_url' => 'http://foobar.com', - 'jwt_days_duration' => $days, - ]); + $action = new MercureInfoAction($this->provider, new MercureOptions( + publicHubUrl: 'http://foobar.com', + version: $version, + )); /** @var JsonResponse $resp */ $resp = $action->handle(ServerRequestFactory::fromGlobals()); @@ -68,15 +61,10 @@ class MercureInfoActionTest extends TestCase self::assertArrayHasKey('token', $payload); self::assertArrayHasKey('jwtExpiration', $payload); self::assertEquals( - Chronos::now()->addDays($days ?? 1)->startOfDay(), + Chronos::now()->addDays(1)->startOfDay(), Chronos::parse($payload['jwtExpiration'])->startOfDay(), ); - } - - public static function provideDays(): iterable - { - yield 'days not defined' => [null]; - yield 'days defined' => [10]; + self::assertEquals($version->value, $payload['version']); } #[Test, AllowMockObjectsWithoutExpectations] From 9a1b61f996454b28194d2efdbe085b169d6572c1 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 8 Oct 2026 21:28:32 +0200 Subject: [PATCH 02/11] Add both mercure 0 and mercure 1 to dev containers --- docker-compose.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4a569e4c..8768f132 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -87,6 +87,7 @@ services: - shlink_redis - shlink_redis_acl - shlink_mercure + - shlink_mercure_0 - shlink_mercure_proxy - shlink_rabbitmq - shlink_matomo @@ -175,7 +176,7 @@ services: shlink_mercure: container_name: shlink_mercure - image: dunglas/mercure:v0.18 + image: dunglas/mercure:v1 ports: - "3080:80" environment: @@ -184,6 +185,17 @@ services: MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005" + shlink_mercure_0: + container_name: shlink_mercure_0 + image: dunglas/mercure:v0 + ports: + - "3081:80" + environment: + SERVER_NAME: ":80" + MERCURE_PUBLISHER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error + MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error + MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005" + shlink_rabbitmq: container_name: shlink_rabbitmq image: rabbitmq:3.11-management-alpine From 51faee98c575b05fe674a31bfe98dfc53792780a Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 9 Oct 2026 13:19:41 +0200 Subject: [PATCH 03/11] Define trusted issuer for mercure --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 8768f132..6ee82588 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,7 @@ services: - shlink_redis - shlink_redis_acl - shlink_mercure + - shlink_mercure_0 - shlink_mercure_proxy - shlink_rabbitmq - shlink_matomo @@ -58,6 +59,7 @@ services: - shlink_redis - shlink_redis_acl - shlink_mercure + - shlink_mercure_0 - shlink_mercure_proxy - shlink_rabbitmq - shlink_matomo @@ -183,6 +185,7 @@ services: SERVER_NAME: ":80" MERCURE_PUBLISHER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error + MERCURE_TRUSTED_ISSUERS: Shlink # Value of the JWT iss claim MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005" shlink_mercure_0: From 463fb25d30538f0547dd0823a66d57da5c86725c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 9 Oct 2026 13:19:53 +0200 Subject: [PATCH 04/11] Fix coding styles --- mago-analyze-baseline.toml | 254 ++++++++++++++++-- .../test/Action/MercureInfoActionTest.php | 1 - 2 files changed, 229 insertions(+), 26 deletions(-) diff --git a/mago-analyze-baseline.toml b/mago-analyze-baseline.toml index 6149e14b..74f12017 100644 --- a/mago-analyze-baseline.toml +++ b/mago-analyze-baseline.toml @@ -684,6 +684,66 @@ code = "possibly-static-access-on-interface" message = "Potential static method call on interface `BackedEnum` via `class-string`." count = 1 +[[issues]] +file = "module/Core/migrations/Version20230211171904.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20230303164233.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20230303164233.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::dropIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240220214031.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Column::getType`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240220214031.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Column::setType`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240220214031.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::modifyColumn`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240224115725.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::createTable`.' +count = 2 + +[[issues]] +file = "module/Core/migrations/Version20240224115725.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::dropTable`.' +count = 3 + +[[issues]] +file = "module/Core/migrations/Version20240224115725.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 9 + +[[issues]] +file = "module/Core/migrations/Version20240224115725.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addForeignKeyConstraint`.' +count = 3 + [[issues]] file = "module/Core/migrations/Version20240224115725.php" code = "deprecated-method" @@ -696,12 +756,72 @@ code = "mixed-assignment" message = "Assigning `mixed` type to a variable may lead to unexpected behavior." count = 2 +[[issues]] +file = "module/Core/migrations/Version20240227080629.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::createTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240227080629.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::dropTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240227080629.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 4 + +[[issues]] +file = "module/Core/migrations/Version20240227080629.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addForeignKeyConstraint`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240227080629.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addUniqueIndex`.' +count = 1 + [[issues]] file = "module/Core/migrations/Version20240227080629.php" code = "deprecated-method" message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::setPrimaryKey`.' count = 1 +[[issues]] +file = "module/Core/migrations/Version20240306132518.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::createTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240306132518.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::dropTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240306132518.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 5 + +[[issues]] +file = "module/Core/migrations/Version20240306132518.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addForeignKeyConstraint`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240306132518.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addUniqueIndex`.' +count = 1 + [[issues]] file = "module/Core/migrations/Version20240306132518.php" code = "deprecated-method" @@ -732,6 +852,30 @@ code = "mixed-operand" message = "Left operand in `>` comparison has `mixed` type." count = 2 +[[issues]] +file = "module/Core/migrations/Version20240331111103.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::createTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240331111103.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::dropTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20240331111103.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 4 + +[[issues]] +file = "module/Core/migrations/Version20240331111103.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addUniqueIndex`.' +count = 1 + [[issues]] file = "module/Core/migrations/Version20240331111103.php" code = "deprecated-method" @@ -780,12 +924,96 @@ code = "mixed-assignment" message = "Assigning `mixed` type to a variable may lead to unexpected behavior." count = 1 +[[issues]] +file = "module/Core/migrations/Version20241124112257.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20241124112257.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::dropColumn`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20241125213106.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addUniqueIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20241125213106.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::dropIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20241212131058.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::createTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20241212131058.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Schema::dropTable`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20241212131058.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 7 + +[[issues]] +file = "module/Core/migrations/Version20241212131058.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addIndex`.' +count = 2 + [[issues]] file = "module/Core/migrations/Version20241212131058.php" code = "deprecated-method" message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::setPrimaryKey`.' count = 1 +[[issues]] +file = "module/Core/migrations/Version20250215100756.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::dropIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20250722060208.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Column::setNotnull`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20260524105410.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addColumn`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20260524105410.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::addIndex`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20260524105410.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::dropColumn`.' +count = 1 + +[[issues]] +file = "module/Core/migrations/Version20260524105410.php" +code = "deprecated-method" +message = 'Call to deprecated method: `Doctrine\DBAL\Schema\Table::dropIndex`.' +count = 1 + [[issues]] file = "module/Core/migrations/Version20260607082210.php" code = "mixed-argument" @@ -2106,30 +2334,6 @@ code = "string-member-selector" message = "This member selector uses a non-literal string type (`string`); its specific value cannot be statically determined." count = 3 -[[issues]] -file = "module/Rest/src/Action/MercureInfoAction.php" -code = "mixed-argument" -message = 'Invalid argument type for argument #1 of `Cake\Chronos\Chronos::addDays`: expected `int`, but found `nonnull`.' -count = 1 - -[[issues]] -file = "module/Rest/src/Action/MercureInfoAction.php" -code = "mixed-argument" -message = "Invalid argument type for argument #2 of `sprintf`: expected `Stringable|null|scalar`, but found `nonnull`." -count = 1 - -[[issues]] -file = "module/Rest/src/Action/MercureInfoAction.php" -code = "mixed-assignment" -message = "Assigning `mixed` type to a variable may lead to unexpected behavior." -count = 1 - -[[issues]] -file = "module/Rest/src/Action/MercureInfoAction.php" -code = "mixed-assignment" -message = "Assigning `nonnull` type to a variable may lead to unexpected behavior." -count = 1 - [[issues]] file = "module/Rest/src/Action/RedirectRule/SetRedirectRulesAction.php" code = "invalid-type-cast" @@ -2530,7 +2734,7 @@ count = 3 file = "module/Rest/test/Action/MercureInfoActionTest.php" code = "mixed-array-access" message = "Unsafe array access on type `mixed`." -count = 2 +count = 3 [[issues]] file = "module/Rest/test/Action/MercureInfoActionTest.php" diff --git a/module/Rest/test/Action/MercureInfoActionTest.php b/module/Rest/test/Action/MercureInfoActionTest.php index 83596295..047d1642 100644 --- a/module/Rest/test/Action/MercureInfoActionTest.php +++ b/module/Rest/test/Action/MercureInfoActionTest.php @@ -8,7 +8,6 @@ use Cake\Chronos\Chronos; use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\ServerRequestFactory; use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; -use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\MockObject\MockObject; From d6239aa5bab927df5107f8d46343b27d424f7eed Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 10 Oct 2026 10:24:07 +0200 Subject: [PATCH 05/11] Update to latest shlink-common --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a4b6a8d5..144df372 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "pagerfanta/core": "^3.8", "ramsey/uuid": "^4.9", "shlinkio/doctrine-specification": "^2.3", - "shlinkio/shlink-common": "dev-main#db84fc4 as 9.1.0", + "shlinkio/shlink-common": "dev-main#078faf1 as 9.1.0", "shlinkio/shlink-config": "^4.1.0", "shlinkio/shlink-event-dispatcher": "^4.4.0", "shlinkio/shlink-importer": "^5.8", From 445ffb18ddb45404d3f96be1d8ec0508f1e3e97d Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 11 Oct 2026 10:09:08 +0200 Subject: [PATCH 06/11] Add mercure auth cookie --- composer.json | 2 +- config/autoload/mercure.global.php | 1 + config/params/shlink_dev_env.php.dist | 3 ++- docker-compose.yml | 4 +++- module/Core/src/Config/EnvVars.php | 3 ++- module/Rest/src/Action/MercureInfoAction.php | 1 + module/Rest/test/Action/MercureInfoActionTest.php | 4 ++-- 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 144df372..854d3444 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "pagerfanta/core": "^3.8", "ramsey/uuid": "^4.9", "shlinkio/doctrine-specification": "^2.3", - "shlinkio/shlink-common": "dev-main#078faf1 as 9.1.0", + "shlinkio/shlink-common": "dev-main#349d779 as 9.1.0", "shlinkio/shlink-config": "^4.1.0", "shlinkio/shlink-event-dispatcher": "^4.4.0", "shlinkio/shlink-importer": "^5.8", diff --git a/config/autoload/mercure.global.php b/config/autoload/mercure.global.php index f6566e90..8a2df9c0 100644 --- a/config/autoload/mercure.global.php +++ b/config/autoload/mercure.global.php @@ -17,6 +17,7 @@ return [ 'jwt_secret' => EnvVars::MERCURE_JWT_SECRET->loadFromEnv(), 'jwt_issuer' => 'Shlink', 'version' => EnvVars::MERCURE_VERSION->loadFromEnv(), + 'auth_cookie_name' => EnvVars::MERCURE_AUTH_COOKIE_NAME->loadFromEnv(), ], 'dependencies' => [ diff --git a/config/params/shlink_dev_env.php.dist b/config/params/shlink_dev_env.php.dist index ff89adfe..8e22203e 100644 --- a/config/params/shlink_dev_env.php.dist +++ b/config/params/shlink_dev_env.php.dist @@ -64,7 +64,8 @@ return [ EnvVars::MERCURE_PUBLIC_HUB_URL->value => 'http://localhost:8002', EnvVars::MERCURE_INTERNAL_HUB_URL->value => 'http://shlink_mercure_proxy', EnvVars::MERCURE_JWT_SECRET->value => 'mercure_jwt_key_long_enough_to_avoid_error', - EnvVars::MERCURE_VERSION->value => 'v1', + EnvVars::MERCURE_VERSION->value => 'stable', + EnvVars::MERCURE_AUTH_COOKIE_NAME->value => 'mercure_access_token', // RabbitMQ EnvVars::RABBITMQ_ENABLED->value => true, diff --git a/docker-compose.yml b/docker-compose.yml index 6ee82588..3c6b8e2f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -186,7 +186,9 @@ services: MERCURE_PUBLISHER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error MERCURE_TRUSTED_ISSUERS: Shlink # Value of the JWT iss claim - MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005" + MERCURE_EXTRA_DIRECTIVES: | + cookie_name mercure_access_token + cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005 shlink_mercure_0: container_name: shlink_mercure_0 diff --git a/module/Core/src/Config/EnvVars.php b/module/Core/src/Config/EnvVars.php index aa4a9427..cc4565f9 100644 --- a/module/Core/src/Config/EnvVars.php +++ b/module/Core/src/Config/EnvVars.php @@ -43,6 +43,7 @@ enum EnvVars: string case MERCURE_INTERNAL_HUB_URL = 'MERCURE_INTERNAL_HUB_URL'; case MERCURE_JWT_SECRET = 'MERCURE_JWT_SECRET'; case MERCURE_VERSION = 'MERCURE_VERSION'; + case MERCURE_AUTH_COOKIE_NAME = 'MERCURE_AUTH_COOKIE_NAME'; case RABBITMQ_ENABLED = 'RABBITMQ_ENABLED'; case RABBITMQ_HOST = 'RABBITMQ_HOST'; case RABBITMQ_PORT = 'RABBITMQ_PORT'; @@ -136,7 +137,7 @@ enum EnvVars: string }, self::DB_USE_ENCRYPTION => false, self::MERCURE_ENABLED => self::MERCURE_PUBLIC_HUB_URL->existsInEnv(), - self::MERCURE_VERSION => MercureVersion::v0->value, + self::MERCURE_VERSION => MercureVersion::LEGACY->value, self::MERCURE_INTERNAL_HUB_URL => self::MERCURE_PUBLIC_HUB_URL->loadFromEnv(), self::RABBITMQ_ENABLED, self::RABBITMQ_USE_SSL => false, self::RABBITMQ_PORT => 5672, diff --git a/module/Rest/src/Action/MercureInfoAction.php b/module/Rest/src/Action/MercureInfoAction.php index ba49ec9b..5c6588dd 100644 --- a/module/Rest/src/Action/MercureInfoAction.php +++ b/module/Rest/src/Action/MercureInfoAction.php @@ -40,6 +40,7 @@ class MercureInfoAction extends AbstractRestAction 'token' => $jwt, 'jwtExpiration' => $expiresAt->toAtomString(), 'version' => $this->mercureOptions->version->value, + 'authCookieName' => $this->mercureOptions->authCookieName, ]); } } diff --git a/module/Rest/test/Action/MercureInfoActionTest.php b/module/Rest/test/Action/MercureInfoActionTest.php index 047d1642..2ece8e6b 100644 --- a/module/Rest/test/Action/MercureInfoActionTest.php +++ b/module/Rest/test/Action/MercureInfoActionTest.php @@ -40,8 +40,8 @@ class MercureInfoActionTest extends TestCase } #[Test] - #[TestWith([MercureVersion::v0])] - #[TestWith([MercureVersion::v1])] + #[TestWith([MercureVersion::LEGACY])] + #[TestWith([MercureVersion::STABLE])] public function returnsExpectedInfoWhenEverythingIsOk(MercureVersion $version): void { $this->provider->expects($this->once())->method('buildSubscriptionToken')->willReturn('abc.123'); From e1c255025b9989f4d651eeeaa790bcbbbee2d91b Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 11 Oct 2026 10:12:26 +0200 Subject: [PATCH 07/11] Fix API docs for mercure version --- docs/swagger/definitions/MercureInfo.json | 2 +- docs/swagger/paths/v2_mercure-info.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/swagger/definitions/MercureInfo.json b/docs/swagger/definitions/MercureInfo.json index db1781d0..e0c05699 100644 --- a/docs/swagger/definitions/MercureInfo.json +++ b/docs/swagger/definitions/MercureInfo.json @@ -16,7 +16,7 @@ }, "version": { "type": "string", - "enum": ["v0", "v1"], + "enum": ["legacy", "stable"], "description": "Indicates the version of the mercure hub that has been configured, so that consumers know how to subscribe" } } diff --git a/docs/swagger/paths/v2_mercure-info.json b/docs/swagger/paths/v2_mercure-info.json index 4e2957da..2600d794 100644 --- a/docs/swagger/paths/v2_mercure-info.json +++ b/docs/swagger/paths/v2_mercure-info.json @@ -28,7 +28,7 @@ "mercureHubUrl": "https://example.com/.well-known/mercure", "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ", "jwtExpiration": "2020-04-15T12:18:52+02:00", - "version": "v1" + "version": "stable" } } } From fd5d49e73e0b1d52bf0ea0fad14ef1e317f9907c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 11 Oct 2026 23:58:53 +0200 Subject: [PATCH 08/11] Update installer --- composer.json | 2 +- config/autoload/installer.global.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 854d3444..a1f552d5 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "shlinkio/shlink-config": "^4.1.0", "shlinkio/shlink-event-dispatcher": "^4.4.0", "shlinkio/shlink-importer": "^5.8", - "shlinkio/shlink-installer": "dev-develop#0aff783 as 10.2.0", + "shlinkio/shlink-installer": "dev-develop#5bd25ec as 10.2.0", "shlinkio/shlink-ip-geolocation": "^5.0.0", "shlinkio/shlink-json": "^1.3", "spiral/roadrunner": "^2025.1", diff --git a/config/autoload/installer.global.php b/config/autoload/installer.global.php index 1b822ba7..ddef5081 100644 --- a/config/autoload/installer.global.php +++ b/config/autoload/installer.global.php @@ -41,6 +41,7 @@ return [ Option\Mercure\MercureInternalUrlConfigOption::class, Option\Mercure\MercureJwtSecretConfigOption::class, Option\Mercure\MercureVersionConfigOption::class, + Option\Mercure\MercureAuthCookieNameConfigOption::class, Option\UrlShortener\GeoLiteLicenseKeyConfigOption::class, Option\UrlShortener\RedirectStatusCodeConfigOption::class, Option\UrlShortener\RedirectCacheLifeTimeConfigOption::class, From c8a748bcfba3e651dc0816eaf729094c06ffadff Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 12 Oct 2026 00:02:23 +0200 Subject: [PATCH 09/11] Update API docs with mercure authCookieName --- docs/swagger/definitions/MercureInfo.json | 4 ++++ docs/swagger/paths/v2_mercure-info.json | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/swagger/definitions/MercureInfo.json b/docs/swagger/definitions/MercureInfo.json index e0c05699..d74155f4 100644 --- a/docs/swagger/definitions/MercureInfo.json +++ b/docs/swagger/definitions/MercureInfo.json @@ -18,6 +18,10 @@ "type": "string", "enum": ["legacy", "stable"], "description": "Indicates the version of the mercure hub that has been configured, so that consumers know how to subscribe" + }, + "authCookieName": { + "type": "string", + "description": "The name of the cookie where subscribers need to set the JWT" } } } diff --git a/docs/swagger/paths/v2_mercure-info.json b/docs/swagger/paths/v2_mercure-info.json index 2600d794..5f30b2ff 100644 --- a/docs/swagger/paths/v2_mercure-info.json +++ b/docs/swagger/paths/v2_mercure-info.json @@ -28,7 +28,8 @@ "mercureHubUrl": "https://example.com/.well-known/mercure", "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ", "jwtExpiration": "2020-04-15T12:18:52+02:00", - "version": "stable" + "version": "stable", + "authCookieName": "__Secure-mercure_access_token" } } } From 51fd63f056350c129381089837d9b6d1e8b40eeb Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 12 Oct 2026 23:56:49 +0200 Subject: [PATCH 10/11] Rollback addition of mercure auth cookie --- composer.json | 4 +- config/autoload/installer.global.php | 1 - config/autoload/mercure.global.php | 1 - config/params/shlink_dev_env.php.dist | 1 - docs/swagger/definitions/MercureInfo.json | 4 - docs/swagger/paths/v2_mercure-info.json | 3 +- mago-analyze-baseline.toml | 56 +------- .../CLI/test-cli/Command/ListApiKeysTest.php | 32 ++--- .../test-cli/Command/ListShortUrlsTest.php | 134 +++++++++--------- .../Command/Api/InitialApiKeyCommandTest.php | 4 +- module/Core/src/Config/EnvVars.php | 1 - module/Core/test/Action/RobotsActionTest.php | 68 ++++----- module/Rest/src/Action/MercureInfoAction.php | 1 - 13 files changed, 123 insertions(+), 187 deletions(-) diff --git a/composer.json b/composer.json index a1f552d5..48c0a1e2 100644 --- a/composer.json +++ b/composer.json @@ -42,11 +42,11 @@ "pagerfanta/core": "^3.8", "ramsey/uuid": "^4.9", "shlinkio/doctrine-specification": "^2.3", - "shlinkio/shlink-common": "dev-main#349d779 as 9.1.0", + "shlinkio/shlink-common": "dev-main#7e5d108 as 9.1.0", "shlinkio/shlink-config": "^4.1.0", "shlinkio/shlink-event-dispatcher": "^4.4.0", "shlinkio/shlink-importer": "^5.8", - "shlinkio/shlink-installer": "dev-develop#5bd25ec as 10.2.0", + "shlinkio/shlink-installer": "dev-develop#af7d57d as 10.2.0", "shlinkio/shlink-ip-geolocation": "^5.0.0", "shlinkio/shlink-json": "^1.3", "spiral/roadrunner": "^2025.1", diff --git a/config/autoload/installer.global.php b/config/autoload/installer.global.php index ddef5081..1b822ba7 100644 --- a/config/autoload/installer.global.php +++ b/config/autoload/installer.global.php @@ -41,7 +41,6 @@ return [ Option\Mercure\MercureInternalUrlConfigOption::class, Option\Mercure\MercureJwtSecretConfigOption::class, Option\Mercure\MercureVersionConfigOption::class, - Option\Mercure\MercureAuthCookieNameConfigOption::class, Option\UrlShortener\GeoLiteLicenseKeyConfigOption::class, Option\UrlShortener\RedirectStatusCodeConfigOption::class, Option\UrlShortener\RedirectCacheLifeTimeConfigOption::class, diff --git a/config/autoload/mercure.global.php b/config/autoload/mercure.global.php index 8a2df9c0..f6566e90 100644 --- a/config/autoload/mercure.global.php +++ b/config/autoload/mercure.global.php @@ -17,7 +17,6 @@ return [ 'jwt_secret' => EnvVars::MERCURE_JWT_SECRET->loadFromEnv(), 'jwt_issuer' => 'Shlink', 'version' => EnvVars::MERCURE_VERSION->loadFromEnv(), - 'auth_cookie_name' => EnvVars::MERCURE_AUTH_COOKIE_NAME->loadFromEnv(), ], 'dependencies' => [ diff --git a/config/params/shlink_dev_env.php.dist b/config/params/shlink_dev_env.php.dist index 8e22203e..31bdc338 100644 --- a/config/params/shlink_dev_env.php.dist +++ b/config/params/shlink_dev_env.php.dist @@ -65,7 +65,6 @@ return [ EnvVars::MERCURE_INTERNAL_HUB_URL->value => 'http://shlink_mercure_proxy', EnvVars::MERCURE_JWT_SECRET->value => 'mercure_jwt_key_long_enough_to_avoid_error', EnvVars::MERCURE_VERSION->value => 'stable', - EnvVars::MERCURE_AUTH_COOKIE_NAME->value => 'mercure_access_token', // RabbitMQ EnvVars::RABBITMQ_ENABLED->value => true, diff --git a/docs/swagger/definitions/MercureInfo.json b/docs/swagger/definitions/MercureInfo.json index d74155f4..e0c05699 100644 --- a/docs/swagger/definitions/MercureInfo.json +++ b/docs/swagger/definitions/MercureInfo.json @@ -18,10 +18,6 @@ "type": "string", "enum": ["legacy", "stable"], "description": "Indicates the version of the mercure hub that has been configured, so that consumers know how to subscribe" - }, - "authCookieName": { - "type": "string", - "description": "The name of the cookie where subscribers need to set the JWT" } } } diff --git a/docs/swagger/paths/v2_mercure-info.json b/docs/swagger/paths/v2_mercure-info.json index 5f30b2ff..2600d794 100644 --- a/docs/swagger/paths/v2_mercure-info.json +++ b/docs/swagger/paths/v2_mercure-info.json @@ -28,8 +28,7 @@ "mercureHubUrl": "https://example.com/.well-known/mercure", "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ", "jwtExpiration": "2020-04-15T12:18:52+02:00", - "version": "stable", - "authCookieName": "__Secure-mercure_access_token" + "version": "stable" } } } diff --git a/mago-analyze-baseline.toml b/mago-analyze-baseline.toml index 74f12017..e8864fdd 100644 --- a/mago-analyze-baseline.toml +++ b/mago-analyze-baseline.toml @@ -522,18 +522,6 @@ code = "mixed-operand" message = "Cannot reliably increment a `mixed` operand." count = 2 -[[issues]] -file = "module/CLI/test/RedirectRule/RedirectRuleHandlerTest.php" -code = "redundant-comparison" -message = "Redundant `<` comparison: left-hand side is always less than right-hand side." -count = 1 - -[[issues]] -file = "module/CLI/test/RedirectRule/RedirectRuleHandlerTest.php" -code = "redundant-logical-operation" -message = "Redundant `&&` operation: left operand is always truthy and right operand is evaluated." -count = 1 - [[issues]] file = "module/CLI/test/Util/CliTestUtils.php" code = "invalid-return-statement" @@ -1293,7 +1281,7 @@ count = 2 [[issues]] file = "module/Core/src/Domain/Repository/DomainRepository.php" code = "mixed-argument" -message = 'Invalid argument type for argument #2 of `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification`: expected `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier`, but found `mixed`.' +message = 'Invalid argument type for argument #2 of `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification`: expected `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier|null`, but found `mixed`.' count = 2 [[issues]] @@ -1614,12 +1602,6 @@ code = "mixed-assignment" message = "Assigning `mixed` type to a variable may lead to unexpected behavior." count = 1 -[[issues]] -file = "module/Core/src/ShortUrl/Repository/ShortUrlListRepository.php" -code = "possibly-null-argument" -message = 'Argument #2 of method `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification` is possibly `null`, but parameter type `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier` does not accept it.' -count = 1 - [[issues]] file = "module/Core/src/ShortUrl/Repository/ShortUrlRepository.php" code = "mixed-assignment" @@ -1650,12 +1632,6 @@ code = "mixed-return-statement" message = 'Could not infer a precise return type for function `Shlinkio\Shlink\Core\ShortUrl\Repository\ShortUrlRepository::findOne`. Saw type `mixed`.' count = 1 -[[issues]] -file = "module/Core/src/ShortUrl/Repository/ShortUrlRepository.php" -code = "possibly-null-argument" -message = 'Argument #2 of method `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification` is possibly `null`, but parameter type `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier` does not accept it.' -count = 1 - [[issues]] file = "module/Core/src/ShortUrl/Resolver/PersistenceShortUrlRelationResolver.php" code = "less-specific-return-statement" @@ -1752,12 +1728,6 @@ code = "mixed-return-statement" message = 'Could not infer a precise return type for function `Shlinkio\Shlink\Core\Tag\Paginator\Adapter\TagsPaginatorAdapter::getSlice`. Saw type `mixed`.' count = 1 -[[issues]] -file = "module/Core/src/Tag/Repository/TagRepository.php" -code = "mixed-argument" -message = 'Invalid argument type for argument #1 of `Doctrine\DBAL\Connection::quote`: expected `string`, but found `mixed`.' -count = 1 - [[issues]] file = "module/Core/src/Tag/Repository/TagRepository.php" code = "mixed-argument" @@ -1866,12 +1836,6 @@ code = "mixed-argument" message = 'Invalid argument type for argument #5 of `Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams::__construct`: expected `null|string`, but found `mixed`.' count = 1 -[[issues]] -file = "module/Core/src/Visit/Repository/ShortUrlVisitsCountRepository.php" -code = "possibly-null-argument" -message = 'Argument #2 of method `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification` is possibly `null`, but parameter type `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier` does not accept it.' -count = 1 - [[issues]] file = "module/Core/src/Visit/Repository/VisitDeleterRepository.php" code = "mixed-return-statement" @@ -1974,12 +1938,6 @@ code = "mixed-return-statement" message = 'Could not infer a precise return type for function `Shlinkio\Shlink\Core\Visit\Repository\VisitRepository::resolveVisitsWithNativeQuery`. Saw type `mixed`.' count = 1 -[[issues]] -file = "module/Core/src/Visit/Repository/VisitRepository.php" -code = "possibly-null-argument" -message = 'Argument #2 of method `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification` is possibly `null`, but parameter type `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier` does not accept it.' -count = 3 - [[issues]] file = "module/Core/src/Visit/RequestTracker.php" code = "mixed-assignment" @@ -2256,12 +2214,6 @@ code = "less-specific-argument" message = 'Argument type mismatch for argument #1 of `ShlinkioTest\Shlink\Core\RedirectRule\Entity\ShortUrlRedirectRuleTest::createRule`: expected `Doctrine\Common\Collections\ArrayCollection`, but provided type `Doctrine\Common\Collections\ArrayCollection` is less specific.' count = 1 -[[issues]] -file = "module/Core/test/ShortUrl/Helper/ShortCodeUniquenessHelperTest.php" -code = "redundant-comparison" -message = "Redundant `<` comparison: left-hand side is always less than right-hand side." -count = 1 - [[issues]] file = "module/Core/test/ShortUrl/Paginator/Adapter/ShortUrlRepositoryAdapterTest.php" code = "less-specific-nested-argument-type" @@ -2873,9 +2825,3 @@ file = "module/Rest/test/Middleware/ShortUrl/ShortUrlOptionsPayloadMiddlewareTes code = "invalid-type-cast" message = "Object of type `object` cast to `array`. Property visibility (public, protected, private) affects the resulting array." count = 1 - -[[issues]] -file = "module/Rest/test/Service/ApiKeyServiceTest.php" -code = "redundant-comparison" -message = "Redundant `<` comparison: left-hand side is always less than right-hand side." -count = 1 diff --git a/module/CLI/test-cli/Command/ListApiKeysTest.php b/module/CLI/test-cli/Command/ListApiKeysTest.php index 28c2dd36..e2b51420 100644 --- a/module/CLI/test-cli/Command/ListApiKeysTest.php +++ b/module/CLI/test-cli/Command/ListApiKeysTest.php @@ -43,23 +43,23 @@ class ListApiKeysTest extends CliTestCase OUT; yield 'no flags' => [[], << [['-e'], $enabledOnlyOutput]; yield '--enabled-only' => [['--enabled-only'], $enabledOnlyOutput]; } diff --git a/module/CLI/test-cli/Command/ListShortUrlsTest.php b/module/CLI/test-cli/Command/ListShortUrlsTest.php index eb958b8c..b7a08088 100644 --- a/module/CLI/test-cli/Command/ListShortUrlsTest.php +++ b/module/CLI/test-cli/Command/ListShortUrlsTest.php @@ -21,79 +21,79 @@ class ListShortUrlsTest extends CliTestCase public static function provideFlagsAndOutput(): iterable { yield 'no flags' => [[], << [['--start-date=2019-01'], << [['-e 2018-12-01'], << [['-s 2018-06-20', '--end-date=2019-01-01T00:00:20+00:00'], << [['--exclude-max-visits-reached', '--exclude-past-valid-until'], << [['--domain=example.com'], << [['--domain=DEFAULT'], << [['--exclude-tag=foo'], << [ApiKey::create(), true, '']; yield 'no api key created, no verbose' => [null, false, '']; yield 'no api key created, verbose' => [null, true, << [['foo', 'bar', 'baz'], new RobotsOptions(), << [['foo', 'bar', 'some', 'thing', 'baz'], new RobotsOptions(), << [[], new RobotsOptions(), << [ ['foo', 'bar', 'some'], new RobotsOptions(allowAllShortUrls: true), @@ -83,20 +83,20 @@ class RobotsActionTest extends TestCase ROBOTS, ]; yield 'no short codes and allow all short urls' => [[], new RobotsOptions(allowAllShortUrls: true), << [[], new RobotsOptions(userAgents: ['foo', 'bar']), << $jwt, 'jwtExpiration' => $expiresAt->toAtomString(), 'version' => $this->mercureOptions->version->value, - 'authCookieName' => $this->mercureOptions->authCookieName, ]); } } From f863e45a67f1991226d1c2a25abdb082ee6f3989 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Tue, 13 Oct 2026 00:00:37 +0200 Subject: [PATCH 11/11] Remove no-longer-needed mercure cookie_name directive --- docker-compose.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3c6b8e2f..6ee82588 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -186,9 +186,7 @@ services: MERCURE_PUBLISHER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error MERCURE_TRUSTED_ISSUERS: Shlink # Value of the JWT iss claim - MERCURE_EXTRA_DIRECTIVES: | - cookie_name mercure_access_token - cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005 + MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000 http://localhost:3002 http://127.0.0.1:3002 http://localhost:3005 http://127.0.0.1:3005" shlink_mercure_0: container_name: shlink_mercure_0