v0.31.1
This commit is contained in:
1 parent
76b8bb7ee2
commit
24af7478b8
29 files changed
+321
-171
No files matched your search
@@ -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
@@ -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
@@ -1716,7 +1716,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-proxy"
|
||||
version = "0.31.0"
|
||||
version = "0.31.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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")
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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("/");
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.')
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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))):
|
||||
|
||||
@@ -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.');
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in new issue
Block a user