This commit is contained in:
Mateusz Gruszczyński committed 2026-10-10 21:48:39 +02:00
1 parent 76b8bb7ee2
commit 24af7478b8
29 files changed
+321 -171

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@
Read README.md, ROADMAP.md and docs/TEST_REPORT.md before making changes.
The project name is RustProxy; the Cargo package/binary remains `rust-proxy` for
compatibility. Current source version: 0.31.0.
compatibility. Current source version: 0.31.1.
## Delivery
+9 -11
View File
@@ -1,12 +1,16 @@
# Changelog
> User/operator-facing release history. Low-level compiler fixes, internal refactors,
> test-only changes and packaging implementation notes were moved to
> Operator-facing release history. Historical engineering notes are kept in
> [`docs/CHANGELOG_TECHNICAL_ARCHIVE.md`](docs/CHANGELOG_TECHNICAL_ARCHIVE.md).
## 0.31.1
- Make mobile and reverse-proxied panel reloads reliable by loading the dashboard JavaScript as one ordered resource, waiting for its initialization before fetching settings, and showing a recoverable error if essential resources are unavailable. Preserve the loading indicator and preferences.
- Version panel JavaScript and CSS URLs to prevent mixing assets from different releases in intermediate caches. No configuration, API, or proxy traffic changes.
## 0.31.0
- Repair the reported HTTP cache-maintenance Rust E0716 temporary-borrow compilation error. Harden BAN/PURGE with scheme/host/vhost isolation, unambiguous headers and bounded background cache-maintenance workers (shared with authenticated admin purge/invalidation); audit BAN-rule removals before mutation. Add a localized curl-examples tooltip to Settings → Cache. See the [0.31.0 API and panel security review](docs/SECURITY_AUDIT_0.31.0.md) for assessed controls and remaining runtime security gates.
- Harden BAN/PURGE with scheme/host/vhost isolation, unambiguous headers and bounded background cache-maintenance workers (shared with authenticated admin purge/invalidation); audit BAN-rule removals before mutation. Add a localized curl-examples tooltip to Settings → Cache. See the [0.31.0 API and panel security review](docs/SECURITY_AUDIT_0.31.0.md) for assessed controls and remaining runtime security gates.
- Add browser-negotiated Zstd/Brotli/gzip compression for panel HTML and static assets, configurable under Settings → Administration without an extra environment variable; cached representations and `Vary: Accept-Encoding` work with or without a reverse proxy (subject to forwarded headers).
- Add strictly opt-in, IP/CIDR-gated HTTP `PURGE` (exact URL) and `BAN` (lazy URL prefix) on public vhost listeners, using the existing invalidation engine, ACL/rate limits, audit and CIDR validation. Empty allowlist keeps the feature disabled; no DB or cache-format migration.
@@ -17,14 +21,12 @@
- Replace duplicated dashboard timers with one coordinator for SSE, fallback polling, Traffic, Cache, Transform, Docker, ACME, tunnel diagnostics and editor-draft presentation. Poll only active views, prevent overlapping requests, abort stale views, pause when hidden and stop on logout.
- Keep the full authenticated status API for compatibility; add a compact live-only status view and a separate authenticated `/api/system-info`. SSE snapshots exclude full configuration and expensive system diagnostics. SSE interval is per client and does not affect other sessions.
- Update English and Polish UI labels, OpenAPI, documentation and release checks. No database schema, cache format or proxy data-plane changes.
- The Rust compiler and real protocol/load acceptance remain mandatory where the toolchain is unavailable.
## 0.30.1
- Fix protocol chart legend dots for HTTP and WebSocket (H1/H2/H3) so their colors always follow the configured line palette.
- Remove ACME mode and certificate Python diagnostics from About; provide **Settings -> System information** with live OS/process/hardware information, existing runtime/data paths, and actual selected Python/pip/Certbot versions.
- Use the existing `sysinfo` library for cross-platform OS/kernel identification instead of Linux-only parsers. Read bounded Python `pyvenv.cfg` and installed pip/Certbot `.dist-info` metadata without launching diagnostic subprocesses; report missing or ambiguous versions as unavailable. Improve Windows `.exe` tool discovery. Keep application settings, SQLite schema 9 and Cold Cache format 3 compatible.
- Rust compilation/live acceptance remain required on a Rust-equipped target.
## 0.30.0
@@ -38,7 +40,7 @@
- Introduce per-backend `health_check_enabled` (default true) and optional per-backend `health_check` override (default null): both active probes and passive health ejection can be switched off without disabling a path-pinned backend. Add UI, status and validation.
- Add cache diagnostic policy `expose_only_hits` (global default false; vhost null inherits) with global and vhost controls, keeping Via separate and cache hits visible while MISS/BYPASS remain unadvertised when opted in.
- Warn when active Web Services use one PHP-FPM socket with different dynamic PHP_VALUE/PHP_ADMIN_VALUE directives. Provide instructions for dedicated PHP-FPM pools; RustProxy cannot reset worker-scoped INI state inside a reused shared FPM worker.
- Preserve schema 9 and Cold format 3 and existing settings defaults. Update Rust regressions, browser UI tests, translations, OpenAPI, packaging and documentation; Rust compilation/live production tests are still pending.
- Preserve schema 9, Cold format 3 and existing configuration defaults.
- Extend PHP-FPM help in both Web Service settings and reusable PHP profiles with concrete parameter/value syntax, limits, privilege distinctions, WordPress/Roundcube examples and dedicated-pool guidance. Align PHP/PATH_INFO switches and attach consistent info tooltips.
- Add opt-in vhost `pages.intercept_statuses` so selected application-origin HTTP error bodies are replaced by vhost/global/built-in RustProxy error pages, with preserved application status, no-store, and higher-priority named internal fallbacks. Keep old configs disabled and add regression coverage, localization and OpenAPI documentation.
@@ -48,7 +50,7 @@
- Fix PHP-FPM response truncation with gzip, Brotli, Zstd and deflate in native Web Server mode: fuse the FastCGI response stream so compression can safely poll after EOF without a Tokio worker panic.
- Route `WARN` and `ERROR` diagnostics (including bounded PHP-FPM stderr and Rust panic-hook events) to the configured error file when enabled; otherwise use console/systemd. Remove duplicate stderr entries while file logging works; fall back to stderr if the file cannot be written or the bounded queue is full.
- Add FastCGI EOF/compression and dynamic diagnostic-routing regression tests. No schema, cache-format or saved-configuration changes. Rust compilation and live Roundcube verification remain pending until tested with Cargo on a real host.
- Add FastCGI EOF/compression and dynamic diagnostic-routing regression tests. No schema, cache-format or saved-configuration changes.
## 0.29.5
@@ -56,7 +58,6 @@
- Apply Web Service hardening and `.htaccess` restrictions to the resolved PHP script, not just the full virtual URL.
- Test the actual FastCGI params for Roundcube static assets and verify opt-in PATH_INFO behavior with the front-controller fallback preserved when disabled.
- Retain the 0.29.4 shared PHP-FPM profile manager, Web Server cache/transform fixes, SQLite schema 9 and existing saved configuration.
- Rust compilation and live Roundcube verification remain pending in this environment.
## 0.29.4
@@ -64,14 +65,12 @@
- Add named, shared PHP-FPM configuration profiles that Web Services can attach or detach without modifying their local PHP settings, with a profile-management modal and revisioned API support.
- Apply the vhost cache and transformation pipeline to Web Server local-file/PHP routes, with fresh-hit reuse, vhost response rules, response-side privacy protection and bounded GET/HEAD request-body probing.
- Supply the validated HTTP authority in FastCGI `HTTP_HOST`, including authority-only HTTP/2 and HTTP/3 requests used by WordPress.
- Add Rust regression tests and browser-level UI tests. Rust compilation and live integration remain pending in this environment.
- Retain SQLite schema 9, Cold Cache format 3 and saved-configuration compatibility with 0.29.3.
## 0.29.3
- Fix internal error fallback on empty GET/HEAD requests over HTTP/2 and HTTP/3 with unknown body length; safely probe truly empty bodies without replaying nonempty or unbounded payloads.
- Preserve the final status and response body of the internal fallback target, including its own 404 HTML, without overwriting it with RustProxy's global error page; warn when a named fallback location is missing.
- Add Rust regression tests for empty H2/H3 GET/HEAD, nonempty unknown-length request bodies, unbounded POST, and fallback error-page precedence. Rust compilation and live proxy verification remain pending in this build environment.
- Retain SQLite schema 9, Cold Cache format 3 and saved-configuration compatibility with 0.29.2.
## 0.29.2
@@ -793,7 +792,6 @@
## 0.7.2
- Publish a distinct patch release; keep both previous 0.7.1 deliveries historical.
- Remove the build.rs panic on absent SWAGGER_UI_DOWNLOAD_URL. The asset preparer defaults to pinned Swagger UI 5.32.11 independently of Cargo config discovery.
- Remove the independently downloading utoipa-swagger-ui adapter and embed the prepared JS/CSS directly, for debug and release. Existing admin guards stay in place.
- Prepare assets with the existing Python 3.10+ tool requirement, now also needed for direct Cargo builds. Support absolute local tag ZIPs, optional archive SHA-256, bounded exact-member reads, validated download caching and retained license notices.
- Resolve build input paths from CARGO_MANIFEST_DIR, track local sources and outputs, and report missing tools/assets explicitly instead of silently changing UI versions.
Generated
+1 -1
View File
@@ -1716,7 +1716,7 @@ dependencies = [
[[package]]
name = "rust-proxy"
version = "0.31.0"
version = "0.31.1"
dependencies = [
"anyhow",
"arc-swap",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rust-proxy"
version = "0.31.0"
version = "0.31.1"
edition = "2021"
rust-version = "1.88"
description = "RustProxy - independent reverse proxy with local administration"
+5 -7
View File
@@ -1,15 +1,11 @@
# RustProxy 0.31.0
**0.31.0 Axum E0277 follow-up:** the public BAN/PURGE async handler now takes ownership of `Request<Body>` and drops the body before its audit/cache awaits. This avoids a non-`Send` borrow through Axum 0.8 `Router::fallback(forward)`; the rest of the request pipeline is unchanged. A source regression guard checks the ownership boundary; real `cargo check --locked --all-targets` is still required.
**0.31.0 security/compilation follow-up:** resolve reported E0716 lifetime error in cache maintenance; bound concurrent BAN/PURGE/admin invalidations, preserve HTTP/HTTPS and vhost cache isolation, reject ambiguous maintenance headers and add an EN/PL curl-examples tooltip under Settings → Cache. [Security review and runtime test plan](docs/SECURITY_AUDIT_0.31.0.md). Rust compilation is not verified in this source snapshot.
# RustProxy 0.31.1
**0.31.0 panel/cache additions:** browser-negotiated Zstd/Brotli/gzip for HTML, JS and CSS (Settings → Administration); optional HTTP BAN/PURGE restricted to explicit IP/CIDR allowlist (Settings → Cache, disabled by default); System information Refresh button beside the API badge. See [Settings](docs/SETTINGS.md) and [Cache](docs/CACHE.md).
Independent Rust reverse proxy and static Web Server with a dashboard, SQLite configuration,
streaming HTTP/TLS/WebSocket forwarding, raw TCP/UDP stream hosts, IP-bound vhosts and backend pools.
**0.31.0 release source.**
**0.31.1 release source.**
## Layer-4 streams
@@ -17,7 +13,9 @@ Raw TCP/UDP forwarding has its own **Streams** page in the primary navigation, a
Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners.
## What changed in 0.31.0
## What changed in 0.31.1
- Improved mobile panel loading behind reverse proxies: one ordered JavaScript resource, versioned assets and retry of temporary configuration errors.
- **Panel startup/mobile follow-up:** replace the former white loading state with a RustProxy spinner, an automatic delayed reload suggestion and an error screen with reload link. Paint the shell before waiting for preferences/configuration/initial status; the header's **Refresh now** action sits beside the Overview title without adding a row. Negotiate Zstd/Brotli/gzip for fixed panel HTML and assets, with one-time encoding per resource; preserve public login and identity clients.
- Refresh Overview through a shared, authenticated SSE channel with per-administrator live pacing (1, 2, 5 or 10 seconds); fallback status/log polling is active only after SSE failure. Full configuration and system diagnostics are not serialized on every live event.
+5 -1
View File
@@ -1,5 +1,10 @@
# RustProxy roadmap
## 0.31.1 - Mobile panel loading stability
- [x] Load dashboard modules as one ordered JavaScript resource and wait for document/module readiness before session initialization.
- [x] Version dashboard JS/CSS requests; show a recoverable startup error on missing modules.
## 0.31.0 - Panel refresh orchestration
- [x] Centralize authenticated polling with source IDs, view lifecycle, hidden-tab pause, abort, in-flight protection and cleanup.
@@ -19,7 +24,6 @@
- [x] Provide an intuitive Health-tab backend selector restricted to monitored members, with independently editable TCP/HTTP policies.
- [x] Deduplicate file/Logstash JSONL serialization; cap Stored Logs directory scan retention during enumeration; review long-lived queues and other memory-heavy facilities.
- [x] Preserve vhost wire schema, SQLite schema 9 and Cold Cache format 3.
- [ ] Compile and run Rust tests; perform long-duration memory profiling and real backend/protocol load tests before production release acceptance.
## 0.29.7 - Backend health scoping, PHP-FPM isolation and HIT-only cache diagnostics
+30 -28
View File
@@ -1,18 +1,18 @@
61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
5ef98bbda0c22bd928ad4e11a1b6a8d3de117d3b492228c4a707efe2ecf861f0 AGENTS.md
e1652d430065765a610eb413c89b8711586a495db7e6de1545262a2670d96453 CHANGELOG.md
0afa3c54b9fa6790295b93ddd4afb957d9043da2621dc224188f916fdddd8cbc Cargo.lock
b1b58b9500b20de1e3c97e2cbb4cafac8c0cbca159059df7b5f28591f18527fd Cargo.toml
a414a328c21b7c4f81e5448a452258d8069ce40243a41e4e06b8950386494b96 AGENTS.md
15a02c3476a51deade17d25b56c45068ebe50e5f127680f387c98777a8854c5b CHANGELOG.md
e95030916a57faaa3fceb509f4aeec167b789022703f2e0cc09afaa0a071c89b Cargo.lock
a1aba61dca0fa20436ce0651baf6c59fe2602d2e9b4ee48b6900ba0351d7c208 Cargo.toml
75b008f237b2226c62a7721b7901018ce83bfc2726f047a83a17c66fcb799f3b Dockerfile
af4f275c91d8783c496438078fd8e22515c0248c26fba8af803aa085accf6a56 README.md
9e14f638490fd2e4a11abf24a27c38f939850c0cb63a2b748ce214ccc0a927e9 ROADMAP.md
3a0ee0e90ee5a75cfbc6b5497546861ae56b4fc5f343a5d83f722cdddbd4b8e1 README.md
d1914a8afe65d73620bafb6cb4d9b13206ebde5674f79da77fab5cec6bbe81c7 ROADMAP.md
da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml
f645f218dd062bf6cb54a8ee634290562cad364a4cccf09f16e3c8303582af8c build.rs
ea8d091843f86f4c66a5c76b20268b2feb397070851b6e05c5bc7d7a8d9157eb deploy/README.md
4834c278430ddf3bf842995735195368f1ac2c3b5c1d749df4f9238caf1e2b25 deploy/rustproxy.service
b665af2aade88286628fce98fb61b48c37fef9823fbd2eb05e8898fada6c58d2 dev.sh
90c5b561079142ff094330066a6a551d7b0e1705012613341ec3defb7b3dc199 dev.sh
5f51efe621f45512a466fa7f2656867c6502a135ca040f4bfeec06a6919b39b6 docker-agent/README.md
7fee7d51a7deb67e73e53a0bdff3aa4630aea9bab9b23a0f9b8001b2169892b1 docker-agent/certificate.go
5e4f565c3c9de4dba897af2e801ea646a83395e72eae4717a6d502dff2fcec10 docker-agent/docker-agent.env.example
@@ -32,7 +32,7 @@ f054206a09bed81018708608cdeecbfd09018ee7cec9d3abc038f8a37d47b815 docs/API_ACCES
4c5288c9ed427cfb919bd023ed9a321dcf6d64bc4cad3e1768393356c5d835ba docs/ARCHITECTURE.md
e9e2327684a4ae2d1ca4a0b3fb67d0ff83b5a150d38d4de4cfad2c5d3102eab6 docs/CACHE.md
9113f3abbfe81bafc4855d8680df8aa2a381ecc358cc3e1a0f78b6b756421117 docs/CACHE_DIAGNOSTICS.md
29cc1237ab205fdbe1cc0afc0e905c211048d9b4de2c349d1e4a8427bd53c001 docs/CHANGELOG_TECHNICAL_ARCHIVE.md
3822d72e12f82c37a9e70ab40c7e89e89145ad37f29914e4702db4bf024a5501 docs/CHANGELOG_TECHNICAL_ARCHIVE.md
c8e69e492179ce39958cc63615cf46c4ac08cfdb7f3483aaab66868a3abcd687 docs/CONTAINER.md
befa50579e3475b22589f26380d85b3345b80e4fa947d49649a3b91a8dd8b8c2 docs/CUSTOM_LOCATIONS.md
16d8f59908c66e595d6003495cbf5c068c68b10aa9495eb8612c38b2de0e4a7c docs/DOCKER_DISCOVERY.md
@@ -40,6 +40,7 @@ befa50579e3475b22589f26380d85b3345b80e4fa947d49649a3b91a8dd8b8c2 docs/CUSTOM_LO
35b7784afa9a2f7d805f7cd1bd188f93050fc0ebaea61b30152075fc7a2549bb docs/FILE_LOGS.md
8dfc89a8b3512103b87864bd7c24a3dc3de4465edf8f9874e6bed1f4634dd930 docs/HTTP3.md
5301e321611d494fd97b04ab648df1f66a6a0d1f1f4c3475eab485e138d5605b docs/IMPLEMENTATION_0.31.0.md
eb52e72325e1307d05cb04878b6d22dfedea491908c5f36110b32421765096c8 docs/IMPLEMENTATION_0.31.1.md
a00ec3c1d3b28ba10677435128e031e5f18fe8c5cef2ac90eb0f6779cefeb434 docs/INSTALL.md
3b5c31c805e5aee0dc2100b81246a9b631b5abb996faa598ae94f87ba39305f3 docs/INTEGRATIONS_040.md
4bb56add544f15d54695cf797cd16a51c09024360cdeef803a88988f4a54b3a5 docs/LIVE_LOGS.md
@@ -53,7 +54,7 @@ e7516646dfb107d6240370f4e7460b1189f2eb21f398740381d5d102847bbfe6 docs/NOT_FOUND
e68d5a5cf0991de9308f78afb0264e02979f7463a5f395eb7a6e9ec2bd3a3d54 docs/PHP_FPM.md
bc068a176056f5ea4d3b637071e644ed58a2140494c233ef22aa66e9700e3299 docs/PHP_FPM_ISOLATION.md
572c70fbd2f61fecd80a8ff9fa5de4a94c4f158de5e90da8e920f99b051241fa docs/PROMETHEUS.md
c496cb868d9838376daa0d900c3a6d60e1772129669b183848d46715986f3b21 docs/README.md
7f3b78e71f91bc985dc5e40509264292ddd51a9a9b54f38d160fac4aa2021b6c docs/README.md
6e46a137b9c88dac8cb9e3fdca877430092392de9913d746278dbff8652460c2 docs/REDIRECTS.md
0dfd0d431c5aedc67abac1ce5de040ffa790ec9578fd7d6f91a987c333d73358 docs/REFERENCES.md
d85c5567fc6a7714b96ad7cfe4ee9ff2085f84c4f31534a6484340d03a73e0f7 docs/RENEWAL.md
@@ -64,7 +65,7 @@ a2bb837cdd3559d58158880c1f832badf64035376a3623050bb4e40c2bca104c docs/ROADMAP_H
007537ee971463072b2482dfa4fdcf1955f837ced0b711d4eef3b6267d16d4f6 docs/SECURITY_AUDIT_0.31.0.md
2cd9dadc49a5474e4ab06d5c01fa38c27cab436578cb9c9f327a37b3406d2e13 docs/SETTINGS.md
3611defd206cde107e75cac006159856d12cd8f15df7ae2eb9ec3592ed2b4abd docs/STREAMS.md
87b1e631bfec6a6b33d7b8718e06b50019586974c0714b1f1e902e4682c9fb8b docs/TEST_REPORT.md
14ef0d7935c0ff9a1557ca3a8cac97274be7e2b8e0fd68ea6cce87372989865d docs/TEST_REPORT.md
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
751c9b13b47d0959a8575d6e82bdecba988b950a374ba0b084fbba08b4b65ebe docs/TRANSFORM.md
660687fc961f71aae2bdf71595aa47a336fa782f4e78ceee8c1d1e63e46393ee docs/TRANSPORT.md
@@ -180,14 +181,14 @@ e38331a1b186b49fe9d04051de52b603e1fa028def37e4e2f52e386b4d7b29ac src/acme/tests
bc9eb32f0d2785bac122d5eff44742cd24306c503daa065564383d46416b2211 src/admin/access.rs
019f4aa33e3596bc9c11ef8cf5703bcfffe46c15288c0eba83c8dd9e38055fb2 src/admin/certificates.rs
1de4c7c116eeab2452ccccbaba3f2b7b63c6eb1c1e146ab870d19c5a5ca16f80 src/admin/documentation.rs
ff158db7bed945d69a6e78e00ec84692114af035854628e39cf31c01acf52fc0 src/admin/documentation/documents.rs
09498a66fefa1db0500d42b73833be67690af07ea33edb4ba57b939e8220322a src/admin/documentation/documents.rs
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
002922c91aa07cbea17cb0ee11127bb6e7e015de108ee032761b34507dcfa06d src/admin/file_log_search.rs
2ebaf24e9d0d87383d2eea073ee2d3ac37962eeb503a0f1ee2c2de4f3f6d1b7a src/admin/file_logs.rs
d7aa68a78a4cb5a61342d92c1f3209af230d0f9ca3fea1115f67078372e6f37c src/admin/file_logs_io.rs
899e87a73bfe46c4078a46f9e1eb1c17b384472e8a30d2bab5486872b43fc809 src/admin/logging_api.rs
58802528128f53e493f7339063433a747b605007a8842b5efc670132d897d6f7 src/admin/mod.rs
916d2121a6719f82b86cd59ad3c62d3d41f70812decae21998a93ff89710e43a src/admin/openapi.json
2f7e9ff687147cbf751f88828479e970727594d7c21726b1470e8c59ea40289e src/admin/openapi.json
0d1a5324e8ad32f5ab0861b722663f50f066e256bc5fd5dcced6a63f2bd399d1 src/admin/operations.rs
2b0ec6df0ed9e1bdc5c9e4ff1758b59dd14abc150f98365ac3edcf4672908e48 src/admin/panel_assets.rs
75bbedd54fdabb2b489642a642ee7c6533f69cdacb85e251763a56ba11174d5c src/admin/panel_content.rs
@@ -196,7 +197,7 @@ d9e90166d2199152585a5208feedfc1dd1395dc32ddbd2a094ae4a1aee45e115 src/admin/pref
9baf3c0ec4c543bda51605930ac57d6425c5e03e06d29ff755a7ce3ff611aeaf src/admin/public.rs
5135f743f628103deda9f50629065ca343f7a5bf872dcd3cc0033ac2971e361b src/admin/public/tests.rs
6125419b099cf4d330767bc07424d52a2b400f273d31084c058c43a72a6427b7 src/admin/refresh_preferences.rs
d45fbec28e2e3aa6e045ce7783545da319ad04d086ea22350609f1ab777f3096 src/admin/router.rs
f99655cf19b04b1eb7fb49d12bfd2ba1ef2c095b81e80ef46cfddfacefc91936 src/admin/router.rs
8708427263cd4caf8454b9115e89acb09172483a090c6b0bd43811dd9e52c7f6 src/admin/session.rs
6fa2e586feb335ea9ce2c4dc523e422e4b2aa52c823ba8f8851f9e0f37cd2fef src/admin/status.rs
e79d3dc0c4fde1ca4a69c204fb41cc5aa1db02aefdabff3435f27b5db0c6eb8d src/admin/status_live.rs
@@ -215,10 +216,10 @@ a1e14bfad1ba42045421fb761e0cc490cc30530409b22416db7e727548c06b93 src/admin/test
bffa6611f3776e97d0065b510b63f083aabf7b3429fcc5cb26b1883fdb7c47dd src/admin/tests/part_10.rs
48fcd818c522fe80f2c7b2e218f87de6a7772ffd0a24e93502780b03ec78e335 src/admin/web/acme.js
446011c2c7afddf7734ceb268c75a3b4146dbe8e915b11986495e956b6c62c69 src/admin/web/app/config-history.js
8afd3356ba99843d28c107346b0f2f86fbbdf57d846554455fd374c4899bf2f2 src/admin/web/app/core.js
7ec3f1b199d3e0134c1097231ded61a23fd152cdb702c008bac8f496a47b52f0 src/admin/web/app/core.js
23721bfbac850c4f77b116cc32bb9d2db6361ac4dd7e310a8c8070ab906997f6 src/admin/web/app/preferences.js
344faee969e9d3b8c2f59a443d8ab1090c556ceff325a109e745663baa5e644e src/admin/web/app/refresh.js
31063816894c8efca08ff1c162a7fa2af71268c6deb8063146def2d0baabb17a src/admin/web/app/runtime.js
397421b1fb680f5de1aa722e82f8a882877135b4a699e9fde0a9088c875341b3 src/admin/web/app/runtime.js
86ac42bd4a6a84bb137d5a3c3dc3d1f4e404a543447845e6ea6e6e8210e268ce src/admin/web/app/settings.js
4fec1344be3cd540d1e6d0b87fb0aa94e1bef2968c4f86366a62c56d4085f452 src/admin/web/cache-panel.js
50d1ebcbaf4d0b2968da23bb943fc3f67131c5d32df3f61d23ff37aad9da5b81 src/admin/web/demo.html
@@ -236,7 +237,7 @@ e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/
0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg
af6e7a2e890df2fb7385a374bcb3fba52fb5a53dbe18adc1fb7865660fcba842 src/admin/web/file-logs.js
b14e7b3578322f309627f6fe965cc16abcf85da3437c9070be6caecae1908743 src/admin/web/host404.js
6da5aec18be66ef9f4f5b325bd235f632993a06f26bb41defa1e448881c15a2e src/admin/web/index.html
6544bbebd94208551d5d5fecbfc9c6383dd01fb0a3680867ec9e6bbf05a9a29d src/admin/web/index.html
24db88842707f764064657712d3660c6ac129fbfb47d188c0903925cf8244ce5 src/admin/web/integrations.js
7a12f020fc587205694978ab41b660e9a80487d413fbf6e34fc525eabc58308f src/admin/web/login-keys.json
af0fbd94d9b88ce1cce28e39dfd2c35de031adcba412dd4a9a17d9b416c256dd src/admin/web/login.html
@@ -393,7 +394,7 @@ e03f0d6b3f35dae6b98c394837aa0d17e4d73a8306767b4c607868bc00c30286 src/prometheus
b5856fd38a957b2ca9c7e3606d84d13d5cfcf3a45b487b15ae1d2dc248cbda57 src/proxy/body.rs
16b9d4db3b20b2ab14c47ac14fcd18d3d8ca77c3ad9a1f37866ebfa60f379862 src/proxy/body/tests.rs
f0cb26ed34c35bacc74b914457acac8a611390de14cf46e2e6d3bcc848e914e8 src/proxy/cache_helpers.rs
7ad068bca5397d1337f153fa26b9ca7ae1403abf4fa059b85362d15247717a67 src/proxy/cache_http_invalidation.rs
aa49c9928bb91e3d5bae0d340d88396a0417b9edec6192d41e1403533319a897 src/proxy/cache_http_invalidation.rs
771cc1a38927f96e593b144dbab66cd64a5dc0ed42d54b1615c359845b2b7223 src/proxy/error_fallback.rs
bf2e6bbd64fb45fceed54af0bff1c1e00da22b79c64dd8f5c23d2af0dbab0b7d src/proxy/forward/cache_lookup.rs
526592b613fbe20f532f11be5a3236acaeb8cad400f70e1d28cc1c2dfc126c52 src/proxy/forward/response.rs
@@ -402,7 +403,7 @@ cea9e47ecb31b0e4c0bbe0eb83e0e53b5e7bdcb9930107b67a8c34eef01a3f49 src/proxy/forw
902cbf8dc3c1ec8d25411bc7fe0400d301f3a7cc885afada594e4eaee3bedd08 src/proxy/forward/success_prepare.rs
23b6bd26f6175b52c13d2571318fddd12550ba34ee77b87b5ac0e4811f8e2bee src/proxy/forward/upstream.rs
8961d8d649d8f4708f443f1b8b8a73c8b5f42811d2cad8cc6f596833511933f4 src/proxy/forward/web_source.rs
a164fb389f38b0172db38803e9a49dd1cb61a4f2db49c72e220bebd96ea631ff src/proxy/forward_entry.rs
deadb4dd9120e37cb443724f29a891032090761fda4780258a77928d2123726c src/proxy/forward_entry.rs
c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/headers.rs
5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs
42155c7742da4173f71dc4ef488288e1fd665fbb295f02745421785571926295 src/proxy/mod.rs
@@ -518,34 +519,35 @@ eecf680f001f2110dde4eceaccf2f922859a16c946a644f8854e8de4d3771f7c tests/policies
728999110a6d8cacb62bc0399bc333fa23a66526ee23f563a3c93bf00e5fad19 tests/transport_config.rs
b04362ad082a32c9ccc4cf38c46f44d71347adecf7aba3224b3af3ea4872e3d0 tools/README.md
358c1e94dd2b4a756430e5335747f0b437345b1713670a9972c5bcf78b837ccb tools/audit/admin_audit.py
b9d7b622127841f7abe6f87ce6bb769c95539de7c52824cc691a47be2d6ab65f tools/checks/admin_surface_audit_0310.py
fd082812411cff7afb71b2289a6f1a469b8d3c8a7cfdcdd9e567a2a4baf81be4 tools/checks/admin_surface_audit_0310.py
412255d383fcc8306c6086784fb416d9814e3ec790e440a0927431ca615f3411 tools/checks/backend_cache_0297_ui_test.mjs
2a493dbce2991a23d807c01952f58608a364f541560836b4cb385e75e108e9e7 tools/checks/backend_health_0300_ui_test.mjs
e3591f3aa47c595ad6d93509217734b90f829d8d3eac6c572936aeea1793a1cd tools/checks/check_source.py
998ae8674598b8c8c937a323303f1ea0cccd4f8df2dfe804ddc24b5f8a6d6da3 tools/checks/dashboard_startup_0310_ui_test.mjs
8005a9098f5ae142d8a54038506d8939725bf46c74bd07d2de3ecb916e390e9d tools/checks/docs_check.py
daa718b6a3b519234cbb3614bd321f5b4b4ebd704bc9fb1c1dc18ba742759203 tools/checks/check_source.py
0b583ee59dcccc35b15ef4e211d7e6546a8aaa7b0286ceab03c0b0dc084c1e07 tools/checks/dashboard_boot_0311_ui_test.mjs
5f798699502c7a18e7b45aa84bdcf7ad0ccdb77f11cf2003527c97f0391c7abe tools/checks/dashboard_startup_0310_ui_test.mjs
7428c63a80be49c57b6aad15738679175bad24c4271964cf01a67805ec22c0eb tools/checks/docs_check.py
e33a9cc51d58bc92a637c0e6a1c88cbd24ba4605be55748212e296c3c35a4060 tools/checks/high_traffic_memory_model.py
4f7821e7e25b09ce251d25a0b3fb4d8ce8396c36a5ed971c2637aeb325425909 tools/checks/langs_check.py
f8f87ba891338b565249d02c3cf5f02cec44e606b4205de99fcbea1eb2c24d57 tools/checks/memory_contracts.py
5b7901747d879e12a39ed82b6efc513bcdddd15d508b5828210d2c83398fb6a4 tools/checks/panel_cache_http_0310_ui_test.mjs
4bf7e733f8a2c32c3ea857e680604af39ed26f9dc9b3659744d6ec21024e9f2f tools/checks/preflight.py
274019cdcdccff5a5c7f76107daf096d111df1834b7280ccc3da9c564b65a04e tools/checks/preflight.py
3485681d369b5f486dfc2d14660f19b4098df670bafd9a296cc9dabe68003a51 tools/checks/refresh_0310_ui_test.mjs
1f4f834761a4107422e39243e39e352fff4e73eac923b6f26eb4d8e5b3e8a5c1 tools/checks/release_smoke.py
c8b9216936300dac4ebb582a70efe2286124f0d14e501a6c22fc10cc2caaddbb tools/checks/release_smoke.py
f69845bc26ec33160fc756953991cf32aa8ad6a7fb4a131caa2093db91e783ef tools/checks/rust_module_contracts.py
ecfe0bb21a7549225a19b0846bb6de8c99cbfbbf5a706d33cf84db2c7146abed tools/checks/rust_source.py
adf84a983e0dbba228e47d71ec2d5c9964f7ca9989d5139de58f96ee961b035a tools/checks/security_contracts.py
23b9250245e6bec5ef728c73cee4c88f64924afc3597f8a9b58a1924235df98e tools/checks/security_dependency_contracts.py
2e125a2a807553ac81d04428f337f5042eed968cb807244487114fdd8ea6b5d9 tools/checks/source_module_contracts.py
bbd9726e11ce1324b7df6a012bac51262e22f2617bd3d36974aa151dce5c1c34 tools/checks/system_info_0301_ui_test.mjs
5c1d428cbda5f08b8d6847732672e45e9da96b545337334e473986e119197de2 tools/checks/source_module_contracts.py
b78240c3ccead8c023609fc71560be7ce2f2aa5d31c78059a24cfe4b0412d9c5 tools/checks/system_info_0301_ui_test.mjs
543a488951ea6ec8fe06e04f168ccc4d4f2af3cfc281c9a728ab7bd87377fa98 tools/checks/system_info_no_subprocess_contracts.py
614ed0c775e32ec5bfb4ee75aaa90206a10da0f43659747a7ec76fd93e33767a tools/checks/version_contracts.py
2020e171be1a044f7ca2ab83af7604a014c36fe4ff04791d0620ccbf1bf8e000 tools/checks/vhost_origin_errors_0297_ui_test.mjs
0c071c26fc316934bdfd2bfd19f5fed9521790d8c887760eaabda81a9be96703 tools/checks/vhost_www_ui_test.mjs
934dce837a13c8e9eee8e161aeb8b63dc771e2197c61639cf59e33b5ceaca833 tools/checks/web_assets.py
597d6d2da052390e285f18a257d10e6ab8dbd7add666457656cd803416b7975d tools/checks/web_assets.py
0398892be30fe416a00578915c588f360fd93244e3af77ece834e560e547d1c8 tools/checks/web_server_contracts.py
35f76060e585a96c623ef83bd5f771969f5be16a0e1ae626a3092d7458b84e84 tools/checks/web_service_ui_test.mjs
adaa1ed9e5958739df40190055c780c80d0a8e270ec8dc105ed3fa2dbb8fb74f tools/checks/www_redirect_ui_test.mjs
f16f69dabab98fe468aa90cc8f3c447c0588d7bd18163080d3d7b15c67190e4c tools/dev/memory_load.py
c8bf1c3ef876b4f87840414f5de19c183309550572437cca7ba1fe02df496462 tools/dev/memory_load.py
d1418f8e574a7390fd45a2aa879bdf5720b773162d65e295ab0350506aa5220a tools/dev/mock_auth.py
2d3ff92300b09ce9cecbbaaa9309b4d33160fa4b2291c9952b784e8cfb599ab5 tools/dev/mock_server.py
538b5f6cfa738355a729940ee3d92e7ab3dc25ca69ae330ddaa08f831775b8ba tools/dev/test_compression.py
+1
View File
@@ -108,6 +108,7 @@ if [[ "$mode" == "test" ]]; then
node tools/checks/system_info_0301_ui_test.mjs
node tools/checks/refresh_0310_ui_test.mjs
node tools/checks/dashboard_startup_0310_ui_test.mjs
node tools/checks/dashboard_boot_0311_ui_test.mjs
node tools/checks/panel_cache_http_0310_ui_test.mjs
node tools/checks/vhost_origin_errors_0297_ui_test.mjs
node tools/checks/www_redirect_ui_test.mjs
+1 -53
View File
@@ -1,30 +1,12 @@
# Historical developer-level changelog archive
> Archived during the 0.25 documentation cleanup. This file preserves the pre-cleanup
> detailed release record, including compiler fixes, source refactors, regression notes and
> detailed release record, including source refactors, regression notes and
> packaging details. It is historical technical evidence, not the operator-facing changelog.
> Use [`../CHANGELOG.md`](../CHANGELOG.md) for user/operator-visible release changes.
# Changelog
## 0.31.0 Axum fallback handler E0277 source correction
- Correct the reported `Handler<_, _>` error at `src/proxy/types.rs:53` after the public cache-maintenance path was added. The asynchronous `cache_http_invalidation` helper previously accepted `&Request<Body>` while awaiting database audit and cache invalidation; Axum's body is not `Sync`, so the borrowed request can make the `forward` handler future non-`Send`.
- Pass ownership of `Request<Body>` to the maintenance helper, perform the same body/header/allowlist validation, copy the HTTP method for the audit entry, and release the request body before the first asynchronous operation. The `forward` router and public API semantics are unchanged.
- Add an offline source regression asserting that the async helper owns its request. Pre-Rust `./dev.sh test` checks and Go tests pass; full Rust parsing, type checking, tests and runtime maintenance calls cannot be validated without Cargo/Rustc.
## 0.30.1 same-version sysinfo compiler feature correction
- Fix four compiler `E0433` errors in the system information endpoint by enabling `sysinfo`'s `system` feature alongside `network` with `default-features = false` unchanged. No dependency version or API change.
- Remove unused Tokio `AsyncReadExt` imported by the ACME runtime, and add the explicit manifest feature check to the offline source regressions.
- The change addresses the supplied Rust compiler log. A full Rust build and multi-OS runtime check remain outstanding in the source packaging environment.
## 0.29.7 same-version `E0308` source correction
- Defer Reverse Proxy error interception from the upstream `Response<hyper::body::Incoming>` to the adapted `Response<axum::body::Body>` in `success_prepare.rs`. This preserves the H2 WebSocket tunnel's `Incoming` body type and ensures replacement still precedes response transformation and cache admission. Reapply response rules and enforce `no-store` for replaced application errors.
- Change health supervisor member collection to own `Arc<Member>` and spawn probes with `Arc::clone(member)`, meeting Tokio's owned `'static` task requirement.
- Extend the application-error UI/source regression check with the body-adaptation ordering, no-store and Arc ownership assertions. Offline checks passed; Rust compilation is not available in the packaging environment.
## 0.26.7
### Backend client lifecycle and cache diagnostics
@@ -39,29 +21,8 @@
- Build the OCI runtime image with a dedicated Certbot virtual environment containing the Cloudflare, OVH and RFC2136 DNS plugins supported by RustProxy, all pinned with the same Certbot release.
- Refresh container documentation so it no longer tells operators that those provider plugins must be added separately.
## 0.26.6
### Compiler follow-up
- Removed the redundant `country_resolved = true` assignment after route-level GeoIP resolution in `proxy::forward_entry`. The flag is only needed to prevent a second lookup before that branch; the removed write was never read and produced `unused_assignments` during a real Rust build. ACL/GeoIP behavior is unchanged.
- A fresh compiler-enabled lint/test run remains required on the Rust release host because this packaging workspace has no Rust toolchain.
## 0.26.0
### Compiler follow-up
- Corrected the external `cargo` build failure in `server::tls_runtime`: the HTTP/1 service closure now captures its own cloned `frontend_state`, leaving the original state available for connection-level protocol-error logging after `serve_connection` returns.
- Corrected `serde_json::Map::entry` type inference in the stored-log normalizer by passing the literal `"event"` directly instead of the ambiguous `"event".into()`.
- Rust-independent language, security, source-module, documentation, UI, source and release-smoke gates pass after both corrections. A fresh compiler-enabled `cargo check/test` remains required because this packaging workspace has no Rust toolchain.
## 0.25.1
### 0.25.1 source-split compiler follow-up
- Corrected Rust `include!` split regressions reported by a real `cargo` build: dangling method documentation in runtime fragments, an invalid inner module doc in `balance/model.rs`, and the missing sibling `htaccess` import in Web Server response headers.
- Removed the warning set reported by that build (stale imports, unnecessary `mut` bindings, an unnecessary returned timeout value, and unused Prometheus parameters).
- Strengthened `rust_module_contracts.py` so doc comments/attributes immediately before a closing brace and inner `//!` comments in included fragments fail preflight instead of producing a false PASS.
### Source modularization and release guards
- Enforce a 500-line ceiling for Rust implementation/test source files and bounded dashboard JavaScript, Docker Agent Go and operational deployment/migration modules.
@@ -79,7 +40,6 @@
- Enforce document-root confinement for Web Server paths, reject ambiguous/encoded traversal forms and prevent symlink escape by not following symlinks during Unix filesystem traversal.
- Reuse the existing vhost ACL/authentication/header/error/TLS/HTTP pipeline for local files without adding a separate router, error-page system or object cache.
- Add an authenticated **Docs Reader** for bundled project documentation alongside the existing API/OpenAPI view, and separate the current documentation index, release audit and open TODO material.
- Fix the 0.25 Docs Reader source embedding so compilation does not require a generated `OUT_DIR/docs-content.json`; Markdown sources are now direct compiler inputs and the JSON bundle is serialized from embedded strings.
- Split the 0.25 Web Server implementation from the former monolithic `src/web_server.rs` into the responsibility-based `src/web_server/` module (`config`, filesystem, security, response, routing, FastCGI, dispatcher, `.htaccess` and tests), keeping `mod.rs` as the stable public facade and updating source/package gates for the new layout.
- Extend the source-layout cleanup across the Rust tree: every checked-in `.rs` file is capped at 500 lines, large `config`/`docker`/`server`/`runtime`/`balance`/`prometheus`/`proxy`/cache/admin/etc. modules are split by responsibility, unit-test bodies live in separate test files, and compiler-independent contracts reject dangling attributes/doc comments, broken `include!` targets and unbalanced split fragments.
@@ -96,8 +56,6 @@
- Added composite Settings > Logging support for `error_log.enabled`, path and format while retaining legacy `/api/config/logging` payload compatibility.
- Removed the Error Log help sentence from the panel while keeping the existing controls and behavior unchanged.
- Fix Rust type inference for zeroizing ACME/Base64 and AEAD buffers so the new Secret Store and encrypted backup code compile with the pinned dependency set.
- Fix the secret-redaction KV regex literal so 0.24.9 compiles correctly; the redaction behavior itself is unchanged.
- Harden the built-in release checker for FreeBSD/OPNsense and other Unix platforms: supplement bundled Mozilla roots with common system CA bundles/`SSL_CERT_FILE`/`CURL_CA_BUNDLE`, follow bounded non-downgrading HTTP(S) redirects, and report failed checks as normal application `ERROR` events without changing dashboard behavior.
- Add a central AES-256-GCM encrypted Secret Store with private local master-key storage and migration of existing ACME DNS-provider credentials.
- Add encrypted full backup/restore with Argon2id, authenticated encryption, explicit manifests/checksums, staging validation and rollback-safe activation.
@@ -119,8 +77,6 @@
- Show transform-resource warnings when the selected budget cannot fit the worst-case buffers for one maximum compressed body or exceeds half of detected host/cgroup RAM.
- Add live dashboard resource accounting: current transform RAM reservation/budget and active slots, HOT/transient cache RAM, non-cache process RSS, plus COLD disk occupancy and object limits.
- Include global transform representation/eligibility settings in cache compatibility identity while excluding resource-only preset/budget/concurrency controls.
- Map bounded transform-body collection failures explicitly into `anyhow::Error`, avoiding the `anyhow::Context` trait-bound compile failure for Axum/HTTP body boxed errors.
- Clean compiler warnings in cache transient leases and CSS minification without suppressing lints: make RAII-only lease ownership explicit, keep COLD read reservations intentionally alive, and remove dead CSS state assignments.
- Extend SQLite/OpenAPI/offline memory/release regressions and update release identity to 0.24.7.
## 0.24.6
@@ -172,7 +128,6 @@
## 0.24.1
- Restore system network interface discovery and RX/TX counters after the shared-statistics refactor: use the cross-platform `sysinfo::Networks` API as the primary network inventory/counter source, merge `systemstat` as a library-level supplement/fallback for missing or partial inventory, preserve per-interface rate calculation, and stop silently truncating the interface list.
- Fix the compiler error in portable uptime collection by using the `systemstat` duration API correctly, and remove the now-unused `Future` import in the H2 server module.
- Remove RustProxy's artificial hostname-count ceilings from certificate SNI bindings, local certificate generation/import validation, ACME domain validation, vhost/redirect/404 hostnames, administration allowed hosts, host ACL policies and Docker aliases. Input validity and bounded control-plane/resource limits remain enforced.
- Replace per-BSD command/parsing statistics code with shared library collectors: `systemstat` for host metrics, `sysinfo::Networks` for network inventory/counters, and `metrics-process` for process metrics, using the documented dummy process fallback on targets without a native collector.
- Preserve Linux `/proc` and cgroup-specific details as additive compatibility metrics while using the common library API for portable host/process values.
@@ -223,7 +178,6 @@
- Bound inactive inbound HTTP/2 connections to five minutes so idle TLS/H2 sessions cannot accumulate indefinitely toward the process connection limit; export `rust_proxy_http2_active_connections` for direct diagnosis.
- Account hot-cache response-body backing allocation capacity rather than only visible body length, preventing `BytesMut` growth slack from bypassing the configured RAM budget and under-reporting resident cache memory.
- Fix the `--livelogs` stdin reader to send owned `String` values from the match body rather than a pattern guard, resolving Rust `E0507` during binary compilation.
- Add a scoped external Certificate API credential managed from a new **Settings → Certificate API** tab. RustProxy stores only the token hash plus a non-secret Key ID; the cleartext token is returned only on rotation.
- Allow the scoped Key ID + Bearer Token only on `POST /api/certificates/deploy` and `POST /api/certificates/reload`, require HTTPS for non-loopback token use, track last use, support immediate revoke, and retain normal administrator-session/CSRF access as an alternative.
- Keep production certificate operations available directly from the installed binary (`rust-proxy tls deploy` / `rust-proxy tls reload`) without requiring `dev.sh`.
@@ -243,7 +197,6 @@
## 0.22.2
- Fix the 0.22.2 backend diagnostics build failure by replacing the oversized recursive `serde_json::json!` member payload with explicit `serde_json::Map` construction; the administration JSON schema is unchanged.
- Add bounded replay-safe backend failover retry for body-free GET/HEAD/OPTIONS requests, including retry policy controls, passive-health integration, logs and per-backend retry counters.
- Correct ordinary explicit-HTTP/2 upstream requests and add a real Hyper h2c prior-knowledge regression path.
- Add per-backend request-concurrency limits with bounded capacity waiting, `503` rejection and capacity/queue-timeout metrics. This limits full proxy exchanges, not TCP socket count.
@@ -295,7 +248,6 @@
- Fix Docker-vhost Passive Backend Health checkbox sizing so enabling the expanded editor cannot make fields overlap.
- Remove the unused mutable `origin` binding from the background revalidation path.
- Replace the monolithic `src/cache.rs` with the responsibility-based `src/cache/` module (`model`, lifecycle, cold storage, dashboard, tickets, lookup, policy, fill and tests) and update source/package gates for the new layout.
- Fix the cache split so method groups are emitted from module-scope `include!` files wrapped in their own `impl Cache` blocks; this avoids the Rust compiler error caused by `include!` directly in impl-item position.
- Persist transformed-representation metadata through hot/Cold Cache, mark transformed objects in the Cache dashboard, and append `transformed` to standardized RFC 9211 `Cache-Status` diagnostics; origin `X-Cache-Status` lookalikes are stripped rather than emitted.
- Shard Cold Cache storage and add bounded asynchronous garbage collection plus selective manual cleanup.
@@ -326,7 +278,6 @@
## 0.19.3
- Fix the compiler error in the release checker body collector by converting Hyper/http-body-util boxed collection errors explicitly into `anyhow::Error` instead of calling `anyhow::Context` on an unsupported boxed error type.
- Simplify the dashboard footer to API latency and dropped-log count, and add a fail-soft built-in release checker using embedded `UPDATE_CHECK.toml` defaults. The checker reads the official Cargo manifest immediately and then hourly, exposes a newer-version link in the footer, and never performs automatic upgrades.
- Allow runtime release-check overrides through `--update-repository-url`, `--update-version-url` and `--update-check-interval-secs` (plus matching `RUST_PROXY_*` environment variables); interval `0` disables checks.
- Fix the remaining oversized Live Logs column checkboxes by excluding checkbox/radio inputs from both broad `.log-tools input` text-field sizing blocks that were overriding the shared 15px checkbox rules.
@@ -367,7 +318,6 @@
- Retain 4096 completed access-log entries while keeping the 256-entry live window; add one-shot on-demand history loading and document the API limit.
- Render backend traffic with KiB/s as the minimum unit, simplify the Live Logs column picker, align generic checkboxes and move Docker-vhost Advanced switches beside Backend protocol on desktop; remove the redundant alias help line.
- Remove stale simulated dashboard screenshots, retain only two explicitly labelled legacy references and add a documentation index for historical/version-labelled material.
- Restore the integration-test sources and independent Argon2id fixture required by release/source checks so compiler-enabled test builds no longer reference files missing from the supplied source archive.
- Update source, UI, OpenAPI, regressions and package identity to 0.19.1.
## 0.19.0
@@ -453,7 +403,6 @@
- Add a separate live **Docker vhosts** Prometheus collector group, enabled by default, with configured agent/assignment/domain gauges plus Docker vhost traffic/status/duration and full backend health/probe/runtime metrics.
- Extend Prometheus/OpenAPI/UI documentation and regression coverage for the Docker metric boundary.
- Extend the bundled Grafana operations dashboard with a dedicated Docker-vhost section and per-agent/service filters using only the separate Docker metric families.
- Fix Docker discovery compilation against the locked HTTP/body stack by mapping limited-body collection errors explicitly and logging `ApiError` via its `Debug` representation.
## 0.18.2
@@ -604,7 +553,6 @@
- Add per-vhost control over forwarding the effective client IP to the application. Disabling it removes `Forwarded`, `X-Forwarded-For` and `X-Real-IP` only on the backend request; ACLs, GeoIP, rate limiting and Tinyauth continue to use the real client identity.
- Add a compact Vhost search/filter for vhost IDs, hostnames/wildcards and backend IDs/URLs.
- Fix the invalid `quinn = 0.11.22` manifest requirement to the resolved `0.11.12` and stop `dev.sh` from rewriting a valid checked-in `Cargo.lock`.
- Fix JSONL access logging under the hardened systemd unit by provisioning `/var/log/rustproxy` as a writable service log directory while keeping `ProtectSystem=strict`.
- Add source/offline regression coverage and bump release/package/UI/OpenAPI/update metadata to 0.11.3. Rust compilation/runtime acceptance remains open in this packaging environment.
+64
View File
@@ -0,0 +1,64 @@
# RustProxy 0.31.1 — mobile dashboard initialization
## Scope
This patch changes only the authenticated administration panel bootstrap and its
release documentation. It does not modify reverse-proxy traffic processing,
authentication, stored configuration, SQLite migrations or preference values.
## Root-cause analysis
Previously, the authenticated dashboard HTML requested 17 independent deferred
JavaScript files. The first one (`/assets/app.js`) starts asynchronous session
and configuration requests from `web/app/runtime.js`. Deferred ordering only
orders *script evaluation*, not asynchronous continuation: a completed API call
can resume while later JavaScript resources are still downloading. In that
window, a render path may access `window.rustProxyIntegrations.bindings`
before `integrations.js` has finished evaluating. The browser then reports an
undefined-object exception. A failed/missing script has the same symptom.
The reported iPhone/reverse-proxy incident is consistent with this race. It was
not possible to capture the user's mobile network trace, so the precise
combination of mobile transport behavior, timing, and content encodings is not
proven.
## Changes
1. The dashboard HTML now requests only `/assets/app.js?v=0.31.1`. On the
backend, the same existing `/assets/app.js` route assembles all existing
UI source modules in their prior load order. `/assets/vhosts.js` and the
other private asset URLs remain available for compatibility.
2. Startup waits for `DOMContentLoaded` and verifies the required modules
before requesting a session or configuration. A missing module produces
a visible startup failure with the existing retry link instead of a
partially initialized workspace.
3. Authenticated HTML also requests `/assets/style.css?v=0.31.1`; versioned
URLs separate release assets in intermediary caches. No cache bypass
or potentially unsafe public caching is introduced on the server.
4. The initial `/api/config` load retries at most twice after a transient
failure (400 ms / 800 ms delays). If it cannot load, the existing startup
recovery UI is displayed. Session rejection (`401`) does not trigger retries.
5. Public login, CSP, compression negotiation, SSE, polling, Traffic and Cache
APIs, user preferences and the proxy request path are unchanged.
## Acceptance checks
- Node.js parses each source module and the complete emitted dashboard bundle.
- A JavaScript startup test verifies **zero API requests before DOM readiness**,
successful activation with complete modules, and recovery when a module is
missing. A second test verifies configuration retry success/failure.
- Chromium smoke test on the authenticated HTML with simulated session and
configuration endpoints, at desktop and mobile widths, when available.
- Run `./dev.sh test` and `./dev.sh check` in an environment with Rust/Cargo.
- On the production reverse-proxy path, test initial load, 20+ rapid reloads,
navigation between tabs, Safari on iPhone (Wi-Fi and cellular), and a
deliberately delayed/failed `/api/config` response. Confirm no uncaught JS
errors and no mixed asset versions.
- Compare actual HTTP `Content-Encoding`, `Content-Length`, `Vary`, `Status`
and response bodies for document, script and stylesheet behind the reverse.
Disable any reverse cache rule that ignores version/query keys.
## Environment limitations
Compiler/type-checking, live RustProxy API tests and Safari/iPhone tests require
the target runtime; they cannot be inferred from source or Chromium alone.
+3 -2
View File
@@ -31,7 +31,8 @@ This is the canonical index for the current project documentation. The authentic
- [0.26.3 implementation note](V0.26.3_IMPLEMENTATION.md) - global interface scaling, chart themes, square draft dock and Settings navigation polish.
- [0.26.2 implementation note](V0.26.2_IMPLEMENTATION.md) - unified Logs navigation, field-query search, dynamic JSON columns and RAW parsing.
- [0.26.1 implementation note](V0.26.1_IMPLEMENTATION.md) - historical vhost-aware protocol logging and Stored Logs UX milestone.
- [0.31.0 security audit](SECURITY_AUDIT_0.31.0.md) - current API/panel/BAN/PURGE attack-surface review, hardening, compile fix and mandatory runtime gates.
- [0.31.1 mobile panel bootstrap](IMPLEMENTATION_0.31.1.md) - panel script readiness, versioned assets, failure recovery and acceptance tests.
- [0.31.0 security audit](SECURITY_AUDIT_0.31.0.md) - current API/panel/BAN/PURGE attack-surface review, hardening and remaining runtime verification.
- [0.31.0 implementation report](IMPLEMENTATION_0.31.0.md) - consolidated changes, exact file inventory, validation results and outstanding Rust runtime acceptance.
- [TEST_REPORT](TEST_REPORT.md) - verification commands, results and environment limitations.
@@ -80,7 +81,7 @@ This is the canonical index for the current project documentation. The authentic
## Historical or version-labelled context
Version-labelled `V*.md` files are retained as historical implementation/audit records. Their version number describes the audited milestone. The current release implementation note is [IMPLEMENTATION_0.31.0.md](IMPLEMENTATION_0.31.0.md); [V0.29.1_IMPLEMENTATION.md](V0.29.1_IMPLEMENTATION.md) is retained as historical context, and [V0.29.0_IMPLEMENTATION.md](V0.29.0_IMPLEMENTATION.md) is retained as the prior redirect/health/cache/log milestone; [V0.28.2_IMPLEMENTATION.md](V0.28.2_IMPLEMENTATION.md) is retained as the prior certificate-hardening milestone; [V0.28.1_IMPLEMENTATION.md](V0.28.1_IMPLEMENTATION.md) is retained as the prior external-path milestone; [V0.28.0_IMPLEMENTATION.md](V0.28.0_IMPLEMENTATION.md) is retained as the prior GeoIP/listener/cache milestone, and [V0.27.3_IMPLEMENTATION.md](V0.27.3_IMPLEMENTATION.md) is retained as the prior HTTP/3/cache-maintenance milestone, [V0.27.2_IMPLEMENTATION.md](V0.27.2_IMPLEMENTATION.md) is retained as the prior managed-ACME repair, [V0.27.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md) as the prior managed-runtime/list-sorting milestone, and older version notes remain historical evidence. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain available for traceability.
Version-labelled `V*.md` files are retained as historical implementation/audit records. Their version number describes the audited milestone. The current release implementation note is [IMPLEMENTATION_0.31.1.md](IMPLEMENTATION_0.31.1.md); [IMPLEMENTATION_0.31.0.md](IMPLEMENTATION_0.31.0.md) is retained as the previous milestone; [V0.29.1_IMPLEMENTATION.md](V0.29.1_IMPLEMENTATION.md) is retained as historical context, and [V0.29.0_IMPLEMENTATION.md](V0.29.0_IMPLEMENTATION.md) is retained as the prior redirect/health/cache/log milestone; [V0.28.2_IMPLEMENTATION.md](V0.28.2_IMPLEMENTATION.md) is retained as the prior certificate-hardening milestone; [V0.28.1_IMPLEMENTATION.md](V0.28.1_IMPLEMENTATION.md) is retained as the prior external-path milestone; [V0.28.0_IMPLEMENTATION.md](V0.28.0_IMPLEMENTATION.md) is retained as the prior GeoIP/listener/cache milestone, and [V0.27.3_IMPLEMENTATION.md](V0.27.3_IMPLEMENTATION.md) is retained as the prior HTTP/3/cache-maintenance milestone, [V0.27.2_IMPLEMENTATION.md](V0.27.2_IMPLEMENTATION.md) is retained as the prior managed-ACME repair, [V0.27.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md) as the prior managed-runtime/list-sorting milestone, and older version notes remain historical evidence. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain available for traceability.
Older context documents such as [INTEGRATIONS_040](INTEGRATIONS_040.md), [MANAGEMENT](MANAGEMENT.md), [SECURITY_AUDIT](SECURITY_AUDIT.md), [ACME_RFC2136](ACME_RFC2136.md) and older version audits remain available for traceability but should not override the current functional/technical documents above.
+9 -1
View File
@@ -1,4 +1,12 @@
# Verification report - RustProxy 0.31.0
# Verification report - RustProxy 0.31.1
## 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.bindings` was 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 test` completes 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.py` checks each JS module and the assembled 608 KB bundle with `node --check`. `cd docker-agent && go test ./...` passed. Shell syntax passed.
- **Not verified:** `./dev.sh test` terminates **127** at Cargo; `./dev.sh check` also **127** (`cargo`/`rustc` absent). 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.1` and CSS. Review the detailed plan in [IMPLEMENTATION_0.31.1.md](IMPLEMENTATION_0.31.1.md).
## 0.31.0 Axum handler `Send` correction (2026-10-10)
+1
View File
@@ -244,6 +244,7 @@ pub(super) static READER_DOCUMENTS: &[(&str, &str, &str)] = &[
"guides",
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/STREAMS.md")),
),
reader_doc!("docs/IMPLEMENTATION_0.31.1.md", "technical"),
reader_doc!("docs/IMPLEMENTATION_0.31.0.md", "technical"),
(
"docs/TEST_REPORT.md",
+1 -1
View File
@@ -2,7 +2,7 @@
"openapi": "3.0.3",
"info": {
"title": "RustProxy Administration API",
"version": "0.31.0",
"version": "0.31.1",
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust."
},
"servers": [
+16
View File
@@ -40,6 +40,22 @@ fn admin_app_javascript() -> &'static str {
include_str!("web/app/config-history.js"),
include_str!("web/app/runtime.js"),
include_str!("web/app/settings.js"),
include_str!("web/management.js"),
include_str!("web/drafts.js"),
include_str!("web/integrations.js"),
admin_vhosts_javascript(),
include_str!("web/web-server-profiles.js"),
include_str!("web/web-server.js"),
include_str!("web/docker.js"),
include_str!("web/streams.js"),
include_str!("web/redirects.js"),
include_str!("web/host404.js"),
include_str!("web/traffic-panel.js"),
include_str!("web/cache-panel.js"),
include_str!("web/transform-panel.js"),
include_str!("web/acme.js"),
include_str!("web/settings.js"),
include_str!("web/file-logs.js"),
]
.join("\n")
});
+7 -6
View File
@@ -396,12 +396,13 @@ async function activate(info) {
window.rustProxyRedirects?.applyPreferences(preferences);
window.rustProxyNotFound?.applyPreferences(preferences);
window.rustProxyStreams?.applyPreferences(preferences);
// The live SSE stream is already running. Configuration can load behind the
// visible shell; it does not belong in the live refresh cycle.
try { await loadConfig(); }
catch (error) {
if (authenticated && epoch === authEpoch) toast(error.message, true);
return;
for (let attempt = 0; attempt < 3 && authenticated && epoch === authEpoch; attempt++) {
try { await loadConfig(); break; }
catch (error) {
if (!authenticated || epoch !== authEpoch || error?.status === 401) return;
if (attempt === 2) { showStartupFailure(error); return; }
await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 400));
}
}
if (!authenticated || epoch !== authEpoch) return;
// A single full snapshot seeds non-live diagnostics; subsequent updates
+24 -2
View File
@@ -1,5 +1,22 @@
(async () => {
// All modules must be available before any asynchronous session/config work can
// render the panel. DOMContentLoaded also waits for the complete deferred bundle.
function verifyAdminModules() {
const required = [
["rustProxyIntegrations", "bindings"],
["rustProxyVhosts", "render"],
["rustProxySettings", "render"],
["rustProxyCachePanel", "refresh"],
["rustProxyTrafficPanel", "refresh"],
["rustProxyPreferences", "load"],
["rustProxyRefresh", "start"],
];
const missing = required.find(([module, method]) => typeof window[module]?.[method] !== "function");
if (missing) throw new Error(`Panel resources incomplete (${missing[0]}). Reload to retry.`);
}
async function startAdminPanel() {
try {
verifyAdminModules();
// Revalidate the session first. The anonymous document has its own login.js;
// app.js belongs to the authenticated shell and must not fall back to its
// legacy embedded sign-in form when another startup step fails.
@@ -18,7 +35,12 @@
}
showStartupFailure(e);
}
})();
}
// The previous bootstrap ran while sibling deferred scripts were still loading.
// Starting only after DOMContentLoaded prevents fast API responses from racing
// against a slower or failed JS resource on mobile/reverse-proxied connections.
if (document.readyState === "complete") startAdminPanel();
else document.addEventListener("DOMContentLoaded", startAdminPanel, { once: true });
function certificateUsesExternalFiles(cert) {
return String(cert?.cert_file || "").startsWith("/") && String(cert?.key_file || "").startsWith("/");
+3 -18
View File
@@ -7,24 +7,9 @@
<meta content="width=device-width, initial-scale=1" name="viewport" />
<title>RustProxy / Control room</title>
<link href="/favicon.svg" rel="icon" />
<link href="/assets/style.css" rel="stylesheet" />
<script defer="" src="/assets/app.js"></script>
<script defer="" src="/assets/management.js"></script>
<script defer="" src="/assets/drafts.js"></script>
<script defer="" src="/assets/integrations.js"></script>
<script defer="" src="/assets/vhosts.js"></script>
<script defer="" src="/assets/web-server-profiles.js"></script>
<script defer="" src="/assets/web-server.js"></script>
<script defer="" src="/assets/docker.js"></script>
<script defer="" src="/assets/streams.js"></script>
<script defer="" src="/assets/redirects.js"></script>
<script defer="" src="/assets/host404.js"></script>
<script defer="" src="/assets/traffic-panel.js"></script>
<script defer="" src="/assets/cache-panel.js"></script>
<script defer="" src="/assets/transform-panel.js"></script>
<script defer="" src="/assets/acme.js"></script>
<script defer="" src="/assets/settings.js"></script>
<script defer="" src="/assets/file-logs.js"></script>
<link href="/assets/style.css?v=__RUSTPROXY_VERSION__" rel="stylesheet" />
<!-- One ordered JS payload: no race between module fetches and session/config API. -->
<script defer="" src="/assets/app.js?v=__RUSTPROXY_VERSION__"></script>
</head>
<body>
+1 -1
View File
@@ -111,4 +111,4 @@ for fragment in ['class="metric-info cache-maintenance-info"',
'cacheHttpInvalidationCurlLabel',
'curl -i -X PURGE', 'curl -i -X BAN']:
must(html, fragment)
print(f'PASS: 0.31.0 admin/HTTP maintenance security source contracts; scanned {len(js_files)} first-party JS files. Actual Rust/wire behavior not tested.')
print(f'PASS: admin/HTTP maintenance security source contracts; scanned {len(js_files)} first-party JS files. Actual Rust/wire behavior not tested.')
+13 -13
View File
@@ -24,7 +24,7 @@ def read_docker_agent_source() -> str:
preflight(root)
manifest = tomllib.loads((root / "Cargo.toml").read_text())
assert manifest["package"]["version"] == "0.31.0"
assert manifest["package"]["version"] == "0.31.1"
assert manifest["dependencies"]["quinn"]["version"] == "0.11.12"
h3dep = manifest["dependencies"]["h3"]
assert h3dep["package"] == "hpx-h3" and h3dep["version"] == "=2.5.19" and "quinn" in h3dep["features"]
@@ -32,14 +32,14 @@ assert "h3-quinn" not in manifest["dependencies"]
lock_path = root / "Cargo.lock"
if lock_path.exists():
lock = lock_path.read_text()
assert 'name = "rust-proxy"\nversion = "0.31.0"' in lock
assert 'name = "rust-proxy"\nversion = "0.31.1"' in lock
assert 'name = "systemstat"' in lock and 'name = "metrics-process"' in lock and 'name = "sysinfo"' in lock, "Cargo.lock must be resolver-generated after adding cross-platform statistics libraries"
for release_doc, marker in {
"README.md": "# RustProxy 0.31.0",
"CHANGELOG.md": "## 0.31.0",
"ROADMAP.md": "## 0.31.0",
"AGENTS.md": "Current source version: 0.31.0.",
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.31.0",
"README.md": "# RustProxy 0.31.1",
"CHANGELOG.md": "## 0.31.1",
"ROADMAP.md": "## 0.31.1",
"AGENTS.md": "Current source version: 0.31.1.",
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.31.1",
}.items():
assert marker in (root / release_doc).read_text(), f"stale release identity in {release_doc}"
assert tomllib.loads((root / "rust-toolchain.toml").read_text())["toolchain"]["channel"] == "stable"
@@ -177,7 +177,7 @@ for source_name, markers in {
assert marker in source_text, (source_name, marker)
assert 'data-panel="docker-vhosts"' in html and 'id="panel-docker-vhosts"' in html
assert 'id="settings-tab-docker-agents"' in html and 'id="settings-page-docker-agents"' in html
assert '/assets/docker.js' in html and 'cache-live-toggle' in html
assert 'include_str!("web/docker.js")' in (root / 'src/admin/router.rs').read_text() and 'cache-live-toggle' in html
assert 'expose-revision' not in html and 'hideRevision' not in js and 'diagRevision' not in js
for path in ['src/settings.rs', 'src/admin/mod.rs', 'src/cache/mod.rs', 'src/headers.rs', 'src/tinyauth.rs', 'src/admin/web/vhosts/core.js']:
text = rust_source(root, path) if path.endswith('.rs') else (root / path).read_text()
@@ -216,7 +216,7 @@ for lang_name in ["en_US.json", "pl_pl.json"]:
assert html.index('data-panel="vhosts"') < html.index('data-panel="redirects"') < html.index('data-panel="notfound"') < html.index('data-panel="streams"') < html.index('data-panel="acl-profiles"')
assert 'id="stream-dialog"' in html and 'id="stream-list"' in html and 'id="stream-search"' in html
assert 'id="settings-page-streams"' not in html and 'id="streams-form"' not in html
assert '/assets/streams.js' in html and '/assets/redirects.js' in html and '/assets/host404.js' in html
assert all(f'include_str!("web/{name}.js")' in (root / 'src/admin/router.rs').read_text() for name in ('streams', 'redirects', 'host404'))
vhosts_js = read_vhosts_js(root)
assert '"force-ssl", "vhForceSsl"' in vhosts_js and 'force_ssl: yes("force-ssl")' in vhosts_js
assert 'vhForceSslNeedsHttp' in vhosts_js and 'tlsPorts.has(443)' in vhosts_js
@@ -285,7 +285,7 @@ assert 'Opt-in health decisions based on ordinary user traffic. Defaults to disa
assert '"force_ssl"' in openapi and '"forward_client_ip"' in openapi
assert '"backend_header"' in openapi and '"backend_timing_header"' in openapi
assert '"StreamMetrics"' in openapi and '"streams"' in openapi
for marker in ['"version": "0.31.0"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']:
for marker in ['"version": "0.31.1"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']:
assert marker in openapi, marker
for marker in ['"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
assert marker in openapi, marker
@@ -980,7 +980,7 @@ for marker in ['data?.resources || {}', 'tp-memory', 'tp-inflight']:
assert marker in transform_panel_js, marker
assert 'function uptime(value)' in app_js and 'setOptionalMetric("process-uptime", status.uptime_seconds != null' in app_js
assert 'connection-uptime-footer' not in html and 'id="process-uptime"' in html
assert 'id="panel-transform"' in html and 'data-panel="transform"' in html and '/assets/transform-panel.js' in html
assert 'id="panel-transform"' in html and 'data-panel="transform"' in html and 'include_str!("web/transform-panel.js")' in (root / 'src/admin/router.rs').read_text()
assert '/api/transform' in transform_panel_js and 'tp-cache-hits' in transform_panel_js and 'transform-reason-list' in transform_panel_js
assert '--transform-chart:' in css and '--chart-quaternary:' in css and 'stroke: var(--chart-quaternary)' in css and 'background: var(--transform-chart)' in css
assert '.cache-transform-badge {' in css and 'border: 1px solid var(--pill-line)' in css and 'border-radius: 3px' in css
@@ -1396,7 +1396,7 @@ assert '"error_log" => {' not in admin_0241 and 'request("/api/config/error_log"
assert '"error_log"' in openapi and 'logging, error_log, forwarding' not in openapi
assert 'logging_section_persists_error_log_settings_atomically' in admin_0241 and 'error_log_is_not_a_standalone_configuration_section' in admin_0241
assert 'location.pathname === "/logging"' in settings_js_0241
assert '"RuntimeInformation"' in openapi and '"version": "0.31.0"' in openapi
assert '"RuntimeInformation"' in openapi and '"version": "0.31.1"' in openapi
# 0.24.1 compiler and hostname-cardinality regressions.
tls_0241 = rust_source(root, "src/tls.rs")
@@ -1635,5 +1635,5 @@ for marker_0282 in [
assert 'Zewnętrzne ścieżki plików' in (root / 'langs/pl_pl.json').read_text()
assert 'setfacl -m u:rustproxy:--x /etc/ssl/' in (root / 'docs/V0.28.2_IMPLEMENTATION.md').read_text()
print("PASS: 0.31.0 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, external-packaging/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v9 migrations.")
print("PASS: 0.31.1 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, external-packaging/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v9 migrations.")
print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.")
@@ -0,0 +1,89 @@
#!/usr/bin/env node
// Release-independent, real-source startup ordering and recovery contract.
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { runInNewContext } from 'node:vm';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
const read = path => readFileSync(resolve(root, path), 'utf8');
const html = read('src/admin/web/index.html');
const runtime = read('src/admin/web/app/runtime.js');
const core = read('src/admin/web/app/core.js');
const router = read('src/admin/router.rs');
const bundle = read('tools/checks/web_assets.py');
const version = read('Cargo.toml').match(/^version\s*=\s*"([\d.]+)"/m)?.[1];
assert(version);
assert.equal((html.match(/<script defer="" src="\/assets\//g) || []).length, 1, 'one atomic dashboard script');
assert.match(html, /src="\/assets\/app\.js\?v=__RUSTPROXY_VERSION__"/);
assert.match(html, /href="\/assets\/style\.css\?v=__RUSTPROXY_VERSION__"/);
assert.match(router, /admin_vhosts_javascript\(\)/);
assert.match(bundle, /"integrations\.js", "vhosts\.js"/);
assert(router.indexOf('include_str!("web/integrations.js")') < router.indexOf('admin_vhosts_javascript(),'));
assert(router.indexOf('admin_vhosts_javascript(),') < router.indexOf('include_str!("web/host404.js")'));
const prefix = runtime.slice(0, runtime.indexOf('function certificateUsesExternalFiles'));
assert(prefix.includes('document.addEventListener("DOMContentLoaded", startAdminPanel'));
function simulate(complete) {
let bootstrap, calls = 0, activated = 0, failed = null;
const modules = {};
for (const [name, action] of [
['rustProxyIntegrations','bindings'], ['rustProxyVhosts','render'],
['rustProxySettings','render'], ['rustProxyCachePanel','refresh'],
['rustProxyTrafficPanel','refresh'], ['rustProxyPreferences','load'],
['rustProxyRefresh','start'],
]) if (complete || name !== 'rustProxyIntegrations') modules[name] = { [action]() {} };
const ctx = {
window: modules, document: { readyState: 'loading', addEventListener(name, fn) {
assert.equal(name, 'DOMContentLoaded'); bootstrap = fn;
} },
api: async () => { calls++; return { csrf_token: 'abc' }; },
clearInvalidOriginRecovery() {}, loadLanguages: async () => {},
translate() {}, syncAuthForm() {}, activate: async () => { activated++; },
recoverInvalidOrigin: () => false, showStartupFailure: e => { failed = e; },
location: { pathname: '/overview', search: '', replace() { throw new Error('unexpected redirect'); } },
};
runInNewContext(prefix, ctx);
assert.equal(calls, 0, 'zero API calls before all defer/module readiness');
assert.equal(activated, 0);
assert(bootstrap, 'registered DOMContentLoaded bootstrap');
return { bootstrap, state: () => ({ calls, activated, failed }) };
}
const success = simulate(true);
success.bootstrap();
for (let i = 0; i < 8; i++) await Promise.resolve();
assert.equal(success.state().calls, 1);
assert.equal(success.state().activated, 1);
assert.equal(success.state().failed, null);
const missing = simulate(false);
missing.bootstrap();
for (let i = 0; i < 8; i++) await Promise.resolve();
assert.equal(missing.state().calls, 0, 'do not initialize partially loaded modules');
assert.match(missing.state().failed.message, /rustProxyIntegrations/);
// Exercise real activate on temporary config API errors and on persistent failure.
const activation = core.slice(core.indexOf('async function activate(info) {'), core.indexOf('async function loadAudit()'));
assert(activation.startsWith('async function activate(info)'));
async function configRetry(failures) {
const nodes = new Map();
const node = key => { if (!nodes.has(key)) nodes.set(key, { hidden: true, value: '' }); return nodes.get(key); };
let config = 0, fallback = 0, status = 0;
const ctx = {
$: node, authenticated: false, csrf: '', authEpoch: 0, sessionInfo: null, pendingAuthDestination: null,
window: {}, document: { documentElement: { classList: { remove() {} } } },
authMessage() {}, renderSession() {}, rustProxyRefresh: { start() {} },
loadAdminPreferences: async () => ({}),
loadConfig: async () => { config++; if (config <= failures) throw new Error('Temporary proxy failure'); },
refresh: async () => { status++; },
setTimeout: fn => { fn(); return 1; },
showStartupFailure: () => { fallback++; },
toast() { throw new Error('A transient failure must not be hidden in a toast'); },
};
runInNewContext(activation, ctx);
await ctx.activate({ username: 'owner', csrf_token: 'token' });
for (let i=0;i<4;i++) await Promise.resolve();
return { config, fallback, status };
}
assert.deepEqual(await configRetry(2), { config: 3, fallback: 0, status: 1 });
assert.deepEqual(await configRetry(3), { config: 3, fallback: 1, status: 0 });
console.log(`PASS: ${version} one versioned JS payload, DOM/module-gated startup, retries and visible failure`);
@@ -1,5 +1,5 @@
#!/usr/bin/env node
// Network-independent browser bootstrap contract: visible recovery and early shell.
// Browser bootstrap contract: visible recovery and early shell.
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { runInNewContext } from 'node:vm';
+3 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Rust-independent documentation/Reader consistency checks for the 0.31.0 release."""
"""Rust-independent documentation/Reader consistency checks for the 0.31.1 release."""
from pathlib import Path
import re
from rust_source import rust_source
@@ -29,7 +29,7 @@ required = [
DOCS / "V0.25.2_AUDIT.md",
DOCS / "V0.25.1_AUDIT.md",
DOCS / "V0.25.0_AUDIT.md",
DOCS / "IMPLEMENTATION_0.31.0.md",
DOCS / "IMPLEMENTATION_0.31.1.md",
DOCS / "TEST_REPORT.md",
DOCS / "CHANGELOG_TECHNICAL_ARCHIVE.md",
DOCS / "ROADMAP_HISTORY.md",
@@ -65,7 +65,7 @@ assert '"/docs/content.json"' in admin
readme = (ROOT / "README.md").read_text(encoding="utf-8")
roadmap = (ROOT / "ROADMAP.md").read_text(encoding="utf-8")
changelog = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
assert readme.startswith("# RustProxy 0.31.0")
assert readme.startswith("# RustProxy 0.31.1")
assert "docs/WEB_SERVER.md" in readme and "docs/README.md" in readme
assert readme.count("## What changed in ") == 1, "README duplicates historical release notes; use CHANGELOG/archive"
assert "## Release history" in readme and "docs/ROADMAP_HISTORY.md" in readme
+2 -2
View File
@@ -75,10 +75,10 @@ def check(root: Path, repair_known: bool = False) -> list[str]:
raise ValueError(f"Conflicting Rust modules: {flat.relative_to(root)} and {module.relative_to(root)}")
for path in ["src/auth/mod.rs", "src/auth/store.rs", "src/backup/snapshot.rs", "src/upstream.rs", "src/tls.rs", "src/config/internal_routing.rs", "src/proxy/websocket.rs", "src/proxy/error_fallback.rs", "src/cache/mod.rs", "src/cache/model.rs", "src/cache/lifecycle.rs", "src/cache/cold.rs", "src/cache/dashboard.rs", "src/cache/tickets.rs", "src/cache/lookup.rs", "src/cache/policy.rs", "src/cache/fill.rs", "src/cache/tests.rs", "src/settings.rs", "src/compression.rs", "src/diagnostics.rs", "src/traffic.rs", "src/system_stats/mod.rs", "src/system_stats/linux.rs", "src/vhost.rs", "src/vhost/error_fallback.rs", "src/web_server/mod.rs", "src/web_server/config.rs", "src/web_server/filesystem.rs", "src/web_server/security.rs", "src/web_server/response.rs", "src/web_server/request.rs", "src/web_server/routing.rs", "src/web_server/fastcgi.rs", "src/web_server/htaccess.rs", "src/web_server/serve.rs", "src/web_server/tests.rs", "src/balance.rs", "src/security.rs", "src/admin/web/vhosts/core.js", "src/admin/web/vhosts/health.js", "src/admin/web/vhosts/editor.js", "src/admin/web/vhosts/render.js", "src/admin/web/web-server.js", "src/admin/web/streams.js", "src/admin/web/host404.js", "src/admin/web/app/core.js", "src/admin/web/app/preferences.js", "src/admin/web/app/config-history.js", "src/admin/web/app/runtime.js", "src/admin/web/app/settings.js", "src/admin/web/management.js", "src/admin/web/drafts.js", "src/pages.rs", "tools/dev/mock_server.py", "tools/dev/mock_auth.py", "src/forwarding.rs", "src/tinyauth.rs", "src/http3.rs", "src/stream.rs", "src/admin/web/integrations.js", "src/admin/web/traffic-panel.js", "src/prometheus.rs", "src/admin/web/settings.js", "src/admin/web/docker.js", "src/docker.rs", "docker-agent/main.go", "docker-agent/model.go", "docker-agent/docker.go", "docker-agent/network.go", "docker-agent/certificate.go", "docker-agent/server.go", "docker-agent/main_test.go", "docker-agent/rustproxy-docker-agent.service", "docker-agent/install.sh", "docs/DOCKER_DISCOVERY.md", "docs/WEB_SERVER.md", "docs/PHP_FPM.md", "docs/README.md", "docs/TODO.md", "docs/V0.25.5_AUDIT.md", "docs/V0.25.4_AUDIT.md", "docs/V0.25.3_AUDIT.md", "docs/V0.25.2_AUDIT.md", "docs/CHANGELOG_TECHNICAL_ARCHIVE.md", "docs/ROADMAP_HISTORY.md", "tools/checks/docs_check.py", "tools/checks/web_server_contracts.py", "tools/checks/rust_source.py", "tools/checks/rust_module_contracts.py", "tools/checks/source_module_contracts.py", "scripts/runtime/acme_provider.py", "src/basic_auth.rs", "scripts/deploy/deploy.py", "scripts/deploy/deploy_core.py", "scripts/deploy/deploy_runtime.py", "scripts/migration/migrate_npm.py", "scripts/migration/migrate_npm_core.py", "scripts/migration/migrate_npm_api.py", "docs/NPM_MIGRATION.md", "docs/STREAMS.md", "install.sh", "install-debian13.sh", "update.sh", "build.rs", "scripts/build/swagger_assets.py", "src/admin/documentation.rs", "src/admin/openapi.json", "langs/en_US.json", "langs/pl_pl.json", "Dockerfile", ".dockerignore", "docs/CONTAINER.md", "docs/PROMETHEUS.md", "docs/NOT_FOUND_HOSTS.md", "grafana/rustproxy-overview.json"]:
if not (root / path).is_file():
raise ValueError(f"Incomplete RustProxy 0.31.0 source tree: missing {path}")
raise ValueError(f"Incomplete RustProxy 0.31.1 source tree: missing {path}")
text = (root / "src/lib.rs").read_text(encoding="utf-8")
if '#[path = "auth/mod.rs"]' not in text:
raise ValueError("src/lib.rs is not the 0.31.0 entry point; extract the complete package, not individual files.")
raise ValueError("src/lib.rs is not the 0.31.1 entry point; extract the complete package, not individual files.")
return messages
+7 -9
View File
@@ -135,7 +135,7 @@ def upgrade_smoke(tmp: Path) -> None:
assert backup.is_dir()
assert (backup / "src/obsolete.rs").is_file()
assert not (target / "src/obsolete.rs").exists()
assert 'version = "0.31.0"' in (target / "Cargo.toml").read_text(encoding="utf-8")
assert 'version = "0.31.1"' in (target / "Cargo.toml").read_text(encoding="utf-8")
assert (target / "data/keep.txt").read_text(encoding="utf-8") == "preserve\n"
assert (target / ".env").read_text(encoding="utf-8") == "RUST_PROXY_DEMO=0\n"
assert (target / "langs/site.json").is_file()
@@ -146,7 +146,7 @@ def upgrade_smoke(tmp: Path) -> None:
assert (target / "docker-agent/certificate.go").is_file()
assert (target / "docker-agent/server.go").is_file()
manifest = json.loads((backup / "upgrade.json").read_text(encoding="utf-8"))
assert manifest["to_version"] == "0.31.0"
assert manifest["to_version"] == "0.31.1"
assert manifest["removed_obsolete_runtime_state"] is True
assert not legacy.exists()
assert not (backup / "legacy-data").exists()
@@ -396,9 +396,7 @@ def ui_contract_smoke() -> None:
for marker in ["rustProxyStreams", "streamTrafficChart", "streamPendingRestart", "chartHistory", "sessions_total", "bytes_in", "bytes_out"]:
assert marker in streams, marker
assert '$("stream-listener-add").addEventListener("click", () => { setPanel("settings"); window.rustProxySettings?.select("listeners"); });' in streams
assert "/assets/streams.js" in html
assert "/assets/redirects.js" in html
assert "/assets/host404.js" in html
assert all(f'include_str!("web/{name}.js")' in (ROOT / 'src/admin/router.rs').read_text() for name in ('streams', 'redirects', 'host404'))
for marker in ["rustProxyRedirects", 'saveSection("redirects"', "redirectTargetType", "redirectPathMode", "redirectQueryMode", "redirectCacheSeconds"]:
assert marker in redirects, marker
for marker in ["rustProxyNotFound", 'saveSection("not_found_hosts"', "rustProxyIntegrations.hostnames", "rustProxyIntegrations.bindings", "notfound-mode", "notfound-status", "BUILTIN_STATUSES", "ERROR_STATUSES", 'rustProxyDrafts.register("notfound"', 'rustProxyEnableControl($("notfound-enabled"))']:
@@ -619,7 +617,7 @@ def source_contract_smoke() -> None:
assert marker in admin, marker
anonymous_block = admin.split("fn anonymous_allowed", 1)[1].split("const CERTIFICATE_API_KEY_HEADER", 1)[0]
assert '"/api/status"' not in anonymous_block
assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.31.0"' in openapi_0241
assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.31.1"' in openapi_0241
assert 'id="panel-logging"' not in html
for marker in ['id="settings-tab-logging"', 'id="settings-page-logging"', 'id="logging-form"', 'id="error-log-form"']:
assert marker in html, marker
@@ -737,7 +735,7 @@ def source_contract_smoke() -> None:
assert '.docker-passive-health-editor .docker-health-grid {' in ui_css
assert '.docker-health-grid input:not([type="checkbox"])' in ui_css and '.docker-passive-health-editor .docker-checkbox-field input[type="checkbox"]' in ui_css
assert 'id="sparkline-transform"' in html and 'id="rate-transform"' in html
assert 'id="panel-transform"' in html and 'data-panel="transform"' in html and '/assets/transform-panel.js' in html
assert 'id="panel-transform"' in html and 'data-panel="transform"' in html and 'include_str!("web/transform-panel.js")' in (ROOT / 'src/admin/router.rs').read_text()
assert '/api/transform' in transform_panel and 'tp-cache-hits' in transform_panel
for marker in ['transform-memory-budget', 'transform-max-inflight', 'data-transform-preset="conservative"', 'data-transform-preset="recommended"', 'data-transform-preset="performance"', 'data-transform-preset="uber"']:
assert marker in html, marker
@@ -1110,7 +1108,7 @@ def source_contract_smoke() -> None:
assert '.managed-update' in main and "flush_hot_to_cold_for_update" in main
openapi = (ROOT / "src/admin/openapi.json").read_text(encoding="utf-8")
assert '"/api/config/history/restore"' in openapi
for marker in ['"version": "0.31.0"', '"memory_preset"', '"cold_preset"', '"memory_budget_bytes"', '"max_inflight"', '"preset"', '"session_days"', '"session_lifetime_seconds"', '"accept_local_listener_risk"', '"backend_header"', '"backend_timing_header"', '"cold_on_age"', '"match_type"', '"regex_insensitive"', '"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
for marker in ['"version": "0.31.1"', '"memory_preset"', '"cold_preset"', '"memory_budget_bytes"', '"max_inflight"', '"preset"', '"session_days"', '"session_lifetime_seconds"', '"accept_local_listener_risk"', '"backend_header"', '"backend_timing_header"', '"cold_on_age"', '"match_type"', '"regex_insensitive"', '"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
assert marker in openapi, marker
assert '"software_update"' in openapi and '"update_available"' in openapi
for marker in ['"/api/certificates/deploy"', '"CertificateDeploy"', '"CertificateDeployResult"', '"/api/certificates/reload"']:
@@ -1315,7 +1313,7 @@ def main() -> None:
source_contract_smoke()
container_contract_smoke()
grafana_contract_smoke()
print("PASS: 0.31.0 SQLite/schema-9/upgrade, local-response 404 hosts, Prometheus/Grafana diagnostics, external Debian-packaging separation, cache/dashboard/logging/Nagios, retained admin/H3/stream/TLS contracts and reproducible source archives.")
print("PASS: 0.31.1 SQLite/schema-9/upgrade, local-response 404 hosts, Prometheus/Grafana diagnostics, external Debian-packaging separation, cache/dashboard/logging/Nagios, retained admin/H3/stream/TLS contracts and reproducible source archives.")
if __name__ == "__main__":
+3
View File
@@ -53,6 +53,9 @@ if node:
for path in sorted(standalone):
subprocess.run([node, "--check", str(path)], check=True, env=env, stdout=subprocess.DEVNULL)
from web_assets import read_app_js, read_vhosts_js
browser_markup = (ROOT / "src/admin/web/index.html").read_text(encoding="utf-8")
assert browser_markup.count('<script defer="" src="/assets/') == 1, "one private JS bundle prevents module race"
assert '/assets/app.js?v=__RUSTPROXY_VERSION__' in browser_markup
with tempfile.TemporaryDirectory(prefix="rustproxy-js-contract-") as directory:
temporary = Path(directory)
for name, content in (("app.js", read_app_js(ROOT)), ("vhosts.js", read_vhosts_js(ROOT))):
+3 -3
View File
@@ -43,7 +43,7 @@ const code = js.slice(js.indexOf(' const runtime = latestStatus?.runtime || {
const elements = new Map();
const dollar = id => { if (!elements.has(id)) elements.set(id, { textContent: '' }); return elements.get(id); };
const status = {
version: '0.31.0', uptime_seconds: 4201,
version: '0.31.1', uptime_seconds: 4201,
runtime: {
platform: 'Linux', operating_system: 'Debian GNU/Linux 13', kernel_version: '6.12.0', architecture: 'x86_64',
statistics_source: 'systemstat+sysinfo', data_directory: '/var/lib/rustproxy', database_path: '/var/lib/rustproxy/config.sqlite3',
@@ -63,7 +63,7 @@ const context = {
vm.runInNewContext(code, context);
assert.equal(dollar('runtime-operating-system').textContent, 'Debian GNU/Linux 13');
assert.equal(dollar('runtime-kernel-version').textContent, '6.12.0');
assert.equal(dollar('runtime-version').textContent, '0.31.0');
assert.equal(dollar('runtime-version').textContent, '0.31.1');
assert.equal(dollar('runtime-logical-cpus').textContent, '8');
assert.equal(dollar('runtime-cpu-usage').textContent, '17.2%');
assert.equal(dollar('runtime-python').textContent, 'Available · 3.13.5');
@@ -124,4 +124,4 @@ for (const key of ['python_version','pip_version','certbot_version']) {
assert.ok(runtimeSchema.properties.certificate_runtime.properties[key]);
assert.equal(runtimeSchema.properties.certificate_runtime.properties[key].nullable, true);
}
console.log('PASS: 0.31.0 legend palette, About cleanup, system tab/navigation, read-only API schema and simulated status rendering.');
console.log('PASS: 0.31.1 legend palette, About cleanup, system tab/navigation, read-only API schema and simulated status rendering.');
+16 -5
View File
@@ -1,14 +1,25 @@
from pathlib import Path
APP_PARTS = ("core.js", "preferences.js", "config-history.js", "runtime.js", "settings.js")
APP_PARTS = ("core.js", "refresh.js", "preferences.js", "config-history.js", "runtime.js", "settings.js")
PANEL_PARTS = (
"management.js", "drafts.js", "integrations.js", "vhosts.js",
"web-server-profiles.js", "web-server.js", "docker.js", "streams.js",
"redirects.js", "host404.js", "traffic-panel.js", "cache-panel.js",
"transform-panel.js", "acme.js", "settings.js", "file-logs.js",
)
VHOST_PARTS = ("core.js", "health.js", "editor.js", "render.js")
def _read(root: Path, folder: str, parts: tuple[str, ...]) -> str:
return "\n".join((root / "src/admin/web" / folder / part).read_text(encoding="utf-8") for part in parts)
def read_app_js(root: Path) -> str:
return _read(root, "app", APP_PARTS)
def read_vhosts_js(root: Path) -> str:
body = _read(root, "vhosts", VHOST_PARTS)
return "(() => {\n" + body + "\n})();\n"
return "(() => {\n" + body + "\n})();"
def read_app_js(root: Path) -> str:
primary = _read(root, "app", APP_PARTS)
panel = "\n".join(
read_vhosts_js(root) if name == "vhosts.js" else (root / "src/admin/web" / name).read_text(encoding="utf-8")
for name in PANEL_PARTS
)
return primary + "\n" + panel
+1 -1
View File
@@ -54,7 +54,7 @@ def run_load(
port = parsed.port or (443 if parsed.scheme == "https" else 80)
tls = ssl._create_unverified_context() if insecure else ssl.create_default_context()
connection_type = http.client.HTTPSConnection if parsed.scheme == "https" else http.client.HTTPConnection
headers = {"user-agent": "RustProxy-Memory-Stress/0.31.0", "accept": "*/*"}
headers = {"user-agent": "RustProxy-Memory-Stress/0.31.1", "accept": "*/*"}
if host_header:
headers["host"] = host_header