daggerhart-openid-connect-generic calls wp_remote_post() against http://auth.<onion>/.../token, which bottoms out in libcurl -- and libcurl refuses a .onion host at name resolution (RFC 7686) before /etc/hosts, extra_hosts or DNS is consulted. The result is cURL error 6, which WordPress turns into WP_Error('http_request_failed') and a bounce to /wp-login.php?login-error=http_request_failed. Five specs of WordPress 0 in run 31340965955 failed on that single cause, 60 occurrences in the log. Only a configured proxy makes curl skip the check, and socks5h:// hands the name to Tor. The mu-plugin hooks http_api_curl because http_request_args cannot express a proxy and WP core's WP_HTTP_Proxy hardcodes CURLPROXY_HTTP, so SOCKS5 is reachable only on the raw handle. env.j2 sets WORDPRESS_OIDC_SOCKS_PROXY only when the issuer is an onion, so a clearnet deployment never routes through Tor. Deliberately not adding the onion_oidc_socks include:238b8b41festablished it is a no-op for this client, since libcurl never reads /etc/hosts here. Depends on1bb31fba4-- without it swarm renders socks5h://host.docker.internal, which is unreachable from inside the overlay. The plugin's behaviour is unexercised: syntax checked, never run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.5 KiB
WordPress Must-Use Plugins 🔒
Scope 🎯
This directory holds PHP files that the web-app-wordpress role copies into the running container at /var/www/html/wp-content/mu-plugins/.
mu-plugins is a WordPress core convention for must-use plugins. WordPress automatically loads every top-level *.php file in that directory before normal plugins, without a database activation record. As a result, code shipped here:
- MUST be loaded on every request as soon as the file is present.
- MUST NOT be deactivated from the
Plugins -> Must-Useadmin screen. - MUST NOT be placed in a subdirectory, because WordPress does not recurse into
mu-plugins.
See the WordPress Must-Use Plugins handbook for the upstream contract.
When to add code here 📋
Put a file in this directory only when the behavior it implements is part of the security or integration contract of this role and MUST remain in effect for every request. Everyday feature plugins SHOULD stay in normal wp-content/plugins/ and be managed through 05_enable_plugin.yml so operators can disable them per site if needed.
Each file in this directory SHOULD declare its purpose and the hooks it registers at the top of the file so readers can understand why it cannot be switched off.
OIDC -> RBAC mapping (infinito-oidc-rbac-mapper.php) 🎫
infinito-oidc-rbac-mapper.php implements the OIDC -> WordPress role contract:
- Single-Site path: the claim MUST contain
/roles/web-app-wordpress/<role>entries. The highest-privilege role across all matches wins (administrator > editor > author > contributor > subscriber). When no entry matches, the user's role is set tosubscriberas a deterministic fallback. - Multisite path (auto-detected via
is_multisite()): per-site roles come from/roles/web-app-wordpress/<canonical-domain>/<role>entries; the super-admin capability comes from/roles/web-app-wordpress/network-administrator. The mapper adds the user to any site they have a role for (add_user_to_blog) and removes them from sites it previously added them to (remove_user_from_blog) when a role for that site disappears from the claim. A user-meta marker (_infinito_oidc_added_blog_ids) records which blog memberships the mapper owns, so memberships added throughwp-adminor the REST API outside the OIDC flow are never touched.
For the broader RBAC contract (LDAP layout, rbac.tenancy schema, the rbac_group_path lookup plugin), see rbac.md.
HTTP CA trust (infinito-http-ca-trust.php) 🔐
infinito-http-ca-trust.php points WordPress's HTTP API at the deployment's CA bundle so outbound calls to internal HTTPS endpoints (OIDC discovery, REST loopback) verify instead of failing.
HTTP onion SOCKS (infinito-http-onion-socks.php) 🧅
infinito-http-onion-socks.php sends server-side wp_remote_* calls whose host ends in .onion through the Tor SOCKS proxy named by WORDPRESS_OIDC_SOCKS_PROXY, which env.j2 sets only when the OIDC issuer is an onion, so a clearnet deployment never routes through Tor.
It hooks http_api_curl rather than http_request_args because the args array cannot express a proxy: WordPress core's WP_HTTP_Proxy hardcodes CURLPROXY_HTTP, so SOCKS5 is reachable only on the raw cURL handle. Without it, libcurl refuses an .onion host at name resolution under RFC 7686 — before /etc/hosts, extra_hosts or DNS is consulted — and the token exchange fails with cURL error 6, which WordPress surfaces as wp-login.php?login-error=http_request_failed.
Deployment 🚚
Every file here is declared as an addon under meta/addons/ with mechanism: mu_plugin and source: vendored, and the addon id is the file stem. 04_mu_plugins.yml loops over those declarations and copies <addon_id>.php into the container on every deploy; a new file therefore needs its meta/addons/<addon_id>.yml entry and a Playwright spec before it is installed.
Credits 🙏
Developed and maintained by Kevin Veen-Birkenbach. Learn more at veen.world. Part of the Infinito.Nexus Project. Licensed under the Infinito.Nexus Community License (Non-Commercial).