diff --git a/.gitea/workflows/docker-test.yaml b/.gitea/workflows/docker-test.yaml new file mode 100644 index 0000000..2a131fc --- /dev/null +++ b/.gitea/workflows/docker-test.yaml @@ -0,0 +1,201 @@ +name: Docker Image Test + +on: + push: + branches: + - main + paths: + - 'dockerfile/**' + - 'docker-compose.example.yaml' + - '.example.env' + - '.gitea/workflows/**' + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + build-and-test: + name: Build & Test PHP 8.5 Apache Image + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Build Docker Image + run: | + docker build -t webhost-test:ci ./dockerfile + + - name: Start Container with Test ENV + run: | + docker rm -f webhost-test 2>/dev/null || true + docker run -d \ + --name webhost-test \ + -e SMTP_HOST=127.0.0.1 \ + -e SMTP_PORT=2525 \ + -e SMTP_USER=testuser@example.com \ + -e SMTP_PASS=supersecret \ + -e SMTP_FROM=noreply@example.com \ + -e SMTP_TLS=off \ + -e SMTP_STARTTLS=off \ + webhost-test:ci + + echo "Waiting for Apache to start..." + for i in $(seq 1 15); do + if [ "$(docker inspect -f '{{.State.Running}}' webhost-test 2>/dev/null)" = "true" ]; then + if docker exec webhost-test apache2ctl -t >/dev/null 2>&1; then + echo "Container is running and Apache config is valid." + break + fi + fi + if [ "$i" -eq 15 ]; then + echo "Container failed to start in time!" + docker logs webhost-test + exit 1 + fi + sleep 1 + done + + - name: Verify PHP Version & Extensions + run: | + echo "--- Checking PHP Version (8.5.x) ---" + docker exec webhost-test php -v + docker exec webhost-test php -r ' + if (version_compare(PHP_VERSION, "8.5.0-dev", "<")) { + fwrite(STDERR, "Expected PHP 8.5+, got " . PHP_VERSION . PHP_EOL); + exit(1); + } + ' + + echo "--- Checking Required PHP Extensions ---" + docker exec webhost-test php -r ' + $required = ["mysqli", "gd", "imagick", "intl", "zip", "exif", "Zend OPcache"]; + $missing = []; + foreach ($required as $ext) { + if (!extension_loaded($ext)) { + $missing[] = $ext; + } + } + if (!empty($missing)) { + fwrite(STDERR, "Missing PHP extensions: " . implode(", ", $missing) . PHP_EOL); + exit(1); + } + echo "All required extensions are loaded: " . implode(", ", $required) . PHP_EOL; + ' + + echo "--- Checking GD WebP & PNG Support ---" + docker exec webhost-test php -r ' + $gd = gd_info(); + if (empty($gd["WebP Support"]) || empty($gd["PNG Support"])) { + fwrite(STDERR, "GD is missing WebP or PNG support!" . PHP_EOL); + print_r($gd); + exit(1); + } + echo "GD WebP & PNG support verified." . PHP_EOL; + ' + + echo "--- Checking OPcache Configuration ---" + docker exec webhost-test php -r ' + $checks = [ + "opcache.enable" => "1", + "opcache.validate_timestamps" => "0", + "opcache.max_accelerated_files" => "10000", + "opcache.memory_consumption" => "192", + "opcache.max_wasted_percentage" => "10", + "opcache.interned_strings_buffer" => "16", + ]; + foreach ($checks as $key => $expected) { + $actual = (string) ini_get($key); + if ($actual !== $expected) { + fwrite(STDERR, "Config mismatch for $key: expected $expected, got $actual" . PHP_EOL); + exit(1); + } + } + echo "OPcache settings verified." . PHP_EOL; + ' + + - name: Verify Apache Modules & SSL Certificate + run: | + echo "--- Checking Apache Modules (ssl, rewrite) ---" + MODULES=$(docker exec webhost-test apache2ctl -M) + echo "$MODULES" | grep -q "ssl_module" || { echo "ssl_module not enabled"; exit 1; } + echo "$MODULES" | grep -q "rewrite_module" || { echo "rewrite_module not enabled"; exit 1; } + echo "Apache modules ssl and rewrite are enabled." + + echo "--- Checking Self-Signed SSL Certificate ---" + docker exec webhost-test test -s /etc/apache2/certs/apache.crt + docker exec webhost-test test -s /etc/apache2/certs/apache.key + docker exec webhost-test openssl x509 -in /etc/apache2/certs/apache.crt -noout -subject -dates + + - name: Verify msmtp Entrypoint & Configuration + run: | + echo "--- Checking /etc/msmtprc & /var/log/msmtp.log ---" + docker exec webhost-test sh -c ' + test -f /etc/msmtprc + PERMS=$(stat -c "%a" /etc/msmtprc) + OWNER=$(stat -c "%U:%G" /etc/msmtprc) + if [ "$PERMS" != "600" ] || [ "$OWNER" != "www-data:www-data" ]; then + echo "Unexpected /etc/msmtprc permissions ($PERMS) or owner ($OWNER)" + exit 1 + fi + grep -q "^host 127.0.0.1$" /etc/msmtprc + grep -q "^port 2525$" /etc/msmtprc + grep -q "^from noreply@example.com$" /etc/msmtprc + grep -q "^user testuser@example.com$" /etc/msmtprc + grep -q "^password supersecret$" /etc/msmtprc + + test -f /etc/aliases + grep -q "^default: noreply@example.com$" /etc/aliases + + test -f /var/log/msmtp.log + LOG_OWNER=$(stat -c "%U:%G" /var/log/msmtp.log) + if [ "$LOG_OWNER" != "www-data:www-data" ]; then + echo "Unexpected /var/log/msmtp.log owner ($LOG_OWNER)" + exit 1 + fi + echo "msmtp configuration and permissions verified." + ' + + - name: Test HTTP, HTTPS & .htaccess Rewrite + run: | + docker exec webhost-test sh -c ' + cat << "EOF" > /var/www/html/index.php + "ok", + "php" => PHP_VERSION, + "https" => (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off"), + "rewritten" => ($_GET["rewritten"] ?? "0") === "1" + ]); + EOF + + cat << "EOF" > /var/www/html/.htaccess + RewriteEngine On + RewriteRule ^rewrite-test$ index.php?rewritten=1 [L,QSA] + EOF + ' + + echo "--- Testing HTTP (Port 80) ---" + HTTP_RESP=$(docker exec webhost-test curl -fsS http://127.0.0.1/index.php) + echo "HTTP Response: $HTTP_RESP" + echo "$HTTP_RESP" | grep -q '"status":"ok"' + + echo "--- Testing HTTPS (Port 443) ---" + HTTPS_RESP=$(docker exec webhost-test curl -fsSk https://127.0.0.1/index.php) + echo "HTTPS Response: $HTTPS_RESP" + echo "$HTTPS_RESP" | grep -q '"status":"ok"' + echo "$HTTPS_RESP" | grep -q '"https":true' + + echo "--- Testing .htaccess mod_rewrite ---" + REWRITE_RESP=$(docker exec webhost-test curl -fsS http://127.0.0.1/rewrite-test) + echo "Rewrite Response: $REWRITE_RESP" + echo "$REWRITE_RESP" | grep -q '"rewritten":true' + + - name: Cleanup Container + if: always() + run: | + echo "--- Container Logs ---" + docker logs webhost-test || true + docker rm -f webhost-test || true