Skip to content

Commit 8f5aa92

Browse files
authored
Prevent 4.x upgrade to 5.0 (#1328)
* feat: implement version guard to block 5.x installation if pre-5.x version is detected * feat: add tests to block 5.x installation when 4.x is present and allow same-major reinstall * feat: update Dockerfile and test scripts to enforce 5.x installation rules with force option and improved test naming * feat: add logic to skip upgrade tests for cross-major version upgrades * feat: improve container cleanup logic to ensure proper removal before image deletion * feat: enhance error messaging for blocked upgrades from pre-5.x versions * feat: add real cross-major upgrade block test and generalize version guard message * feat: refine version guard logic to block upgrades from pre-5.x versions * fix: remove redundant conditional statement in RPM spec file * feat: implement tests to block 5.x installation under specific conditions (3.x remnants and unknown version) * feat: remove 3.x installation block tests and related logic for Wazuh dashboard upgrade * fix: correct casing in error message for direct upgrade block in dashboard build workflow
1 parent 7fa1a4b commit 8f5aa92

6 files changed

Lines changed: 413 additions & 20 deletions

File tree

.github/workflows/5_builderpackage_dashboard.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,24 @@ jobs:
503503
bash ./test-packages.sh \
504504
-p ${{needs.setup-variables.outputs.PACKAGE_NAME}}
505505
506+
- name: Test package negative (5.x install blocked when 4.x present)
507+
run: |
508+
cd ${{ needs.setup-variables.outputs.CURRENT_DIR }}/dev-tools/test-packages
509+
bash ./test-packages.sh --block-4x-install \
510+
-p ${{needs.setup-variables.outputs.PACKAGE_NAME}}
511+
512+
- name: Test package negative (5.x install blocked when remnants exist but version unknown)
513+
run: |
514+
cd ${{ needs.setup-variables.outputs.CURRENT_DIR }}/dev-tools/test-packages
515+
bash ./test-packages.sh --block-unknown-install \
516+
-p ${{needs.setup-variables.outputs.PACKAGE_NAME}}
517+
518+
- name: Test package reinstall (5.x install over 5.x succeeds)
519+
run: |
520+
cd ${{ needs.setup-variables.outputs.CURRENT_DIR }}/dev-tools/test-packages
521+
bash ./test-packages.sh --allow-same-major-reinstall \
522+
-p ${{needs.setup-variables.outputs.PACKAGE_NAME}}
523+
506524
- name: DEB - Test package install/uninstall
507525
if: ${{ inputs.system == 'deb' }}
508526
run: |
@@ -533,6 +551,13 @@ jobs:
533551
- name: DEB - Test package upgrade
534552
if: ${{ needs.setup-variables.outputs.PREVIOUS != '' && inputs.system == 'deb' }}
535553
run: |
554+
# Skip when previous and current major differ (pre-install guard blocks cross-major upgrades)
555+
VERSION_MAJOR=$(echo "${{needs.setup-variables.outputs.VERSION}}" | cut -d. -f1)
556+
PREVIOUS_MAJOR=$(echo "${{needs.setup-variables.outputs.PREVIOUS}}" | cut -d. -f1)
557+
if [ "$VERSION_MAJOR" != "$PREVIOUS_MAJOR" ]; then
558+
echo "Skipping upgrade test — different major ($PREVIOUS_MAJOR -> $VERSION_MAJOR)"
559+
exit 0
560+
fi
536561
sudo apt-get install debhelper tar curl libcap2-bin gnupg apt-transport-https #debhelper version 9 or later
537562
sudo curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import && sudo chmod 644 /usr/share/keyrings/wazuh.gpg
538563
sudo echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | sudo tee -a /etc/apt/sources.list.d/wazuh.list
@@ -558,6 +583,37 @@ jobs:
558583
exit 1
559584
fi
560585
586+
- name: DEB - Verify cross-major upgrade is blocked
587+
if: ${{ needs.setup-variables.outputs.PREVIOUS != '' && inputs.system == 'deb' }}
588+
run: |
589+
sudo apt-get install debhelper tar curl libcap2-bin gnupg apt-transport-https
590+
sudo curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import && sudo chmod 644 /usr/share/keyrings/wazuh.gpg
591+
sudo echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | sudo tee -a /etc/apt/sources.list.d/wazuh.list
592+
sudo apt-get update || sudo apt-get update
593+
sudo apt-get -y install wazuh-dashboard=${{needs.setup-variables.outputs.PREVIOUS}}
594+
sudo systemctl daemon-reload
595+
sudo systemctl enable wazuh-dashboard
596+
sudo systemctl start wazuh-dashboard
597+
598+
# Attempt 5.x upgrade — MUST fail
599+
set +e
600+
OUTPUT=$(sudo dpkg -i ${{ needs.setup-variables.outputs.CURRENT_DIR }}/dev-tools/test-packages/${{needs.setup-variables.outputs.PACKAGE_NAME}} 2>&1)
601+
EXIT_CODE=$?
602+
set -e
603+
604+
if [ "$EXIT_CODE" -eq 0 ]; then
605+
echo "ERROR: Installation should have been blocked but succeeded"
606+
exit 1
607+
fi
608+
609+
if echo "$OUTPUT" | grep -F -q "ERROR: Direct upgrade from Wazuh dashboard"; then
610+
echo "Cross-major upgrade correctly blocked"
611+
else
612+
echo "ERROR: Expected block message not found"
613+
echo "$OUTPUT"
614+
exit 1
615+
fi
616+
561617
- name: RPM - Clone automation repo
562618
if: ${{ inputs.system == 'rpm' }}
563619
env:
@@ -638,6 +694,13 @@ jobs:
638694
- name: RPM - Test package upgrade
639695
if: ${{ needs.setup-variables.outputs.PREVIOUS != '' && inputs.system == 'rpm' }}
640696
run: |
697+
# Skip when previous and current major differ (pre-install guard blocks cross-major upgrades)
698+
VERSION_MAJOR=$(echo "${{needs.setup-variables.outputs.VERSION}}" | cut -d. -f1)
699+
PREVIOUS_MAJOR=$(echo "${{needs.setup-variables.outputs.PREVIOUS}}" | cut -d. -f1)
700+
if [ "$VERSION_MAJOR" != "$PREVIOUS_MAJOR" ]; then
701+
echo "Skipping upgrade test — different major ($PREVIOUS_MAJOR -> $VERSION_MAJOR)"
702+
exit 0
703+
fi
641704
${{ steps.setup_rpm_env.outputs.ssh_command }} "sudo yum install libcap; \
642705
sudo rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH; \
643706
sudo echo -e '[wazuh]\ngpgcheck=1\ngpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH\nenabled=1\nname=EL-$releasever - Wazuh\nbaseurl=https://packages.wazuh.com/4.x/yum/\nprotect=1' | sudo tee /etc/yum.repos.d/wazuh.repo; \
@@ -660,6 +723,41 @@ jobs:
660723
exit 1; \
661724
fi
662725
"
726+
- name: RPM - Verify cross-major upgrade is blocked
727+
if: ${{ needs.setup-variables.outputs.PREVIOUS != '' && inputs.system == 'rpm' }}
728+
run: |
729+
${{ steps.setup_rpm_env.outputs.ssh_command }} "sudo yum install libcap; \
730+
sudo rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH; \
731+
sudo echo -e '[wazuh]\ngpgcheck=1\ngpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH\nenabled=1\nname=EL-$releasever - Wazuh\nbaseurl=https://packages.wazuh.com/4.x/yum/\nprotect=1' | sudo tee /etc/yum.repos.d/wazuh.repo; \
732+
sudo yum install -y wazuh-dashboard-${{needs.setup-variables.outputs.PREVIOUS}}; \
733+
sudo systemctl daemon-reload; \
734+
sudo systemctl enable wazuh-dashboard; \
735+
sudo systemctl start wazuh-dashboard; \
736+
if sudo systemctl status wazuh-dashboard | grep -q 'active (running)'; then \
737+
echo 'Service running'; \
738+
else \
739+
echo 'ERROR: Service not running'; \
740+
exit 1; \
741+
fi"
742+
743+
set +e
744+
OUTPUT=$(${{ steps.setup_rpm_env.outputs.ssh_command }} "sudo yum install -y ${{needs.setup-variables.outputs.PACKAGE_NAME}} 2>&1")
745+
EXIT_CODE=$?
746+
set -e
747+
748+
if [ "$EXIT_CODE" -eq 0 ]; then
749+
echo "ERROR: Installation should have been blocked but succeeded"
750+
exit 1
751+
fi
752+
753+
if echo "$OUTPUT" | grep -F -q "ERROR: Direct upgrade from Wazuh dashboard"; then
754+
echo "Cross-major upgrade correctly blocked"
755+
else
756+
echo "ERROR: Expected block message not found"
757+
echo "$OUTPUT"
758+
exit 1
759+
fi
760+
663761
- name: Destroy Allocator Machine
664762
#DO NOT DELETE. This ensures that the generated instance is destroyed even if the job fails.
665763
if: ${{ always() }}

dev-tools/build-packages/deb/debian/preinst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,51 @@
99

1010
set -e
1111

12+
# Version guard: block 5.x installation when a pre-5.x Wazuh version is detected on disk.
13+
# NOTE: we check files on disk rather than dpkg -s because during
14+
# dpkg -i the old package data remains on disk until postinst runs.
15+
# Detection order:
16+
# 1. VERSION.json — wazuh-dashboard 5.x+
17+
# 2. VERSION — wazuh-dashboard 4.x (legacy file)
18+
# 3. plugin package.json — wazuh-dashboard 4.x+ (plugin metadata)
19+
if [ -f /usr/share/wazuh-dashboard/VERSION.json ]; then
20+
INSTALLED_VER=$(grep -m 1 '"version"' /usr/share/wazuh-dashboard/VERSION.json 2>/dev/null | sed 's/.*"version": *"\([^"]*\)".*/\1/')
21+
elif [ -f /usr/share/wazuh-dashboard/VERSION ]; then
22+
INSTALLED_VER=$(cat /usr/share/wazuh-dashboard/VERSION 2>/dev/null)
23+
elif [ -f /usr/share/wazuh-dashboard/plugins/wazuh/package.json ]; then
24+
INSTALLED_VER=$(grep -m 1 '"version"' /usr/share/wazuh-dashboard/plugins/wazuh/package.json 2>/dev/null | sed 's/.*"version": *"\([^"]*\)".*/\1/')
25+
fi
26+
27+
if [ -n "$INSTALLED_VER" ]; then
28+
MAJOR=$(echo "$INSTALLED_VER" | cut -d. -f1)
29+
if [ "$MAJOR" -lt 5 ]; then
30+
cat >&2 <<EOF
31+
==============================================================
32+
ERROR: Direct upgrade from Wazuh dashboard versions prior to 5.x
33+
is not supported.
34+
35+
Detected installed version: $INSTALLED_VER
36+
A clean installation of Wazuh dashboard 5.x is required.
37+
==============================================================
38+
EOF
39+
exit 1
40+
fi
41+
elif [ "$1" = "upgrade" ] && [ -d /usr/share/wazuh-dashboard/plugins ]; then
42+
# Upgrade requested but version could not be determined from any source.
43+
# Files may have been removed or corrupted. Block the upgrade; a fresh
44+
# install ($1=install) is still allowed.
45+
cat >&2 <<EOF
46+
==============================================================
47+
ERROR: A previous Wazuh installation was detected but the
48+
installed version could not be determined.
49+
50+
A clean installation of Wazuh dashboard 5.x is required.
51+
Please remove the previous installation before proceeding.
52+
==============================================================
53+
EOF
54+
exit 1
55+
fi
56+
1257
#
1358
# This script is executed in the pre-installation phase
1459
#

dev-tools/build-packages/rpm/wazuh-dashboard.spec

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,51 @@ find %{buildroot}%{INSTALL_DIR}/plugins/wazuh/ -type f -perm 744 -exec chmod 740
102102
# -----------------------------------------------------------------------------
103103

104104
%pre
105+
# Block installation of 5.x if any Wazuh < 5.0.0 is detected on disk.
106+
# NOTE: we check files on disk rather than rpm -qa because during
107+
# rpm -Uvh the old package header is removed from the DB before %pre runs.
108+
# Detection order:
109+
# 1. VERSION.json — wazuh-dashboard 5.x+
110+
# 2. VERSION — wazuh-dashboard 4.x (legacy file)
111+
# 3. plugin package.json — wazuh-dashboard 4.x+ (plugin metadata)
112+
if [ -f %{INSTALL_DIR}/VERSION.json ]; then
113+
INSTALLED_VER=$(grep -m 1 '"version"' %{INSTALL_DIR}/VERSION.json 2>/dev/null | sed 's/.*"version": *"\([^"]*\)".*/\1/')
114+
elif [ -f %{INSTALL_DIR}/VERSION ]; then
115+
INSTALLED_VER=$(cat %{INSTALL_DIR}/VERSION 2>/dev/null)
116+
elif [ -f %{INSTALL_DIR}/plugins/wazuh/package.json ]; then
117+
INSTALLED_VER=$(grep -m 1 '"version"' %{INSTALL_DIR}/plugins/wazuh/package.json 2>/dev/null | sed 's/.*"version": *"\([^"]*\)".*/\1/')
118+
fi
119+
120+
if [ -n "$INSTALLED_VER" ]; then
121+
MAJOR=$(echo "$INSTALLED_VER" | cut -d. -f1)
122+
if [ "$MAJOR" -lt 5 ]; then
123+
cat >&2 <<EOF
124+
==============================================================
125+
ERROR: Direct upgrade from Wazuh dashboard versions prior to 5.x
126+
is not supported.
127+
128+
Detected installed version: $INSTALLED_VER
129+
A clean installation of Wazuh dashboard 5.x is required.
130+
==============================================================
131+
EOF
132+
exit 1
133+
fi
134+
elif [ "$1" = "2" ] && [ -d %{INSTALL_DIR}/plugins ]; then
135+
# Upgrade requested but version could not be determined from any source.
136+
# Files may have been removed or corrupted. Block the upgrade; a fresh
137+
# install ($1=1) is still allowed.
138+
cat >&2 <<EOF
139+
==============================================================
140+
ERROR: A previous Wazuh installation was detected but the
141+
installed version could not be determined.
142+
143+
A clean installation of Wazuh dashboard 5.x is required.
144+
Please remove the previous installation before proceeding.
145+
==============================================================
146+
EOF
147+
exit 1
148+
fi
149+
105150
# Create the wazuh-dashboard group if it doesn't exists
106151
if [ $1 = 1 ]; then
107152
if command -v getent > /dev/null 2>&1 && ! getent group %{GROUP} > /dev/null 2>&1; then
Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,37 @@
11
FROM ubuntu:jammy
22
ARG PACKAGE
3+
ARG BLOCK_4X_INSTALL
4+
ARG BLOCK_UNKNOWN_INSTALL
5+
ARG ALLOW_SAME_MAJOR_REINSTALL
36
RUN mkdir -p /tmp
47
RUN apt-get update --fix-missing
58
RUN apt-get install -y curl libcap2-bin
9+
10+
# If BLOCK_4X_INSTALL is set, simulate a 4.x installation via the plugin's package.json
11+
# (the preinst guard falls through VERSION.json -> VERSION -> plugin package.json)
12+
RUN if [ -n "$BLOCK_4X_INSTALL" ]; then \
13+
mkdir -p /usr/share/wazuh-dashboard/plugins/wazuh && \
14+
printf '{"name":"wazuh","version":"4.14.5"}\n' > /usr/share/wazuh-dashboard/plugins/wazuh/package.json; \
15+
fi
16+
617
COPY ${PACKAGE} /tmp/wazuh.deb
7-
RUN dpkg -i /tmp/wazuh.deb
18+
19+
# BLOCK_UNKNOWN_INSTALL: install once (fresh, $1=install — allowed), then corrupt
20+
# version files so the version cannot be determined, then attempt a reinstall
21+
# ($1=upgrade) which must be blocked by the preinst guard.
22+
#
23+
# ALLOW_SAME_MAJOR_REINSTALL: install twice — must succeed (5.x over 5.x).
24+
#
25+
# Default: normal install (also handles BLOCK_4X_INSTALL via the files pre-created above).
26+
RUN if [ -n "$BLOCK_UNKNOWN_INSTALL" ]; then \
27+
dpkg -i /tmp/wazuh.deb && \
28+
rm -f /usr/share/wazuh-dashboard/VERSION.json && \
29+
rm -f /usr/share/wazuh-dashboard/VERSION && \
30+
rm -f /usr/share/wazuh-dashboard/plugins/wazuh/package.json && \
31+
dpkg -i /tmp/wazuh.deb; \
32+
elif [ -n "$ALLOW_SAME_MAJOR_REINSTALL" ]; then \
33+
dpkg -i /tmp/wazuh.deb && \
34+
dpkg -i /tmp/wazuh.deb; \
35+
else \
36+
dpkg -i /tmp/wazuh.deb; \
37+
fi
Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,39 @@
11
FROM centos:8
22
RUN mkdir -p /tmp
33
ARG PACKAGE
4+
ARG BLOCK_4X_INSTALL
5+
ARG BLOCK_UNKNOWN_INSTALL
6+
ARG ALLOW_SAME_MAJOR_REINSTALL
47
RUN cd /etc/yum.repos.d/
58
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
69
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
710
RUN yum update -y
11+
12+
# If BLOCK_4X_INSTALL is set, simulate a 4.x installation via the plugin's package.json
13+
# (the %pre guard falls through VERSION.json -> VERSION -> plugin package.json)
14+
RUN if [ -n "$BLOCK_4X_INSTALL" ]; then \
15+
mkdir -p /usr/share/wazuh-dashboard/plugins/wazuh && \
16+
printf '{"name":"wazuh","version":"4.14.5"}\n' > /usr/share/wazuh-dashboard/plugins/wazuh/package.json; \
17+
fi
18+
819
COPY ${PACKAGE} /tmp/wazuh.rpm
9-
RUN yum install /tmp/wazuh.rpm -y
20+
21+
# BLOCK_UNKNOWN_INSTALL: install once (fresh, $1=1 — allowed), then corrupt
22+
# version files so the version cannot be determined, then attempt an upgrade
23+
# ($1=2) which must be blocked by the %pre guard.
24+
#
25+
# ALLOW_SAME_MAJOR_REINSTALL: install then upgrade — must succeed (5.x over 5.x).
26+
#
27+
# Default: normal install (also handles BLOCK_4X_INSTALL via the files pre-created above).
28+
RUN if [ -n "$BLOCK_UNKNOWN_INSTALL" ]; then \
29+
rpm -ivh /tmp/wazuh.rpm --nodeps && \
30+
rm -f /usr/share/wazuh-dashboard/VERSION.json && \
31+
rm -f /usr/share/wazuh-dashboard/VERSION && \
32+
rm -f /usr/share/wazuh-dashboard/plugins/wazuh/package.json && \
33+
rpm -Uvh /tmp/wazuh.rpm --nodeps --force; \
34+
elif [ -n "$ALLOW_SAME_MAJOR_REINSTALL" ]; then \
35+
rpm -ivh /tmp/wazuh.rpm --nodeps && \
36+
rpm -Uvh /tmp/wazuh.rpm --nodeps --force; \
37+
else \
38+
yum install /tmp/wazuh.rpm -y; \
39+
fi

0 commit comments

Comments
 (0)