12 KiB
RustProxy 0.25.0 specification audit
This document maps every numbered section of the RustProxy 0.25 plan to the implementation. It distinguishes implemented source from release-host runtime verification. The workspace used for this package has no Rust/Cargo toolchain, so no compiler or live H1/H2/H3 result is claimed here.
Status legend:
- IMPLEMENTED - the required source/configuration/UI/documentation exists and Rust-independent contracts pass.
- RELEASE GATE - implementation exists, but compiler/runtime acceptance still has to run on a Rust-enabled host.
Sections 1-22
| Spec section | Status | Implementation / evidence |
|---|---|---|
| 1. Goal of 0.25 | IMPLEMENTED | Web Server is integrated as a source in the existing proxy request pipeline rather than as a second HTTP server. |
| 2. Target concept | IMPLEMENTED | CompiledSource selects Reverse Proxy or Web Server; Reverse Proxy remains the default for old/missing source fields. |
| 3. Separate Web Service | IMPLEMENTED | Config.web_services contains reusable web_server::Service objects independent of vhosts. |
| 4. Attach service to vhost | IMPLEMENTED | Vhost/location Source::WebServer stores only web_service_id; filesystem settings remain in the service. |
| 5. Full usage flow | IMPLEMENTED | Dashboard workflow is Web Server -> create service -> Vhosts -> select Web Server -> select service. |
| 6. Reuse one service | IMPLEMENTED | One Web Service can be referenced by multiple vhosts/locations; a dedicated configuration test covers two vhosts using the same service. |
| 7. Locations integration | IMPLEMENTED | Existing location matcher selects static/proxy source; one vhost can mix / static and /api reverse proxy without a second URL router. |
| 8. First-stage configuration | IMPLEMENTED | Model, validation, normal revisioned storage, section API and CRUD UI are present. No SQLite schema migration is needed because the existing serialized configuration document stores web_services. |
| 9. Static File Server | IMPLEMENTED | GET/HEAD, expanded built-in + per-service MIME, Content-Length, streamed bodies, directories, ordered static/PHP index files, slash redirect, listing, precompressed sidecars and forced-download policy are implemented. |
| 10. Directory Listing | IMPLEMENTED | Service-level switch defaults OFF; listing escapes HTML, percent-encodes names/URLs, distinguishes directories and does not reveal filesystem paths. Each request uses a fresh directory description so refreshes do not inherit an exhausted readdir offset; generated listings send Cache-Control: no-store. Disabled listing returns a normal error that remains eligible for the existing custom-error pipeline. |
| 11. Index | IMPLEMENTED | The ordered index list is optional (0..16). Every requested directory checks configured names in order and serves the first regular file; only that directory's empty/no-match result falls through to listing/error policy. |
| 12. HTTP validators | IMPLEMENTED | Metadata-derived ETag/Last-Modified and If-None-Match/If-Modified-Since -> 304 are implemented without hashing full files. |
| 13. Range | IMPLEMENTED | Single byte Range, If-Range, Accept-Ranges, Content-Range, 206 and 416 are implemented for the selected static/precompressed representation; multipart ranges remain intentionally outside the current scope. |
| 14. Filesystem security | IMPLEMENTED | Routing rejects malformed/ambiguous encoding and dot segments. Default Unix access uses openat + O_NOFOLLOW; Linux can optionally follow a symlink only when each opened descriptor resolves inside the canonical root. PHP-FPM requires the deny policy. |
| 15. Existing RustProxy architecture | IMPLEMENTED | Host/location routing, ACL, Basic Auth/Tinyauth, response/security headers, custom error pages, compression and H1/H2/H3 transport stay in the existing outer pipeline. |
| 16. Cache | IMPLEMENTED | No Web Server object cache was added. Static files use filesystem/OS page cache and HTTP validators/ranges. Web Services support a default Cache-Control plus ordered ext:/mime: rules; existing vhost/location response-header rules apply later. Reverse Proxy cache remains unchanged. |
| 17. Tests | IMPLEMENTED / RELEASE GATE | Rust unit/integration source plus Rust-independent source/UI/docs contracts cover static behavior, configuration, security and integration ordering. Rust tests cannot be executed here without Cargo; live H1/H2/H3 acceptance is still required. |
| 18. Future extensibility | IMPLEMENTED | try_files, Web Service rewrites, bounded .htaccess migration compatibility and bounded FastCGI/PHP-FPM were added without changing the Web Service / source-selection architecture. Remaining follow-up is limited to named locations, optional PATH_INFO, multipart Range, full Apache compatibility and non-Unix confinement. |
| 19. Documentation cleanup | IMPLEMENTED | docs/README.md is canonical; functional, admin/operations, development/testing, technical, audits and historical records are separated. Duplicated historical release notes were removed from README, completed roadmap history was moved to docs/ROADMAP_HISTORY.md, and /docs embeds the Markdown set in Reader. |
| 20. CHANGELOG | IMPLEMENTED | Root CHANGELOG is now operator-facing. Pre-cleanup compiler/refactor/test detail is preserved separately in docs/CHANGELOG_TECHNICAL_ARCHIVE.md. |
| 21. README / Docs / Reader | IMPLEMENTED | README now describes the current 0.25 release instead of duplicating release history; ROADMAP contains active/future work with completed milestones archived. The docs index, Reader/API split, local Markdown links and current version references are checked automatically. Migration history includes 0.24.10 -> 0.25.0. |
| 22. Definition of Done | IMPLEMENTED / RELEASE GATE | All source/documentation items below are implemented; compiler/runtime and live transport acceptance remain the only unexecuted release gate in this workspace. |
Definition of Done - item by item
- Dedicated Web Server administration section exists.
- Web Service can be created.
- Document root is configurable.
- Ordered index-file list is configurable.
- Directory listing can be enabled/disabled and defaults to disabled.
- Web Service can be edited and deleted; referenced deletion is rejected by validation and blocked in the UI.
- Existing vhost/source configuration offers
Reverse Proxy/Web Server. - Selecting Web Server offers an existing Web Service reference.
- Vhost does not store document root/index/listing copies.
- One Web Service can be reused by more than one vhost.
- Web Server uses the existing locations system.
- One vhost can mix Web Server and Reverse Proxy locations.
- GET implemented.
- HEAD implemented.
- MIME implemented.
- Web Service MIME overrides and fallback MIME implemented.
- Optional static
Cache-Controldefault and ordered extension/MIME cache rules implemented without a second object cache; vhost/location header rules can override them. - Fixed Web Service response headers implemented with framing/transport protections.
try_filesand ordered internal/redirect rewrite rules implemented inside the selected Web Service.- Bounded
.htaccesscompatibility implemented for common rewrite/front-controller, index/listing, MIME, header, Expires and PHP AddHandler migration rules; security-sensitive unsupported handlers/access scopes fail closed. - Web Service application presets added as one-shot normal-configuration generators (Static, SPA, PHP generic, WordPress, Drupal, Laravel, Symfony, Joomla, PrestaShop, Downloads) with optional explicit hardening for common exploit probes/sensitive paths and fingerprint-header removal.
- Precompressed
.br/.gzsidecars and configured forced-download extensions implemented. - FastCGI/PHP-FPM implemented with bounded concurrency/timeouts, Unix socket or loopback TCP endpoints, advanced request/header/stderr limits, Authorization forwarding control, validated custom FastCGI/PHP_VALUE parameters and no PHP source fallback.
- Content-Length implemented.
- File streaming implemented without loading the whole file into RAM.
- Index lookup implemented.
- Directory listing implemented.
- Repeated directory-listing refreshes use fresh directory offsets; nested directories independently prefer index files before listing.
- Directory slash redirect implemented with query preservation.
- ETag implemented from metadata.
- Last-Modified implemented.
- 304 implemented.
- Single Range implemented.
- 206 implemented.
- 416 implemented.
- Document-root confinement implemented.
- Symlink handling cannot escape the root; deny is the default and Linux can optionally follow only targets verified inside the canonical root. PHP-FPM requires deny.
- Web Server uses the existing RustProxy request/response pipeline.
- No second URL router was added.
- No second error-page subsystem was added.
- No second object-cache subsystem was added.
- [~] Existing vhost features remain on the shared code path and source contracts verify ordering; full compiler/runtime regression execution is a release-host gate.
- Appropriate Rust tests and Rust-independent contract checks are present.
- Configuration is stored/read through the existing revisioned configuration store; old configs default to Reverse Proxy.
- Documentation has been reorganized.
- Docs and Reader are wired to the same embedded Markdown set and API is separated into its own tab.
- CHANGELOG has been cleaned of developer-only churn; detailed old material is archived as technical history.
- README and ROADMAP describe the actual 0.25 state, historical release/roadmap material is separated into CHANGELOG/audits/archives, and the remaining release-host gate is explicit.
Reported Axum E0277 correction
The reported .fallback(forward) error was caused by passing &Request<Body> into the asynchronous Web Server function. That shared borrow survived across .await; because the body is not Sync, the forward() future no longer satisfied Axum 0.8's Send handler requirement.
Static dispatch now clones only the request metadata needed by the local filesystem source (Method, HeaderMap, Uri) and moves those owned values into web_server::serve. The Web Server no longer holds a shared Request<Body> reference across an await. The Rust-independent contract explicitly rejects the former call shape.
Reported Reader build-artifact correction
The Reader initially embedded a generated OUT_DIR/docs-content.json. A clean/incremental build could therefore reach include_bytes! without that artifact being present. Reader documents are now direct include_str! compiler inputs from the project and docs/ tree; the JSON response is serialized once from those embedded strings. The Reader no longer depends on a generated documentation file in target/, and docs_check.py verifies that every top-level Markdown document is embedded.
Verification performed in this workspace
python3 tools/checks/check_source.py- PASS.python3 tools/checks/release_smoke.py- PASS.python3 tools/checks/memory_contracts.py- PASS.python3 tools/checks/web_server_contracts.py- PASS.python3 tools/checks/docs_check.py- PASS.python3 tools/checks/langs_check.py- PASS.node --checkfor app, Settings, Docs Reader, Web Server and vhost administration JavaScript - PASS.- OpenAPI and both language JSON files parse - PASS.
bash -n dev.sh- PASS.go test ./...indocker-agent- PASS../dev.sh test- all Rust-independent phases PASS, then exits becausecargois not installed in this workspace.
Remaining release-host gate
Before a production release, run on a host with the stable Rust toolchain:
./dev.sh fmt
./dev.sh check
./dev.sh test
Then run live static-file acceptance over HTTP/1.1, HTTP/2 and HTTP/3, including ACL/auth/custom-error/header behavior and a large streamed file. This is verification work, not a missing source feature.