Files
RustProxy/docs/TEST_REPORT.md
T
2026-10-04 16:47:24 +02:00

15 KiB

Verification report - RustProxy 0.25.2

Scope

RustProxy 0.25.2 is a focused live-backup, backup-symlink and resumed-admin-session hardening release on top of the 0.25.1 source tree. Web Services are independent configuration resources; vhosts and custom locations only choose a source type and reference a Web Service ID. The current development tree provides static GET/HEAD streaming, directory/index behavior, validators, single ranges, document-root confinement, ordered try_files, Web Service rewrites, a bounded migration-oriented .htaccess compatibility layer, expanded MIME policy, per-extension/MIME Cache-Control rules, fixed source headers, precompressed sidecars, forced-download extensions and optional bounded FastCGI/PHP-FPM. The Web Service editor is organized into General, Routing, .htaccess, MIME, Cache & headers, Delivery, PHP-FPM and Security tabs, with one-shot presets for Static/SPA/PHP/WordPress/Drupal/Laravel/Symfony/Joomla/PrestaShop/Downloads. Existing 0.25 work also includes repeatable directory listing, Web Server vhost-wide metrics, Logging sub-tabs, corrected structured-log source validation, bounded per-vhost Traffic analytics with effective-client-IP rankings/donut charts, User-Agent/optional-country logging, stable Web Service rendering after fast refreshes, generic/customizable 403 handling and automatic RSS relief for reclaimable allocator/HOT-cache memory. The /docs surface separates the Markdown Reader from API/OpenAPI and documents the implemented PHP-FPM runtime.

