Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit f642485

Browse files
committed
fix: [#21] resolve e2e test failures and validate SSL automation infrastructure
- Fixed linting issues in compose.test.yaml (trailing spaces, missing newline) - Updated lint.sh to exclude informational SC1091 shellcheck warnings - Fixed health-check.sh to validate correct storage path /var/lib/torrust/ - Added ssl-generate-test-certs.sh for self-signed certificate testing - Updated SSL testing guide with e2e test validation results - All e2e tests now pass: 14/14 health checks (100% success rate) - SSL automation infrastructure validated and ready for Phase 2 testing Critical architectural fix: Storage location updated from repository-based (/home/torrust/github/torrust/torrust-tracker-demo/application/storage) to Docker volume-based (/var/lib/torrust/) persistent storage.
1 parent 2325952 commit f642485

File tree

7 files changed

+415
-348
lines changed

7 files changed

+415
-348
lines changed

application/compose.test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ services:
2727
image: ghcr.io/letsencrypt/pebble-challtestsrv:latest
2828
container_name: pebble-challtestsrv
2929
command: [
30-
"-defaultIPv6", "",
30+
"-defaultIPv6", "",
3131
"-defaultIPv4", "proxy",
3232
"-http01", "proxy:80",
3333
"-https01", "",
@@ -163,4 +163,4 @@ volumes:
163163
grafana_test_data:
164164
driver: local
165165
mysql_test_data:
166-
driver: local
166+
driver: local

application/share/bin/ssl-configure-nginx.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ process_template() {
104104

105105
log_info "Processing template: $(basename "${template_file}")"
106106

107-
# Use envsubst to substitute domain name
108-
if ! DOMAIN_NAME="${DOMAIN}" envsubst "\${DOMAIN_NAME}" < "${template_file}" > "${output_file}"; then
107+
# Use envsubst to substitute domain name, then convert ${DOLLAR} back to $
108+
if ! DOMAIN_NAME="${DOMAIN}" envsubst "\${DOMAIN_NAME}" < "${template_file}" | sed "s/\${DOLLAR}/\$/g" > "${output_file}"; then
109109
log_error "Failed to process template: $(basename "${template_file}")"
110110
exit 1
111111
fi
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
#!/bin/bash
2+
# SSL Test Certificate Generation Script
3+
# Usage: ./ssl-generate-test-certs.sh <domain>
4+
#
5+
# This script generates self-signed certificates for local SSL testing.
6+
# These certificates are suitable for testing nginx HTTPS configuration
7+
# without requiring external certificate authorities or DNS setup.
8+
9+
set -euo pipefail
10+
11+
# Source shell utilities for logging (optional for standalone operation)
12+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
14+
15+
# Try to source shell-utils.sh, fallback to simple logging if not available
16+
if [[ -f "${PROJECT_ROOT}/scripts/shell-utils.sh" ]]; then
17+
# shellcheck source=../../../../scripts/shell-utils.sh
18+
source "${PROJECT_ROOT}/scripts/shell-utils.sh"
19+
else
20+
# Fallback logging functions
21+
log_info() { echo "[INFO] $*"; }
22+
log_success() { echo "[SUCCESS] $*"; }
23+
log_error() { echo "[ERROR] $*"; }
24+
fi
25+
26+
# Configuration
27+
DOMAIN="${1:-test.local}"
28+
29+
# Certificate parameters
30+
CERT_DAYS=365
31+
KEY_SIZE=2048
32+
COUNTRY="US"
33+
STATE="Test State"
34+
CITY="Test City"
35+
ORG="Torrust Test"
36+
OU="Testing Department"
37+
38+
main() {
39+
log_info "🔐 Generating self-signed SSL certificates for: ${DOMAIN}"
40+
41+
validate_domain
42+
43+
# Generate certificates for each subdomain (like Let's Encrypt does)
44+
local subdomains=("tracker.${DOMAIN}" "grafana.${DOMAIN}")
45+
46+
for subdomain in "${subdomains[@]}"; do
47+
log_info "Generating certificate for ${subdomain}..."
48+
49+
create_certificate_directory "${subdomain}"
50+
generate_private_key "${subdomain}"
51+
generate_certificate "${subdomain}"
52+
create_certificate_chain "${subdomain}"
53+
set_permissions "${subdomain}"
54+
validate_certificates "${subdomain}"
55+
56+
log_success "✅ Certificate generated for ${subdomain}"
57+
done
58+
59+
log_success "✅ All test SSL certificates generated successfully!"
60+
print_usage_instructions
61+
}
62+
63+
validate_domain() {
64+
if [[ -z "${DOMAIN}" ]]; then
65+
log_error "Domain name is required"
66+
echo "Usage: $0 <domain>"
67+
echo "Example: $0 test.local"
68+
exit 1
69+
fi
70+
71+
log_info "Domain: ${DOMAIN}"
72+
log_info "Will generate certificates for:"
73+
log_info " - tracker.${DOMAIN}"
74+
log_info " - grafana.${DOMAIN}"
75+
}
76+
77+
create_certificate_directory() {
78+
local subdomain="$1"
79+
local cert_dir="/var/lib/torrust/certbot/etc/live/${subdomain}"
80+
81+
log_info "Creating certificate directory for ${subdomain}..."
82+
83+
# Create the directory structure (same as Let's Encrypt)
84+
sudo mkdir -p "${cert_dir}"
85+
86+
# Ensure proper ownership (torrust user should own the files)
87+
sudo chown -R torrust:torrust "$(dirname "${cert_dir}")"
88+
89+
log_success "Certificate directory created: ${cert_dir}"
90+
}
91+
92+
generate_private_key() {
93+
local subdomain="$1"
94+
local cert_dir="/var/lib/torrust/certbot/etc/live/${subdomain}"
95+
local private_key="${cert_dir}/privkey.pem"
96+
97+
log_info "Generating private key for ${subdomain} (${KEY_SIZE} bits)..."
98+
99+
openssl genrsa -out "${private_key}" "${KEY_SIZE}"
100+
101+
log_success "Private key generated: ${private_key}"
102+
}
103+
104+
generate_certificate() {
105+
local subdomain="$1"
106+
local cert_dir="/var/lib/torrust/certbot/etc/live/${subdomain}"
107+
local private_key="${cert_dir}/privkey.pem"
108+
local cert_only="${cert_dir}/cert.pem"
109+
110+
log_info "Generating self-signed certificate for ${subdomain}..."
111+
112+
# Create certificate with Subject Alternative Names for subdomains
113+
openssl req -new -x509 -key "${private_key}" \
114+
-out "${cert_only}" \
115+
-days "${CERT_DAYS}" \
116+
-config <(
117+
cat <<EOF
118+
[req]
119+
distinguished_name = req_distinguished_name
120+
req_extensions = v3_req
121+
prompt = no
122+
123+
[req_distinguished_name]
124+
C=${COUNTRY}
125+
ST=${STATE}
126+
L=${CITY}
127+
O=${ORG}
128+
OU=${OU}
129+
CN=${subdomain}
130+
131+
[v3_req]
132+
keyUsage = keyEncipherment, dataEncipherment
133+
extendedKeyUsage = serverAuth
134+
subjectAltName = @alt_names
135+
136+
[alt_names]
137+
DNS.1 = ${subdomain}
138+
DNS.2 = ${DOMAIN}
139+
DNS.3 = *.${DOMAIN}
140+
EOF
141+
)
142+
143+
log_success "Certificate generated: ${cert_only}"
144+
}
145+
146+
create_certificate_chain() {
147+
local subdomain="$1"
148+
local cert_dir="/var/lib/torrust/certbot/etc/live/${subdomain}"
149+
local cert_only="${cert_dir}/cert.pem"
150+
local cert_chain="${cert_dir}/chain.pem"
151+
local cert_file="${cert_dir}/fullchain.pem"
152+
153+
log_info "Creating certificate chain files for ${subdomain}..."
154+
155+
# For self-signed certificates, the chain is just the certificate itself
156+
cp "${cert_only}" "${cert_chain}"
157+
cp "${cert_only}" "${cert_file}"
158+
159+
log_success "Certificate chain files created"
160+
}
161+
162+
set_permissions() {
163+
local subdomain="$1"
164+
local cert_dir="/var/lib/torrust/certbot/etc/live/${subdomain}"
165+
local private_key="${cert_dir}/privkey.pem"
166+
local cert_file="${cert_dir}/fullchain.pem"
167+
local cert_chain="${cert_dir}/chain.pem"
168+
local cert_only="${cert_dir}/cert.pem"
169+
170+
log_info "Setting certificate file permissions for ${subdomain}..."
171+
172+
# Set secure permissions
173+
chmod 600 "${private_key}"
174+
chmod 644 "${cert_file}" "${cert_chain}" "${cert_only}"
175+
176+
# Ensure torrust user owns all certificate files
177+
chown torrust:torrust "${private_key}" "${cert_file}" "${cert_chain}" "${cert_only}"
178+
179+
log_success "Permissions set correctly"
180+
}
181+
182+
validate_certificates() {
183+
local subdomain="$1"
184+
local cert_dir="/var/lib/torrust/certbot/etc/live/${subdomain}"
185+
local cert_file="${cert_dir}/fullchain.pem"
186+
187+
log_info "Validating generated certificates for ${subdomain}..."
188+
189+
# Check if files exist
190+
for file in "${cert_dir}/privkey.pem" "${cert_dir}/fullchain.pem" "${cert_dir}/chain.pem" "${cert_dir}/cert.pem"; do
191+
if [[ ! -f "${file}" ]]; then
192+
log_error "Certificate file not found: ${file}"
193+
exit 1
194+
fi
195+
done
196+
197+
# Validate certificate content
198+
if openssl x509 -in "${cert_file}" -text -noout > /dev/null 2>&1; then
199+
log_success "Certificate validation passed for ${subdomain}"
200+
else
201+
log_error "Certificate validation failed for ${subdomain}"
202+
exit 1
203+
fi
204+
205+
# Display certificate information
206+
log_info "Certificate details for ${subdomain}:"
207+
openssl x509 -in "${cert_file}" -text -noout | grep -E "(Subject:|DNS:|Not Before|Not After)"
208+
}
209+
210+
print_usage_instructions() {
211+
echo
212+
echo "📋 Next Steps:"
213+
echo "1. Configure nginx for HTTPS:"
214+
echo " ./ssl-configure-nginx.sh ${DOMAIN}"
215+
echo
216+
echo "2. Restart nginx to load certificates:"
217+
echo " docker compose restart proxy"
218+
echo
219+
echo "3. Test HTTPS endpoints (expect certificate warnings for self-signed):"
220+
echo " curl -k https://tracker.${DOMAIN}/"
221+
echo " curl -k https://grafana.${DOMAIN}/"
222+
echo
223+
echo "4. View certificate details:"
224+
echo " openssl x509 -in /var/lib/torrust/certbot/etc/live/tracker.${DOMAIN}/fullchain.pem -text -noout"
225+
echo " openssl x509 -in /var/lib/torrust/certbot/etc/live/grafana.${DOMAIN}/fullchain.pem -text -noout"
226+
echo
227+
echo "⚠️ Note: Self-signed certificates will show security warnings in browsers."
228+
echo " Use -k flag with curl or add certificate to trusted store for testing."
229+
}
230+
231+
# Run main function
232+
main "$@"

0 commit comments

Comments
 (0)