Skip to content

Commit 3cf3d34

Browse files
committed
.
1 parent a5d75a3 commit 3cf3d34

3 files changed

Lines changed: 175 additions & 27 deletions

File tree

.github/scripts/smoke-test-deb.sh

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
# - Binary is functional (--help, --config-init-only)
99
# - systemd unit file is installed (part of the .deb package)
1010
# - Default configuration file is generated
11+
# - Config directory has secure permissions
12+
# - Service starts, responds to health check, and stops cleanly
13+
# - Package uninstall removes files but preserves config
1114
#
1215
# Environment variables (required):
1316
# PACKAGE_FILE Absolute path to the .deb file inside the container.
@@ -16,8 +19,8 @@
1619
#
1720
# LIMITATION — systemd in containers:
1821
# Docker containers do not normally run systemd. The postinst gates
19-
# service enable/start on /run/systemd/system. Full service start/stop
20-
# validation is best-effort and only attempted when systemd is detected.
22+
# service enable/start on /run/systemd/system. When systemd is not
23+
# detected, the service is started directly for the health check.
2124
# ──────────────────────────────────────────────────────────────────────────────
2225

2326
set -euo pipefail
@@ -102,13 +105,13 @@ info "Updating apt and installing prerequisites…"
102105
export DEBIAN_FRONTEND=noninteractive
103106
apt-get update -qq
104107
PREREQ_LOG=$(mktemp)
105-
if apt-get install -y -qq file python3 > "$PREREQ_LOG" 2>&1; then
108+
if apt-get install -y -qq file python3 curl openssl > "$PREREQ_LOG" 2>&1; then
106109
rm -f "$PREREQ_LOG"
107110
else
108111
echo "Prerequisites installation output:"
109112
cat "$PREREQ_LOG"
110113
rm -f "$PREREQ_LOG"
111-
fail "Prerequisites installation failed (file, python3)"
114+
fail "Prerequisites installation failed (file, python3, curl, openssl)"
112115
diagnostics
113116
summary
114117
fi
@@ -146,6 +149,11 @@ check_native_library
146149
check_webapp
147150
check_config_dir
148151

152+
# ── Config directory permissions ──────────────────────────────────────────────
153+
154+
info "Checking config directory permissions…"
155+
check_config_dir_permissions
156+
149157
# ── Binary functionality ──────────────────────────────────────────────────────
150158

151159
info "Checking binary functionality…"
@@ -167,9 +175,31 @@ check_unit_file "fail"
167175
info "Checking service file has exactly one ExecStart directive…"
168176
check_single_execstart
169177

170-
# ── Service startup (best-effort) ─────────────────────────────────────────────
178+
# ── Provisioner key ───────────────────────────────────────────────────────────
179+
# The gateway requires a provisioner public key to start.
180+
# Generate a key pair and place the public key where gateway.json points.
181+
182+
info "Generating provisioner key…"
183+
check_provisioner_key
184+
185+
# ── Service health ────────────────────────────────────────────────────────────
171186

172-
check_service_startup
187+
info "Checking service health…"
188+
check_service_health
189+
190+
# ── Uninstall ─────────────────────────────────────────────────────────────────
191+
192+
info "Checking package uninstall…"
193+
REMOVE_LOG=$(mktemp)
194+
if apt-get remove -y "$PACKAGE_NAME" >"$REMOVE_LOG" 2>&1; then
195+
pass "Package removal succeeded"
196+
else
197+
echo "Removal output:"
198+
cat "$REMOVE_LOG"
199+
fail "Package removal failed"
200+
fi
201+
rm -f "$REMOVE_LOG"
202+
check_post_uninstall
173203

174204
# ── Final output ──────────────────────────────────────────────────────────────
175205

.github/scripts/smoke-test-lib.sh

Lines changed: 101 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ summary() {
3636
fi
3737
}
3838

