From 6299391f231223f7b33b369ff1ecf23be6fd0667 Mon Sep 17 00:00:00 2001 From: Twooey Date: Thu, 27 Aug 2026 13:39:19 -0400 Subject: [PATCH] Run wp-cli as www-data instead of root; drop --allow-root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --allow-root was routing around wp-cli's own safety check rather than addressing why root was there in the first place: docker exec defaults to the container's root user because the image never sets a non-root user for exec sessions — it was never about the actual web-facing attack surface, which already runs as www-data (verified: php-fpm's worker processes, the ones executing plugin/theme code for real requests, run as uid 33, not root; only our own deliberate admin commands were root). wp-config.php and the rest of wp-core are already owned by www-data (the official entrypoint sets this up), so there's no actual reason for our own commands to run as anything else. Verified: a full clean deploy and a bookstore-core wp-cli command both work identically running as www-data, no functional change, just removed an unnecessary privilege. Co-Authored-By: Claude Sonnet 5 --- Makefile | 5 +++-- deploy/backup.sh | 2 +- deploy/deploy.sh | 30 +++++++++++++++++------------- deploy/restore.sh | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index eff0f53..13b4872 100644 --- a/Makefile +++ b/Makefile @@ -22,12 +22,13 @@ ps: logs: $(COMPOSE) logs -f +# add -u root yourself for one-off root debugging (installing a package, etc.) shell: - $(COMPOSE) exec wordpress bash + $(COMPOSE) exec -u www-data wordpress bash # make wp ENV=staging ARGS="plugin list" wp: - $(COMPOSE) exec wordpress wp $(ARGS) --allow-root + $(COMPOSE) exec -u www-data wordpress wp $(ARGS) deploy: ./deploy/deploy.sh $(ENV) diff --git a/deploy/backup.sh b/deploy/backup.sh index 0cc305f..906c3d6 100755 --- a/deploy/backup.sh +++ b/deploy/backup.sh @@ -33,7 +33,7 @@ $COMPOSE exec -T db sh -c "exec mariadb-dump -u\"\$MARIADB_USER\" -p\"\$(cat /ru | gzip > "$BACKUP_DIR/db-${TIMESTAMP}.sql.gz" echo "==> archiving uploads" -$COMPOSE run --rm -T wordpress tar -czf - -C /var/www/html/wp-content uploads \ +$COMPOSE run --rm -T -u www-data wordpress tar -czf - -C /var/www/html/wp-content uploads \ > "$BACKUP_DIR/uploads-${TIMESTAMP}.tar.gz" if [[ -n "${BACKUP_REMOTE:-}" ]]; then diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 0405aa3..df627e0 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -44,6 +44,11 @@ grep -Ev '^(DB_PASSWORD|DB_ROOT_PASSWORD)=' "$ENV_FILE" > "$COMPOSE_ENV_FILE" # directory name, which every environment shares — that made staging quietly # reuse dev's db_data volume/credentials the first time this ran). COMPOSE="docker compose -p bookstore-${ENVIRONMENT} -f docker-compose.yml -f docker-compose.${ENVIRONMENT}.yml --env-file ${COMPOSE_ENV_FILE}" +# wp-cli runs as www-data (who already owns wp-config.php etc.), not root — +# `docker exec` defaults to root only because the image never sets a +# non-root default user for exec sessions; the actual web-facing php-fpm +# workers already run as www-data regardless. +WP="$COMPOSE exec -T -u www-data wordpress wp" echo "==> writing DB secret files (bypasses compose's \${VAR} interpolation entirely)" SECRETS_DIR="secrets/${ENVIRONMENT}" @@ -78,36 +83,35 @@ for i in $(seq 1 60); do done echo "==> ensuring WordPress is installed" -if ! $COMPOSE exec -T wordpress wp core is-installed --allow-root; then - $COMPOSE exec -T wordpress wp core install \ +if ! $WP core is-installed; then + $WP core install \ --url="${SITE_URL:?set SITE_URL in ${ENV_FILE}}" \ --title="${SITE_TITLE:-Bookstore}" \ --admin_user="${WP_ADMIN_USER:?set WP_ADMIN_USER in ${ENV_FILE}}" \ --admin_password="${WP_ADMIN_PASSWORD:?set WP_ADMIN_PASSWORD in ${ENV_FILE}}" \ --admin_email="${WP_ADMIN_EMAIL:?set WP_ADMIN_EMAIL in ${ENV_FILE}}" \ - --skip-email \ - --allow-root + --skip-email fi echo "==> installing/activating theme (Blocksy — free; Book Store starter site needs a manual license + import, see README)" -$COMPOSE exec -T wordpress wp theme install blocksy --activate --allow-root +$WP theme install blocksy --activate echo "==> installing/activating required plugins" -$COMPOSE exec -T wordpress wp plugin install woocommerce redis-cache blocksy-companion --activate --allow-root -$COMPOSE exec -T wordpress wp plugin activate bookstore-core --allow-root -$COMPOSE exec -T wordpress wp redis enable --allow-root || true +$WP plugin install woocommerce redis-cache blocksy-companion --activate +$WP plugin activate bookstore-core +$WP redis enable || true echo "==> enabling WooCommerce HPOS (custom order tables)" -$COMPOSE exec -T wordpress wp option update woocommerce_custom_orders_table_enabled yes --allow-root -$COMPOSE exec -T wordpress wp option update woocommerce_custom_orders_table_data_sync_enabled yes --allow-root +$WP option update woocommerce_custom_orders_table_enabled yes +$WP option update woocommerce_custom_orders_table_data_sync_enabled yes if [[ "$ENVIRONMENT" != "production" ]]; then echo "==> discouraging search engines (non-production)" - $COMPOSE exec -T wordpress wp option update blog_public 0 --allow-root + $WP option update blog_public 0 fi echo "==> flushing caches and rewrite rules" -$COMPOSE exec -T wordpress wp cache flush --allow-root -$COMPOSE exec -T wordpress wp rewrite flush --allow-root +$WP cache flush +$WP rewrite flush echo "==> deploy complete: ${ENVIRONMENT}" diff --git a/deploy/restore.sh b/deploy/restore.sh index e50dc27..2b50a34 100755 --- a/deploy/restore.sh +++ b/deploy/restore.sh @@ -31,7 +31,7 @@ gunzip -c "$DB_DUMP" | $COMPOSE exec -T db sh -c "exec mariadb -u\"\$MARIADB_USE echo "==> restoring uploads" ARCHIVE_DIR="$(cd "$(dirname "$UPLOADS_ARCHIVE")" && pwd)" ARCHIVE_NAME="$(basename "$UPLOADS_ARCHIVE")" -$COMPOSE run --rm -T -v "${ARCHIVE_DIR}:/restore:ro" wordpress \ +$COMPOSE run --rm -T -u www-data -v "${ARCHIVE_DIR}:/restore:ro" wordpress \ tar -xzf "/restore/${ARCHIVE_NAME}" -C /var/www/html/wp-content echo "==> restore complete — verify the site before treating the drill as passed"