diff --git a/README.rst b/README.rst index 5b5da7c..86dfcd8 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,7 @@ numerous large-scale, mission-critical web applications across a diverse range of industries and organizations. This appliance configures Tomcat as a standalone application server -(I.e., without an external web server). A `Tomcat on Apache Appliance`_ +(that is, without an external web server). A `Tomcat on Apache Appliance`_ is also available for integrations requiring a fully-featured web server. @@ -17,17 +17,19 @@ and on top of that: - Tomcat configurations: - - Installed from package management. - - Using OpenJDK Java runtime. + - Tomcat 10.1 installed from Debian package management. + - Using the OpenJDK 21 Java runtime from Debian. - Web applications in /var/lib/tomcat10/webapps. - Includes TurnKey web control panel. - Created Tomcat admin/manager roles and admin user. - - Bind Tomcat HTTP connector to port 80 (default: 8080). - - Bind SSL interface to port 443 (default: 8443). + - Tomcat Manager at /manager/html and Virtual Host Manager at + /host-manager/html. + - Binds the Tomcat HTTP connector directly to port 80 (default: 8080). + - Binds the Tomcat SSL interface directly to port 443 (default: 8443). - Disabled AJP connector on port 8009 (security). - Tomcat and Java environment variables configuration system wide. -- Includes MySQL. +- Includes MariaDB, a MySQL-compatible database server. - SSL support out of the box. - Postfix MTA (bound to localhost) to allow sending of email from web applications (e.g., password recovery). @@ -35,7 +37,7 @@ and on top of that: Credentials *(passwords set at first boot)* ------------------------------------------- -- Webmin, SSH, MySQL: username **root** +- Webmin, SSH, MariaDB: username **root** - Tomcat administration applications: username **admin** diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 0000000..46a81f7 --- /dev/null +++ b/TESTING.md @@ -0,0 +1,70 @@ +# Tomcat 19.0 acceptance + +## Source decision + +Tomcat 19.0 uses Debian 13 Trixie packages for Tomcat 10.1, its manager +applications, OpenJDK 21 and MariaDB. Webmin and its MariaDB module continue to +come from the signed TurnKey Trixie repository. The complete documented stack +is maintained through APT, so this appliance does not need an upstream package +source or a separate updater. + +The standalone appliance binds Tomcat directly to ports 80 and 443. It does +not use the Apache reverse proxy provided by the separate Tomcat on Apache +appliance. + +The shared v19 cipher substitution leaves its quoted placeholder attached to +the selected Tomcat cipher list. The appliance removes only that invalid XML +suffix after shared configuration, preserving the shared Trixie cipher +selection. + +## Acceptance command + +```sh +/sandboxed-git/turnkey/tools/test-v19-appliance tomcat \ + --source /home/agent/.local/worktrees/turnkey-apps/tomcat/wish-tomcat-v19-trixie +``` + +## README crosswalk + +| README contract | Focused check | Required result | +| --- | --- | --- | +| Tomcat 10.1 and OpenJDK 21 come from Debian | Query packages, versions and binary ownership | Versions match Trixie packages | +| Standalone HTTP and HTTPS on ports 80 and 443 | Request the landing page through both connectors | Both responses identify TurnKey Tomcat | +| Manager and Virtual Host Manager use the firstboot admin account | Check unauthenticated denial, then authenticate to both applications and the text manager | Anonymous access is denied and the generated password succeeds | +| Applications deploy under `/var/lib/tomcat10/webapps` | Upload a minimal JSP WAR through the manager, request it through HTTP and HTTPS, then undeploy it | Deployment, both readbacks and removal succeed | +| AJP on port 8009 is disabled | Inspect runtime listeners | No listener exists on port 8009 | +| MariaDB is available for applications | Create a temporary database and table, write and read a row, then remove them | The database roundtrip succeeds | +| Webmin is the documented system management surface | Request its HTTPS endpoint and verify the MariaDB module package | Webmin responds and the module is installed | +| APT maintains the packaged stack | Refresh metadata and inspect candidates for identity-defining packages | Signed Trixie metadata is accepted, candidates exist and installed versions remain unchanged | +| Root Webmin and SSH credentials are inherited from Core | Cite the unchanged Core layer | Core 19 passed at source `24c82ee3540ce545422742b0e28ba6b687c53ec2` | + +## Updater check + +`tests/v19.sh` runs `apt-get update` and checks candidates for `tomcat10`, +`tomcat10-admin`, `openjdk-21-jre-headless` and `mariadb-server`. It confirms +that the refresh does not change installed versions and that no Bookworm +source remains. + +## Core evidence and limitations + +Core 19 run `20260824t010251z-1634-32241` passed normal init, multi-user, SSH, +cron, Trixie identity and the signed APT updater at source +`24c82ee3540ce545422742b0e28ba6b687c53ec2`. + +Docker acceptance does not exercise the installer, kernel, bootloader or +physical hardware. Tomcat adds no behavior at those boundaries, so the Core +19 result supplies the inherited evidence. + +## Accepted run + +The exact acceptance command passed at source commit +`7323dd61d1fe75d56afc7831124985aefe278739`. Run identity, appliance +evidence and known limitations are recorded in +[`docs/v19.0-testing.md`](docs/v19.0-testing.md). + +## Deferred minor issues + +- The package plan still includes `authbind` and its historical port files. + Trixie's Tomcat systemd unit grants only the low-port capability needed for + ports 80 and 443, so Tomcat no longer relies on authbind. The compatibility + files are harmless and remain for v19.0. diff --git a/changelog b/changelog index 000da43..8033a87 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,15 @@ +turnkey-tomcat-19.0 (1) turnkey; urgency=low + + * Update the standalone appliance for Debian 13 Trixie packages, including + Tomcat 10.1 and OpenJDK 21. + + * Update the bundled Tomcat documentation link for the packaged release. + + * Add focused runtime acceptance for the Tomcat managers, direct HTTP and + HTTPS connectors, WAR deployment, MariaDB, Webmin and APT updates. + + -- TurnKey Linux Developers Mon, 24 Aug 2026 00:00:00 +0000 + turnkey-tomcat-18.0 (1) turnkey; urgency=low * Updated all relevant Debian packages to Bookworm/12 versions; including diff --git a/conf.d/main b/conf.d/main index 1f07bae..ccabd03 100755 --- a/conf.d/main +++ b/conf.d/main @@ -13,6 +13,11 @@ done sed -i "s|HOSTNAME_DESC|Tomcat|g" $WEBROOT/index.jsp sed -i "s|HOSTNAME|tomcat|g" $WEBROOT/index.jsp +sed -i "s|tomcat-9.0-doc|tomcat-10.1-doc|g" $WEBROOT/index.jsp + +# The shared cipher substitution leaves its quoted placeholder behind. +# Preserve the selected Trixie cipher list and remove that invalid XML suffix. +sed -i 's|""ZZ_SSL_CIPHERS"|"|' /etc/tomcat10/server.xml setup_authbind() { touch /etc/authbind/byport/$1 diff --git a/docs/v19.0-testing.md b/docs/v19.0-testing.md new file mode 100644 index 0000000..8324fc0 --- /dev/null +++ b/docs/v19.0-testing.md @@ -0,0 +1,67 @@ +# Tomcat 19.0 test report + +## Accepted candidate + +- Source commit: `7323dd61d1fe75d56afc7831124985aefe278739` +- Run: `20260826t100659z-2340-26438` +- Verdict: `PASS` +- Retained report SHA-256: + `12f5386f7d4fa14237ba3e69db5924abd4b64bda72f971bcc27e831d296fff85` +- Source archive SHA-256: + `20d40f45a0b9bb8f379b108a9aaace6705c7980ca66a03056267a75dfaaef1c1` + +The accepted candidate was built from the recorded source archive, imported +into Docker, booted through the normal systemd and firstboot path, and tested +with the appliance-owned `tests/v19.sh` acceptance script. + +## Exact command + +```sh +/sandboxed-git/turnkey/tools/test-v19-appliance tomcat \ + --source /home/agent/.local/worktrees/turnkey-apps/tomcat/wish-tomcat-v19-trixie +``` + +## Source and updater evidence + +Tomcat 10.1, OpenJDK 21 and MariaDB came from Debian 13 Trixie APT +repositories. Webmin came from the TurnKey Trixie APT repository. The +accepted runtime reported: + +- `tomcat10` and `tomcat10-admin` version `10.1.55-1~deb13u1`; +- OpenJDK package `21.0.12.1+1-1~deb13u1`; +- `mariadb-server` version `1:11.8.6-0+deb13u1`. + +The acceptance script refreshed signed repository metadata with +`apt-get update`, then checked eligible Trixie candidates for `tomcat10`, +`tomcat10-admin`, `openjdk-21-jre-headless` and `mariadb-server`. Installed +versions remained unchanged. Configured Deb822 sources named Trixie, no +Bookworm source remained, and APT accepted the configured repository keyrings. + +## README primary-flow crosswalk + +| README contract | Accepted evidence | +| --- | --- | +| Tomcat 10.1 and OpenJDK 21 from Debian | Package versions, runtime versions and Debian ownership of the Tomcat and Java binaries were checked. | +| Standalone HTTP and HTTPS | The TurnKey Tomcat landing page was fetched directly over ports 80 and 443. | +| Firstboot administrator credentials | Anonymous manager access returned 401. The generated `admin` credential authenticated to Manager, Virtual Host Manager and the text manager API. The historical default password was absent. | +| Deploy applications under `/var/lib/tomcat10/webapps` | A temporary JSP WAR was deployed through Manager, read over HTTP and HTTPS, undeployed, then confirmed absent with HTTP 404. | +| AJP is disabled | No listener existed on port 8009. | +| MariaDB for applications | A temporary database and table were created, written, read and removed using the firstboot root credential. | +| Webmin administration | The Webmin HTTPS endpoint responded and the MariaDB module package was installed. | +| Managed package updates | Signed Trixie metadata refreshed, eligible candidates existed, and installed application versions remained stable. | +| Core administration | Core 19 acceptance run `20260824t010251z-1634-32241` at source `24c82ee3540ce545422742b0e28ba6b687c53ec2` supplies inherited SSH, root and common platform evidence. | + +## Limitations + +Docker runtime acceptance does not exercise the installer, kernel, bootloader +or physical hardware. Tomcat adds no appliance-specific behavior at those +boundaries, so the accepted Core 19 result supplies the inherited evidence. +The Docker kernel rejected the appliance hostname firstboot call and the +`systemd-sysctl` unit; the acceptance run checked the application services +and primary flows explicitly. + +## Deferred minor issues + +- The package plan retains `authbind` and its historical port files. Trixie's + Tomcat systemd unit supplies the low-port capability used for ports 80 and + 443, so the compatibility files do not affect the accepted runtime path. diff --git a/plan/main b/plan/main index d92142e..95c8127 100644 --- a/plan/main +++ b/plan/main @@ -5,8 +5,8 @@ ant authbind /* Allows non-root programs to bind() to low ports */ -openjdk-17-jdk-headless -openjdk-17-jre-headless +openjdk-21-jdk-headless +openjdk-21-jre-headless default-mysql-server libmariadb-java diff --git a/tests/v19.sh b/tests/v19.sh new file mode 100755 index 0000000..07f50bd --- /dev/null +++ b/tests/v19.sh @@ -0,0 +1,149 @@ +#!/bin/bash +set -Eeuo pipefail +umask 077 + +result=${TKL_TEST_RESULT:?TKL_TEST_RESULT is required} +password=${TKL_TEST_APP_PASS:?TKL_TEST_APP_PASS is required} +db_password=${TKL_TEST_DB_PASS:?TKL_TEST_DB_PASS is required} +manager=http://127.0.0.1/manager/text +context=/turnkey-v19-test +war_root=$(mktemp -d /tmp/tkl-tomcat-war.XXXXXX) +war=/tmp/tkl-tomcat-v19.$$.war +response=/tmp/tkl-tomcat-response.$$ +policy=/tmp/tkl-tomcat-policy.$$ +database=tkl_tomcat_v19_acceptance +deployed=false +database_created=false + +report_error() { + printf 'test_failure line=%s status=%s command=%q\n' \ + "$1" "$2" "$3" >&2 + exit "$2" +} + +cleanup() { + if $deployed; then + curl --fail --silent --show-error --user "admin:$password" \ + "$manager/undeploy?path=$context" >/dev/null || true + fi + if $database_created; then + mariadb --user=root --password="$db_password" \ + --execute "DROP DATABASE IF EXISTS $database" || true + fi + rm -rf -- "$war_root" + rm -f -- "$war" "$response" "$policy" +} +trap 'report_error "$LINENO" "$?" "$BASH_COMMAND"' ERR +trap cleanup EXIT + +systemctl --quiet is-active tomcat10.service mariadb.service multi-user.target +systemctl --quiet is-enabled tomcat10.service mariadb.service + +tomcat_package=$(dpkg-query -W -f='${Version}' tomcat10) +tomcat_admin_package=$(dpkg-query -W -f='${Version}' tomcat10-admin) +java_package=$(dpkg-query -W -f='${Version}' openjdk-21-jre-headless) +mariadb_package=$(dpkg-query -W -f='${Version}' mariadb-server) +java_version=$(java -version 2>&1 | head -n 1) +tomcat_version=$(/usr/share/tomcat10/bin/version.sh 2>&1 | \ + awk -F':[[:space:]]*' '/^Server number:/ {print $2}') + +grep -q '^10\.1\.' <<<"$tomcat_version" +grep -q 'version "21\.' <<<"$java_version" +java_binary=$(readlink -f "$(command -v java)") +dpkg-query -S /usr/share/tomcat10/bin/catalina.sh "$java_binary" >/dev/null +test -d /usr/share/tomcat10-admin/manager +test -d /usr/share/tomcat10-admin/host-manager +test -d /usr/share/tomcat10-docs/docs +test -s /etc/tomcat10/cert.p12 +grep -q 'CATALINA_HOME="/usr/share/tomcat10"' /etc/environment +grep -q 'JAVA_HOME="/usr/lib/jvm/java-21-openjdk-amd64"' /etc/environment +! ss -ltnH 'sport = :8009' | grep -q . + +curl --retry 15 --retry-all-errors --retry-delay 1 \ + --fail --silent --show-error http://127.0.0.1/ >"$response" +grep -q 'TurnKey Tomcat' "$response" +grep -q 'href="/manager/html"' "$response" +grep -q 'href="/host-manager/html"' "$response" +grep -q 'https://127.0.0.1:12321' "$response" +curl --insecure --fail --silent --show-error \ + https://127.0.0.1/ >"$response" +grep -q 'TurnKey Tomcat' "$response" + +test "$(curl --silent --output /dev/null --write-out '%{http_code}' \ + http://127.0.0.1/manager/html)" = 401 +curl --fail --silent --show-error --user "admin:$password" \ + http://127.0.0.1/manager/html >"$response" +grep -q 'Tomcat Web Application Manager' "$response" +curl --fail --silent --show-error --user "admin:$password" \ + http://127.0.0.1/host-manager/html >"$response" +grep -q 'Tomcat Virtual Host Manager' "$response" +curl --fail --silent --show-error --user "admin:$password" \ + "$manager/serverinfo" >"$response" +grep -Fxq 'OK - Server info' "$response" +grep -q '^Tomcat Version: \[Apache Tomcat/10\.1\.' "$response" +grep -q 'username="admin"' /etc/tomcat10/tomcat-users.xml +! grep -q 'password="turnkey"' /etc/tomcat10/tomcat-users.xml + +cat >"$war_root/index.jsp" <<'EOF' +<%@ page contentType="text/plain" %>turnkey-tomcat-v19-deploy-ok +EOF +jar --create --file "$war" -C "$war_root" . +curl --fail --silent --show-error --user "admin:$password" \ + --upload-file "$war" \ + "$manager/deploy?path=$context&update=true" >"$response" +grep -q '^OK - Deployed application at context path' "$response" +deployed=true +curl --retry 5 --retry-delay 1 --fail --silent --show-error \ + "http://127.0.0.1$context/" >"$response" +grep -Fxq 'turnkey-tomcat-v19-deploy-ok' "$response" +curl --insecure --fail --silent --show-error \ + "https://127.0.0.1$context/" >"$response" +grep -Fxq 'turnkey-tomcat-v19-deploy-ok' "$response" +curl --fail --silent --show-error --user "admin:$password" \ + "$manager/undeploy?path=$context" >"$response" +grep -q '^OK - Undeployed application at context path' "$response" +deployed=false +test "$(curl --silent --output /dev/null --write-out '%{http_code}' \ + "http://127.0.0.1$context/")" = 404 + +dpkg-query -W webmin-mysql >/dev/null +curl --insecure --fail --silent --show-error --head \ + https://127.0.0.1:12321/ >/dev/null + +mariadb --user=root --password="$db_password" \ + --execute "CREATE DATABASE $database" +database_created=true +mariadb --user=root --password="$db_password" "$database" --execute \ + 'CREATE TABLE probe (value VARCHAR(32)); INSERT INTO probe VALUES ("database-ok")' +mariadb --user=root --password="$db_password" --batch --skip-column-names \ + "$database" \ + --execute 'SELECT value FROM probe' | grep -Fxq 'database-ok' +mariadb --user=root --password="$db_password" "$database" \ + --execute 'DELETE FROM probe; DROP TABLE probe' +mariadb --user=root --password="$db_password" \ + --execute "DROP DATABASE $database" +database_created=false + +before="$tomcat_package|$tomcat_admin_package|$java_package|$mariadb_package" +apt-get update >/dev/null +for package in tomcat10 tomcat10-admin openjdk-21-jre-headless mariadb-server; do + apt-cache policy "$package" >"$policy" + candidate=$(awk '/Candidate:/ {print $2}' "$policy") + test -n "$candidate" + test "$candidate" != '(none)' + grep -Eq 'trixie|deb13' "$policy" +done +after="$(dpkg-query -W -f='${Version}' tomcat10)|$(dpkg-query -W -f='${Version}' tomcat10-admin)|$(dpkg-query -W -f='${Version}' openjdk-21-jre-headless)|$(dpkg-query -W -f='${Version}' mariadb-server)" +test "$after" = "$before" +grep -Rqs '^Suites: trixie' /etc/apt/sources.list.d +! grep -Rqi bookworm /etc/apt/sources.list.d + +cat >"$result" <