You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Merge Develop into Master for Core 6 Release - #49
Merges develop into master for the Core 6.0.0 release (58 commits ahead of master). This is a major release: PHP 8.3+, current dependency majors (DBAL 4, PHP-DI 7, Monolog 3, Symfony 7.4) and several security fixes. The full list is in CHANGELOG.md under 6.0.0.
Connectors don't get Core 6 automatically: their jtl/connector constraints stay on 5.x, and each connector moves to ^6.0 in its own ticket. The first one is connector-woocommerce3#85.
Breaking changes for endpoints
PHP >=8.3 (was >=8.1); Application::MIN_PHP_VERSION is now 8.3
Dependency injection reads PHP attributes (#[Inject]); docblock @Inject annotations are no longer read
Jtl\Connector\Dbc and the mapping tables use the DBAL 4 API (e.g. executeQuery()/executeStatement() instead of execute())
jtl/connector-dbc and jtl/connector-mapping-tables are declared as conflict instead of provide. Endpoints must remove both from their composer.json and use the classes bundled with core; installing them next to core 6 fails at install time
CO-3450: Zip::extract() throws FileTooLargeException (a CompressionException) instead of \RuntimeException
CO-3671: requests without a valid session get 789 No session before the RPC method is resolved, and an empty jtlauth counts as missing
Fixes and security
CO-3671: authenticate the session before resolving the RPC method, so unauthenticated callers can no longer probe which controllers and actions exist
CO-3468: constant-time token comparison in TokenValidator
CO-3450: oversized-image errors name the image as known in JTL-Wawi
CVE-2026-108082: require symfony/http-foundation ^7.4.19 (ReDoS via the Cache-Control request header, reachable on every request before authentication)
Schema updates no longer run inside a transaction, which made them fail on MySQL with "There is no active transaction"
An empty languageISO value no longer breaks deserialization
No more PHP 8.5 deprecation notices from setAccessible()
Upgrading existing installations
Tested 5.3.2 → 6.0.0 on MySQL 8.0.46 and SQLite, with 1000 rows per table (a mapping table, the dbc session table, and every column type core uses):
The first schema update after the upgrade only removes DBAL 2's (DC2Type:…) column comments:
MySQL: one ALTER TABLE … CHANGE per affected table. It is metadata-only (accepted with ALGORITHM=INSTANT), so large tables are not rebuilt.
SQLite: affected tables are rebuilt (copied to a temp table and back). This is not atomic, because schema updates no longer run in a transaction.
Row data was identical before and after (checksums), and no further schema updates were pending.
Replace the single Mockery usage in IdentityLinkerTest with PHPUnit's
built-in createMock(). Sequential return values are handled via
willReturnCallback() with array queues. This also removes the transitive
hamcrest/hamcrest-php dependency.
… as success
DBAL 4 executeStatement() returns int; using > 0 would return false on an
idempotent UPDATE (0 rows changed), breaking the previous contract where any
non-exception result was considered success. Reverts to >= 0 to match
delete() and clear() semantics.
- src/dbc/DbManager.php: SchemaManagerFactory no longer used after
schema diffing was rewritten with Comparator
- tests/src/dbc/TestCase.php: AbstractPlatform and Result were leftover
from removed jtl/unit-test helpers
- tests/src/dbc/DbManagerStub.php: RuntimeException import not referenced
- RequestParamsTransformSubscriberTest: three docblocks had bare
"\Exception" lines without the @throws tag prefix
- SqliteSessionHandlerTest: @throws \InvalidArgumentException was
listed twice in testWriteInsert() and testWriteUpdate()
- DbManagerStub: duplicate @throws DbcRuntimeException on getSchemaTables()
CO-3450: the too-large exception referenced the numeric ZipArchive
loop index instead of the affected entry's name, making it impossible
to identify which image exceeded the 20MB limit from the error alone.
Replace the single Mockery usage in IdentityLinkerTest with PHPUnit's
built-in createMock(). Sequential return values are handled via
willReturnCallback() with array queues. This also removes the transitive
hamcrest/hamcrest-php dependency.
… as success
DBAL 4 executeStatement() returns int; using > 0 would return false on an
idempotent UPDATE (0 rows changed), breaking the previous contract where any
non-exception result was considered success. Reverts to >= 0 to match
delete() and clear() semantics.
- src/dbc/DbManager.php: SchemaManagerFactory no longer used after
schema diffing was rewritten with Comparator
- tests/src/dbc/TestCase.php: AbstractPlatform and Result were leftover
from removed jtl/unit-test helpers
- tests/src/dbc/DbManagerStub.php: RuntimeException import not referenced
- RequestParamsTransformSubscriberTest: three docblocks had bare
"\Exception" lines without the @throws tag prefix
- SqliteSessionHandlerTest: @throws \InvalidArgumentException was
listed twice in testWriteInsert() and testWriteUpdate()
- DbManagerStub: duplicate @throws DbcRuntimeException on getSchemaTables()
CO-3450: the too-large exception referenced the numeric ZipArchive
loop index instead of the affected entry's name, making it impossible
to identify which image exceeded the 20MB limit from the error alone.
QA: the error only contained the archive entry name
"{kArtikelBildPlattform}_{relationType}.jpg", which merchants can only
resolve via the Wawi database.
- Zip throws FileTooLargeException (entry name, size, limit) instead of
a RuntimeException
- handleImagePush maps the entry back to the pushed image and throws
ApplicationException::imageTooLarge with the Wawi image name (fallback:
Wawi file name, then entry name), related entity ID (e.g. kArtikel),
image ID, and size/limit
- archive entry to image matching extracted into isFileOfImage() so the
extraction loop and the error mapping share it
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…#46)
Application::run() validated controller and action before startSession(),
so a request without a valid session got "Unknown controller"/"Unknown
action" for invalid methods and "No session" for valid ones. That allowed
unauthenticated callers to probe which methods exist, and made it look as
if authentication had been skipped.
startSession() also treated an empty jtlauth as "start a fresh session"
rather than "no session".
- start the session right after the request packet validity check, before
the method is resolved
- reject an empty or non-string jtlauth with "No session" for every method
except core.connector.auth
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
composer analyse failed on develop with 19 phpstan errors and 5 phpcs
errors, all in this file (introduced by the CO-3583 hotfix):
- `@throws InvalidArgumentException` was never imported and resolved to the
non-existent `Jtl\Connector\Core\Test\Session\InvalidArgumentException`;
use `\InvalidArgumentException` like the rest of the suite and drop the
resulting duplicate tags
- findSessionData() passed a mixed PDO value to base64_decode(); validate it
is a string first (same guard as SqliteSessionHandler::read())
- mark findSessionData() `@phpstan-impure`: it queries the database, so
phpstan must not assume a second call returns the same result
- reorder @throws tags (phpcbf)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
ReflectionProperty/ReflectionMethod::setAccessible() has had no effect since
PHP 8.1 and is deprecated as of PHP 8.5. Core requires PHP >= 8.3, so the
calls can simply go. Application::extendExceptionMessageWithIdentifiers()
ran them at runtime, so endpoints on PHP 8.5 got a deprecation notice there;
the remaining 20 calls were in tests (22 test-run deprecations on PHP 8.5).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
composer tests passed but reported "OK, but there were issues!":
- ModelTest::testModelsInitialization (106 data sets) was risky: PHPUnit 11
ignores doc-comment metadata on methods that carry attributes, so its
`@doesNotPerformAssertions` was dead. Use #[DoesNotPerformAssertions].
- 9 ApplicationTest cases were risky because Application::run() registers
the core and the Monolog error/exception handlers. tearDown() now pops
whatever the test added on top of the stack depth recorded in setUp(),
which also covers tests where run() throws.
- Replace getMockForAbstractClass(), deprecated and removed in PHPUnit 12,
with anonymous subclasses; AbstractModel/AbstractImage have no abstract
methods.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The unreleased section only listed CO-3450, CO-3468 and CO-3671. Add the
breaking changes since 5.3.2 (PHP 8.3, dependency majors, removed
dependencies, PHP-DI attributes instead of annotations, DBAL 4 for Dbc and
mapping tables) plus the LanguageIsoSubscriber fix and the PHP 8.5
deprecation cleanup. Versions are taken from the composer.json diff between
master and develop. The heading stays "unreleased"; the release commit
renames it, as for earlier releases.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
… stack
Counting handlers meant popping the whole stack and pushing it back with
set_error_handler($handler), which resets each handler's error mask to
E_ALL (review feedback on #47). Record the handlers on top of the stack in
setUp() with a push-and-restore probe, which leaves the stack and its masks
untouched, and in tearDown() pop only what the test added on top of them.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…CHANGELOG) (#48)
* test: narrow $_SESSION through a local in SessionHelperTest
phpstan 2.3 drops @var-narrowed types of superglobals after method calls,
since those calls may modify them. testSet() and testUnset() read
$_SESSION after $helper->set()/unset() and assertion calls, which became
"offset access on mixed". Copy $_SESSION into a local after the call and
narrow that instead, typed as the string values these tests store.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* fix: require symfony/http-foundation ^7.4.19 and jms/serializer ^3.32
- symfony/http-foundation < 7.4.19 is affected by CVE-2026-108082, a ReDoS
in HeaderUtils::split() reachable through the Cache-Control request
header. Core reaches it on every request, unauthenticated: the
Application constructor calls Request::createFromGlobals(), whose
HeaderBag parses Cache-Control. Raise the floor so no endpoint can
resolve a vulnerable version through core.
- Bound jms/serializer from * to ^3.32: the models use PHP 8 attributes
and were tested with 3.32 (composer validate --strict warned about the
unbound constraint).
- Refresh composer.lock under PHP 8.3 (lowest supported version) with
Composer 2.10.3: 24 updates, including symfony/* 7.4.21 and
squizlabs/php_codesniffer 4.0.4 (dev-only advisory). composer audit
reports no advisories.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* fix: conflict with jtl/connector-dbc and connector-mapping-tables
Core 5 declared `provide` for jtl/connector-dbc v2.1.13 and
jtl/connector-mapping-tables 4.0.8 because it bundled identical copies.
Core 6 bundles DBAL 4 ports of both, while the standalone packages are
still DBAL 2. With `provide`, an endpoint that still requires e.g.
jtl/connector-dbc ^2.1 resolves against core 6 without any notice and gets
the DBAL 4 API under a 2.1.13 label, so it only fails at runtime
($qb->execute(), fetchAll(), ...).
Declare `conflict` instead: installing either standalone package next to
core 6 now fails at install time ("jtl/connector 6.0.0 conflicts with
jtl/connector-dbc v2.1.14"), telling endpoints to drop the requirement and
use the bundled classes. The standalone packages stay untouched for core 5.
Update the agent guides accordingly: they referenced `provide` and asked
to re-sync from upstream, which would now revert the DBAL 4 migration.
The lock only gets a new content-hash.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* fix: set Application::MIN_PHP_VERSION to 8.3
System\Check::run(), called from ConnectorController, still enforced and
reported PHP 8.2 as the minimum while composer.json requires >=8.3. Add a
test that ties the constant to the composer.json PHP requirement so the
two can't drift apart again.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* docs: release 6.0.0 in CHANGELOG
Rename the unreleased section to 6.0.0 and start a new, empty unreleased
section above it. Mention that Application::MIN_PHP_VERSION is now 8.3.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Major dependency and persistence migrations need human validation, and replacement automated quality checks are missing.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Add replacement CI workflow for analysis, tests, and hygiene checks
.gitlab-ci.yml:1
Deleting this pipeline leaves no checked-in workflow running quality checks: .github/workflows/close-issue.yml only performs scheduled issue cleanup. Add a replacement GitHub Actions workflow for pushes and pull requests that runs composer analyse, composer tests on PHP 8.3/8.4, and the repository-hygiene check, with failures failing the workflow. Otherwise this release and subsequent changes have no automated regression checks in the repository.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Merges
developintomasterfor the Core 6.0.0 release (58 commits ahead ofmaster). This is a major release: PHP 8.3+, current dependency majors (DBAL 4, PHP-DI 7, Monolog 3, Symfony 7.4) and several security fixes. The full list is inCHANGELOG.mdunder6.0.0.Connectors don't get Core 6 automatically: their
jtl/connectorconstraints stay on 5.x, and each connector moves to^6.0in its own ticket. The first one is connector-woocommerce3#85.Breaking changes for endpoints
>=8.3(was>=8.1);Application::MIN_PHP_VERSIONis now8.3doctrine/dbal^4.0,doctrine/collections^2.6,php-di/php-di^7.0,monolog/monolog^3.0,jms/serializer^3.32,symfony/*^7.4 (symfony/http-foundation^7.4.19)doctrine/annotationsanddoctrine/cache#[Inject]); docblock@Injectannotations are no longer readJtl\Connector\Dbcand the mapping tables use the DBAL 4 API (e.g.executeQuery()/executeStatement()instead ofexecute())jtl/connector-dbcandjtl/connector-mapping-tablesare declared asconflictinstead ofprovide. Endpoints must remove both from theircomposer.jsonand use the classes bundled with core; installing them next to core 6 fails at install timeZip::extract()throwsFileTooLargeException(aCompressionException) instead of\RuntimeException789 No sessionbefore the RPC method is resolved, and an emptyjtlauthcounts as missingFixes and security
TokenValidatorsymfony/http-foundation^7.4.19 (ReDoS via theCache-Controlrequest header, reachable on every request before authentication)languageISOvalue no longer breaks deserializationsetAccessible()Upgrading existing installations
Tested 5.3.2 → 6.0.0 on MySQL 8.0.46 and SQLite, with 1000 rows per table (a mapping table, the dbc session table, and every column type core uses):
(DC2Type:…)column comments:ALTER TABLE … CHANGEper affected table. It is metadata-only (accepted withALGORITHM=INSTANT), so large tables are not rebuilt.Included PRs
#32, #34, #35, #36, #38, #42, #43, #45, #46, #47, #48
Verification (on develop
d811d6ae)composer validate --strict: valid, no warningscomposer audit: no advisoriescomposer analyse: phpcs clean, phpstan (level max) no errorscomposer tests: OK on PHP 8.3.32, 8.4.26 and 8.5.1After merging
6.0.0onmaster(novprefix, like5.3.2).composer update jtl/connector.🤖 Generated with Claude Code