From 71c470a10df0b36aaaf1c7d786b42aa817e8f187 Mon Sep 17 00:00:00 2001 From: Mohamed Abdulalim <33574895+megyptm@users.noreply.github.com> Date: Tue, 29 Sep 2026 18:29:17 +0300 Subject: [PATCH 1/2] chore: open Gate 9 remediation draft From 2546e730dd2454b948fb3dc256301a7a50791897 Mon Sep 17 00:00:00 2001 From: Mohamed Abdulalim Date: Tue, 29 Sep 2026 18:48:35 +0300 Subject: [PATCH 2/2] Fix return-target exception contract integrity --- ...alidReturnTargetConfigurationException.php | 18 ++++- ...turnTargetCryptoConfigurationException.php | 18 +++++ .../ReturnTargetExceptionContractTest.php | 70 +++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Exception/ReturnTargetExceptionContractTest.php diff --git a/src/Exception/InvalidReturnTargetConfigurationException.php b/src/Exception/InvalidReturnTargetConfigurationException.php index c965c3d..220c2a0 100644 --- a/src/Exception/InvalidReturnTargetConfigurationException.php +++ b/src/Exception/InvalidReturnTargetConfigurationException.php @@ -8,5 +8,21 @@ /** * Reports a configuration value outside the canonical return-target bounds. + * + * Its package-owned constructor always exposes the INVALID_ARGUMENT error code + * inherited from the validation exception hierarchy. */ -final class InvalidReturnTargetConfigurationException extends InvalidArgumentMaatifyException implements ReturnTargetExceptionInterface {} +final class InvalidReturnTargetConfigurationException extends InvalidArgumentMaatifyException implements ReturnTargetExceptionInterface +{ + /** + * Keeps the package-owned constructor intentionally narrow while preserving + * the previous throwable through the shared exception implementation. + */ + public function __construct( + string $message = '', + int $code = 0, + ?\Throwable $previous = null, + ) { + parent::__construct($message, $code, $previous); + } +} diff --git a/src/Exception/ReturnTargetCryptoConfigurationException.php b/src/Exception/ReturnTargetCryptoConfigurationException.php index 110e50c..172a9a5 100644 --- a/src/Exception/ReturnTargetCryptoConfigurationException.php +++ b/src/Exception/ReturnTargetCryptoConfigurationException.php @@ -10,9 +10,27 @@ /** * Reports a canonical cryptographic or key-configuration failure. + * + * Its package-owned constructor always exposes the MAATIFY_ERROR error code. */ final class ReturnTargetCryptoConfigurationException extends SystemMaatifyException implements ReturnTargetExceptionInterface { + /** + * Keeps the package-owned constructor intentionally narrow while preserving + * the previous throwable through the shared exception implementation. + */ + public function __construct( + string $message = '', + int $code = 0, + ?\Throwable $previous = null, + ) { + parent::__construct($message, $code, $previous); + } + + /** + * Selects the stable package error code for cryptographic configuration + * failures. + */ protected function defaultErrorCode(): ErrorCodeInterface { return ErrorCodeEnum::MAATIFY_ERROR; diff --git a/tests/Unit/Exception/ReturnTargetExceptionContractTest.php b/tests/Unit/Exception/ReturnTargetExceptionContractTest.php new file mode 100644 index 0000000..3d08ccb --- /dev/null +++ b/tests/Unit/Exception/ReturnTargetExceptionContractTest.php @@ -0,0 +1,70 @@ +getErrorCode()); + self::assertSame('invalid configuration', $exception->getMessage()); + self::assertSame(17, $exception->getCode()); + self::assertSame($previous, $exception->getPrevious()); + + $this->assertPackageOwnedConstructorSurface(InvalidReturnTargetConfigurationException::class); + } + + public function testCryptoConfigurationExceptionContract(): void + { + $previous = new RuntimeException('previous failure'); + $exception = new ReturnTargetCryptoConfigurationException( + 'crypto configuration failure', + 23, + $previous, + ); + + self::assertInstanceOf(ReturnTargetExceptionInterface::class, $exception); + self::assertSame(ErrorCodeEnum::MAATIFY_ERROR, $exception->getErrorCode()); + self::assertSame('crypto configuration failure', $exception->getMessage()); + self::assertSame(23, $exception->getCode()); + self::assertSame($previous, $exception->getPrevious()); + + $this->assertPackageOwnedConstructorSurface(ReturnTargetCryptoConfigurationException::class); + } + + /** + * @param class-string<\Throwable> $exceptionClass + */ + private function assertPackageOwnedConstructorSurface(string $exceptionClass): void + { + $constructor = (new ReflectionClass($exceptionClass))->getConstructor(); + + self::assertNotNull($constructor); + self::assertSame($exceptionClass, $constructor->getDeclaringClass()->getName()); + self::assertSame( + ['message', 'code', 'previous'], + array_map( + static fn($parameter): string => $parameter->getName(), + $constructor->getParameters(), + ), + ); + } +}