Skip to content

Add asset proxy for all included webroot assets#112

Merged
alexander-zierhut merged 3 commits intozubzet:mainfrom
alexander-zierhut:feature/asset-proxy
Apr 21, 2026
Merged

Add asset proxy for all included webroot assets#112
alexander-zierhut merged 3 commits intozubzet:mainfrom
alexander-zierhut:feature/asset-proxy

Conversation

@alexander-zierhut
Copy link
Copy Markdown
Contributor

@alexander-zierhut alexander-zierhut commented Apr 17, 2026

Summary

Adds an asset proxy so framework-included webroot assets (CSS, JS) are served directly from framework_root/IncludedComponents/assets/ instead of having to be copied into each project's webroot. Projects register additional sources via zubzet()->assetProxy->registerWebRootSource($path).

Includes PR #133 (merged in): adds $res->json() as a first-class Response helper — sends raw JSON with Content-Type: application/json, applies JSON_THROW_ON_ERROR, and does not exit. Used by the AssetProxy e2e controller for cleanliness.

Security hardening

Review on the initial commit surfaced several unsafe paths in AssetProxy::serve(). All are now guarded and covered by e2e regressions:

  • Path traversalrealpath() resolution + str_starts_with($resolved, $source . DIRECTORY_SEPARATOR) boundary check. Catches literal ../, URL-encoded %2e%2e%2f, sibling-prefix (webroot_security.txt next to webroot/), and symlink escapes.
  • Source-root resolution — inputs like "", ".", "./" that realpath() collapses to the source directory itself are rejected by the boundary check (the resolved path equals the source without the trailing separator).
  • Directory requestsis_file() check before readfile() so a directory path doesn't crash; returns 404.
  • Null-byte injection — PHP 8's realpath() rejects null bytes natively; the fatal bubbles up and the masked extension trick (file.txt\0.png) cannot expose the real file.
  • Unknown MIME typesFinfoMimeTypeDetector returns null for empty or unclassified files; falls back to application/octet-stream instead of emitting a malformed header.

Tests

tests/e2e/tests/cypress/e2e/core/asset-proxy.cy.js — 14 cases covering both the production route (/_zubzet/asset-proxy/...) and an isolated AssetProxyController that drives controlled inputs (null bytes, empty paths, symlinks) which the URL layer can't carry cleanly. Fixtures live in tests/e2e/webroot/assets/ and tests/e2e/webroot_security.txt (the sentinel used to detect content leakage).

Test plan

  • /_zubzet/asset-proxy/js/Z.js returns 200 with Content-Type: application/javascript.
  • /_zubzet/asset-proxy/css/bootstrap.min.css returns 200 with text/css.
  • /_zubzet/asset-proxy/../../../../webroot_security.txt and the URL-encoded equivalent do not leak the sentinel.
  • /_zubzet/asset-proxy//etc/passwd does not expose host files.
  • Symlink inside source pointing outside is rejected.
  • Directory path returns 404, doesn't crash.
  • Unknown-extension file returns application/octet-stream.
  • Null-byte suffix does not unmask the real extension.
  • Empty / . / ./ inputs do not dump the source directory.

Merge order

  1. Add $res->json() method for JSON responses #133$res->json() helper into this branch (merged)
  2. This PR → main

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a framework-level asset proxy endpoint for serving bundled “IncludedComponents” static assets, updates the default layout essentials to load JS/CSS via that proxy, and removes duplicated vendored webroot assets from the e2e fixture.

Changes:

  • Add /_zubzet/asset-proxy/{assetPath} route and an AssetProxy service to serve framework assets from src/IncludedComponents/assets.
  • Update layout essentials to reference assets through the new asset proxy URL scheme.
  • Include framework route files automatically and refactor booter settings access into a reusable trait; add MIME type detection dependency.

Reviewed changes

Copilot reviewed 16 out of 36 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/e2e/webroot/assets/js/popper.min.js Remove vendored test webroot JS (now served via framework asset proxy).
tests/e2e/webroot/assets/js/jquery.csv.js Remove vendored test webroot JS (now served via framework asset proxy).
tests/e2e/webroot/assets/js/bs-custom-file-input.js Remove vendored test webroot JS (now served via framework asset proxy).
tests/e2e/webroot/assets/js/bootstrap.min.js Remove vendored test webroot JS (now served via framework asset proxy).
tests/e2e/webroot/assets/js/Z.js Remove vendored test webroot JS (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-solid-900.woff2 Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-solid-900.woff Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-solid-900.ttf Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-solid-900.eot Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-regular-400.woff2 Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-regular-400.woff Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-regular-400.ttf Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-regular-400.eot Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-brands-400.woff2 Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-brands-400.woff Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-brands-400.ttf Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/webfonts/fa-brands-400.eot Remove vendored test webroot font (now served via framework asset proxy).
tests/e2e/webroot/assets/css/font-awesome/v4-shims.min.css Remove vendored test webroot CSS (now served via framework asset proxy).
tests/e2e/webroot/assets/css/font-awesome/fontawesome.min.css Remove vendored test webroot CSS (now served via framework asset proxy).
tests/e2e/webroot/assets/css/font-awesome/brands.min.css Remove vendored test webroot CSS (now served via framework asset proxy).
src/ZubZet.php Instantiate/register the asset proxy and add booter-settings trait usage.
src/Support/GlobalReferences.php Update config() helper to use booter instance settings retrieval.
src/Routing/Router.php Include both user route files and framework-provided IncludedComponents route files.
src/Resources/AssetProxy.php New service to resolve and stream assets from configured webroot sources.
src/Message/RequestResponseHandler.php Replace in-class booter settings accessor with shared trait.
src/IncludedComponents/views/layout/layout_essentials.php Switch default JS/CSS URLs to go through /_zubzet/asset-proxy/....
src/IncludedComponents/routes/DefaultRoutes.php New default route group exposing the asset proxy endpoint.
src/Core/CanRetrieveBooterSettings.php New trait centralizing getBooterSettings() logic.
composer.lock Lockfile updates for new dependency and platform metadata changes.
composer.json Add league/mime-type-detection dependency used by the asset proxy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ZubZet.php
Comment thread src/Resources/AssetProxy.php
Comment thread src/Resources/AssetProxy.php
Comment thread src/Resources/AssetProxy.php Outdated
@alexander-zierhut alexander-zierhut merged commit ef8ec95 into zubzet:main Apr 21, 2026
6 checks passed
@alexander-zierhut alexander-zierhut deleted the feature/asset-proxy branch April 21, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request #module-render

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants