Skip to content

fix: pin plugin and theme sources and clone them as www-data - #45

Open
YvesCesar wants to merge 1 commit into
mainfrom
fix/pin-setup-sources
Open

YvesCesar wants to merge 1 commit into
mainfrom
fix/pin-setup-sources

Conversation

@YvesCesar

Copy link
Copy Markdown
Member

Depends on #44 (based on its branch, reuses its entrypoint test helper).

The setup YAML could only point at moving targets: wordpress_custom_plugins and wordpress_custom_themes were cloned from the default branch, wordpress_archive_plugins installed whatever the URL returned and wordpress_org_plugins took the latest release. Nothing recorded or checked what ended up in wp-content, and the clone ran as root.

Changes

  • wordpress_custom_plugins and wordpress_custom_themes accept an optional ref (tag or full commit SHA). The repository is cloned as www-data, the ref is fetched from the configured source and checked out detached. For a SHA, HEAD is verified and a plugin that does not match is not activated. An existing checkout whose HEAD differs from the ref is moved to it.
  • wordpress_archive_plugins accepts sha256: the archive is downloaded, checked and installed from the local file; a mismatch skips the plugin.
  • wordpress_org_plugins accepts a mapping with slug and version; an installed plugin at another version is reinstalled at the pinned one. Plain slugs keep working.
  • Entries without a pin are reported in the log. WORDPRESS_SETUP_REQUIRE_PINNED=1 skips them instead (passed through common-services.yml, default 0).
  • README shows the new fields.

Tests

tests/security/pinned-setup-sources.bats runs the real entrypoint in the published image with a stubbed wp and local Git and archive sources: commit and tag pins, a commit that cannot be fetched, moving an existing checkout, a pinned theme, the unpinned warning, WORDPRESS_SETUP_REQUIRE_PINNED=1, a pinned wordpress.org version, and archives with a matching and a wrong checksum. 9 of the 10 cases fail on the base branch (the remaining one, "not activated when the commit cannot be checked out", passes there only because the clone itself fails). bats tests/security: 33/33; ShellCheck clean.

On a fresh stack with WooCommerce and WORDPRESS_SETUP_REQUIRE_PINNED=1: a GitHub plugin pinned to a commit is cloned at that commit, owned by www-data and activated, an unpinned one is skipped, WooCommerce pinned to the installed version is left alone, and login, wp-admin, /wp-json/, wp-cron.php, checkout and My Account keep working.

Base automatically changed from fix/local-only-password-reset to main November 14, 2026 14:22

@vitormattos vitormattos left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renovate is already configured in renovate.json, but its only custom manager currently tracks WORDPRESS_BASE_IMAGE in the Docker publishing workflow. The new version, ref, and sha256 fields introduced here are not covered.

Could we extend the existing Renovate configuration to track real, version-controlled plugin and theme declarations, and validate dependency detection and update proposals with a dry run? WordPress.org plugin versions and Git tags/refs need appropriate data sources; archive URLs and SHA-256 values must only be updated together when a trustworthy checksum is available.

The values in the README and Bats tests are examples/fixtures and should not be treated as production dependencies. Since WORDPRESS_SETUP_CONFIG_YAML can be supplied externally, please also clarify where the actual dependency declarations will live and how Renovate can access them. Otherwise, adding a manager that only detects example values would not solve the maintenance problem.

allow_unpinned_entry "Plugin $plugin_slug" || return 0
fi

if runuser -u www-data -- wp plugin is-installed "$plugin_slug" 2>/dev/null; then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

install_plugin_archive() returns immediately if the plugin is already installed, before checking the configured archive or checksum. If the pinned archive URL/SHA-256 is updated, subsequent starts silently retain the old installed plugin, so even a future Renovate update would not be applied.

Could we reconcile the installed artifact when the configured pin changes, or explicitly document that archive pins only control first-time installation? Please cover two successive starts with different archive pins and verify the intended installed version or artifact identity.

cd /var/www/html/wp-content/plugins/
if git clone "$git_url" "$plugin_name" 2>/dev/null; then
echo " ✓ Plugin $plugin_name cloned"
runuser -u www-data -- git -C "$target_dir" fetch --quiet "$git_url" "$git_ref" || return 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git tags are mutable, but ref is currently treated as a pin even when it names a tag. Re-fetching that tag can resolve to a different commit without any change to the configured ref.

Could we distinguish immutable full-commit-SHA pins from movable tag references in the strict pinning policy? Either require commit SHAs for strict reproducibility or explicitly document the weaker guarantee of tags. A test that moves a tag between starts would make the expected behavior clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants