66 KiB
Verification report - RustProxy 0.31.7
0.31.7 — pruned source package correction (2026-10-11)
- Reported: deleting 47 historical audit/implementation Markdown files made
dev.shfail at source preflight (docs/V0.25.5_AUDIT.md). They were not needed at runtime, but hardcoded documentation/source checks still demanded them. - Additional build hazard fixed: the embedded documentation Reader still contained seven
include_str!registrations for deletedIMPLEMENTATION_0.31.x.mdfiles. These would cause actual Rust compilation failures even if the Python preflight were bypassed. - Changed: remove obsolete audit/implementation requirements from preflight, source/release smoke tests and documentation checks; keep strict runtime source checks and validate the existence of every Markdown file still embedded in the Reader. Update Reader integration test, documentation index and broken relative links. No SQL, proxy runtime, UI or packaging policy changes.
- PASS:
./dev.sh testpassed Python source/upgrade/SQLite/security/memory regressions, Node UI checks, docs/locale checks and the new source-pruning test. It terminated 127 only because Cargo is not installed here. New regression exercises the expected failure when a live Reader document or source module is deleted.GOPROXY=off go test ./...passed indocker-agent;bash -nfordev.sh/update.shpassed. - OPEN: Rust compilation/linking and real update on the user's host remain unverified. After deploying this source archive, run
bash dev.sh releaseandbash update.shin the usual release workflow.
0.31.7 — revision history UI follow-up
- Move Full JSON comparison directly below Restore revision inside the existing action group, without additional separators. Preserve existing revision selection, restore handlers, diff logic and JSON display behavior.
- Bound the revision history dialog to the viewport. Large change lists and day-revision buttons scroll inside their desktop panes; the calendar and the stacked mobile layout scroll without forcing page-level overflow. Make the full JSON dialog use the same base dialog border/background/padding as other windows, with a right-aligned close button and borderless JSON blocks.
- PASS — browser layout fixture: headless Chromium with the actual HTML/CSS dialog fragments, 200 changed fields, 50 day revisions and six month calendars at viewport sizes 1280×800, 1024×600, 800×600, 390×760 and 320×568. Desktop change list has independently scrollable content (including the final change); narrow viewports have a scrollable modal body and do not expand the document width. Full JSON dialog shares the generic border rule. This is synthetic browser rendering, not a running Rust server or real Safari.
- OPEN: end-to-end panel render with authenticated session, actual revision content and iPhone browser. Rust/Cargo compilation remains unverified in this environment.
0.31.7 — source, updater and UI regression verification (2026-10-11)
- PASS:
./dev.sh testexecuted all bundled Python security/source/version/SQLite-9 migration/upgrade/memory checks, Node.js UI regressions, documentation validation and language-pack checks. It exits 127 only at the missing Rust/Cargo toolchain gate. Rust tests and release compilation did not run. - PASS: new
tools/checks/release_0317.pyexercised the actual Bashupdate.shretention code using a sandboxed fake installer: successful, failed and--planupdates; release directory names with spaces; active symlink protection; exactly two installed releases and three backups; age-based Cargo incremental cleanup while preserving recent state,deps,.fingerprint,build, binaries and locks; and skip on symlinked Cargo targets. Systemd was not called. - PASS: new
tools/checks/release_0317_ui_test.mjsexecuted the real configuration diff function against changed leaves, reordered ID-bearing arrays, created/deleted fields and the 200-entry bound. Validated Settings form relocation, listener spacing, collapsed ACL attachments, user-agent editor/OpenAPI and separate JSON dialog at the source level. This was not a live browser render. - PASS:
GOPROXY=off GOSUMDB=off go test ./...indocker-agent,node --checkfor all browser JavaScript modules, OpenAPI JSON parsing,bash -n dev.sh update.sh,docs_check.pyandlangs_check.py. - CHECKED IN SOURCE, NOT LIVE:
scripts/deploy/deploy_runtime.pycreates.managed-updatebeforesystemctl stop;src/main/admin_runtime.rschecks the marker and calls forced HOT→COLD even withcold_on_shutdown=false; shutdown time budget is 90 seconds with a 120-second systemd stop budget. The cache persistence worker now returns a success boolean somovedcounts only successfully inserted COLD objects. Existing Rust cold-tier unit tests cover enabled COLD with ordinary shutdown disabled, but could not run without Cargo. - OPEN: Rust type checking/formatting, cargo --locked consistency, compiled vhost 429/Retry-After behavior, actual update/rollback and persistence after restart, browser UI on a live server, H2/H3 performance and iPhone reload acceptance. No production-ready claim.
0.31.6 - iPhone H3 full navigation and observability (2026-10-11)
- Target: iPhone Safari and Chrome when an existing dashboard session navigates through the unchanged sidebar logo link (
<a class="brand" href="/">). It creates an H3 document GET while older SSE/API requests can be cancelled. - Fix candidates implemented: The H3 GET/HEAD cache and 404 preflight avoids unbounded waiting on a delayed request FIN; on an H3->HTTP/1.1 vhost, a truly empty GET or HEAD stream is normalized before forwarding (bounded 35 ms first-frame probe; nonempty data replayed; pending client keeps streaming). On an H3 accept error, no longer
abort_allactive responses; bounded drain still applies. - Diagnostics: Persist
http3_peer_cancelled_before_headersevents with status 0 (not 400). For interrupted responses writehttp3_peer_cancelled_after_headersorhttp3_response_write_error, including sanitized path without query, stream ID, response phase/status, bytes sent and redacted error. Normal process INFO/WARN logs also record the start, completion or interruption of root-document H3 GET/using its stream ID; no cookies or query strings. These records remain in vhost file logs and are subject to configured log sinks. They are distinct from application response access logs. - Rust regression cases added: GET/HEAD empty-body normalization, nonempty GET payload replay, bounded cache preflight and stalled GET; retained 0.31.5 H3 cancellation classification tests. Static release and documentation contract check extended.
- NOT VERIFIED: Rust compilation, a live QUIC listener, reverse-proxy-to-panel traffic, iOS Safari/Chrome, frame captures, HTTP/3 stream integrity, TLS/QUIC delivery, persisted data upgrades. Do not describe root cause or fix as proven until captured on device. No WS-over-H3 is assumed; H1 websocket origins do not activate RFC 9220 by themselves.
- No changes: Sidebar logo link, H3 on/off configuration, SQLite schema 9, cache format, frontend routes, authentication/session/CSRF or WebSocket settings.
- PASS — executed for 0.31.6:
./dev.sh testcompleted all pre-Cargo Python/SQLite/schema/upgrade/security/source checks, 300,000 simulated memory-model operations, 2,000 requests to a Python test peer, all Node UI regressions (including the 0.31.5 mobile/H3 suite updated for the new error path), documents and both language packs.tools/checks/h3_navigation_0316.pyalso passed. The script then exited 127 solely because Rust/Cargo is unavailable.GOPROXY=off go test ./...indocker-agent,bash -n dev.shand OpenAPI JSON parsing passed. Source guards are not execution of Rust tests.
0.31.5 follow-up - mobile Stored Logs, H3 peer aborts, cache preservation (2026-10-11)
- Problem 1, mobile
/logs: narrow pages grew horizontally under dynamically selected log columns and large JSON/error fields. CSS now scopes width to the Logs workspace, presents entries as two-column, keyboard-expandable cards at widths<=700px, preserves every user-selected field in its card, stacks dense filters, wraps long values, and retains independently horizontally scrollable code/aggregate data. Details and Raw JSON remain accessible. Existing row interaction and per-user column choices are unchanged. - Problem 2, H3 synthetic status:
resolver.resolve_request()returnedStreamError::RemoteTerminate(H3_REQUEST_CANCELLED)for a browser-cancelled stream before request headers; RustProxy previously calledlog_protocol_error(..., 400, ...), making a transport cancellation appear to be an application HTTP 400 with no method/path. Now peer cancellations (H3_REQUEST_CANCELLEDor peerH3_NO_ERROR) are low-level debug observations, while malformed messages still retain an attributed HTTP 400. Response send errors directly classified as peer cancellations no longer provoke a redundantH3_INTERNAL_ERRORreset. We deliberately retain the oldReceiveBody::Dropsafeguards against h3/quinn pending-read panic. - Important limit: the supplied log cannot establish why the new navigation rendered a blank page; an old request may simply have been cancelled by F5. Missing HTTP method, path, authority, User-Agent, and 0 sent bytes prevent correlation to the failed top-level document. The root cause of the blank page has not been reproduced or verified. Validate Safari and Chrome with actual RustProxy QUIC/HTTPS, the reverse-proxy Host/Origin/
X-Forwarded-Protochain, browser Network waterfall (especially HTML and fingerprinted JS/CSS), and connection-level debug/qlog before accepting the fix as complete. - Problem 3, cache:
cache_revision()used to hash complete vhost configuration, includinghttp2_enabledandhttp3_enabled; an unrelated frontend protocol toggle rotated the global compatibility identity and triggeredCacheInvalidation::All, flushing HOT and COLD. Normalize these two flags to the defaulttrueonly for the cache-identity digest; live routing and serialized configuration remain unmodified. Rust tests cover H2, H3, combined toggles and a true cache-policy edit. - Problem 4, public origin vs allowlist: public HTTPS origin fixes scheme + host + port for security checks behind a trusted proxy (and implicitly allows its DNS host); extra allowed DNS hosts only expand allowed names. Retain both; improve Polish and English help text, no API/SQLite format changes.
- Verification, 2026-10-11:
./dev.sh testpassed its entire available Python/SQL/schema/upgrade/security/security-dependency/Node/docs/language pre-Cargo suite, including newh3_cache_mobile_0315_test.mjs, then exited 127 becausecargois absent../dev.sh checksimilarly exited 127 for missing Cargo.GOPROXY=off go test ./...indocker-agentpassed.bash -n dev.sh, Node syntax, JSON syntax and focused source gates also passed. Rust unit tests were not compiled or executed. - Browser layout smoke: headless Chromium/Python Playwright rendered a synthetic fixture with the actual HTML/CSS log workspace at widths 320, 375, 430, 700, 768, 1024px. In every case
body.scrollWidth === innerWidth; cards were grid rows at<=700px, with desktop table rows at 768px+. Parsed fields, long unbroken values and raw JSON were included. This was a static layout simulation, not authenticated panel/live H3 acceptance.
0.31.5 follow-up - Stored Logs navigation polish
- Split Stored Logs into Log entries and Repeated values tabs, sharing source/search filters; the count query is only included while the analysis tab is active. Move the persisted consolidation toggle into the header. Verify via dedicated Node UI source regression. Rust compilation/browser acceptance remain outstanding.
0.31.5 follow-up - build-specific JS/CSS filenames
scripts/build/swagger_assets.pycreates a fresh random 64-bit hex identifier using Pythonsecretswhen Cargo invokes the build script. The identifier is embedded in the binary and substituted into dashboard, public login and Docs HTML. HTML retains its existing cache-header behavior. Matching fingerprint paths serve the existing embedded asset bytes without runtime disk access; unrecognized fingerprints return 404. Legacy URLs remain for compatibility. Package remains 0.31.5; rebuilding with unchanged source changes these asset URLs whenever the build script reruns.- Regression checks cover URL templates, version independence, build token generation, asset routing and anonymous allowlist. Source/UI checks run without Cargo; compilation and real browser/cache tests remain open.
0.31.5 follow-up - Stored Logs consolidation preference
- Stored Logs now restores the last selected consolidation mode from browser-local storage (
rp-file-logs-consolidate-vhosts) on panel load; saves changes immediately; defaults to the existing checked mode if no preference is present or storage is blocked. Clearing browser storage restores the default. No API or SQLite change. - Verification:
security_logs_0315_ui_test.mjschecks preference read/write integration. Rust compile and runtime acceptance remain open as described below.
0.31.5 - User-Agent blocking and consolidated log analysis (2026-10-11)
- Scope: global and per-vhost User-Agent blocklists, copyable Traffic values, Stored Logs repeated-value aggregation and optional per-vhost consolidation of active JSONL plus gzip rotations.
- Compatibility: no SQLite migration; existing configurations load with User-Agent blocking disabled. Existing Stored Logs physical source IDs remain available when consolidation is disabled.
- Security: User-Agent matching is bounded and runs before upstream contact; Stored Logs continue to accept only server-derived sources with existing symlink/gzip/scan limits. User-Agent is client-controlled and is not treated as an identity boundary.
- PASS — full Rust-independent release run:
./dev.sh testpassed module/version/source contracts, SQLite schema-9 migration/upgrade smoke, security/dependency checks, the 300,000-PURGE memory model, 2,000 HTTP requests to the Python test peer, every bundled Node UI/simulation test (includingsecurity_logs_0315_ui_test.mjs), documentation and both language packs. It then exited 127 only at the missing Rust/Cargo guard; the Python peer is not a RustProxy binary. - PASS — focused 0.31.5 regression:
security_logs_0315_ui_test.mjsverifies global/per-vhost UA wiring and pre-origin ordering, Traffic copy controls, Stored Logs aggregation/consolidation markers, OpenAPI and English/Polish locale keys. - PASS — other available checks:
go test ./...indocker-agent;bash -n dev.sh; Node syntax checks for the modified UI files/test; OpenAPI JSON parsing;docs_check.py;langs_check.py;check_source.py; andrust_module_contracts.py. - Rust release gate OPEN:
./dev.sh checkexits 127 because this environment does not providerustc,cargoorrustfmt; new Rust unit/regression tests are present but cannot be compiled/executed here.
0.31.4 reissue - origin protection and one-field administration public URL (2026-10-11)
-
Reissue verification (2026-10-11): rebased the complete previously prepared simplified-config source onto release identifier
0.31.4in the manifest, existing resolved-lock snapshot package entry, OpenAPI, source/version checks, documentation and deterministic ZIP metadata. Merged the panel Origin and one-field config release notes; no backend validation logic changes were introduced during this renumbering. -
PASS — executed for this reissue:
version_contracts.py,docs_check.py,langs_check.py,check_source.py,release_smoke.py,security_contracts.py,dependency_upgrade_0312.py,rust_module_contracts.py,system_info_no_subprocess_contracts.py,source_module_contracts.py,memory_contracts.py,web_server_contracts.py,admin_surface_audit_0310.py,security_dependency_contracts.py; 15 standalone Node frontend/simulation scripts (including the updated original 53-case and expanded 61-case administration simulations and 9 UI scenarios);go test ./...fordocker-agent;bash -n dev.shand OpenAPI JSON parsing. -
Not executed for this reissue: full Rust compile/test/release (
cargoandrustcabsent), real mobile Safari/Chrome or live reverse-proxy verification. Passing Node simulations is not proof of compiled Rust behavior. The inherited Cargo.lock requires verification and/or re-resolution on the declared Rust 1.99+ toolchain. -
Scope: panel administration settings/config and narrow self-admin cookie opt-in only.
allowed_hostsstores only additional DNS hostnames; the HTTPS pin contributes its hostname to the active/desired Host allowlist without persisting a duplicate. -
Compatibility: older configurations with a duplicate hostname remain valid; validation canonicalizes the in-memory config and the next save omits the duplicate without an automatic SQLite migration; changing/removing the pin does not silently retain a stale implicit hostname.
-
Security: Host, single forwarded Host, trusted reverse proxy, first-hop HTTPS, CSRF and
Origin/cross-site guard rules are unchanged. No SQLite schema migration, TLS listener or other vhost route changes. -
PASS — source/release gates:
version_contracts.py,rust_module_contracts.py,check_source.py,release_smoke.py,docs_check.py,langs_check.py,security_contracts.py,admin_surface_audit_0310.py,security_dependency_contracts.py, anddependency_upgrade_0312.py; SQLite schema-9/upgrade smoke and the source/HTML/Reader/translation checks also passed. -
PASS — focused simulated regressions:
admin_public_origin_0314_config_sim.mjs: 61/61 local Node HTTP guard-simulation assertions, comprising 37 cases and 24 repeated session GETs. Invalid forwarded-proto on 3/12 unpinned GETs produced 403; with a pinned HTTPS public URL and no duplicate DNS allowlist entry, the same sequence produced 0/12. This simulation is not compiled RustProxy and cannot prove actual mobile/proxy headers. -
PASS — real frontend helper/UI checks:
admin_panel_config_0314_ui_test.mjs: 9/9 settings-normalization scenarios plus form/HTML/locale/OpenAPI consistency;panel_cache_http_0310_ui_test.mjsalso executes the updated real administration form callback with a duplicated legacy hostname and verifies it is omitted on save. -
PASS — other standalone checks: all 14 bundled Node UI/simulation scripts, memory model (300,000 simulated PURGEs), 2,000 HTTP requests to a Python mock peer (not RustProxy), and
cd docker-agent && go test ./.... -
Harness and compiler limitations: an initial
./dev.sh testrun exposed a legacy UI-test harness that lacked the new form helper; the harness was corrected and passed separately. A subsequent monolithic run exceeded the execution time limit after the memory/load-model stage, so no complete./dev.sh testsuccess is claimed../dev.sh checkexited 127 becausecargo/rustcare not installed. New Rust tests insrc/settings/tests.rsandsrc/admin/tests/part_11.rswere not compiled/executed. The inherited Cargo.lock still needs resolution on Rust 1.99+; live mobile and real reverse-proxy acceptance remain OPEN.
Earlier 0.31.4 validation baseline (2026-10-11)
- User scope: admin panel only; public vhosts, proxy forwarding, streams and database migrations are unchanged. The 0.31.3 BFCache/session resume and visible retry protections are retained.
- Source correction: optional
administration.public_originpins a browser-facing HTTPS panel origin to a configured DNS allowlist; it takes effect after restart and only with a trusted last-hop proxy. It accepts boundedX-Forwarded-Proto: https, httpwithout relying on an ambiguous forwarded-proto element for the expected origin. Without the pin, 0.31.3's strict handling remains. - Security: actual Host is validated, forwarded Host must be single/matching, the protocol's first hop must be HTTPS, and Origin, cross-site and CSRF checks remain. Untrusted peers and credential-bearing certificate automation retain their previous scheme validation. The earlier build required explicit
allowed_hosts; the reissue now derives the pinned hostname without wildcard trust. - Node HTTP guard simulation (not compiled RustProxy): PASS, 53/53 assertions, including 29 individual scenarios and 24 repeated session GETs: without the pin and with intentionally malformed XFP every fourth request, 3/12 GETs returned 403; with an explicit pin and otherwise identical simulated headers, 0/12 returned 403.
tools/checks/admin_public_origin_0314_sim.mjschecks relevant code anchors and operates a local Node HTTP test peer. This does not confirm production headers or backend runtime behavior. - PASS (2026-10-11):
./dev.sh testpassed every available Rust-independent stage: source-module boundaries, version/contracts, SQLite schema-9 migrations and upgrade, security source/dependency checks, 300,000 PURGE-model iterations, 2,000 real HTTP requests to a Python test peer, all bundled Node/browser UI regressions (including BFCache/resume), 0.31.4 HTTP simulation, documentation and both language packs. Exit 127 at the missing Rust/Cargo toolchain guard only. The simulated peer is not a running RustProxy binary../dev.sh checklikewise exits 127 due to missing Cargo. - PASS:
(cd docker-agent && go test ./...),node --check tools/checks/admin_public_origin_0314_sim.mjs; source-package size/integrity checks are performed separately. - Rust regression tests added, NOT EXECUTED:
src/settings/tests.rsandsrc/admin/tests/part_11.rscover pin validation, restart, strict opt-out, session Secure cookie, CSRF, foreign Origin, cross-site, host spoofing and untrusted peers. - Remaining release gate OPEN: the sandbox has no Rust/Cargo/rustfmt and the inherited lockfile remains unresolved against 0.31.2+ dependencies. Before production use: resolve on Rust 1.99+, format, clippy, test/build, then capture actual mobile Safari/Chrome and reverse-proxy traffic and run the acceptance matrix in SETTINGS.md. No claim is made that the original field
auth.invalid_originwas directly observed or eliminated.
0.31.3 - invalid-Origin resume and mobile panel recovery (2026-10-11)
- Source: the uploaded RustProxy 0.31.2 ZIP plus the user's case description. No remote repository/history or real mobile network capture was provided.
- Reproduced in the original source: two overlapping session validations; a 403 during return-to-tab caused
location.reload(); a concurrent successful validation cleared the recovery marker; another 403 could reload again. Separately, refresh tasks and SSE restarted before a resumed session was validated. - Corrections: single-flight session verification and coalesced visibility/BFCache events; suspend polling and SSE until verified; visible localized retry on 403/network errors; unchanged login handling on 401; clear the startup recovery marker only after full initialization; stop refresh on startup failure. Invalid-Origin top-level HTML navigation returns an explicit 403 error page rather than raw JSON. Server Origin/CSRF/cross-site enforcement is unchanged; structured diagnostic logging redacts credentials and untrusted forwarding data.
- Regression coverage:
tools/checks/origin_resume_0313_ui_test.mjsexercises actual JavaScript source against deterministic session API outcomes, repeated tab cycles, stale auth epoch, SSE suspension/resume, retry, 401 and startup marker. Rust unit/integration tests were added for blocked foreign origins, safe diagnostic values and readable 403 document handling, but cannot run here without Cargo. - PASS (2026-10-11):
tools/checks/origin_resume_0313_ui_test.mjsand all 11 other bundled Node UI tests; actual assembled dashboard bundle parsed by Node; original-source Node reproduction recorded the duplicate request/reload race. - PASS (2026-10-11): source/module/version/security/dependency contracts, SQLite schema-9 migration and upgrade smoke (
release_smoke.py), documentation/Reader (docs_check.py), language packs (langs_check.py), shell syntax and Go Docker Agentgo test ./.... Memory workload simulated 300,000 PURGEs; 2,000 HTTP requests targeted a Python test peer, not the RustProxy executable. - NOT VERIFIED:
./dev.sh checkexits 127 becausecargo/rustcare absent../dev.sh testpassed all Rust-independent stages through docs/locales and reached the same missing-Cargo gate; it did not run Rust unit tests. No compiled RustProxy, iOS/Android browser, trusted reverse-proxy trace or production rollout was exercised. - Verification limit: the new Rust tests are written but unexecuted; the lockfile is an inherited dependency snapshot, not a resolved 0.31.3 graph. The code has not passed a compiler-enabled release gate.
- Release gate remains OPEN: the local environment has no rustc/cargo/rustfmt. The inherited lockfile is unresolved for 0.31.2/0.31.3 dependency families. Run Cargo resolution, fmt, clippy, Rust tests and real admin/reverse-proxy/mobile acceptance on a Rust 1.99+ host before production release.
0.31.2 — stable library upgrade candidate (2026-10-10)
- Source basis: shipped RustProxy 0.31.1 archive, without local Git history; no confirmation of current remote
master. - Changed dependency branches: Rust 1.99 (manifest and Docker builders), SQLx 0.9, Argon2 0.6, Rand 0.10, rcgen 0.14, Tower HTTP 0.7, Brotli 9 and sysinfo 0.39; HTTP/3 hpx-h3 is pinned to reviewed 2.5.20. Existing SemVer-compatible crates remain range-defined for a full
cargo update. Embedded Swagger UI is pinned to upstream 5.33.1. - Code adaptations: secure RNG API, Argon2 PHC generation/verification and TLS certificate signing key representation. No intended changes to JSON schema, SQLite schema 9, cache format, credential storage, TLS policy, or proxy traffic processing.
- Executed locally:
./dev.sh testpassed all offline code/API/SQLite/upgrade/security/translation/UI/Node/documentation checks; then exited 127 because Rust/Cargo is absent.cd docker-agent && go test ./...passed.python3 tools/checks/dependency_upgrade_0312.pyreports PENDING for the old lockfile. Python compilation and Bash syntax checks passed. This does not prove a Rust build. - CRITICAL: This sandbox has no Rust/Cargo/rustfmt and cannot reach the crates registry. The existing
Cargo.lockcarries the previous dependency graph: only the root package version has been updated, with all third-party resolved entries left untouched. It is NOT the resolved lockfile for 0.31.2 and--lockedis expected to reject it untilcargo updateruns. Do not treat this source package as a built or production-accepted release. Do not fake checksums or mark compilation/tests as passing. - Required on a Rust 1.99 build host: run
cargo update, review and commit the newly resolvedCargo.lock,cargo metadata --locked,cargo fmt --all -- --check,cargo clippy --locked --all-targets -- -D warnings,./dev.sh check,./dev.sh test,./dev.sh release, pluscargo auditwhen installed. Fix all compilation/API errors revealed by real Cargo before approving a release. - Runtime regression gate: real H1/H2/h2c/H3 QUIC, WebSocket, TLS and certificates, SQLite upgrade/backup/restore with preexisting data, sessions/Basic Auth/API security, SSE and panel on Safari behind reverse proxy, cache HOT/COLD and BAN/PURGE, and zstd/br/gzip negotiation. Compare load/RSS and avoid overwriting production data.
Historical verification records (0.31.1 and earlier)
0.31.1 — mobile/reverse-proxy dashboard startup (2026-10-10)
- Cause found in source: dashboard HTML fetched 17 deferred JS resources, while the first bundle launched an async session/config bootstrap without waiting for all later scripts to finish. A fast API response could invoke the renderer before
window.rustProxyIntegrations.bindingswas registered. An interrupted script transfer could cause the same exception. The reported Safari error is consistent with this race, but the specific production network failure was not captured. - Implemented: one ordered embedded JS payload at
/assets/app.js?v=0.31.1; CSS URL also versioned; DOMContentLoaded/module gating and explicit startup recovery; up to two bounded retries of initial configuration (400/800 ms). Old private asset URLs remain available. No API, authentication, saved preferences, database or proxy data path changes. - PASS:
./dev.sh testcompletes all source checks, SQLite migration/backup and upgrade smoke tests, security and language checks, Node UI tests (including new startup-order and retry test), and documentation checks before Cargo.python3 tools/checks/source_module_contracts.pychecks each JS module and the assembled 608 KB bundle withnode --check.cd docker-agent && go test ./...passed. Shell syntax passed. - Not verified:
./dev.sh testterminates 127 at Cargo;./dev.sh checkalso 127 (cargo/rustcabsent). Browser smoke against a local simulated API was attempted, but Chromium navigation was blocked by sandbox policy (ERR_BLOCKED_BY_ADMINISTRATOR); no successful browser smoke run is claimed. Playwright WebKit browser binaries are not installed here. No real iPhone Safari or production reverse-proxy test was possible. - Release-host checks:
./dev.sh check && ./dev.sh test && ./dev.sh release, followed by Safari/Chrome iPhone tests behind the reverse: 20+ full reloads from Overview/Cache/Settings, initial config API failures, SSE reconnect, browser console errors, and response encoding/version consistency for HTML,/assets/app.js?v=0.31.1and CSS. Review the detailed plan in HTTP3.md.
0.31.0 Axum handler Send correction (2026-10-10)
- Reported failure:
error[E0277]atsrc/proxy/types.rs:53,.fallback(forward), on Axum 0.8.9.forwardcalls asynchronous public BAN/PURGE handling. That helper accepted&Request<Body>across.await, which requires aSyncbody to produce theSendfuture thatHandlerexpects. - Source correction: move
Request<Body>intocache_http_invalidation, validate it synchronously, copy the method for audit logging and explicitly drop the body before the first.await. No cache selectors, IP permissions, status codes, API routes or session flows were changed. Strengthentools/checks/admin_surface_audit_0310.pyto reject a reintroduced borrowed request in the async handler. - Executed:
./dev.sh test— all pre-Rust checks PASS (source/security/SQLite, UI Node, docs, language packs); command terminates 127 when Cargo is required../dev.sh check— 127, Cargo absent.cd docker-agent && go test ./...— PASS.bash -n dev.sh, Python source compile and manifest version probe — PASS (0.31.0). - Not executed: Rust
cargo check --locked --all-targets,cargo test --locked --all-targets,cargo build --locked --release, rustfmt or live HTTP regression. Nocargo/rustcor download access is available in this environment. This source correction is not claimed as a compiler-verified release.
0.31.0 BAN/PURGE compilation fix, security review and UI help (2026-10-10)
- Addressed reported Rust E0716 (
format!temporary borrowed as&'static str) by returning a fixed 422 response and logging the specific rejection. - Restricted public HTTP maintenance to one external scheme and matched Host/vhost, rejected duplicate controls and invalid bodies, and added a shared two-slot limit plus
spawn_blockingfor heavy HTTP/admin cache invalidation work; audit removal before BAN-rule deletion. - Added localized EN/PL
curlhelp popover beside the Cache allowlist; added protocol/host/scheme/headers Rust regression sources, admin anonymous/CSRF test sources and an offline source audit script. The detailed findings, attack-surface table and operator acceptance checklist are in SECURITY_AUDIT_0.31.0.md. - Executed this follow-up:
./dev.sh testpassed every pre-Rust static/SQLite/security/JS/docs/translation check, then exited 127 on unavailable Cargo../dev.sh checkalso exited 127.go test ./...underdocker-agent/, syntax checking all 27 browser JS files, OpenAPI JSON parse, shell syntax and separate source audits passed. A separate Chromium screenshot attempt timed out and does not count as verified UI rendering. - Rust compiler and runtime tests NOT RUN HERE:
cargo,rustcandrustfmtare absent; the only safe conclusion about E0716 is that its offending lifetime pattern was removed in source. Live BAN/PURGE over H1/H2/H3, TLS, reverse trust, performance and regression gates remain open.
0.31.0 negotiated panel content compression and HTTP BAN/PURGE follow-up (2026-10-10)
administration.panel_compressiondefaults to{zstd:true,br:true,gzip:true}and uses the existing Administration form/config revisions. Authenticated panel HTML and embedded/assets/CSS/JS/language bundles are precompressed only once per resource; per-request browserAccept-Encoding/qselects zstd, br, gzip or identity. The public login HTML remains identity (static login assets can negotiate compression).Vary,Content-Encoding,Content-Lengthare set per response. Compression for public proxied responses is unchanged. An upstream reverse proxy can overrideAccept-Encodingand therefore the negotiated result.- Empty-by-default
cache.http_invalidation_allowed_cidrsrestricts public-vhostPURGE /path?queryexact removal andBAN /prefixlazy invalidation to allowed client IPv4/IPv6 ranges;/0rejected. Existing vhost/host ACL, rate limit and trusted forwarding logic remain in force.BAN /requires explicit confirmation; operation is audited, usesspawn_blockingaround the existing cache engine and is never sent upstream. CIDR changes do not rotate cached objects. - System information Refresh button is next to the API badge, without another row. EN/PL locales, OpenAPI and settings/cache/API docs were updated; SQLite schema remains 9 and Cold format remains 3.
- PASS:
./dev.sh testcompleted all pre-Rust checks (SQLite migrations, release smoke, security, translations, Node UI, source contracts) then exited 127 becausecargo/rustcare missing../dev.sh checklikewise exits 127. Standalonego test ./...indocker-agent/, JavaScript syntax checks, OpenAPI JSON parse and Node form roundtrip passed. Chromium headless verified that API badge and System information Refresh button remain on the same row at viewport widths 320, 390, 1024 px. - Source-byte measurements (not wire captures): authenticated HTML after version substitution 320,756 B; Zstd level 3 around 50,526 B, Brotli level 5 around 43,654 B, gzip level 6 around 47,343 B using local utilities. The actual wire choice follows browser
qvalues, not necessarily the smallest encoded representation. FCP/LCP and mobile real-browser startup were not measured on a running RustProxy. - Rust NOT RUN: no Cargo/Rustc; Rust codec decoding, actual vhost BAN/PURGE authorization/HTTP/1-H2-H3, live proxy integration and exact wire metrics require a Rust-capable host. Production acceptance remains open.
0.31.0 mobile startup / HTML payload follow-up (2026-10-10)
- Removed
html.app-loading body { visibility: hidden }. An initial CSS-driven overlay shows a loading spinner before the application code runs, a delayed (12 s) retry link when scripts or requests stall, and an explicit localized EN/PL failure state. No inline scripts or styles were introduced; authenticated CSP and the public login document are preserved. Reduced-motion preferences disable the spinner animation. - Dashboard shell and live SSE start once the authenticated session and language bundle are resolved, without blocking on preferences, configuration, certificate inventory or initial
/api/status. Unavailable configuration shows a visible toast and does not blank the page. This improves perceived startup but is not a measured FCP improvement. - Moved the Overview Refresh now button into the title row, with no additional top-level row; the button remains hidden outside Overview.
- Private HTML is gzip-compressed and cached once in memory (no per-request recompression);
Accept-Encoding: gzipyieldsContent-Encoding: gzip,Vary: Accept-Encodingand compressedContent-Length. Without gzip or withgzip;q=0, the existing identity HTML remains. Public login is not compressed/altered by this handler; API, SSE and proxy paths are not changed. - Measured from source bytes: HTML source 318,905 B, authenticated response after substituting two version placeholders 318,875 B (previous packaged authenticated response 317,723 B); Python gzip level 6 of the response 46,821 B (about 85.3% less HTML transfer). These are source-based estimates, not HTTP wire captures from running RustProxy, so browser-delivered Content-Length remains to be confirmed with a compiled server.
- PASS: deterministic Node startup/placement test, Chromium 320/390/1024 px rendering and title/button alignment, existing static checks and Node coordinator regressions. NOT RUN: Rust compilation or Rust tests (
cargo/rustcunavailable), live HTTP gzip/identity/auth, real mobile hardware reproduction and field measurements (FCP/LCP/white-screen rate). Acceptance remains open.
0.31.0 dashboard refresh implementation and source verification (2026-10-10)
- Source delivery based on the supplied
RustProxy-0.30.1.zip(no.git; remotemasternot verifiable). Implemented one per-browser scheduler, per-account/validated preferences, per-client SSE interval and fallback isolation, active-view Traffic/Cache, separated/api/system-info, compatible full/api/status, version/docs and English/Polish UI. - PASS: source/version/module/security checks, SQLite schema-9/upgrade smoke, translations/docs, all bundled Node UI tests including deterministic refresh scheduler, Go agent unit tests, all admin JS syntax. Browser simulation checks 20 view transitions, no duplicated timers/in-flight requests, 0/manual, hidden tab, SSE failure/recovery, independent errors and logout.
- NOT RUN: Rust compilation, Rust tests and release build because
cargo/rustc/rustfmtare missing (./dev.sh test/check/fmt/releaseexit 127 at toolchain gate). Real RustProxy API/SSE/traffic/regression tests and SSE bandwidth/CPU measurement remain unverified. The stress suite's Python HTTP test peer is not a RustProxy runtime test. - See current verification report. No database schema changes, git commit or tag.
0.30.1 sysinfo compiler-feature fix (2026-10-10)
- The operator's Rust compiler reported four
E0433errors because the pinnedsysinfo = 0.38.4dependency enabled onlynetwork, but the new OS/kernel status methods require thesystemfeature. Enabled bothnetworkandsystemwithout changing dependency versions or status API behavior. - Removed the reported unused Tokio
AsyncReadExtimport fromsrc/acme/runtime_env.rs. - Added a guard for both
sysinfofeatures tosystem_info_no_subprocess_contracts.py, wired that source check into./dev.sh test, and synchronized the older manifest assertions incheck_source.pyandrelease_smoke.py. Cargo compilation on the operator's machine is still required to verify the full Rust build. - Offline checks passed after the correction: system-info feature/source contracts, Rust and browser module contracts, version/source/release-smoke (SQLite/schema 9 and upgrade), memory, web server, security/dependency, simulated system-info UI, docs/translations, and Bash syntax. These static checks do not establish Rust compile success.
0.30.1 no-subprocess system information refinement (2026-10-10)
- Reused
sysinfo::System::{long_os_version, name, os_version, kernel_version}for OS and kernel metadata on supported Linux/BSD/macOS/Windows targets; results remain cached. The status endpoint no longer reads Linux/etc/os-releaseor/proc/sys/kernel/osreleasedirectly. - Removed the extra Python, pip and Certbot version subprocesses. At ACME startup, bounded local reads of the selected interpreter's
pyvenv.cfgand the selected installation'spip-*.dist-info/METADATAandcertbot-*.dist-info/METADATAprovide versions when possible; missing/ambiguous values remainnull. System Python full patch versions cannot be guaranteed without an executable probe, so they may be unavailable. ACME operational dependency checks and actual issuance still require subprocesses; those are not system-information collection. - Added Windows
.exelookup for system Python/Certbot, metadata source unit regressions (not executed without Cargo) and compiler-independent source-contract regressionsystem_info_no_subprocess_contracts.py. No new Rust dependencies, schema or API property changes. - Compiler-independent checks passed:
system_info_no_subprocess_contracts.py,rust_module_contracts.py,source_module_contracts.py,version_contracts.py,check_source.py,release_smoke.py(SQLite/schema 9 and upgrade),memory_contracts.py,web_server_contracts.py,security_contracts.py,security_dependency_contracts.py,docs_check.py,langs_check.py, all shipped Node UI regressions (including no-metadata fallback) andhigh_traffic_memory_model.py(simulated PURGE + 2,000 requests against a Python peer, not RustProxy). Rust/Cargo are absent, socargo check, Rust unit tests and live multi-OS acceptance were not performed; production acceptance remains open.
0.30.1 system information and legend change (2026-10-10)
- Corrected H1/H2/H3 Overview legend markers to use exactly the protocol series theme variables (HTTP and WebSocket cards).
- Removed certificate runtime details from About, moved existing authenticated runtime metadata to Settings -> System information, added OS/version/kernel/architecture and existing process telemetry. Initial implementation used bounded ACME version subprocess probes for the selected binaries; the later refinement above replaces them with non-executing metadata reads, and leaves missing versions unavailable.
- Updated locale packs (English/Polish), authenticated OpenAPI status schema and release identity. SQLite schema 9, Cold Cache format 3 and persisted configuration have not changed.
- Passed offline:
rust_module_contracts.py,source_module_contracts.py,version_contracts.py,check_source.py,release_smoke.py(including SQLite/schema 9 and source upgrade),memory_contracts.py,high_traffic_memory_model.py(simulated PURGE plus 2,000 requests against a Python peer, not RustProxy),web_server_contracts.py,security_contracts.py,security_dependency_contracts.py, all seven shipped Node UI regressions (includingsystem_info_0301_ui_test.mjs),docs_check.pyandlangs_check.py. The full./dev.sh testpipeline exceeded this environment's execution limit after passing through the Web Server contracts; remaining checks were run individually../dev.sh checkexited 127 because Rust/Cargo are absent. No Rust compilation, Rust unit tests or real managed/system Certbot runtime checks were performed. Production acceptance remains open.
0.30.0 same-version sustained-memory audit (2026-10-10)
- Reviewed cache metadata, HOT/COLD admission and cleanup, file/remote JSON sinks, live log history, analytics, local directory listings, HTTP/2/HTTP/3, TCP/UDP sessions, DNS/health tasks, PHP-FPM streaming, transforms, rate-limit buckets, and periodic tasks. See memory verification for audited invariants and the real-runtime acceptance procedure.
- Confirmed a long-run retention issue: the selective PURGE path incremented
Store.key_generationsfor affected base keys and never reclaimed those identities until an all-cache purge. Its existing globalgenerationbarrier already invalidates all older fills/tickets, so obsolete per-key metadata can be reset per selective PURGE. Also release large HashMap capacity after mass invalidations. Added a 512-distinct-PURGE Rust regression (not executed without Cargo). - Removed unnecessary repeated analytics-label allocations using borrowed map lookups and allocation on insertion only. Filtered local directory listings in place rather than building a second metadata vector and moved generated HTML into the response instead of cloning it. Reused the existing redacted JSONL serialization when sending the same access event to Loki (while preserving the Loki-only path).
- Offline test: 300,000 simulated distinct PURGE identities over six intervals. Legacy bookkeeping model retained 50k → 300k keys, whereas the corrected epoch model retained 1 key after each operation. The load driver sent 10,000 real HTTP requests using 24 persistent clients and 1,000 distinct paths to a Python test peer, with expected status/body counts. These tests validate model behavior and driver operation only: they do not measure RustProxy RSS, heap, or leak freedom.
./dev.sh test: all Rust-independent source, security, SQL/upgrade, Node/browser UI, documentation/translation and memory-replay checks passed (including its 2,000-request peer smoke); exit 127 only at the missing Cargo toolchain guard../dev.sh checkalso exits 127 for missing Cargo.go test ./...indocker-agentpassed.- Rust/Cargo unavailable in this environment. Actual
cargo check, Rust unit tests, RustProxy GET/PURGE under load, production-like JSON sinks, HTTP/2/3 and TCP/UDP traffic, and long-duration RSS/heap plateau measurements remain pending. No API, SQLite schema, Cold Cache format or version changes.
0.30.0 source verification (2026-10-10)
- Moved per-backend health-check overrides into the Health tab: a monitored-only backend selector reveals one persistent editor at a time, without changing the JSON configuration schema. Newly enabled custom policies start from the current shared policy; previously customized backends keep their configured values. Disabling monitor hides the editor but retains the override. Preserving draft switching, validation routing, rename and removal is covered by the simulated DOM regression.
- Memory audit: access-file JSONL and Logstash now share one serialization for each event. Existing bounded file/error sink queues, live history, open files, traffic analytics and cache/transform budgets were checked in source. Removed two avoidable directory-inventory memory spikes: per-vhost log scanning now retains at most 256 candidates while enumerating and gzip-rotation scanning at most 64. Added a source contract and a Rust unit regression for 10,000 candidate filenames and deterministic newest-first ties.
- The Node/UI, source, security, upgrade, SQL migration, translation and documentation checks in
./dev.sh testare run in this environment; the Rust suite and full./dev.sh checkcannot complete becausecargoandrustcare unavailable (exit 127).go test ./...indocker-agentis run separately. The Rust unit regression is included but not executed. No real request-load test or long-running RSS/heap profile was performed, so the review cannot prove complete absence of runtime leaks. - No SQLite schema migration or Cold Cache format change; root Cargo package/lock and OpenAPI version set to
0.30.0. Use a Rust toolchain for./dev.sh checkand./dev.sh test, and measure RSS during sustained file/JSON logging, before deploying.
Same-version 0.29.7 PHP profile UI, Rust warning and error interception review (2026-10-09)
- Move the shared PHP-FPM Syntax and safety help button to the bottom of the profile-management dialog, below Add profile, with a visible horizontal separator. Keep the service-local help button where it was. The simulated Web Service UI test asserts this placement and that the help modal still opens.
- Remove the unused
mutin theweb_server::servebinding (src/proxy/forward/web_source.rs). - Correct application-error interception semantics in both Reverse Proxy and Web Server/PHP-FPM: responses supplied by a backend/service (including cache hits) are explicitly marked and are not overwritten by global/vhost error pages when
pages.intercept_statusesis disabled. RustProxy-generated routing/upstream failures remain eligible for the configured local error page. Interception is performed before cache admission; selected statuses receiveno-storeeven after response-header rules and always retain the application's HTTP status, ignoring a standalone error page's status override. An internal named-location fallback remains terminal and has precedence. - Rust regression tests cover the opt-in behavior, the marker's effect in the response observer, precedence and preservation of status with a differently configured page status. Source/UI contracts verify both forwarding paths and correct ordering around HTTP/2 WebSocket body adaptation; these are not substitutes for live protocol tests.
./dev.sh test: all Rust-independent source, JS, SQL/upgrade, security, documentation and translation checks passed; then exited 127 due to unavailablecargo/rustc. Rust compilation, unit tests and runtime HTTP/FastCGI/WebSocket acceptance have not been performed here. No configuration schema change or version bump.
0.29.7 same-version compile error corrections (2026-10-09)
- Correct the three operator-reported
E0308mismatches. Reverse Proxy origin interception now receives anaxum::body::Bodyresponse only after adapting the upstreamResponse<hyper::body::Incoming>, preserving the originalIncomingbody expected by the HTTP/2 WebSocket tunnel wrapper. The operation remains before transformation and cache admission. - Reapply configured response-header rules to an intercepted page, then restore
Cache-Control: no-storeso the admin page cannot accidentally enter shared cache through a custom header policy. Internal named error fallbacks retain precedence. - Build owned
Arc<Member>candidates for the active health-check supervisor and clone theArcinto eachJoinSet::spawntask, rather than attempting to spawn a future carrying&Arc<Member>. - Static/UI/source/SQL/upgrade/security/documentation checks passed via
./dev.sh testup to the Rust guard (exit 127)../dev.sh checkexited 127 before compilation due to missing Rust/Cargo. These are source-level corrections, not a verified Rust build. Operator should run./dev.sh checkand./dev.sh teston a Cargo-equipped host before deployment.
0.29.7 in-version PHP UX and origin error interception (2026-10-09)
- Both Web Service local PHP fields and shared PHP-FPM profiles now expose per-field examples, units, bounded syntax, PATH_INFO/Authorization/PHP enablement info tooltips and a common detailed help dialog; all localized through language packs. Configuration semantics remain unchanged.
- New optional
vhosts[].pages.intercept_statuses: supported unique HTTP error codes are validated; selected application-origin responses are replaced by vhost/global/built-in RustProxy pages before admission to cache, preserve the HTTP status by default, and carryCache-Control: no-store. The existing internal error fallback runs first. Empty/default list leaves existing origin error responses intact. - Added Rust source-level regression tests for default preservation, replacement, headers, precedence and malformed codes plus JS form behavior checks.
./dev.sh testran all pre-Cargo contracts (including Web Service PHP profile editing, origin-interception roundtrip, offline migration and security checks) successfully but exited 127 at the missingcargoguard../dev.sh checkalso exited 127 for that reason. Rust compilation, Rust unit execution, and live Web Server/FastCGI/backend routing remain unverified.
0.29.7 backend/cache/FPM policy review (2026-10-09)
- Backend monitoring now has an explicit per-member switch and optional policy; tests cover backwards-compatible defaults, serialization, inherited Host and validation. Membership in the balanced pool remains a separate setting.
cache.expose_only_hitsdefaults to false globally and may be overridden at a vhost. Tests cover HIT/MISS/BYPASS suppression, origin diagnostic removal, independently configured Via and cache identity stability. Actual wire behavior requires Cargo/runtime tests.- PHP limitation: user-supplied WordPress and Roundcube services both target
unix:/run/php/php_rustproxy.sock. Only Roundcube passes a restrictive FastCGIPHP_ADMIN_VALUE: open_basedir; PHP-FPM may retain this value across worker reuse, causing WordPress to fail. The 302 to setup-config.php is a consequence of missing access to wp-config.php. Added conflict warning, inline guidance and pool-isolation instructions; code changes cannot alter an already-shared PHP-FPM worker's isolation. The operator must provision and select a dedicated Roundcube FPM pool and restart/recycle affected old workers. - Source changes keep SQLite schema 9/Cold Cache format 3. Compiler-independent tests and verification are reported below; Rust compilation/live HTTP/2/H3/PHP integration is not asserted in this environment.
0.29.7 verification summary
./dev.sh test: all Rust-independent contracts, SQLite migration/backup/source-upgrade checks, JS vhost/Web Server regressions, source security/dependency audits, docs and translation checks passed. It exits with code 127 at the Rust/Cargo availability guard, becauserustcandcargoare not installed. This is not a successful Rust test-suite run.node tools/checks/backend_cache_0297_ui_test.mjs: passed; simulates the actual backend form toggles and verifies independent monitoring/pool-eligibility state, per-member health override and cache controls.- Rust-only regression tests were added but could not execute: effective active/passive member policies and validation, HTTP Host defaults, HIT-only cache headers, per-vhost policy resolution, and cache compatibility identity.
- Operator acceptance remains open: Rust compilation, real PHP-FPM worker isolation on separate sockets, alternating WordPress/Roundcube requests, live 404 fallback, and actual wire-level cache HIT/MISS/BYPASS checks on HTTP/1.1, H2 and H3.
0.29.6 FastCGI EOF and error-log routing (2026-10-09)
- Operator reproduced: uncompressed
/static.php/...returned HTTP 200 and 29,309 bytes with cache BYPASS; gzip returned HTTP 200 then TLS unexpected EOF and zero bytes. Repeated panics infutures-util 0.3.34stream/unfold.rs:108correlate with these failures. This is operator evidence, not a reproduced in-house integration test. - Cause identified in source: native Web Server FastCGI response bodies used an unfused
stream::unfoldover a Tokio MPSC receiver. The compression wrapper may poll the stream after it returnsNone; the unfusedUnfoldthen panics. The Reverse Proxy source uses an HTTP client body rather than this FastCGI stream. - Change: wrap the FastCGI response stream in
.fuse(). Add repeated-post-EOF polling test and mocked FastCGI-to-gzip completion/decode test. No changes to PHP-FPM parameters, vhost configuration or migrations. - Logging change: the existing error-file controller receives WARN and ERROR (including PHP-FPM stderr); the console tracing layer suppresses these only when the file is enabled, with fallback to stderr on file/queue failure. A Rust panic hook emits structured ERROR diagnostics instead of bypassing the sink via the default stderr hook.
- Add asynchronous file routing and live enabled/disabled toggle tests. Actual Rust compilation, FastCGI compressor tests, panic runtime acceptance and live Roundcube regression require a Cargo-equipped environment and remain unverified here.
- Release: Cargo package/lock root/OpenAPI and release checks moved to 0.29.6; retained SQLite schema 9 and Cold Cache format 3.
- Static checks passed:
version_contracts.py,docs_check.py,langs_check.py,rust_module_contracts.py,web_server_contracts.py,check_source.py,release_smoke.py,web_service_ui_test.mjs, and Node syntax/OpenAPI JSON parsing. The./dev.sh testrun passed its source, browser UI, security, memory and upgrade checks before reaching the missing Rust toolchain;./dev.sh checkexited 127 for the same reason.
0.29.5 Roundcube PHP PATH_INFO dispatch (2026-10-09)
- Cause confirmed by source:
serve_inneroriginally rantry_filesbefore recognizing/static.php/skins/...as a PHP script plusPATH_INFO. For an existingstatic.php, the lasttry_filescandidate/index.phpintercepted the asset request and could return HTML instead of the asset. - Fixed dispatch order following rewrites and path ACLs; execute existing PHP PATH_INFO targets before
try_files. Access restrictions also apply to the resolved PHP script path; the other fallback path remains protected. - Added
roundcube_static_php_path_info_runs_before_front_controller_try_filesandwithout_php_path_info_try_files_keeps_legacy_front_controller_fallbackusing a local test FastCGI server and decoded FastCGI params. These are source tests until run with Cargo, not validated against live PHP-FPM or Roundcube. - Operator action: ensure PHP-FPM PATH_INFO splitting enabled on the chosen Web Service / shared profile; keep
try_filesfor the main service. No extra special-case URL rewrite is needed for Roundcubestatic.phpURLs. - Static checks passed:
version_contracts.py,web_server_contracts.py,rust_module_contracts.py,docs_check.py,langs_check.py,web_service_ui_test.mjs, andrelease_smoke.py../dev.sh testexceeded the available execution limit while running broader staticcheck_source.py.cargo/rustcare unavailable; the new Rust FastCGI tests were not executed and neither was a live Roundcube integration.
0.29.4 PHP-FPM profile toolbar shortcut (2026-10-09)
The Web Server list toolbar now contains a PHP-FPM profiles button immediately before New Web Service. Both this shortcut and the PHP tab's existing profile button open the same shared profile-management dialog; no API or configuration schema changes were required. English/Polish button translations and a UI regression covering placement, both entry paths and closing the dialog were added.
node --check on the changed Web Server script and its profile helper,
node tools/checks/web_service_ui_test.mjs, and the focused version,
language, Web Server architecture and documentation checks passed.
./dev.sh test was attempted but exceeded the execution time limit during
the Rust-independent verification phase, so it did not complete in this run.
Rust compilation and runtime tests remain unverified without Cargo.
0.29.4 version bump (2026-10-09)
The PHP-FPM profiles, Web Server cache/transforms and HTTP_HOST fixes have
been assigned to a new 0.29.4 release. The source version, root Cargo.lock
package entry, OpenAPI metadata, release checks and documentation match 0.29.4.
The 0.29.3 internal-fallback changes remain included. This is a source release;
no compiled artifacts are included.
Release verification: python3 tools/checks/version_contracts.py,
python3 tools/checks/check_source.py, python3 tools/checks/docs_check.py,
python3 tools/checks/release_smoke.py and the Node Web Service profile
UI regression checks passed. ./dev.sh test completed its Rust-independent
source, migration/upgrade, security, browser and documentation checks, then
exited 127 because Rust/Cargo is not installed. Compilation, Rust unit tests
and live HTTP/FastCGI/cache/transform verification remain unperformed.
0.29.4 feature verification (2026-10-09)
The operator-requested follow-up adds reusable PHP-FPM profiles, fixes the
Web Server cache/transform bypass and supplies HTTP_HOST for authority-only
HTTP/2 and HTTP/3 FastCGI requests. Changes include Config serialization,
revisioned administration section and OpenAPI, Web Server browser modal,
route cache/transform pipeline and FastCGI parameter encoding. New Rust unit
tests cover profile resolution, detach, validation and HTTP_HOST; the Node UI
test exercises opening/editing a profile and attaching it to a service.
Rust compilation, proxy/PHP-FPM integration tests and performance acceptance remain unverified without Rust/Cargo. Static contracts and browser tests are run separately and do not substitute for production acceptance.
Changes
0.29.3 fallback correction (operator report): the replay-body guard treated HTTP/2 and HTTP/3 GET/HEAD bodies with unknown size hints as non-replayable, even when the stream was empty. The fallback guard now performs the existing bounded empty-body probe for GET/HEAD; a true empty stream is replayable, while nonempty/unknown-length request bodies are forwarded only once. The internal target lookup now warns when the named location cannot be resolved. Added Rust async regression tests for empty H2/H3 GET/HEAD, unknown-length GET payload preservation, and unbounded POST non-consumption. The observer also preserves the final internal fallback response (including its 404 HTML) instead of applying a second global/vhost error page; a Rust test exercises this precedence. These Rust tests have not been executed in this environment because Cargo is unavailable.
Same-version 0.29.2 correction: Web Server main routes no longer inherit transient_unavailable from the vhost backend configuration. When the Web Server source has no enabled Reverse Proxy Custom Locations, backend definitions are not compiled. An enabled reverse-proxy Custom Location still compiles and uses the backend pool. Removed fallback-only Prometheus metrics, retained PHP/Web Server metrics.
Validated operator-controlled PHP_ADMIN_VALUE FastCGI configuration per Web Service, with distinct PHP_VALUE/ADMIN directive sets, explicit panel controls and OpenAPI schema. Prometheus PHP Web Service request/status counters, response header latency and available concurrency permit gauge, plus Web Server service-scoped response statuses and header latency.
Acceptance limitations
The build environment has no Rust compiler (cargo/rustc). Rust compilation,
unit tests, FastCGI integration with a live PHP-FPM pool and runtime load tests
have not been performed here. Rust-independent checks are recorded separately.
This source package is not certified for production deployment.
Checks performed
-
0.29.3 release identity:
Cargo.toml, the rootrust-proxyentry inCargo.lock, administration OpenAPI version, README, CHANGELOG, ROADMAP, AGENTS and verification-report heading were updated to 0.29.3; the fallback source changes from the tested 0.29.2 correction are retained. -
0.29.3 offline validation:
python3 tools/checks/version_contracts.py,python3 tools/checks/check_source.py,python3 tools/checks/release_smoke.pypassed;bash ./dev.sh testpassed all listed non-Rust checks and stopped at missing Cargo with exit 127. This does not constitute compilation or successful runtime testing of RustProxy 0.29.3. -
Fallback correction:
bash ./dev.sh testpassed Rust-independent module, source, upgrade/SQLite, security, browser UI and documentation checks. It exited 127 at the missing Rust/Cargo toolchain.bash ./dev.sh checkalso exited 127 because Rust/Cargo is unavailable. The added Rust regression tests and the live HTTP/2/HTTP/3 proxy behavior remain unverified pending a compiler-enabled runtime and an operator test againstorigin-1/origin-2. -
Same-version correction:
python3 tools/checks/check_source.pyandpython3 tools/checks/release_smoke.pypassed.bash ./dev.sh testpassed the Rust-independent checks and stopped at missing Rust/Cargo (exit 127). No live 503 regression test or Rust compilation could be performed. -
./dev.sh test: all Rust-independent release, upgrade, security, JS, UI, documentation and source checks passed; exited 127 at the missingcargotoolchain guard. -
node --check src/admin/web/web-server.js: passed. -
python -m json.tool src/admin/openapi.json: passed. -
./dev.sh check: exited 127 because Rust/Cargo is unavailable.
Debian deployment maintenance (same 0.29.2)
Installer/update now installs /etc/logrotate.d/rustproxy using the recorded service user/group. Updates repair /etc/profile.d/rustproxy-path.sh rather than warning. logrotate uses copytruncate because RustProxy holds open log descriptors; some log records may be lost during truncate. Rust build and live Debian/systemd acceptance remain unverified in this environment.
Version identity (0.29.7 source release)
Cargo.toml package version is the canonical release identity (now 0.29.7). Rust uses CARGO_PKG_VERSION at build time; build.rs substitutes the admin HTML placeholder. Packaging, upgrade and dev scripts read the manifest with scripts/version.py. Run python3 tools/checks/version_contracts.py to check that executable paths do not hardcode a version. Historical documentation and external dashboards may retain manually managed versions. Rust compilation/runtime verification is still pending.
Shared PHP-FPM profiles and Web Server cache/transform/Host patch (0.29.4)
- Added a revisioned
php_fpm_profilescollection with per-Web-Servicephp_profile_id, preserving the local PHP configuration when a shared profile is attached/detached. Added profile editor modal, schema, Polish/English messages and browser regression test. - Web Server vhost/location responses now pass the configured RustProxy cache, vhost response rules and transforms. Cache skips ineligible/private/
Set-Cookieresponses and handles cache hits, conditional requests and range requests. Filesystem/PHP requests are refreshed synchronously rather than using the reverse-proxy background revalidator. - FastCGI always supplies
HTTP_HOSTwhen HTTP/2 or HTTP/3 omitted the ordinaryHostheader; existing explicit Host with port is retained. Added Rust regression tests for both paths. bash ./dev.sh test: all Rust-independent release, source, security, browser UI, documentation, migration and dependency checks passed; stopped at absent Rust/Cargo (exit 127).bash ./dev.sh checkalso stopped at absent Cargo (exit 127). Rust compilation, new Rust tests and live PHP-FPM/HTTP2/HTTP3 cache/transform verification remain unverified in this environment.