generated from bisco/codex-bootstrap
153 lines
4.8 KiB
Bash
Executable File
153 lines
4.8 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
compose_file="${1:-/workspace/docker-compose.yml}"
|
|
|
|
awk '
|
|
/^[[:space:]]{2}wordpress:/ {
|
|
in_wordpress = 1
|
|
next
|
|
}
|
|
in_wordpress && /^[[:space:]]{2}[A-Za-z0-9_-]+:/ {
|
|
in_wordpress = 0
|
|
}
|
|
in_wordpress && /^[[:space:]]{4}ports:/ {
|
|
print "The wordpress service must not publish host ports; route traffic through proxy only." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
' "$compose_file"
|
|
|
|
grep -q 'azionelab-apache-hardening.conf' /workspace/wordpress/Dockerfile || {
|
|
echo "The WordPress image must install Apache hardening rules." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q '^FROM wordpress:7\.0\.2-php8\.3-apache$' /workspace/wordpress/Dockerfile || {
|
|
echo "The WordPress image must use the patched 7.0.2 PHP 8.3 Apache tag." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q 'wp-content/plugins/akismet' /workspace/wordpress/Dockerfile || {
|
|
echo "The WordPress image must remove the bundled Akismet plugin." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q 'wp-content/plugins/hello.php' /workspace/wordpress/Dockerfile || {
|
|
echo "The WordPress image must remove the bundled Hello Dolly plugin." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q 'wp-content/plugins/akismet' /workspace/wordpress/entrypoint-wrapper.sh || {
|
|
echo "The WordPress entrypoint must remove Akismet from existing persistent volumes." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q 'wp-content/plugins/hello.php' /workspace/wordpress/entrypoint-wrapper.sh || {
|
|
echo "The WordPress entrypoint must remove Hello Dolly from existing persistent volumes." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q 'wp-content/(uploads|files)' /workspace/wordpress/apache-hardening.conf || {
|
|
echo "Apache hardening must block PHP execution below uploads/files." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q 'wp-content/mu-plugins' /workspace/wordpress/apache-hardening.conf || {
|
|
echo "Apache hardening must block direct mu-plugin probing." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "'publicly_queryable'[[:space:]]*=>[[:space:]]*false" /workspace/wordpress/mu-plugins/azionelab-content.php || {
|
|
echo "Structured show content must not be exposed as standalone public routes." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "location = /wp-cron.php" /workspace/nginx/proxy-routes.conf || {
|
|
echo "NGINX must block external wp-cron.php requests." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "location = /readme.html" /workspace/nginx/proxy-routes.conf || {
|
|
echo "NGINX must hide the WordPress readme.html file." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "location ^~ /wp-content/mu-plugins/" /workspace/nginx/proxy-routes.conf || {
|
|
echo "NGINX must hide the mu-plugins directory from public probing." >&2
|
|
exit 1
|
|
}
|
|
|
|
[ -f /workspace/docker-compose.maintenance.yml ] || {
|
|
echo "The maintenance Compose override must exist for controlled wp-cli egress." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "^[[:space:]]*wp-cli:" /workspace/docker-compose.maintenance.yml || {
|
|
echo "The maintenance override must target only the wp-cli service." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "^[[:space:]]*-[[:space:]]*data$" /workspace/docker-compose.maintenance.yml || {
|
|
echo "The maintenance wp-cli service must keep database network access." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "^[[:space:]]*-[[:space:]]*web$" /workspace/docker-compose.maintenance.yml || {
|
|
echo "The maintenance wp-cli service must explicitly opt into the web network." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -Eq "^[[:space:]]{2}wp-cron:" "$compose_file" || {
|
|
echo "Compose must define an internal wp-cron service." >&2
|
|
exit 1
|
|
}
|
|
|
|
grep -q "wp cron event run --due-now" /workspace/wp-cli/cron.sh || {
|
|
echo "The wp-cron runner must execute due WordPress cron events via WP-CLI." >&2
|
|
exit 1
|
|
}
|
|
|
|
awk '
|
|
/^ wp-cron:/ {
|
|
in_wp_cron = 1
|
|
has_data_network = 0
|
|
has_db_host = 0
|
|
next
|
|
}
|
|
in_wp_cron && /^ [A-Za-z0-9_-]+:/ {
|
|
if (!has_data_network) {
|
|
print "The wp-cron service must join the internal data network." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
if (!has_db_host) {
|
|
print "The wp-cron service must receive WordPress database environment variables." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
in_wp_cron = 0
|
|
}
|
|
in_wp_cron && /^ ports:/ {
|
|
print "The wp-cron service must not publish host ports." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
in_wp_cron && /^[[:space:]]+WORDPRESS_DB_HOST:/ {
|
|
has_db_host = 1
|
|
}
|
|
in_wp_cron && /^ - data$/ {
|
|
has_data_network = 1
|
|
}
|
|
in_wp_cron && /^ - web$/ {
|
|
print "The wp-cron service must not join the public web network." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
END {
|
|
if (in_wp_cron && !has_data_network) {
|
|
print "The wp-cron service must join the internal data network." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
if (in_wp_cron && !has_db_host) {
|
|
print "The wp-cron service must receive WordPress database environment variables." > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
}
|
|
' "$compose_file"
|