Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
552a762
Modernize Debian and RPM packaging (systemd, dedicated user, CI tests)
vharseko Jun 26, 2026
98da118
Make the opendj service find Java via a stable symlink, and harden th…
vharseko Jun 28, 2026
7b5c11b
systemd: grant CAP_NET_BIND_SERVICE so the non-root service can bind …
vharseko Jun 28, 2026
2ff41db
docs: update deb/rpm install/upgrade/uninstall for systemd + dedicate…
vharseko Jun 28, 2026
67f0d6b
CI: test deb/rpm upgrade from the released 5.1.1 packages
vharseko Jul 2, 2026
515fa9a
test-rpm-upgrade: install "which" for the released 5.1.1 scripts
vharseko Jul 3, 2026
809bd5e
Packages must pull their own dependencies: declare util-linux, drop m…
vharseko Jul 3, 2026
c9b670d
sysv init: pick the function library by file existence, not distribution
vharseko Jul 4, 2026
179b463
Merge branch 'master' into features/linux-distribution
vharseko Jul 6, 2026
9a05884
Merge remote-tracking branch 'origin/master' into features/linux-dist…
vharseko Jul 17, 2026
7d345d9
[#663] set explicit GITHUB_TOKEN permissions in the build workflow
vharseko Jul 20, 2026
f9936b6
Merge origin/master into features/linux-distribution
vharseko Aug 5, 2026
0e30569
Merge remote-tracking branch 'origin/master' into features/linux-dist…
vharseko Aug 5, 2026
436d94b
Merge branch 'master' into features/linux-distribution
vharseko Aug 6, 2026
5e61512
[#663] Upgrade tests: take the released 5.1.2 packages as the upgrade…
vharseko Aug 6, 2026
794154a
[#663] Address review: packaging scriptlets, unit conditions, CI asse…
vharseko Aug 6, 2026
7d46ecf
[#663] Address the second review: upgrade paths, split layout, live-s…
vharseko Aug 6, 2026
3a13158
Merge remote-tracking branch 'origin/master' into features/linux-dist…
vharseko Aug 7, 2026
d249391
Fix packaging CI: setup port probe on 389 and missing systemctl in rp…
vharseko Aug 8, 2026
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
32 changes: 32 additions & 0 deletions .github/scripts/wait-for-ldap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh
#
# The contents of this file are subject to the terms of the Common Development and
# Distribution License (the License). You may not use this file except in compliance with the
# License.
#
# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
# specific language governing permission and limitations under the License.
#
# When distributing Covered Software, include this CDDL Header Notice in each file and include
# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
# Header, with the fields enclosed by brackets [] replaced by your own identifying
# information: "Portions copyright [year] [name of copyright owner]".
#
# Copyright 2026 3A Systems, LLC.

# Waits until the OpenDJ instance under /opt/opendj answers a base search on
# localhost:$1 (default 1389) with the CI test credentials. Exits non-zero if
# the server does not come up within ~60 seconds.

PORT="${1:-1389}"
i=0
while [ "$i" -lt 20 ] ; do
if /opt/opendj/bin/ldapsearch -h localhost -p "$PORT" -D "cn=Directory Manager" -w password \
-b "dc=example,dc=com" -s base "(objectClass=*)" 1.1 >/dev/null 2>&1 ; then
exit 0
fi
i=$((i + 1))
sleep 3
done
echo "OpenDJ did not answer on port $PORT within the timeout" >&2
exit 1
237 changes: 236 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ concurrency:
cancel-in-progress: true

# Nothing in this workflow writes back to the repository: the docker jobs push to
# the local registry service, not to a remote one. The docker jobs additionally get
# the local registry service, not to a remote one, and the other jobs only
# publish artifacts through the actions API. The docker jobs additionally get
# security-events: write to upload Trivy scan results to code scanning.
permissions:
contents: read
Expand Down Expand Up @@ -663,6 +664,240 @@ jobs:
if-no-files-found: warn
retention-days: 90

test-deb:
needs: build-maven
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v6
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: ubuntu-latest-11
- name: Clean-room install + SysV start/stop (debian:12 container)
shell: bash
run: |
docker run --rm -v "$PWD:/work" -w /work debian:12 bash -c '
set -e
export DEBIAN_FRONTEND=noninteractive
DEB=$(ls opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb | head -1)
echo "Found $DEB"
apt-get update
apt-get install -y lintian
lintian --info --no-tag-display-limit "$DEB" || true
dpkg-deb -I "$DEB"
# Both service files must be present (two greps: a single alternation
# would pass with either one missing).
dpkg-deb -c "$DEB" | grep "lib/systemd/system/opendj.service"
dpkg-deb -c "$DEB" | grep "etc/init.d/opendj"
# /etc/default/opendj must be a real conffile, so admin edits survive
# upgrades and the file survives "apt remove".
dpkg-deb -e "$DEB" /tmp/ctrl
grep -qx "/etc/default/opendj" /tmp/ctrl/conffiles
apt-get install -y "./$DEB"
id opendj
test "$(stat -c %U /opt/opendj)" = opendj
# No JAVA_HOME in this clean container: Java resolves from the PATH
# java that the package JRE dependency pulled in.
runuser -u opendj -- /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
--rootUserDN "cn=Directory Manager" --rootUserPassword password \
--hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
--baseDN dc=example,dc=com --addBaseEntry
/etc/init.d/opendj start
bash .github/scripts/wait-for-ldap.sh 1389
/etc/init.d/opendj status
/etc/init.d/opendj stop
apt-get purge -y opendj
'
- name: Live systemd install + start/stop (runner)
shell: bash
run: |
DEB=$(ls opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb | head -1)
sudo apt-get update
sudo apt-get install -y "$PWD/$DEB"
test "$(stat -c '%U' /opt/opendj)" = opendj
# postinst must have enabled the unit; do not enable by hand here or
# the postinst registration would go untested.
sudo systemctl is-enabled --quiet opendj
# Before setup the unit's start condition must keep it from
# start-bursting: "start" succeeds but no process may appear.
sudo systemctl start opendj
sleep 2
if sudo systemctl is-failed --quiet opendj; then echo "unit failed before setup"; exit 1; fi
# sudo/runuser/systemd strip JAVA_HOME -> the service uses the PATH java.
# Privileged port 389: only AmbientCapabilities=CAP_NET_BIND_SERVICE lets
# the non-root service bind it - the very reason it can drop root. setup
# itself runs via runuser WITHOUT that capability, so it must skip its
# own bind probe; the systemd start below performs the real 389 bind.
sudo runuser -u opendj -- /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
--rootUserDN "cn=Directory Manager" --rootUserPassword password \
--hostname localhost --ldapPort 389 --adminConnectorPort 4444 \
--baseDN dc=example,dc=com --addBaseEntry --skipPortCheck
sudo systemctl start opendj
bash .github/scripts/wait-for-ldap.sh 389
sudo systemctl is-active --quiet opendj
echo "OpenDJ is active under systemd"
sudo systemctl stop opendj
sleep 3
if sudo systemctl is-active --quiet opendj; then echo "still active"; exit 1; fi
sudo apt-get purge -y opendj

# Known coverage limit: the container has no booted systemd (/run/systemd/system
# is absent), so only the SysV/chkconfig path of the scriptlets is exercised
# here; start/stop through systemd is covered by the deb live-systemd jobs on
# the runner. The enable registration IS asserted below - systemctl enable is
# a pure symlink operation and works without a booted systemd.
test-rpm:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
needs: build-maven
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v6
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: ubuntu-latest-11
- name: Install and start/stop in Rocky Linux 9
shell: bash
run: |
docker run --rm -v "$PWD:/work" -w /work rockylinux:9 bash -c '
set -e
RPM=$(ls opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm | head -1)
echo "Found $RPM"
# Both service files must be shipped.
rpm -qlp "$RPM" | grep "^/usr/lib/systemd/system/opendj.service$"
rpm -qlp "$RPM" | grep "^/etc/init.d/opendj$"
# The %pre user-creation dependency must be declared for minimal images.
rpm -qp --requires "$RPM" | grep "shadow-utils"
# A real EL9 host always has systemd, but the container image ships no
# systemctl at all - %post then (correctly) skips the enable in silence.
# Preinstall it as host infrastructure, deliberately NOT a package
# Requires, so the is-enabled assertion below tests the enable path.
dnf install -y systemd
# No further manual dependencies: the package must pull everything else
# itself (Requires).
dnf install -y "$RPM"
id opendj
test "$(stat -c %U /opt/opendj)" = opendj
# %post must have enabled the unit on initial install.
systemctl is-enabled opendj.service
# No JAVA_HOME here: Java resolves from the PATH java pulled in by
# the java-headless dependency.
runuser -u opendj -- /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
--rootUserDN "cn=Directory Manager" --rootUserPassword password \
--hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
--baseDN dc=example,dc=com --addBaseEntry
/etc/init.d/opendj start
bash .github/scripts/wait-for-ldap.sh 1389
/etc/init.d/opendj status
/etc/init.d/opendj stop
rpm -e opendj
'

# Upgrade path: released 5.1.2 deb (root-owned, SysV) -> this build's deb, on the
# runner's LIVE systemd. The new package must stop the running server, create the
# opendj user, migrate ownership, run the upgrade tool and restart the server with
# the old data - through deb-systemd-invoke and the native unit, the path a real
# systemd host takes (docs: chap-upgrade).
test-deb-upgrade:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
needs: build-maven
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v6
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: ubuntu-latest-11
- name: Download released 5.1.2 deb
shell: bash
run: |
curl -fsSL -o opendj-5.1.2.deb https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj_5.1.2-1_all.deb
# Pin the upgrade source: a retagged release asset must fail loudly here,
# not surface as an unrelated upgrade-job failure.
echo "8f7f8bdd526b2d63eaef0621545be6aa55749cb60200d3bc2a2849d9ab69eb59 opendj-5.1.2.deb" | sha256sum -c -
- name: Upgrade 5.1.2 -> new deb (live systemd on the runner)
shell: bash
run: |
NEW=$(ls opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb | head -1)
echo "New deb: $NEW"
sudo apt-get update
# No manual dependencies: even the released 5.1.2 deb declares a JRE dependency.
sudo apt-get install -y "$PWD/opendj-5.1.2.deb"
# 5.1.2 model: no dedicated user, root-owned tree, SysV only - on this
# booted host its unit comes from the systemd-sysv-generator.
sudo /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
--rootUserDN "cn=Directory Manager" --rootUserPassword password \
--hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
--baseDN dc=example,dc=com --addBaseEntry
sudo systemctl daemon-reload
sudo /etc/init.d/opendj start
bash .github/scripts/wait-for-ldap.sh 1389
# Leave the server RUNNING: the new package must stop it, upgrade and
# restart it - through deb-systemd-invoke and the native unit this time.
sudo apt-get install -y "$PWD/$NEW"
id opendj
test "$(stat -c %U /opt/opendj)" = opendj
test -f /opt/opendj/config/config.ldif
# The systemd-hosted upgrade must leave the unit enabled and active.
sudo systemctl is-enabled --quiet opendj
sudo systemctl is-active --quiet opendj
# The pre-upgrade data must be served again, now by the dedicated user.
bash .github/scripts/wait-for-ldap.sh 1389
test "$(stat -c %U /proc/$(cat /opt/opendj/logs/server.pid))" = opendj
sudo systemctl stop opendj
sleep 3
if sudo systemctl is-active --quiet opendj; then echo "still active"; exit 1; fi
sudo apt-get purge -y opendj

test-rpm-upgrade:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
needs: build-maven
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v6
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: ubuntu-latest-11
- name: Download released 5.1.2 rpm
shell: bash
run: |
curl -fsSL -o opendj-5.1.2.rpm https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj-5.1.2-1.noarch.rpm
# Pin the upgrade source: a retagged release asset must fail loudly here,
# not surface as an unrelated upgrade-job failure.
echo "9622ef7c3292f0c156c96029a647ca704064aa93b567e5608734fe07d224ec58 opendj-5.1.2.rpm" | sha256sum -c -
- name: Upgrade 5.1.2 -> new rpm (Rocky Linux 9 container)
shell: bash
run: |
docker run --rm -v "$PWD:/work" -w /work rockylinux:9 bash -c '
set -e
NEW=$(ls opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm | head -1)
echo "New rpm: $NEW"
# No manual dependencies: the released 5.1.2 rpm already declares its runtime
# requirements (#677), and everything the NEW package needs must come from its
# own Requires.
dnf install -y ./opendj-5.1.2.rpm
# 5.1.2 model: no dedicated user, root-owned tree, SysV only
/opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
--rootUserDN "cn=Directory Manager" --rootUserPassword password \
--hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
--baseDN dc=example,dc=com --addBaseEntry
/etc/init.d/opendj start
bash .github/scripts/wait-for-ldap.sh 1389
# Leave the server RUNNING: the new package must stop it, upgrade and restart it.
dnf install -y "./$NEW"
id opendj
test "$(stat -c %U /opt/opendj)" = opendj
test -f /opt/opendj/config/config.ldif
# 5.1.2 was chkconfig-enabled and the native unit now shadows the
# sysv-generator unit: %post must have migrated that enable state
# (a pure symlink operation, asserted fine without booted systemd).
systemctl is-enabled opendj.service
# The package restarted the server; the pre-upgrade data must be served again,
# now by the dedicated user.
bash .github/scripts/wait-for-ldap.sh 1389
test "$(stat -c %U /proc/$(cat /opt/opendj/logs/server.pid))" = opendj
/etc/init.d/opendj stop
rpm -e opendj
'

test-msi:
needs: build-maven
runs-on: 'windows-latest'
Expand Down
Loading
Loading