Skip to content

fix: keep the site fragment sync within the configured static site and repository - #21

Open
YvesCesar wants to merge 1 commit into
mainfrom
fix/validate-site-fragment-sync
Open

YvesCesar wants to merge 1 commit into
mainfrom
fix/validate-site-fragment-sync

Conversation

@YvesCesar

Copy link
Copy Markdown
Member

What was wrong

The site deploy webhook copies the header and footer fragments of the static site into wp-content/uploads. Several values used by that sync came from the fetched content without being checked:

  • The data-fragment-css and data-fragment-js URLs were fetched with wp_remote_get, whatever their host, so the sync could request internal addresses (private networks, loopback, cloud metadata) and store the response in a public uploads folder.
  • Locales read from the links of the default header were URL-decoded and joined into the storage path without validation, so a locale containing ../ wrote the fragment files into another existing folder.
  • After the sync, the pull request comment used the repository field of _deployment-info.json to build the GitHub API path, so the deploy token could post to another repository or endpoint.
  • The stored fragments were deleted before the new ones were written, so a sync that failed while writing left the site without them.
  • LIBRESIGN_GITHUB_WEBHOOK_SECRET was read after the theme setting, so the secret could not be enforced from the environment.

What changed

  • Asset URLs are accepted only when scheme, host and port match the configured origin; root-relative URLs are resolved against it. Fragments are fetched with wp_safe_remote_get, and only the configured origin's host and port are allowed while the request runs, so a local static site still works in development and redirects are checked the same way.
  • SiteFragment::language_tag() only returns tags matching ^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$. Fragments are written to a staging folder and each locale folder must resolve directly inside it; the stored fragments are replaced only after every artifact has been written, and kept when the sync fails.
  • The comment always goes to the configured repository, which must match owner/name.
  • LIBRESIGN_GITHUB_WEBHOOK_SECRET now takes precedence over the theme setting.

Verification

  • New unit and integration tests for each item above; they fail on main and pass with the change.
  • composer ci green locally on PHP 8.3: lint, PHPCS, PHPStan, 162 unit and 174 integration tests (also with --order-by=random).
  • On a local install, the sync functions were run with all outgoing HTTP answered by a pre_http_request filter and uploads redirected to a temporary folder. Before the change, an internal URL was fetched and stored, a crafted locale wrote outside the fragments folder, a failed write removed the stored fragments, and the comment went to the repository named in _deployment-info.json. After the change, none of these happen.

…d repository

Signed-off-by: YvesCesar <yvesamorim73@gmail.com>
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.

1 participant