39+
# ── Helpers ───────────────────────────────────────────────────────────────────
40+
41+
# Returns 0 if systemd is running AND the unit file is installed on disk.
42+
systemd_and_unit_available() {
43+
[ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 || return 1
44+
for path in "${UNIT_FILE_PATHS[@]}"; do
45+
[ -f "$path" ] && return 0
46+
done
47+
return 1
48+
}
49+
3950
# ── Check functions ───────────────────────────────────────────────────────────
4051

4152
check_binary_executable() {
@@ -77,6 +88,16 @@ check_config_dir() {
7788
fi
7889
}
7990

91+
check_config_dir_permissions() {
92+
local perms
93+
perms=$(stat -c '%a' "$CONFIG_DIR" 2>/dev/null)
94+
if [ "$perms" = "750" ]; then
95+
pass "Config directory has secure permissions ($perms): $CONFIG_DIR"
96+
else
97+
fail "Config directory has insecure permissions ($perms, expected 750): $CONFIG_DIR"
98+
fi
99+
}
100+
80101
check_binary_help() {
81102
HELP_OUTPUT=$("$BINARY" --help 2>&1) && HELP_RC=$? || HELP_RC=$?
82103
if [ "$HELP_RC" -eq 0 ] || echo "$HELP_OUTPUT" | grep -qi 'gateway\|usage\|help'; then
@@ -147,19 +168,87 @@ check_single_execstart() {
147168
fi
148169
}
149170

150-
check_service_startup() {
151-
info "[Best-effort] Checking service startup…"
152-
warn "systemd service startup testing is best-effort in containers."
153-
warn "Full service validation requires a real systemd environment."
154-
if [ -d /run/systemd/system ]; then
155-
info "systemd detected; attempting service start…"
156-
if systemctl start devolutions-gateway 2>&1; then
157-
pass "[Best-effort] Service started successfully"
158-
systemctl status devolutions-gateway 2>&1 || true
159-
else
160-
warn "Service start failed (expected in some container environments)."
171+
check_provisioner_key() {
172+
info "Generating RSA-2048 provisioner key pair with openssl…"
173+
KEY_LOG=$(mktemp)
174+
if openssl genrsa -out "$CONFIG_DIR/provisioner.key" 2048 >"$KEY_LOG" 2>&1 \
175+
&& openssl rsa -in "$CONFIG_DIR/provisioner.key" \
176+
-pubout -out "$CONFIG_DIR/provisioner.pem" >>"$KEY_LOG" 2>&1; then
177+
pass "Provisioner key pair generated: $CONFIG_DIR/provisioner.pem"
178+
else
179+
echo "openssl output:"
180+
cat "$KEY_LOG"
181+
fail "Failed to generate provisioner key pair"
182+
fi
183+
rm -f "$KEY_LOG"
184+
}
185+
186+
check_service_health() {
187+
info "Checking service health…"
188+
189+
local health_url="http://localhost:7171/jet/health"
190+
local gateway_pid=""
191+
192+
if systemd_and_unit_available; then
193+
info "systemd available — using systemctl start/stop"
194+
if ! systemctl start devolutions-gateway >/dev/null 2>&1; then
195+
fail "systemctl start devolutions-gateway failed"
196+
return
197+
fi
198+
else
199+
info "systemd not available — starting binary directly"
200+
"$BINARY" &
201+
gateway_pid=$!
202+
fi
203+
204+
# Wait for the service to be ready (up to 10 s).
205+
local i=0
206+
while [ "$i" -lt 10 ]; do
207+
curl -sf "$health_url" >/dev/null 2>&1 && break
208+
sleep 1
209+
i=$((i + 1))
210+
done
211+
212+
HEALTH_OUTPUT=$(curl -sf "$health_url" 2>/dev/null) && HEALTH_RC=$? || HEALTH_RC=$?
213+
214+
# Stop the service.
215+
if systemd_and_unit_available; then
216+
systemctl stop devolutions-gateway >/dev/null 2>&1 || true
217+
elif [ -n "$gateway_pid" ]; then
218+
kill "$gateway_pid" 2>/dev/null || true
219+
wait "$gateway_pid" 2>/dev/null || true
220+
fi
221+
222+
if [ "$HEALTH_RC" -eq 0 ]; then
223+
pass "Health endpoint responded: $HEALTH_OUTPUT"
224+
else
225+
fail "Health endpoint did not respond at $health_url"
226+
fi
227+
}
228+
229+
check_post_uninstall() {
230+
if [ ! -f "$BINARY" ]; then
231+
pass "Binary removed after uninstall"
232+
else
233+
fail "Binary still present after uninstall: $BINARY"
234+
fi
235+
236+
local unit_file_found=0
237+
for path in "${UNIT_FILE_PATHS[@]}"; do
238+
if [ -f "$path" ]; then
239+
unit_file_found=1
240+
break
161241
fi
242+
done
243+
if [ "$unit_file_found" -eq 0 ]; then
244+
pass "Unit file removed after uninstall"
245+
else
246+
fail "Unit file still present after uninstall"
247+
fi
248+
249+
if [ -d "$CONFIG_DIR" ]; then
250+
pass "Config directory preserved after uninstall: $CONFIG_DIR"
162251
else
163-
info "No systemd detected; skipping service startup test."
252+
fail "Config directory was removed after uninstall (should be preserved)"
164253
fi
165254
}

.github/scripts/smoke-test-rpm.sh

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
# ──────────────────────────────────────────────────────────────────────────────
33
# RPM Package Installation Test for Devolutions Gateway
44
#
5-
# Runs inside a Rocky Linux 9 (RHEL 9-compatible) container to validate:
5+
# Runs inside a Rocky Linux (RHEL-compatible) container to validate:
66
# - Package installs correctly via dnf
77
# - Expected files and directories are present
88
# - Binary is functional (--help, --config-init-only)
99
# - systemd unit file is installed (part of the .rpm package)
1010
# - Default configuration file is generated
11+
# - Config directory has secure permissions
12+
# - Service starts, responds to health check, and stops cleanly
13+
# - Package uninstall removes files but preserves config
1114
#
1215
# Environment variables (required):
1316
# PACKAGE_FILE Absolute path to the .rpm file inside the container.
@@ -16,9 +19,8 @@
1619
#
1720
# LIMITATION — systemd in containers:
1821
# Docker containers do not normally run systemd. The RPM postinst
19-
# gates service enable/start on /run/systemd/system. Full service
20-
# start/stop validation is best-effort and only attempted when
21-
# systemd is detected.
22+
# gates service enable/start on /run/systemd/system. When systemd is
23+
# not detected, the service is started directly for the health check.
2224
# ──────────────────────────────────────────────────────────────────────────────
2325

2426
set -euo pipefail
@@ -101,20 +103,20 @@ echo ""
101103

102104
info "Installing prerequisites…"
103105
PREREQ_LOG=$(mktemp)
104-
if dnf install -y -q file python3 > "$PREREQ_LOG" 2>&1; then
106+
if dnf install -y -q file python3 curl openssl > "$PREREQ_LOG" 2>&1; then
105107
rm -f "$PREREQ_LOG"
106108
else
107109
echo "Prerequisites installation output:"
108110
cat "$PREREQ_LOG"
109111
rm -f "$PREREQ_LOG"
110-
fail "Prerequisites installation failed (file, python3)"
112+
fail "Prerequisites installation failed (file, python3, curl, openssl)"
111113
diagnostics
112114
summary
113115
fi
114116

115117
info "Installing package: $(basename "$PACKAGE_FILE")"
116118
# Use dnf to resolve and satisfy dependencies automatically.
117-
# The package declares a glibc dependency; Rocky Linux 9 provides glibc 2.34+.
119+
# The package declares a glibc dependency; Rocky Linux provides glibc 2.28+.
118120
INSTALL_LOG=$(mktemp)
119121
if dnf install -y "$PACKAGE_FILE" > "$INSTALL_LOG" 2>&1; then
120122
pass "Package installation succeeded"
@@ -145,6 +147,11 @@ check_native_library
145147
check_webapp
146148
check_config_dir
147149

150+
# ── Config directory permissions ──────────────────────────────────────────────
151+
152+
info "Checking config directory permissions…"
153+
check_config_dir_permissions
154+
148155
# ── Binary functionality ──────────────────────────────────────────────────────
149156

150157
info "Checking binary functionality…"
@@ -169,9 +176,31 @@ check_unit_file "fail"
169176
info "Checking service file has exactly one ExecStart directive…"
170177
check_single_execstart
171178

172-
# ── Service startup (best-effort) ─────────────────────────────────────────────
179+
# ── Provisioner key ───────────────────────────────────────────────────────────
180+
# The gateway requires a provisioner public key to start.
181+
# Generate a key pair and place the public key where gateway.json points.
182+
183+
info "Generating provisioner key…"
184+
check_provisioner_key
185+
186+
# ── Service health ────────────────────────────────────────────────────────────
173187

174-
check_service_startup
188+
info "Checking service health…"
189+
check_service_health
190+
191+
# ── Uninstall ─────────────────────────────────────────────────────────────────
192+
193+
info "Checking package uninstall…"
194+
REMOVE_LOG=$(mktemp)
195+
if dnf remove -y "$PACKAGE_NAME" >"$REMOVE_LOG" 2>&1; then
196+
pass "Package removal succeeded"
197+
else
198+
echo "Removal output:"
199+
cat "$REMOVE_LOG"
200+
fail "Package removal failed"
201+
fi
202+
rm -f "$REMOVE_LOG"
203+
check_post_uninstall
175204

176205
# ── Final output ──────────────────────────────────────────────────────────────
177206

0 commit comments

Comments
 (0)