Source contracts reviewed

  • Config.web_services is a separate persisted collection; vhost/location source defaults to Reverse Proxy for old documents and Web Server stores only web_service_id.
  • Full configuration compilation validates Web Service IDs, absolute/existing document roots, index names, duplicate IDs and every active Web Service reference. A pure static vhost does not require a backend pool; mixed Web Server and Reverse Proxy locations do.
  • Web Server dispatch occurs after normal frontend routing, ACL and Basic/Tinyauth authorization and before backend selection/DNS/cache/upstream work. Static responses continue through the existing custom error-page, response-header/security, compression and transport pipeline.
  • Static files use streamed Tokio file bodies with explicit lengths rather than whole-file buffering.
  • Files support metadata-based ETag/Last-Modified, If-None-Match/If-Modified-Since, one Range/If-Range and 304/206/416 behavior.
  • Directory requests redirect to a slash path, then search the optional ordered index list (which may be empty), then optionally render an HTML-escaped and URL-encoded RustProxy-styled listing without exposing filesystem paths.
  • Root directory listing opens a fresh directory file description per request rather than a dup sharing the persistent root descriptor offset; a regression test requests the same listing twice. Nested directories independently apply index lookup first and listing fallback only when no index exists. Generated listings send Cache-Control: no-store.
  • A directory with no matching index and directory listing disabled returns the built-in generic 403 page (or the configured vhost/global 403 replacement in the outer response pass), not a Web Server implementation-detail string. HEAD keeps an empty body.
  • Web Services support up to 64 normalized MIME overrides, a validated fallback MIME header and an optional validated default Cache-Control header. Static files remain backed by the filesystem/OS page cache; existing vhost/location response-header rules run later and can override the source-level cache policy.
  • Web Services additionally support ordered ext:/mime: Cache-Control rules, validated fixed response headers, ordered try_files, regex internal/redirect rewrites, precompressed .br/.gz sidecars and attachment extensions. Protected framing/transport headers cannot be overridden by the source header map.
  • Optional .htaccess compatibility compiles a bounded root/subdirectory set at Web Service Apply time rather than parsing per request. It supports common RewriteRule/RewriteCond front controllers, DirectoryIndex/Indexes, AddType, Header, Expires, PHP AddHandler and simple Require all granted/denied. Unsupported access/handler scopes fail closed, .ht* control files are never served, and PHP AddHandler requires PHP-FPM.
  • Web Service presets are UI-only generators: they populate ordinary configuration fields and do not persist a hidden CMS mode. ID/name/document root and PHP-FPM endpoint/tuning remain operator-owned. Optional hardening is persisted explicitly and defaults off for compatibility.
  • block_common_attacks rejects TRACE/CONNECT/TRACK, sensitive dot/control/backup paths and a bounded set of high-confidence exploit probes; it also suppresses FastCGI HTTP_PROXY derivation from the inbound Proxy header. It does not claim generic WAF/SQLi/XSS filtering.
  • strip_unnecessary_headers removes common source/PHP fingerprint headers after Web Service and .htaccess response handling while leaving the later vhost/location response-header pipeline authoritative.
  • Optional PHP handling executes configured extensions through a bounded FastCGI connector over Unix socket or loopback TCP. PHP concurrency uses a fixed semaphore without an unbounded wait queue, request/response bodies use bounded streaming, and connection failure cannot fall back to serving PHP source. Advanced configuration adds Authorization forwarding control, a streaming request-body ceiling, bounded CGI response headers/stderr, trusted custom FastCGI parameters and validated PHP_VALUE overrides that cannot replace core CGI/HTTP fields or PHP_ADMIN_VALUE.
  • Web Service symlink policy defaults to deny/O_NOFOLLOW; Linux-only inside_root verifies opened descriptors through /proc/self/fd against the canonical root. PHP-FPM is intentionally limited to deny because the external worker reopens SCRIPT_FILENAME.
  • Routing rejects malformed/ambiguous encoded paths before filesystem lookup. Unix filesystem lookup walks from an opened root descriptor; deny uses openat + O_NOFOLLOW, while Linux-only inside_root verifies every opened descriptor against the canonical root. PHP-FPM requires deny. The secure Web Server compile path remains Unix-only.
  • No second URL router, custom-error subsystem or object cache was introduced. Reverse Proxy remains the default source for existing configuration.
  • Dashboard CRUD, source selectors, English/Polish strings and OpenAPI schemas expose the new model.
  • Web Service index files are optional (0..16). An empty list skips index lookup, allowing directory-listing-only services without synthetic index names.
  • Generated directory listings use a self-contained RustProxy panel-style layout (matching palette/typography, responsive light/dark treatment and RustProxy footer) while preserving HTML escaping, URL encoding and filesystem-path secrecy.
  • Pure Web Server vhosts no longer present backend diagnostics as though an origin pool existed; their Backends summary identifies Web Server, while mixed static/proxy vhosts retain backend diagnostics.
  • Status payloads expose fixed-cardinality per-vhost metrics independently of backend pools. The Vhosts dashboard uses those counters for Web Server-only request/active/error values, EWMA latency and byte-rate traffic while retaining backend health details for reverse-proxy sources.
  • Logging settings are split into Outputs, JSON format and Error log sub-tabs inside one card, matching the Cache subsection layout. route, cache_effective_enabled and transform_effective_enabled are accepted by the same backend validator that saves custom JSON mappings, and the regression test validates then renders those fields.
  • Structured logging now exposes user_agent and country. User-Agent capture defaults on; country capture defaults off and GeoIP resolution is skipped unless capture or an existing country ACL/rate-limit needs it.
  • The authenticated Traffic workspace uses a bounded 2048-sample non-blocking queue, at most 64 vhost buckets and 32-entry approximate top tables for countries, User-Agents, effective client IPs, paths, routes, methods, status classes and cache outcomes. It never writes per-request analytics to SQLite. The Traffic UI is split into Overview, Clients, Requests and Delivery sub-tabs. Countries/methods/status/cache use donut summaries; User-Agent, effective client IP, path, route and request/response byte volume use bounded horizontal bar charts from the same in-memory TOP state.
  • Sustained-traffic memory maintenance calls malloc_trim(0) every 60 seconds on Linux/glibc to release already-free allocator pages and trims HOT objects only when above the configured waterline and idle past the configured age. It does not periodically reload vhosts, purge active objects or reset bounded upstream keep-alive pools.
  • Cache compatibility currently includes vhost configuration, so a cache-affecting vhost save can purge cache during snapshot publication; replacing the compiled snapshot also retires its upstream clients after outstanding references drain. These mechanisms explain why a manual vhost save can visibly reduce RSS without implying that reloads are required for steady-state operation.
  • The Web Server list now uses the same vhost card/detail-cell visual structure as the Vhosts list. Reverse Proxy vhost creation reports a dedicated “at least one backend” validation error instead of the generic paths/ACL/headers JSON error.
  • Web Service cards use only the shared el(...) DOM helper; a regression contract rejects the previous undefined text(...) call that aborted list rendering. Authenticated-shell startup now verifies /api/auth/session first and never reveals the legacy embedded sign-in form for non-authentication JavaScript/API failures, preventing F5 from falsely presenting the user as logged out.
  • The Web Server UI module performs a catch-up render when it registers after app.js; this closes the race where a very fast /api/config response could finish before web-server.js existed and leave the Web Service list blank until a later render.
  • The Web Service editor now builds its configuration tabs with the same vh-tabs + quiet button pattern and active/ARIA state handling as the Vhost editor; the source contract also checks this shared modal-tab pattern and invalid-field navigation switches to the owning tab.
  • Static dispatch clones only Method, HeaderMap and Uri before awaiting the filesystem source; it does not hold &Request<Body> across an await, keeping the Axum 0.8 fallback handler future Send. This addresses the reported Handler<_, _> / E0277 failure at .fallback(forward).
  • /docs is an authenticated documentation surface with a Markdown Reader, searchable embedded docs bundle and a separate API/OpenAPI tab. Reader Markdown files are direct include_str! compiler inputs and no longer depend on a generated OUT_DIR/docs-content.json, preventing clean/incremental builds from failing on a missing documentation artifact.
  • Documentation cleanup keeps README and the active ROADMAP current-only; operator release history, developer-level changelog history and completed roadmap milestones are separated into CHANGELOG/audit/archive documents.

