From a35b4404afd304f3b7cb744bed641728214a22d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= Date: Fri, 31 Jul 2026 17:05:42 +0200 Subject: [PATCH 1/4] [TASK] DPL-204: Run MySQL functional jobs on MySQL The four workflow steps named "Functional MySQL 8.0 mysqli" and "Functional MySQL 8.0 pdo_mysql" passed "-d mariadb", so they ran the same database as the two MariaDB steps directly above them and only duplicated their coverage under a MySQL name. No workflow invoked "-d mysql" at all, leaving MySQL untested on every core version. They run "-d mysql" now. No version is pinned here: "handleDbmsOptions" already defaults "-i" to 8.0 for MySQL, which is what the step names promise, and the explicit pin follows in its own change. The harness needs nothing else - the "mysql" branch, the "mysql-func" container and "IMAGE_MYSQL" have always been there and were simply never reached from CI. The readiness budget covers the slower startup: "waitFor" allows 60 seconds since the docker adoption, and mysql:8.0 needs 12-13 seconds under docker to initialise a fresh data directory. The MariaDB steps are left alone. They claim 10.5 while passing no "-i" and therefore run the 10.4 default, which is a separate label defect and not part of this change. "testcore12.yml" is untouched: on this branch it is a dispatch-only stub that runs no tests. --- .github/workflows/testcore13.yml | 4 ++-- .github/workflows/testcore14.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/testcore13.yml b/.github/workflows/testcore13.yml index c339aa0..36a9098 100644 --- a/.github/workflows/testcore13.yml +++ b/.github/workflows/testcore13.yml @@ -87,10 +87,10 @@ jobs: run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -a pdo_mysql" - name: "Functional MySQL 8.0 mysqli" - run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -a mysqli" + run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mysql -a mysqli" - name: "Functional MySQL 8.0 pdo_mysql" - run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -a pdo_mysql" + run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mysql -a pdo_mysql" - name: "Functional PostgresSQL 10" run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d postgres" diff --git a/.github/workflows/testcore14.yml b/.github/workflows/testcore14.yml index 65500ac..b6ae2cc 100644 --- a/.github/workflows/testcore14.yml +++ b/.github/workflows/testcore14.yml @@ -84,10 +84,10 @@ jobs: run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -a pdo_mysql" - name: "Functional MySQL 8.0 mysqli" - run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -a mysqli" + run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mysql -a mysqli" - name: "Functional MySQL 8.0 pdo_mysql" - run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -a pdo_mysql" + run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mysql -a pdo_mysql" - name: "Functional PostgresSQL 10" run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d postgres" From 06873cdccc9695b68f88a5a6d41169f07d60356c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= Date: Fri, 31 Jul 2026 17:06:38 +0200 Subject: [PATCH 2/4] [TASK] DPL-204: Own the sqlite tmpfs from the host "${USERSET}" passes "--user ${HOST_UID}" without a group, so a docker container runs as "uid=${HOST_UID} gid=0(root)". A "--tmpfs" is created "root:root" and inherits the mode of its host mountpoint, which is 0755 at a CI umask of 0022 - group 0 gets "r-x" only, and the functional sqlite suite fails with "unable to open database file". The docker adoption worked around this by mounting the sqlite tmpfs "mode=1777". That is correct and umask independent, but it treats the one mount rather than the missing group. The mount options move into "TMPFS_MOUNT_OPTIONS", assigned next to the container parameters they belong to, so the two container binaries can state what they actually need: docker adds "uid" and "gid" and keeps "mode=1777", rootless podman maps the container root to the host user and needs neither, keeping "mode=1777" for the rootful case. "${USERSET}" is deliberately left alone. It is evaluated for both container binaries, and appending a group there would change which host group rootless podman maps the container to, which is a different question from who owns a tmpfs. The comment moves along with the options and now names the umask that makes this visible: at the 0002 of a typical workstation the mountpoint comes up 0775 and the defect cannot be reproduced at all. --- Build/Scripts/runTests.sh | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index f47688a..7e0c9fd 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -395,6 +395,7 @@ handleDbmsOptions COMPOSER_ROOT_VERSION="2.0.2-dev" CONTAINER_INTERACTIVE="-it --init" HOST_UID=$(id -u) +HOST_GID=$(id -g) USERSET="" if [ $(uname) != "Darwin" ]; then USERSET="--user $HOST_UID" @@ -448,9 +449,25 @@ if [ "${CONTAINER_BIN}" == "docker" ]; then CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm --network ${NETWORK} --add-host ${CONTAINER_HOST}:host-gateway ${USERSET} -v ${ROOT_DIR}:${ROOT_DIR} -w ${ROOT_DIR}" CONTAINER_SIMPLE_PARAMS="${CONTAINER_INTERACTIVE} --rm --network ${NETWORK} --add-host ${CONTAINER_HOST}:host-gateway ${USERSET} -v ${ROOT_DIR}:${ROOT_DIR} -w ${ROOT_DIR}" DOCUMENTATION_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm ${USERSET} -v ${ROOT_DIR}:/project" + # docker creates a tmpfs owned by "root:root", inheriting the mode of its host + # mountpoint, while "${USERSET}" above passes a uid but no group and therefore runs + # the container as "uid=${HOST_UID} gid=0". At a CI umask of 0022 the mountpoint is + # 0755, so group 0 gets "r-x" and no test database can be created. + # + # "uid"/"gid" address that at the source: the mount is owned by the user the container + # runs as, whatever the umask of the host mountpoint. "mode=1777" is the workaround the + # docker adoption introduced instead, and is kept next to them - it is what has been + # proven on a GitHub hosted runner, and it costs nothing to leave in place. + # + # None of this reproduces at the 0002 umask of a typical workstation, where the + # mountpoint comes up 0775 and the group bit already grants access. Use "umask 0022". + TMPFS_MOUNT_OPTIONS="rw,noexec,nosuid,uid=${HOST_UID},gid=${HOST_GID},mode=1777" else # podman CONTAINER_HOST="host.containers.internal" + # Rootless podman maps the container root to the host user, so the tmpfs is writable + # without an explicit owner. "mode=1777" is kept for the rootful case. + TMPFS_MOUNT_OPTIONS="rw,noexec,nosuid,mode=1777" CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm --network ${NETWORK} -v ${ROOT_DIR}:${ROOT_DIR} -w ${ROOT_DIR}" CONTAINER_SIMPLE_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm -v ${ROOT_DIR}:${ROOT_DIR} -w ${ROOT_DIR}" DOCUMENTATION_COMMON_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm -v ${ROOT_DIR}:${ROOT_DIR} -v ${ROOT_DIR}:/project" @@ -562,13 +579,11 @@ case ${TEST_SUITE} in sqlite) # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues mkdir -p "${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/" - # "mode=1777" is required for docker and harmless for podman: docker runs - # the container as "--user $HOST_UID" with group 0, while the tmpfs comes - # up owned by root with mode 0755, so the test databases cannot be created - # and every test fails with "unable to open database file". Rootless podman - # passes no "--user" (it is root inside its user namespace), which is why - # this only shows with docker. - CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid,mode=1777 -e DEEPL_API_KEY=mock_server -e DEEPL_HOST=deepl-func-${SUFFIX} -e DEEPL_PORT=3000 -e DEEPL_SERVER_URL=deepl-func-${SUFFIX}:3000 -e DEEPL_MOCK_SERVER_PORT=3000 -e DEEPL_SCHEME=http -e DEEPL_MOCKSERVER_USED=1" + # "${TMPFS_MOUNT_OPTIONS}" carries the owner and mode the mount needs, which + # differ per container binary - see where it is assigned. Without them the + # test databases cannot be created and every test fails with "unable to open + # database file". + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/:${TMPFS_MOUNT_OPTIONS} -e DEEPL_API_KEY=mock_server -e DEEPL_HOST=deepl-func-${SUFFIX} -e DEEPL_PORT=3000 -e DEEPL_SERVER_URL=deepl-func-${SUFFIX}:3000 -e DEEPL_MOCK_SERVER_PORT=3000 -e DEEPL_SCHEME=http -e DEEPL_MOCKSERVER_USED=1" ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" SUITE_EXIT_CODE=$? ;; From 8de3f0c80afac5b27f89e8a5fd20197481fe9556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= Date: Fri, 31 Jul 2026 17:07:16 +0200 Subject: [PATCH 3/4] [TASK] DPL-204: Revive two unused harness variables Two variables were referenced or built but never took effect, and both misled anyone reading the script. "CI_PARAMS" is expanded into the podman container parameters and into the mock server container - four sites, and the mock server one is unconditional, so it also applies under docker - but was never assigned. It is not a leftover though: the harnesses this one is modelled on assign it as "CI_PARAMS="${CI_PARAMS:-}"" and treat it as an escape hatch a caller can export to inject additional container flags. Only that assignment was missing here, so it is added rather than the references removed. "DOCUMENTATION_COMMON_PARAMS" was assigned for both container binaries and then never used: "renderDocumentation" ran with "CONTAINER_COMMON_PARAMS" instead and therefore also received "--network", "--add-host" and a "-w ${ROOT_DIR}" which the later "-w /project" overrode again. It renders documentation, it does not talk to a database container, so it now uses the parameters built for it. The bind mount that the run line repeated is part of them and is dropped from the line. No behaviour the suite depends on changes: the container still runs "--rm", still mounts the project at "/project", still works from there and, under docker, still runs as the host user. That matters here because "publish.yml" and "documentation.yml" both render the documentation. --- Build/Scripts/runTests.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index 7e0c9fd..9e3195d 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -396,6 +396,9 @@ COMPOSER_ROOT_VERSION="2.0.2-dev" CONTAINER_INTERACTIVE="-it --init" HOST_UID=$(id -u) HOST_GID=$(id -g) +# Additional container parameters, provided by the environment. Empty unless the caller +# exports it, which is how the portfolio harnesses inject CI specific flags. +CI_PARAMS="${CI_PARAMS:-}" USERSET="" if [ $(uname) != "Darwin" ]; then USERSET="--user $HOST_UID" @@ -600,7 +603,7 @@ case ${TEST_SUITE} in SUITE_EXIT_CODE=$? ;; renderDocumentation) - ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name rendering-documentation-${SUFFIX} --pull always -w /project -v ${ROOT_DIR}:/project ${IMAGE_RSTRENDERING} --fail-on-error --no-progress --config=Documentation Documentation + ${CONTAINER_BIN} run ${DOCUMENTATION_COMMON_PARAMS} --name rendering-documentation-${SUFFIX} --pull always -w /project ${IMAGE_RSTRENDERING} --fail-on-error --no-progress --config=Documentation Documentation SUITE_EXIT_CODE=$? ;; phpstan) From ed794335db2943dbb54429703004664a0eecb10b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= Date: Fri, 31 Jul 2026 17:07:37 +0200 Subject: [PATCH 4/4] [TASK] DPL-214: Pin the database versions in CI No functional workflow step passed "-i", so every one of them ran the harness default. Where a step is named "Functional MariaDB 10.5" the job actually started "mariadb:10.4", and the four MySQL steps only became truthful with the previous change - they still relied on the default rather than saying what they run. The eight steps that name a version now pass it: "-i 10.5" for MariaDB and "-i 8.0" for MySQL. Both values are inside what this branch's "handleDbmsOptions" accepts (MariaDB 10.4 to 11.1, MySQL 8.0 to 8.4), so nothing has to be approximated, and the label is now what the container image is built from. The remaining two are left as they are. "Functional PostgresSQL 10" already matches the postgres default, and "-i" is rejected together with "-d sqlite", so "Functional SQLite" cannot carry one. Branch "1" carries the same labels but its whole "testsuite" job is commented out, so there is nothing live to fix there. It is left untouched rather than uncommented. --- .github/workflows/testcore13.yml | 8 ++++---- .github/workflows/testcore14.yml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/testcore13.yml b/.github/workflows/testcore13.yml index 36a9098..8676d00 100644 --- a/.github/workflows/testcore13.yml +++ b/.github/workflows/testcore13.yml @@ -81,16 +81,16 @@ jobs: run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d sqlite" - name: "Functional MariaDB 10.5 mysqli" - run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -a mysqli" + run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -i 10.5 -a mysqli" - name: "Functional MariaDB 10.5 pdo_mysql" - run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -a pdo_mysql" + run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mariadb -i 10.5 -a pdo_mysql" - name: "Functional MySQL 8.0 mysqli" - run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mysql -a mysqli" + run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mysql -i 8.0 -a mysqli" - name: "Functional MySQL 8.0 pdo_mysql" - run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mysql -a pdo_mysql" + run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d mysql -i 8.0 -a pdo_mysql" - name: "Functional PostgresSQL 10" run: "Build/Scripts/runTests.sh -b docker -t 13 -p ${{ matrix.php-version }} -s functional -d postgres" diff --git a/.github/workflows/testcore14.yml b/.github/workflows/testcore14.yml index b6ae2cc..9fde23b 100644 --- a/.github/workflows/testcore14.yml +++ b/.github/workflows/testcore14.yml @@ -78,16 +78,16 @@ jobs: run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d sqlite" - name: "Functional MariaDB 10.5 mysqli" - run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -a mysqli" + run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -i 10.5 -a mysqli" - name: "Functional MariaDB 10.5 pdo_mysql" - run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -a pdo_mysql" + run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mariadb -i 10.5 -a pdo_mysql" - name: "Functional MySQL 8.0 mysqli" - run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mysql -a mysqli" + run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mysql -i 8.0 -a mysqli" - name: "Functional MySQL 8.0 pdo_mysql" - run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mysql -a pdo_mysql" + run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d mysql -i 8.0 -a pdo_mysql" - name: "Functional PostgresSQL 10" run: "Build/Scripts/runTests.sh -b docker -t 14 -p ${{ matrix.php-version }} -s functional -d postgres"