Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
COMMON_OVERLAYS = apache
COMMON_CONF += apache-credit apache-vhost
COMMON_CONF += apache-credit

include $(FAB_PATH)/common/mk/turnkey/mysql.mk
include $(FAB_PATH)/common/mk/turnkey/lamp.mk
include $(FAB_PATH)/common/mk/turnkey.mk
10 changes: 7 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ and on top of that:

- Bugzilla configurations:

- Installed from upstream source code (HEAD of '5.0' branch) via git to
/var/www/bugzilla.
- Installed from the maintained upstream ``5.2`` branch via git to
``/var/www/bugzilla``. The initial appliance build pins the upstream
commit while retaining the branch and official remote for supervised
updates.

**Security note**: Updates to Bugzilla may require supervision so
they **ARE NOT** configured to install automatically. See `Bugzilla
Expand All @@ -25,6 +27,7 @@ and on top of that:
- SSL support out of the box.
- Postfix MTA (bound to localhost) to allow sending of email (e.g.,
password recovery).
- Adminer database management at https://*appliance\_ip*:12322.
- Webmin modules for configuring Apache2, MySQL and Postfix.

Initial configuration: http://*appliance\_ip*/editparams.cgi
Expand All @@ -42,7 +45,8 @@ Initial configuration: http://*appliance\_ip*/editparams.cgi
Credentials *(passwords set at first boot)*
-------------------------------------------

- Webmin, Webshell, SSH, MySQL: username **root**
- Webmin, SSH, MySQL: username **root**
- Adminer: username **adminer**
- Bugzilla:

- username is email set at first boot
Expand Down
9 changes: 9 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
turnkey-bugzilla-19.0 (1) turnkey; urgency=low

* Install Bugzilla 5.2 from a pinned commit on the maintained upstream
branch and use its MariaDB driver.

* Port the appliance to Debian 13/Trixie.

-- TurnKey Linux release engineering <release@turnkeylinux.org> Mon, 24 Aug 2026 00:00:00 +0000

turnkey-bugzilla-18.0 (1) turnkey; urgency=low

* Downgrade Bugzilla to 5.0.4 branch via git. See
Expand Down
16 changes: 15 additions & 1 deletion conf.d/downloads
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,18 @@
[[ -z "$FAB_HTTP_PROXY" ]] || export http_proxy=$FAB_HTTP_PROXY
[[ -z "$FAB_HTTPS_PROXY" ]] || export https_proxy=$FAB_HTTPS_PROXY

git clone --depth 1 --branch 5.0.4 https://github.com/bugzilla/bugzilla.git /var/www/bugzilla
BUGZILLA_COMMIT=5756ec67b506c20ff4b2c32d80e6fcf35e536b76
BUGZILLA_URL=https://github.com/bugzilla/bugzilla.git
TEMPLATE_URL=https://cpan.metacpan.org/authors/id/T/TO/TODDR/Template-Toolkit-3.106.tar.gz
TEMPLATE_SHA256=c7474050be80201f1fb55f0a569b9c0ab6c1c3f0cebbd7e601bda9b4046eec85

git init /var/www/bugzilla
git -C /var/www/bugzilla remote add origin "$BUGZILLA_URL"
git -C /var/www/bugzilla fetch --depth 1 origin "$BUGZILLA_COMMIT"
git -C /var/www/bugzilla checkout -b 5.2 FETCH_HEAD
test "$(git -C /var/www/bugzilla rev-parse HEAD)" = "$BUGZILLA_COMMIT"

curl --fail --location --output /usr/local/src/Template-Toolkit-3.106.tar.gz \
"$TEMPLATE_URL"
echo "$TEMPLATE_SHA256 /usr/local/src/Template-Toolkit-3.106.tar.gz" \
| sha256sum --check
31 changes: 21 additions & 10 deletions conf.d/main
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ ADMIN_PASS=turnkey
SRC=/usr/local/src
WEBROOT=/var/www/bugzilla

# Bugzilla 5.2 requires Template Toolkit 3.009 or newer. Trixie's package is
# older, so install the pinned official CPAN release downloaded above.
tar --extract --gzip --file $SRC/Template-Toolkit-3.106.tar.gz --directory $SRC
cd $SRC/Template-Toolkit-3.106
perl Makefile.PL INSTALLDIRS=site
make
make test
make install

# set ownership
chown -R www-data:www-data $WEBROOT

Expand All @@ -20,11 +29,21 @@ a2enmod rewrite
a2enmod headers
a2enmod expires
a2enmod cgid
a2enmod ssl

# setup the database
service mysql start
mysqladmin create $DB_NAME --default-character-set=utf8;
mysql --batch --execute "grant all privileges on $DB_NAME.* to $DB_USER@localhost identified by '$DB_PASS'; flush privileges;"
cat >/etc/mysql/mariadb.conf.d/60-bugzilla.cnf <<'EOF'
[mysqld]
max_allowed_packet = 1G
innodb_file_per_table = ON
ft_min_word_len = 2

[mysql]
max_allowed_packet = 1G
EOF

# configure bugzilla
cat > $WEBROOT/answers <<EOF
Expand All @@ -37,7 +56,7 @@ cat > $WEBROOT/answers <<EOF
\$answer{'diffpath'} = '/usr/bin';
\$answer{'site_wide_secret'} = '$(mcookie)$(mcookie)';
\$answer{'db_host'} = 'localhost';
\$answer{'db_driver'} = 'mysql';
\$answer{'db_driver'} = 'mariadb';
\$answer{'db_name'} = '$DB_NAME';
\$answer{'db_user'} = '$DB_USER';
\$answer{'db_pass'} = '$DB_PASS';
Expand All @@ -54,12 +73,6 @@ EOF

cd $WEBROOT

# configure build proxy for cpan
export http_proxy="$FAB_HTTP_PROXY" https_proxy="$FAB_HTTPS_PROXY"

echo -e 'y\nq\n' | cpan
echo -e 'y\n' | cpan install PatchReader || true

# note checksetup.pl creates appropriate .htaccess files (if they don't already exist; unless $create_htaccess = 0)
./checksetup.pl $WEBROOT/answers
echo 'admin\n' | ./checksetup.pl $WEBROOT/answers
Expand All @@ -77,8 +90,6 @@ echo "
0,15,30,45 * * * * (cd $WEBROOT && ./whine.pl)
" | crontab -u root -

rm -rf /root/.cpan
apt-get purge -y gcc make
apt-get autoremove -y

unset http_proxy https_proxy
rm -rf $SRC/Template-Toolkit-3.106 $SRC/Template-Toolkit-3.106.tar.gz
74 changes: 74 additions & 0 deletions docs/v19.0-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Bugzilla 19.0 testing

## Scope and source decision

Debian 13 Trixie does not package the Bugzilla server. Bugzilla 19.0 therefore
installs official upstream Bugzilla 5.2 commit
`5756ec67b506c20ff4b2c32d80e6fcf35e536b76` from the maintained `5.2` Git
branch. The deployed checkout retains that branch and its official GitHub
remote for supervised updates.

Trixie's Template Toolkit 2.27 is older than Bugzilla 5.2's minimum supported
version. The build installs official CPAN Template Toolkit 3.106 from its
pinned source URL and verifies SHA-256
`c7474050be80201f1fb55f0a569b9c0ab6c1c3f0cebbd7e601bda9b4046eec85`.
Apache, MariaDB, Postfix, Adminer and the remaining Perl dependencies come from
signed Debian Trixie and TurnKey repositories.

The v18 appliance briefly selected Bugzilla 5.2, then reverted because its
MySQL Perl driver inherited a Debian MariaDB TLS defect. The v19 appliance uses
Bugzilla 5.2's native `mariadb` driver and Trixie's `DBD::MariaDB` package.

## Acceptance command

```sh
/sandboxed-git/turnkey/tools/test-v19-appliance bugzilla \
--source /home/agent/.local/worktrees/turnkey-apps/bugzilla/wish-bugzilla-v19-trixie
```

## README crosswalk

| README contract | Focused check | Required result | Evidence |
| --- | --- | --- | --- |
| Bugzilla 5.2 comes from maintained upstream source | Inspect the Git commit, branch and remote | The checkout is on `5.2` at the pinned initial commit with the official origin | `tests/v19.sh` |
| First boot configures the Bugzilla administrator | Authenticate through Bugzilla's REST login using the preseeded email and password | Bugzilla returns an administrator session token | `tests/v19.sh` |
| Bugzilla provides a working bug tracker | Create and read a bug through REST, read it from MariaDB, restart MariaDB and read it again | The same bug and summary survive the complete round trip | `tests/v19.sh` |
| Apache supplies SSL | Validate Apache and request the Bugzilla HTTPS entry point | Apache is active and its TLS endpoint serves Bugzilla | `tests/v19.sh` |
| Postfix supports application email from loopback | Inspect service state, listener binding and Bugzilla mail parameters | Postfix is active on loopback and Bugzilla uses Sendmail with the firstboot mail identity | `tests/v19.sh` |
| Statistics and whine jobs run periodically | Inspect root's cron table and executable targets | `collectstats.pl`, `whineatnews.pl` and `whine.pl` are scheduled | `tests/v19.sh` |
| Adminer manages MariaDB | Open Adminer over HTTPS and authenticate to the Bugzilla database | Adminer displays the Bugzilla database with the firstboot credential | `tests/v19.sh` |
| Webmin manages Apache, MariaDB and Postfix | Check the modules and request Webmin HTTPS | All three modules are installed and Webmin responds | `tests/v19.sh` |
| Debian and upstream components retain maintained update paths | Refresh APT metadata, fetch the upstream `5.2` branch and replay the current module check | Eligible Trixie candidates remain, upstream history descends from the pinned commit and `checksetup.pl --check-modules` passes without changing the installation | `tests/v19.sh` |
| Root SSH, backup and other base services are inherited from Core | Cite the unchanged Core layer | Core 19 baseline passes | Core run `20260824t010251z-1634-32241`, source `24c82ee3540ce545422742b0e28ba6b687c53ec2`, verdict `PASS` |

## Supervised updates

Back up the appliance and place Bugzilla in maintenance mode before updating.
For updates within the 5.2 branch, run the supervised workflow as root. The
checkout contains files written by both the build and the web service, so each
Git command explicitly trusts only this appliance-managed checkout:

```sh
git -c safe.directory=/var/www/bugzilla -C /var/www/bugzilla fetch origin 5.2
git -c safe.directory=/var/www/bugzilla -C /var/www/bugzilla merge --ff-only FETCH_HEAD
/var/www/bugzilla/checksetup.pl --check-modules
/var/www/bugzilla/checksetup.pl
systemctl restart apache2
```

If the module check reports a dependency newer than Trixie's package, use
Bugzilla's `install-module.pl` for that named module before running
`checksetup.pl` again. Version-family upgrades require reviewing Bugzilla's
upstream upgrade notes before changing branches.

## Known limitation

Docker runtime validation does not exercise the installer, kernel, bootloader
or physical hardware. Bugzilla adds no appliance-specific behavior at those
boundaries, so the validated Core 19 baseline supplies inherited evidence.

## Deferred issues

- The build includes upstream documentation source and Sphinx tooling, but the
Docker acceptance does not render every documentation format. The normal
Bugzilla application flow does not depend on generated documentation.
10 changes: 7 additions & 3 deletions plan/main
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ libdate-calc-perl
libtemplate-perl
libdatetime-timezone-perl
libdatetime-perl
libdbix-connector-perl
libmoo-perl
libemail-sender-perl
libemail-address-xs-perl
libemail-mime-perl
libemail-mime-modifier-perl
libdbi-perl
libdbd-mysql-perl
libdbd-mariadb-perl
libcgi-pm-perl
liburi-perl
liblist-moreutils-perl
libmath-random-isaac-perl
libmath-random-isaac-xs-perl
libapache2-mod-perl2
Expand All @@ -46,7 +50,7 @@ libauthen-sasl-perl
libfile-mimeinfo-perl
libhtml-formattext-withlinks-perl
libgd-dev
libmariadbclient-dev-compat
libmariadb-dev-compat
lynx
lynx-common
graphviz
Expand Down
147 changes: 147 additions & 0 deletions tests/v19.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/bin/bash
set -Eeuo pipefail
umask 077

result=${TKL_TEST_RESULT:?TKL_TEST_RESULT is required}
app_password=${TKL_TEST_APP_PASS:?TKL_TEST_APP_PASS is required}
db_password=${TKL_TEST_DB_PASS:?TKL_TEST_DB_PASS is required}
base=https://localhost
admin_email=admin@example.invalid
response=/tmp/tkl-bugzilla-response.$$
payload=/tmp/tkl-bugzilla-payload.$$
policy=/tmp/tkl-bugzilla-policy.$$
cookies=/tmp/tkl-bugzilla-adminer-cookies.$$

cleanup() {
rm -f -- "$response" "$payload" "$policy" "$cookies"
}
trap cleanup EXIT
trap 'printf "test_failure line=%s status=%s command=%q\n" "$LINENO" "$?" "$BASH_COMMAND" >&2' ERR

systemctl --quiet is-active apache2.service mariadb.service postfix.service \
cron.service multi-user.target
systemctl --quiet is-enabled apache2.service mariadb.service postfix.service \
cron.service
apache2ctl -t

git_safe=(git -c safe.directory=/var/www/bugzilla -C /var/www/bugzilla)
bugzilla_commit=$("${git_safe[@]}" rev-parse HEAD)
test "$bugzilla_commit" = 5756ec67b506c20ff4b2c32d80e6fcf35e536b76
test "$("${git_safe[@]}" branch --show-current)" = 5.2
test "$("${git_safe[@]}" remote get-url origin)" = \
https://github.com/bugzilla/bugzilla.git
test "$(perl -MTemplate -e 'print $Template::VERSION')" = 3.106
test "$(perl -MDBD::MariaDB -e 'print $DBD::MariaDB::VERSION')" != ""
grep -Eq "^[$]db_driver[[:space:]]*=[[:space:]]*'mariadb';" \
/var/www/bugzilla/localconfig

curl --insecure --fail --silent --show-error "$base/" >"$response"
grep -qi '<title>.*Bugzilla' "$response"

curl --insecure --fail --silent --show-error \
--get --data-urlencode "login=$admin_email" \
--data-urlencode "password=$app_password" \
"$base/rest/login" >"$response"
token=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])' <"$response")
test -n "$token"

cat >"$payload" <<EOF
{"product":"TestProduct","component":"TestComponent","version":"unspecified","summary":"TurnKey v19 acceptance bug","description":"Created through the Bugzilla REST API","op_sys":"All","platform":"All","priority":"Normal","severity":"normal","token":"$token"}
EOF
curl --insecure --fail --silent --show-error \
-H 'Content-Type: application/json' --data-binary @"$payload" \
"$base/rest/bug" >"$response"
bug_id=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <"$response")
test "$bug_id" -gt 0

curl --insecure --fail --silent --show-error \
"$base/rest/bug/$bug_id?token=$token" >"$response"
python3 - "$bug_id" "$response" <<'PYTHON'
import json
import sys

bug_id = int(sys.argv[1])
with open(sys.argv[2], encoding='utf-8') as stream:
data = json.load(stream)
bug = data['bugs'][0]
assert bug['id'] == bug_id
assert bug['summary'] == 'TurnKey v19 acceptance bug'
PYTHON
mariadb --batch --skip-column-names bugzilla --execute \
"SELECT short_desc FROM bugs WHERE bug_id=$bug_id" | \
grep -Fxq 'TurnKey v19 acceptance bug'
systemctl restart mariadb.service
curl --insecure --fail --silent --show-error \
"$base/rest/bug/$bug_id?token=$token" >"$response"
grep -q 'TurnKey v19 acceptance bug' "$response"

test "$(postconf -h inet_interfaces)" = localhost
ss -ltn | awk '$4 ~ /^(127\.0\.0\.1|\[::1\]):25$/ { found=1 } END { exit !found }'
python3 - <<'PYTHON'
import json

with open('/var/www/bugzilla/data/params.json', encoding='utf-8') as stream:
params = json.load(stream)
assert params['mailfrom'] == 'bugzilla-daemon@example.com'
assert params['mail_delivery_method'] == 'Sendmail'
PYTHON

crontab -u root -l | grep -Fq './collectstats.pl'
crontab -u root -l | grep -Fq './whineatnews.pl'
crontab -u root -l | grep -Fq './whine.pl'
test -x /var/www/bugzilla/collectstats.pl
test -x /var/www/bugzilla/whine.pl

dpkg-query -W adminer webmin-apache webmin-mysql webmin-postfix >/dev/null
curl --insecure --fail --silent --show-error \
https://127.0.0.1:12322/ >"$response"
grep -qi 'Adminer' "$response"
curl --insecure --silent --show-error --location \
--cookie-jar "$cookies" --cookie "$cookies" \
--data-urlencode 'auth[driver]=server' \
--data-urlencode 'auth[server]=localhost' \
--data-urlencode 'auth[username]=adminer' \
--data-urlencode "auth[password]=$db_password" \
--data-urlencode 'auth[db]=bugzilla' \
https://127.0.0.1:12322/ >"$response"
grep -qi 'bugzilla' "$response"
grep -qi 'Logout' "$response"
curl --insecure --fail --silent --show-error --head \
https://127.0.0.1:12321/ >/dev/null

"${git_safe[@]}" fetch --quiet origin 5.2
candidate=$("${git_safe[@]}" rev-parse FETCH_HEAD)
"${git_safe[@]}" merge-base --is-ancestor \
"$bugzilla_commit" "$candidate"
/var/www/bugzilla/checksetup.pl --check-modules \
>"$response"
grep -q 'COMMANDS TO INSTALL' "$response"
test "$("${git_safe[@]}" rev-parse HEAD)" = \
"$bugzilla_commit"

apache_version=$(dpkg-query -W -f='${Version}' apache2)
mariadb_version=$(dpkg-query -W -f='${Version}' mariadb-server)
adminer_version=$(dpkg-query -W -f='${Version}' adminer)
before="$apache_version|$mariadb_version|$adminer_version"
apt-get update >/dev/null
for package in apache2 mariadb-server adminer libdbd-mariadb-perl; do
apt-cache policy "$package" >"$policy"
candidate_version=$(awk '/Candidate:/ {print $2}' "$policy")
test -n "$candidate_version"
test "$candidate_version" != '(none)'
grep -Eq 'trixie|deb13' "$policy"
done
after="$(dpkg-query -W -f='${Version}' apache2)|$(dpkg-query -W -f='${Version}' mariadb-server)|$(dpkg-query -W -f='${Version}' adminer)"
test "$after" = "$before"
grep -Rqs '^Suites: trixie' /etc/apt/sources.list.d
! grep -Rqi bookworm /etc/apt/sources.list.d

cat >"$result" <<EOF
package_source=Debian 13 Trixie APT repositories for Apache, MariaDB, Postfix, Adminer and Perl dependencies; pinned official Bugzilla 5.2 Git commit and Template Toolkit CPAN release
installed_version=bugzilla 5.2 commit $bugzilla_commit; Template Toolkit 3.106; apache2 $apache_version; mariadb-server $mariadb_version; adminer $adminer_version
runtime_checks=normal init; Apache HTTPS; Bugzilla administrator REST login; bug create and read with MariaDB readback and service restart; Postfix loopback and mail settings; cron; Adminer authenticated database view; Webmin endpoint
updater_command=apt-get update and apt-cache policy for Debian packages; git fetch origin 5.2 and checksetup.pl --check-modules for Bugzilla
updater_result=signed Debian metadata refreshed with installed packages unchanged; upstream 5.2 candidate $candidate descends from installed commit; current checksetup module replay passed without changing source
updater_channel=Debian and TurnKey Trixie APT repositories; official Bugzilla 5.2 Git branch
integrity_evidence=APT accepted signed repository metadata; Bugzilla initial commit pinned to $bugzilla_commit; Template Toolkit 3.106 download pinned by SHA-256; no Bookworm source remained
EOF