Implemented automated coverage

Rust unit tests in src/web_server/tests.rs cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, try_files, rewrite redirect/internal behavior, .htaccess WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. src/traffic/tests.rs includes bounded-table and effective-client-IP view coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. ACL tests include encoded traversal/separator/malformed-encoding cases.

Rust-independent release checks additionally validate UI/JSON/language/source contracts and reproducible packaging.

Modular source-tree verification

  • python3 scripts/rust_module_contracts.py: PASS. Every repository .rs file is at most 500 lines.
  • python3 scripts/source_module_contracts.py: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational deploy/NPM-migration Python modules are at most 500 lines; Docker tests remain in _test.go, and browser split boundaries/public bundles parse with Node when available.
  • Oversized app.js/vhosts.js source is split while the public /assets/app.js and /assets/vhosts.js URLs remain stable; the Docker Agent is split into model/Docker/network/certificate/server/entry-point files.
  • Rust unit-test bodies are isolated under tests.rs / tests/; implementation files contain only guarded test includes/declarations.
  • All include!("*.rs") targets resolve, split fragments have balanced delimiters, and no fragment ends in a dangling Rust attribute or doc comment.
  • Regression guards cover the Web Server split errors previously observed around #[derive], htaccess, server_protocol and anyhow::Context.
  • This is a compiler-independent structural check; Cargo parsing/type checking remains a release-host requirement when the Rust toolchain is unavailable in the packaging environment.

Verification status in this workspace

Check Status
python3 scripts/langs_check.py PASS
python3 scripts/docs_check.py PASS
python3 scripts/memory_contracts.py PASS
python3 scripts/web_server_contracts.py PASS
Browser JavaScript node --check PASS for split app source, vhost split boundaries/public bundle, Settings, Docs Reader, Web Server and Traffic
OpenAPI/language JSON parse PASS
Shell bash -n PASS in source/release checks
go test ./... in docker-agent PASS
Python source parsing/contract checks PASS
python3 scripts/check_source.py PASS
python3 scripts/release_smoke.py PASS
./dev.sh test Rust-independent phases PASS; Rust phase BLOCKED because Cargo is unavailable
cargo fmt --all / ./dev.sh fmt BLOCKED: Rust/Cargo toolchain unavailable in this workspace
cargo check --locked --all-targets / ./dev.sh check BLOCKED: Rust/Cargo toolchain unavailable in this workspace
cargo test --locked --all-targets / Rust phase of ./dev.sh test BLOCKED: Rust/Cargo toolchain unavailable in this workspace
Live H1/H2/H3 Web Server integration and large-file acceptance release-host acceptance gate

The source package therefore has static/source-contract verification here, but compiler-enabled and live transport acceptance must still be run on the release host before production release.