From 6f1b065f1a84b4a639fb968335ae8742cd2db900 Mon Sep 17 00:00:00 2001 From: Dom Sekotill Date: Fri, 14 Jun 2024 14:45:25 +0100 Subject: [PATCH 1/3] Add a writable cache location in wp-content --- data/nginx/server.conf | 5 +++++ scripts/entrypoint.sh | 25 ++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/data/nginx/server.conf b/data/nginx/server.conf index 0d79c45..d7b1fff 100644 --- a/data/nginx/server.conf +++ b/data/nginx/server.conf @@ -120,4 +120,9 @@ server { include safe.types; default_type application/octet-stream; } + + # Disable serving directly from any page cache in /wp-content/cache + location /wp-content/cache/ { + return 404; + } } diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 7f79934..48d361a 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -167,24 +167,26 @@ setup_components() { return 0 } -get_media_dir() +get_writable_dirs() { - [[ -v MEDIA ]] && return - MEDIA=$( + [[ -v MEDIA && -v CACHE ]] && return + local content=$( + wp config get WP_CONTENT_DIR --type=constant || echo wp-content + ) + local media=$( wp config get UPLOADS --type=constant || wp option get upload_path ) - [[ -n "${MEDIA}" ]] && return - local _wp_content=$(wp config get WP_CONTENT_DIR --type=constant) - MEDIA=${_wp_content:-wp-content}/uploads + MEDIA=${media:-${content}/uploads} + CACHE=${content}/cache } -setup_media() +setup_writable() { # UID values change on every run, ensure the owner and group are set # correctly on the media directory/volume. - get_media_dir - chown -R ${WORKER_USER}:${WORKER_USER} "${MEDIA}" + get_writable_dirs + chown -R ${WORKER_USER}:${WORKER_USER} "${MEDIA}" "${CACHE}" } setup_sandbox() @@ -233,7 +235,7 @@ setup_debug() collect_static() { - get_media_dir + get_writable_dirs local IFS=, declare -a flags=(flist stats remove del) test -t 1 && flags+=(progress2) @@ -244,6 +246,7 @@ collect_static() --exclude-from=- \ --exclude='*.php' \ --exclude="${MEDIA}" \ + --exclude="${CACHE}" \ --exclude=/static/ \ --exclude=/vendor/ \ --force \ @@ -349,7 +352,7 @@ case "$1" in create_config setup_components setup_debug - setup_media + setup_writable collect_static generate_static setup_sandbox -- GitLab From 06fe7b705918f7668531e6b369f533365347a111 Mon Sep 17 00:00:00 2001 From: Dom Sekotill Date: Fri, 14 Jun 2024 14:46:44 +0100 Subject: [PATCH 2/3] Writable dirs implicitly made writable by collect_static in entrypoint --- scripts/entrypoint.sh | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 48d361a..406df6f 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -179,13 +179,7 @@ get_writable_dirs() ) MEDIA=${media:-${content}/uploads} CACHE=${content}/cache -} - -setup_writable() -{ - # UID values change on every run, ensure the owner and group are set - # correctly on the media directory/volume. - get_writable_dirs + mkdir -p "${MEDIA}" "${CACHE}" chown -R ${WORKER_USER}:${WORKER_USER} "${MEDIA}" "${CACHE}" } @@ -352,7 +346,6 @@ case "$1" in create_config setup_components setup_debug - setup_writable collect_static generate_static setup_sandbox -- GitLab From 9120581ff6fe689591de8b4d263a662056f40712 Mon Sep 17 00:00:00 2001 From: Dom Sekotill Date: Tue, 18 Jun 2024 17:03:21 +0100 Subject: [PATCH 3/3] Add tests for writable cache dir --- tests/configs/test-cache.php | 33 +++++++++++++++++++++++++++++++++ tests/regression-28.feature | 17 +++++++++++++++++ tests/steps/site.py | 11 +++++++++++ 3 files changed, 61 insertions(+) create mode 100644 tests/configs/test-cache.php create mode 100644 tests/regression-28.feature diff --git a/tests/configs/test-cache.php b/tests/configs/test-cache.php new file mode 100644 index 0000000..a01188b --- /dev/null +++ b/tests/configs/test-cache.php @@ -0,0 +1,33 @@ + WP_REST_Server::READABLE, + 'callback' => function($request) { + if ( !isset($request['file']) ) { + return new WP_Error('Missing param file'); + } + $file = WP_CONTENT_DIR . "/cache/{$request['file']}"; + file_put_contents($file, "Generated file"); + return rest_ensure_response( "Cache file created" ); + }, + 'args' => array( + 'file' => array( + 'description' => 'File to touch on the server host', + 'type' => 'string', + ) + ) + )); +}); + +/* register_activation_hook( __FILE__, function() { */ +/* if ( !defined('WP_CLI') && $_SERVER['REQUEST_URI'] == '/test-cache' ) { */ +/* $file = WP_CONTENT_DIR . "/cache/${_GET['file']}"; */ +/* file_put_contents($file, "Generated file"); */ +/* wp_die("Cache file created", 200); */ +/* } */ +/* }); */ diff --git a/tests/regression-28.feature b/tests/regression-28.feature new file mode 100644 index 0000000..c978863 --- /dev/null +++ b/tests/regression-28.feature @@ -0,0 +1,17 @@ +@wip +Feature: Page cache directory + Ensure that the page cache directory at WP_CONTENT_DIR/cache is writable for + plugins, but is not served by the server. + + Scenario: After the entrypoint has completed, there is a writable cache dir + Given the site is not running + And test-cache.php is mounted in /app/wp-content/mu-plugins/ + When the site is started + And /wp-json/test/v1/write-cache?file=foo.txt is requested + Then OK is returned + And /app/wp-content/cache/foo.txt exists in the backend + + Scenario: The contents of the cache dir are not served by the proxy + Given /app/wp-content/cache/foo exists in the backend + When /wp-content/cache/foo is requested + Then Not Found is returned diff --git a/tests/steps/site.py b/tests/steps/site.py index 2dbcbae..3a14a81 100644 --- a/tests/steps/site.py +++ b/tests/steps/site.py @@ -231,6 +231,17 @@ def is_plugin_installed( assert site.backend.cli(addon.value, "is-active", name, query=True) == status.value +@then("{path:Path} exists in the {container_name}") +def check_file_exists(context: Context, path: Path, container_name: str) -> None: + """ + Check a file exists in the named container + """ + site = use_fixture(site_fixture, context) + container = getattr(site, container_name) + assert container.run(["sh", "-c", f"test -e {path}"]).returncode == 0, \ + f"{path} not found in the {container_name}" + + @then("the email address of {user} is \"{value}\"") @then("the email address of {user} is '{value}'") def is_user_email(context: Context, user: str, value: str) -> None: -- GitLab