v0.27.3
This commit is contained in:
1 parent
e84df445c6
commit
e87a382a7e
109 files changed
+1092
-2925
No files matched your search
+3
-3
@@ -1,4 +1,4 @@
|
||||
# Administration API access - 0.27.2
|
||||
# Administration API access - 0.27.3
|
||||
|
||||
## Sign-in boundary
|
||||
|
||||
@@ -132,7 +132,7 @@ promise to erase browser/OS screenshots or data intentionally downloaded by an a
|
||||
## First build / offline assets (fixed in 0.7.2)
|
||||
|
||||
No `SWAGGER_UI_DOWNLOAD_URL` environment variable or `.cargo/config.toml` is required.
|
||||
The default is Swagger UI **5.32.11**, selected by `scripts/swagger_assets.py` and
|
||||
The default is Swagger UI **5.32.11**, selected by `scripts/build/swagger_assets.py` and
|
||||
called from this application's `build.rs`. The former `utoipa-swagger-ui` adapter
|
||||
is removed: there is no separate dependency build silently choosing its older
|
||||
historical browser default. Direct Cargo builds using `--manifest-path` use the
|
||||
@@ -204,7 +204,7 @@ build server. Browser tests still label their simulated API/Swagger renderer.
|
||||
After running the built server:
|
||||
|
||||
```bash
|
||||
python3 scripts/admin_audit.py --url http://127.0.0.1:9090
|
||||
python3 tools/audit/admin_audit.py --url http://127.0.0.1:9090
|
||||
```
|
||||
|
||||
The script sends anonymous read-only loopback probes, follows no redirects, ignores
|
||||
|
||||
@@ -42,7 +42,7 @@ committed document at startup; this is not one cross-memory/SQLite transaction.
|
||||
### Rust source organization
|
||||
|
||||
Rust modules are kept as small responsibility-oriented files. Every checked-in `.rs` file
|
||||
is limited to **500 lines**; `scripts/rust_module_contracts.py` enforces the limit across
|
||||
is limited to **500 lines**; `tools/checks/rust_module_contracts.py` enforces the limit across
|
||||
the repository. Large logical modules use a thin facade (`config.rs`, `docker.rs`,
|
||||
`server.rs`, `runtime.rs`, `balance.rs`, `prometheus.rs`, and similar) plus files in a
|
||||
matching directory. `web_server` uses the standard `web_server/mod.rs` facade with
|
||||
@@ -190,7 +190,7 @@ the 0.7 scheduler and automated publication.
|
||||
same canonical vhost model used by the UI. Validated startup migration uses one
|
||||
CAS write; failure before validation completion leaves the stored JSON untouched.
|
||||
|
||||
`acme` manages one private worker job; `scripts/acme_provider.py` adapts Certbot
|
||||
`acme` manages one private worker job; `scripts/runtime/acme_provider.py` adapts Certbot
|
||||
webroot/Cloudflare/OVH/RFC2136. Only the running HTTP-01 job's names and token files
|
||||
are exposed by the reserved challenge middleware. Provider files remain private,
|
||||
not part of SQLite or generic configuration exports. Issuance/import are separate.
|
||||
|
||||
+2
-2
@@ -77,10 +77,10 @@ When cold storage is enabled,
|
||||
`cold_after_seconds` measures time since the last access. `cold_max_hot_seconds` measures total
|
||||
hot-tier residency, so it can move a frequently accessed object to disk after a configured age.
|
||||
The administration UI exposes these as separate policies to avoid conflating "old" with "unused".
|
||||
Demotions use an asynchronous queue bounded by both object count and `cold_queue_max_bytes`. A demoted `Entry` is removed from HOT accounting and moved, not copied, into a `ColdDraft`; its `Bytes` payload remains charged to `transient_max_bytes` until persistence completes and the draft is dropped. The persisted `ColdEntry` contains paths/metadata rather than the body allocation. This prevents the COLD writer queue from becoming a second unbounded RAM cache. If an HTTP response is already using a clone of the same `Bytes`, that last transport-owned reference can keep the backing allocation alive until the response finishes; the cache-owned HOT/COLD reference itself is released after persistence. Process RSS is therefore monitored separately from cache accounting. Supported
|
||||
Demotions use an asynchronous queue bounded by both object count and `cold_queue_max_bytes`. A demoted `Entry` is removed from HOT accounting and moved, not copied, into a `ColdDraft`; its `Bytes` payload remains charged to `transient_max_bytes` until persistence completes and the draft is dropped. The persisted `ColdEntry` contains compact lookup/invalidation/LRU metadata rather than the body allocation. Since 0.27.3 it also does not retain the full response `HeaderMap` or origin validator values per COLD object; those are validated and loaded from the existing metadata JSON only for an actual COLD read. The in-memory body digest is 32 raw bytes and the map-owned cache key is not duplicated inside the entry. This reduces long-lived COLD index RAM without changing Cold format 3 on disk. This prevents the COLD writer queue from becoming a second unbounded RAM cache. If an HTTP response is already using a clone of the same `Bytes`, that last transport-owned reference can keep the backing allocation alive until the response finishes; the cache-owned HOT/COLD reference itself is released after persistence. Process RSS is therefore monitored separately from cache accounting. Supported
|
||||
glibc/Linux builds ask the allocator to release unused pages after bulk demotion. During
|
||||
ordinary graceful shutdown, `cold_on_shutdown` performs a best-effort direct flush of remaining hot
|
||||
objects before the store is closed. A **managed software update** (`update.sh` / `scripts/deploy.py`)
|
||||
objects before the store is closed. A **managed software update** (`update.sh` / `scripts/deploy/deploy.py`)
|
||||
uses a private one-shot marker and, on RustProxy 0.13.2+, forces this hot-to-cold handoff whenever
|
||||
the cold tier is enabled even if `cold_on_shutdown=false`. The updater gives the process a larger
|
||||
stop budget and removes the marker before backing up state. If the cold tier is disabled there is
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ each Docker host, so the proxy container never needs Docker-socket access. See
|
||||
Build locally with a normal OCI builder:
|
||||
|
||||
```bash
|
||||
docker build -t rustproxy:0.27.2 .
|
||||
docker build -t rustproxy:0.27.3 .
|
||||
```
|
||||
|
||||
Persist `/var/lib/rustproxy`; it contains the SQLite database, certificates and the
|
||||
@@ -22,7 +22,7 @@ docker volume create rustproxy-data
|
||||
docker run --rm -d --name rustproxy \
|
||||
-p 8080:8080 \
|
||||
-v rustproxy-data:/var/lib/rustproxy \
|
||||
rustproxy:0.27.2
|
||||
rustproxy:0.27.3
|
||||
|
||||
docker exec rustproxy rust-proxy admin setup-token
|
||||
```
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Stored log explorer
|
||||
|
||||
RustProxy 0.27.2 provides an authenticated, read-only **Logs** workspace at `/logs`. The top bar has one **Logs** menu with separate **Stored logs** and **Live Logs** actions; the two data paths remain independent.
|
||||
RustProxy 0.27.3 provides an authenticated, read-only **Logs** workspace at `/logs`. The top bar has one **Logs** menu with separate **Stored logs** and **Live Logs** actions; the two data paths remain independent.
|
||||
|
||||
## Separation from Live Logs
|
||||
|
||||
|
||||
@@ -74,6 +74,9 @@ All changes to socket/ALPN/QUIC transport parameters require restart.
|
||||
of forbidden connection/framing headers; streamed bodies and trailers.
|
||||
- Shared routing pipeline: real local socket -> validated authority -> trusted client
|
||||
address -> ACL -> Tinyauth -> cache -> origin -> response/security/Server policies.
|
||||
- HTTP cache semantics are shared with HTTP/1.1 and HTTP/2. In 0.27.3, body-less
|
||||
`HEAD` requests use the same bounded empty-body probe as `GET`, so an initially
|
||||
unpolled HTTP/3 receive stream does not cause a false `request_body` cache bypass.
|
||||
- 0-RTT is disabled to avoid replaying writes; no retry to another origin or transport.
|
||||
- Endpoint active migration is disabled. Missing real local destination data on a
|
||||
wildcard QUIC connection fails closed rather than substituting a forwarded IP.
|
||||
|
||||
+13
-4
@@ -1,13 +1,22 @@
|
||||
# Installing and updating RustProxy 0.27.2
|
||||
# Installing and updating RustProxy 0.27.3
|
||||
|
||||
The scripts prepare a Linux/systemd installation. This source archive is **not a
|
||||
verified production build**: Rust/Cargo, real CA operations, live systemd startup
|
||||
and rollback against a real Rust database have not been exercised in the packaging
|
||||
environment. Perform the acceptance steps below on an isolated server first.
|
||||
|
||||
Ready-to-use Debian packages are published separately at `https://rustproxy.linuxiarz.pl`. The Debian package-build repository and metadata are intentionally maintained outside this source tree.
|
||||
## Official installation repositories
|
||||
|
||||
## Debian 13+ one-line source install/update
|
||||
Use the project-maintained package repositories as the normal installation/update path:
|
||||
|
||||
- **DEB/RPM:** `https://rustproxy.linuxiarz.pl/`
|
||||
- **OPNsense plugin:** `https://rustproxy-opn.linuxiarz.pl/`
|
||||
|
||||
Package-build metadata is intentionally maintained outside this source tree. The Debian source
|
||||
bootstrap below remains supported for development, custom builds and environments where the
|
||||
packaged path is not suitable.
|
||||
|
||||
## Optional: Debian 13+ one-line source install/update
|
||||
|
||||
```bash
|
||||
# auto: first install or managed update
|
||||
@@ -179,7 +188,7 @@ A source-tree preflight can still inspect a distribution-provided fallback envir
|
||||
|
||||
```bash
|
||||
sudo -u rustproxy env PATH=/usr/local/bin:/usr/bin:/bin \
|
||||
python3 scripts/acme_provider.py --doctor
|
||||
python3 scripts/runtime/acme_provider.py --doctor
|
||||
```
|
||||
|
||||
The provider script is embedded in the RustProxy binary; this command is diagnostic only.
|
||||
|
||||
+6
-6
@@ -46,7 +46,7 @@ The administration server keeps the same strict Host/Origin/request-marker/CSRF
|
||||
|
||||
There is no SQLite schema or saved-configuration migration. 0.25.1 reorganizes the Traffic dashboard and source tree only; existing Web Services, vhosts, traffic settings, cache state and administrator data remain compatible. Browser asset URLs remain `/assets/app.js` and `/assets/vhosts.js` even though their source is now split into bounded modules.
|
||||
|
||||
When updating a source checkout by extracting the archive over an older tree, remove the obsolete source monoliths `src/admin/web/app.js` and `src/admin/web/vhosts.js` if they remain. Checkouts older than the Web Server module split may also retain obsolete `src/web_server.rs`; remove it as well. Do **not** remove `src/config.rs`, `src/docker.rs`, `src/runtime.rs`, `src/balance.rs`, `scripts/deploy.py`, `scripts/migrate_npm.py` or `docker-agent/main.go`: these are intentional module/CLI entry points in 0.25.1. Build/cache artifacts such as `target/` and `__pycache__/` may be deleted safely, but `.env`, `data/`, databases and local certificates are runtime/operator state and must not be deleted as part of a source refresh.
|
||||
When updating a source checkout by extracting the archive over an older tree, remove the obsolete source monoliths `src/admin/web/app.js` and `src/admin/web/vhosts.js` if they remain. Checkouts older than the Web Server module split may also retain obsolete `src/web_server.rs`; remove it as well. Do **not** remove `src/config.rs`, `src/docker.rs`, `src/runtime.rs`, `src/balance.rs`, `scripts/deploy/deploy.py`, `scripts/migration/migrate_npm.py` or `docker-agent/main.go`: these are intentional module/CLI entry points in 0.25.1. Build/cache artifacts such as `target/` and `__pycache__/` may be deleted safely, but `.env`, `data/`, databases and local certificates are runtime/operator state and must not be deleted as part of a source refresh.
|
||||
|
||||
## 0.24.10 -> 0.25.0
|
||||
|
||||
@@ -80,7 +80,7 @@ There is no schema or configuration-format migration. This patch changes only ad
|
||||
There is no new SQLite schema version in 0.15.0. Renewal observations remain in the existing
|
||||
schema-v3 `certificate_renewals` table. The application no longer contains a runtime JSON importer.
|
||||
|
||||
When `upgrade.sh` / `scripts/upgrade.py` is used while RustProxy is stopped, an obsolete
|
||||
When `upgrade.sh` / `scripts/deploy/upgrade.py` is used while RustProxy is stopped, an obsolete
|
||||
`<data-dir>/certs/renewals.json` observation sidecar is validated as a regular file and removed as
|
||||
the final source-upgrade step. It is not imported and no second legacy copy is retained. If the
|
||||
source-upgrade transaction fails before that final removal, the old sidecar remains untouched.
|
||||
@@ -189,7 +189,7 @@ removed in 0.7.2 (see the build notes above). Source-tree updates still back up
|
||||
replace that managed directory; retain any unrelated local Cargo settings from
|
||||
your private backup. Read [API_ACCESS.md](API_ACCESS.md) for current build inputs.
|
||||
|
||||
Run `python3 scripts/admin_audit.py --url http://127.0.0.1:9090` after deployment.
|
||||
Run `python3 tools/audit/admin_audit.py --url http://127.0.0.1:9090` after deployment.
|
||||
It prints only status checks, no response bodies or credentials.
|
||||
|
||||
---
|
||||
@@ -302,7 +302,7 @@ unzip RustProxy-0.4.0.zip -d /home/mg/rustproxy-040-staging
|
||||
cd /home/mg/rustproxy-040-staging/RustProxy
|
||||
```
|
||||
|
||||
`scripts/backup.py` is a legacy release-test helper and is not a complete Secret
|
||||
`tools/legacy/backup.py` is a legacy release-test helper and is not a complete Secret
|
||||
Store backup. For current backup/restore behavior see `SECRET_STORE_BACKUP.md`.
|
||||
|
||||
A missing database means there is no database to back up. Do not initialize an empty
|
||||
@@ -354,7 +354,7 @@ and CLI-only `rust-proxy backup restore`; it includes the encrypted Secret Store
|
||||
key material required to recover it, certificates and other durable application
|
||||
state while excluding cache, logs and runtime files.
|
||||
|
||||
The historical `./dev.sh backup` / `scripts/backup.py` snapshot helper described by
|
||||
The historical `./dev.sh backup` / `tools/legacy/backup.py` snapshot helper described by
|
||||
older release notes is not sufficient after Secret Store migration and is retained
|
||||
only for offline compatibility/release tests.
|
||||
|
||||
@@ -378,7 +378,7 @@ Managed paths now include build.rs, langs, deploy and make_zip.py. Extra *.json
|
||||
language packs from the installed langs directory are copied into the new tree
|
||||
when the new distribution does not contain the same filename. Shipped packs are
|
||||
updated, with old bytes preserved in the source backup. Invalid custom packs can
|
||||
correctly block a build; review them with scripts/langs_check.py. No symlinked
|
||||
correctly block a build; review them with tools/checks/langs_check.py. No symlinked
|
||||
language pack is followed. The updater never copies a database from the package.
|
||||
|
||||
The old lockfile is preserved in the managed source backup and a new dependency
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Nginx Proxy Manager migration
|
||||
|
||||
RustProxy ships `scripts/migrate_npm.py` for a one-time, dry-run-first migration of
|
||||
RustProxy ships `scripts/migration/migrate_npm.py` for a one-time, dry-run-first migration of
|
||||
Nginx Proxy Manager (NPM) proxy hosts from its SQLite database.
|
||||
|
||||
The tool reads NPM only. It does not modify the NPM database and it never imports
|
||||
@@ -9,7 +9,7 @@ reads the current revision, merges generated vhosts into the existing configurat
|
||||
and writes only when `--apply` is supplied.
|
||||
|
||||
`migrate_npm.py` is the CLI entry point and requires the sibling modules
|
||||
`scripts/migrate_npm_core.py` and `scripts/migrate_npm_api.py`. They use only the
|
||||
`scripts/migration/migrate_npm_core.py` and `scripts/migration/migrate_npm_api.py`. They use only the
|
||||
Python standard library, so no `pip` packages are required. If the migrator is copied
|
||||
or mounted outside the RustProxy source tree, keep all three files in the same directory.
|
||||
|
||||
@@ -58,7 +58,7 @@ Set the password in the environment or omit it and use the interactive prompt:
|
||||
export RUSTPROXY_USERNAME=admin
|
||||
export RUSTPROXY_PASSWORD='...'
|
||||
|
||||
python3 scripts/migrate_npm.py \
|
||||
python3 scripts/migration/migrate_npm.py \
|
||||
--database /path/to/npm/data/database.sqlite \
|
||||
--rustproxy https://rustproxy.example.net:9090
|
||||
```
|
||||
@@ -89,7 +89,7 @@ same Force SSL policy to every imported host. Select explicit listener IDs when
|
||||
After reviewing `npm-migration-plan.json`:
|
||||
|
||||
```bash
|
||||
python3 scripts/migrate_npm.py \
|
||||
python3 scripts/migration/migrate_npm.py \
|
||||
--database /path/to/npm/data/database.sqlite \
|
||||
--rustproxy https://rustproxy.example.net:9090 \
|
||||
--apply
|
||||
@@ -109,9 +109,9 @@ RustProxy directory:
|
||||
docker run --rm -it \
|
||||
--network host \
|
||||
-v /path/to/npm/data:/npm:ro \
|
||||
-v "$PWD/scripts:/rustproxy-scripts:ro" \
|
||||
-v "$PWD/scripts/migration:/rustproxy-migration:ro" \
|
||||
python:3.13-alpine \
|
||||
python /rustproxy-scripts/migrate_npm.py \
|
||||
python /rustproxy-migration/migrate_npm.py \
|
||||
--database /npm/database.sqlite \
|
||||
--rustproxy https://127.0.0.1:9090 \
|
||||
--insecure-admin-tls
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ This is the canonical index for the current project documentation. The authentic
|
||||
- [0.25.1 release audit](V0.25.1_AUDIT.md) - historical Traffic/module-split release scope and compiler-regression guards.
|
||||
- [0.25.0 specification audit](V0.25.0_AUDIT.md) - Web Server foundation point-by-point implementation status.
|
||||
- [0.25.0 pre-production security audit](V0.25.0_SECURITY_PREPROD_AUDIT.md) - threat-oriented source/configuration review, fixes made in-session and mandatory runtime security gates.
|
||||
- [0.27.3 implementation note](V0.27.3_IMPLEMENTATION.md) - HTTP/3 HEAD cache parity, COLD/rate-limit memory reduction, backup scope and package-path update.
|
||||
- [0.27.2 implementation note](V0.27.2_IMPLEMENTATION.md) - managed Certbot relocation/renewal repair.
|
||||
- [0.27.1 implementation note](V0.27.1_IMPLEMENTATION.md) - first-admin command, managed/fallback certificate runtime and account-scoped route-list sorting.
|
||||
- [0.27.0 implementation note](V0.27.0_IMPLEMENTATION.md) - compression defaults/scoped policy, persistent Docker publications and visible cache occupancy meter fill.
|
||||
@@ -70,7 +71,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 [V0.27.2_IMPLEMENTATION.md](V0.27.2_IMPLEMENTATION.md); [V0.27.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md) is retained as the prior managed-runtime/list-sorting milestone; [V0.27.0_IMPLEMENTATION.md](V0.27.0_IMPLEMENTATION.md) is retained as the prior compression/Docker-publication milestone; [V0.26.7_IMPLEMENTATION.md](V0.26.7_IMPLEMENTATION.md) is retained as the prior cache/backend/container milestone; [V0.26.6_IMPLEMENTATION.md](V0.26.6_IMPLEMENTATION.md) is retained as the prior access-policy/administration milestone; [V0.26.5_IMPLEMENTATION.md](V0.26.5_IMPLEMENTATION.md) is retained as the prior interface-scaling/listener-navigation milestone, [V0.26.4_IMPLEMENTATION.md](V0.26.4_IMPLEMENTATION.md) as the prior administration/backend-lifecycle milestone, [V0.26.3_IMPLEMENTATION.md](V0.26.3_IMPLEMENTATION.md) as the prior appearance/UI milestone, [V0.26.2_IMPLEMENTATION.md](V0.26.2_IMPLEMENTATION.md) as the prior Logs/UI milestone and [V0.26.1_IMPLEMENTATION.md](V0.26.1_IMPLEMENTATION.md) as the prior protocol-attribution milestone. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain historical evidence.
|
||||
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 [V0.27.3_IMPLEMENTATION.md](V0.27.3_IMPLEMENTATION.md); [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.
|
||||
|
||||
|
||||
@@ -147,7 +147,6 @@ Current direction: 0.23.3 -> 0.24.0
|
||||
- [x] Add FreeBSD/OpenBSD/NetBSD native best-effort sampling and explicit unsupported/null metrics.
|
||||
- [x] Surface platform in Proxy Process and Prometheus metadata.
|
||||
- [x] Update source/package/UI identity and source-side regression contracts to 0.24.0.
|
||||
- [ ] Run compiler-enabled `cargo fmt --all`, `cargo check --locked --all-targets` and `cargo test --locked --all-targets` on the release host.
|
||||
|
||||
See [the 0.24.0 specification audit](V0.24.0_AUDIT.md).
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ The encrypted backup contains the durable application state needed for recovery,
|
||||
- other durable RustProxy data accepted by the backup manifest,
|
||||
- validated internal relative symlinks, including Certbot `live/` links into the same profile's `archive/` tree.
|
||||
|
||||
It excludes rebuildable/runtime data such as cache, logs, temporary files, sockets, PID/lock files and SQLite WAL/SHM sidecars. Symlinks are accepted only when their target is relative and resolves inside the staged RustProxy data tree; absolute, escaping or dangling links fail backup/restore. Restore recreates accepted links as links rather than dereferencing them.
|
||||
It excludes rebuildable/runtime data such as cache, logs, temporary files, sockets, PID/lock files, SQLite WAL/SHM sidecars and the managed Certbot Python environment (`acme-python`; the `acme_python` spelling is excluded as well). Certificate/ACME durable state remains included; the virtual environment is rebuilt when needed. Symlinks are accepted only when their target is relative and resolves inside the staged RustProxy data tree; absolute, escaping or dangling links fail backup/restore. Restore recreates accepted links as links rather than dereferencing them.
|
||||
|
||||
The outer container derives a backup key with Argon2id and encrypts authenticated chunks with AES-256-GCM. The backup password is independent from the local Secret Store key.
|
||||
|
||||
|
||||
+26
-33
@@ -1,45 +1,38 @@
|
||||
# Verification report - RustProxy 0.27.2
|
||||
# Verification report - RustProxy 0.27.3
|
||||
|
||||
## Scope
|
||||
|
||||
RustProxy 0.27.2 is a focused repair for managed ACME/Certbot execution while keeping SQLite schema 8 and the saved configuration format unchanged.
|
||||
RustProxy 0.27.3 fixes HTTP/3 `HEAD` cache eligibility, reduces persistent COLD-cache and rate-limit/IP memory retention, excludes rebuildable managed Python environments from backups, and updates the documented installation path. SQLite schema 8, the saved configuration format and COLD format 3 remain unchanged.
|
||||
|
||||
0.27.1 created the private environment under `<data-dir>/acme-python.installing`, installed Certbot there, validated it, and then renamed the directory to `<data-dir>/acme-python`. pip console scripts contain an absolute interpreter path, so `bin/certbot` could retain a shebang pointing at the removed staging directory and fail with `OSError` during issuance/renewal.
|
||||
The H3 repair is intentionally narrow: cache policy already accepts both `GET` and `HEAD`; the forwarding path now performs the existing bounded empty-body probe for both methods. This prevents an initially unpolled HTTP/3 receive body from being mistaken for request content.
|
||||
|
||||
0.27.2 validates and launches managed Certbot through the final venv interpreter with `python -I -m certbot`. Existing 0.27.1 environments can therefore be reused without deleting `/var/lib/rustproxy/acme-python`. The system/distribution Certbot fallback remains unchanged.
|
||||
The COLD index no longer stores full response headers or origin validator values for every disk object. These are loaded and validated from the existing metadata JSON only on an actual COLD read. The in-memory SHA-256 is 32 bytes and the map-owned key is not duplicated inside `ColdEntry`. Rate limiting now groups IP buckets below one vhost string, sweeps expired fixed-window buckets during requests and periodic runtime maintenance, and shrinks sparse hash tables before allocator trimming.
|
||||
|
||||
The 0.27.1 first-administrator, runtime-status and route/list sorting behavior remains unchanged.
|
||||
Compression was reviewed but its wire behavior was not changed: it remains streaming through `tower_http`, uses `CompressionLevel::Fastest`, and does not aggregate a complete response body before encoding. Its primary RAM cost is therefore per concurrently active compressed response/codec state, not long-lived retained objects.
|
||||
|
||||
## Regression coverage
|
||||
|
||||
Static/source contracts cover the managed runtime path and pinned package set, distro fallback markers and the new module-based Certbot launch path. A dedicated relocation regression reproduces the stale-shebang failure after renaming a venv and verifies that module execution through the final interpreter remains valid. Existing release-smoke, language/OpenAPI, source-module, security, web-server, browser-service and Docker-agent gates remain part of the Rust-independent verification set.
|
||||
Application-coupled Python is now separated under `scripts/runtime`, `scripts/build`, `scripts/deploy` and `scripts/migration`; QA/dev/audit/legacy helpers live under `tools/`, while OPNsense/RouterOS helpers live under `integrations/`. Release checks validate the new paths and archive contents.
|
||||
|
||||
## Verification status in this workspace
|
||||
|
||||
Rust/Cargo is not installed in this workspace. Rust-independent checks are run here; compiler/type/runtime gates remain explicitly open until this source is checked on a Rust-enabled release host.
|
||||
Rust/Cargo is not installed in this workspace. Rust-independent checks are run here; compiler/type/runtime gates and real H2/H3 protocol execution remain open until this source is checked on a Rust-enabled host.
|
||||
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| managed ACME relocated-venv regression (`release_smoke.py`) | PASS |
|
||||
| changed administration JavaScript syntax (`node --check`) | PASS |
|
||||
| language/OpenAPI JSON parse | PASS |
|
||||
| `python3 scripts/langs_check.py` | PASS |
|
||||
| `python3 scripts/memory_contracts.py` | PASS |
|
||||
| `python3 scripts/web_server_contracts.py` | PASS |
|
||||
| `python3 scripts/security_contracts.py` | PASS |
|
||||
| `python3 scripts/security_dependency_contracts.py` | PASS |
|
||||
| `python3 scripts/source_module_contracts.py` | PASS |
|
||||
| `python3 scripts/rust_module_contracts.py` | PASS |
|
||||
| `python3 scripts/docs_check.py` | PASS |
|
||||
| `python3 scripts/release_smoke.py` | PASS |
|
||||
| `node scripts/web_service_ui_test.mjs` | PASS |
|
||||
| `go test ./...` in `docker-agent` | PASS |
|
||||
| `python3 scripts/check_source.py` | PASS; explicitly reports Rust parsing/types/runtime as not verified |
|
||||
| `./dev.sh test` | Rust-independent gates PASS; wrapper exits 127 at the Rust stage because Cargo is unavailable |
|
||||
| `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable |
|
||||
| `cargo fmt --check` | BLOCKED: Rust/Cargo toolchain unavailable |
|
||||
| `cargo clippy --all-targets --all-features -- -D warnings` | BLOCKED: Rust/Cargo toolchain unavailable |
|
||||
| `cargo test --all-targets --all-features` | BLOCKED: Rust/Cargo toolchain unavailable |
|
||||
| complete release build | BLOCKED at Rust compilation: Rust/Cargo toolchain unavailable |
|
||||
The final status table is refreshed from the release checks performed for this archive. Static/source contracts do not substitute for Rust parsing, type checking, unit tests or real protocol runtime tests.
|
||||
|
||||
The 0.27.2 source archive must not be described as compiler-verified or production-ready until the Rust-enabled release-host gates pass. Static/source contracts do not substitute for Rust parsing, type checking, Clippy, unit tests or real protocol runtime tests.
|
||||
## Release checks
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| Rust/source module contracts | PASS |
|
||||
| Bounded-memory/cache/rate-limit/compression contracts | PASS |
|
||||
| Documentation and language-pack checks | PASS |
|
||||
| Web Server, security and dependency source contracts | PASS |
|
||||
| `tools/checks/check_source.py` | PASS (compiler/runtime explicitly not verified) |
|
||||
| `tools/checks/release_smoke.py` | PASS |
|
||||
| Python syntax (`py_compile`) for changed release scripts | PASS |
|
||||
| Browser Web Service UI regression (`node tools/checks/web_service_ui_test.mjs`) | PASS |
|
||||
| Docker Agent (`go test ./...`) | PASS |
|
||||
| `./dev.sh test` static/pre-compiler stages | PASS |
|
||||
| Rust `cargo fmt/check/test`, linking and Rust unit tests | NOT VERIFIED - Cargo/Rust is not installed in this workspace |
|
||||
| Live rebuilt HTTP/2 + HTTP/3 `HEAD` cache test | NOT VERIFIED - requires a compiled 0.27.3 binary and QUIC-capable runtime |
|
||||
|
||||
`./dev.sh test` exits with status 127 only when it reaches the Rust toolchain gate; all earlier release/static checks complete successfully.
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
| Requirement | Source implementation | Status |
|
||||
|---|---|---|
|
||||
| Bound glibc arena proliferation for managed systemd installs | `deploy/rustproxy.service` and `scripts/deploy.py::service_unit` set `MALLOC_ARENA_MAX=2`; Debian packaging moved to the external packaging repository in 0.27.0, and `/etc/rustproxy/environment` remains the administrator override | implemented in source |
|
||||
| Bound glibc arena proliferation for managed systemd installs | `deploy/rustproxy.service` and `scripts/deploy/deploy.py::service_unit` set `MALLOC_ARENA_MAX=2`; Debian packaging moved to the external packaging repository in 0.27.0, and `/etc/rustproxy/environment` remains the administrator override | implemented in source |
|
||||
| Avoid a duplicate identity transform buffer | `src/transform/mod.rs::decode` returns `Cow<[u8]>`; identity input is borrowed and compressed input owns only the decoded buffer | implemented in source |
|
||||
| Reduce JS/CSS minifier peak allocations | `src/transform/js.rs` and `src/transform/css.rs` iterate with `Peekable<Chars>` rather than collecting `Vec<char>`, and return the completed `String` allocation with `into_bytes()` | implemented in source |
|
||||
| Release temporary transform buffers earlier | successful changed transforms drop the decoded/collected origin buffers before final response construction | implemented in source |
|
||||
|
||||
@@ -50,7 +50,7 @@ This audit is source/static in the packaging workspace because Rust/Cargo and he
|
||||
|
||||
## Added regression coverage
|
||||
|
||||
Rust tests cover preset serialization/database reopen, preset-only cache identity stability, transform memory-budget math, bounded decompression, false Content-Length aggregation, proactive pending-task limits, stale revalidation limits and single-flight COLD cleanup. `scripts/memory_contracts.py` independently verifies the source-level bounds above when Cargo is unavailable and is part of `./dev.sh test`.
|
||||
Rust tests cover preset serialization/database reopen, preset-only cache identity stability, transform memory-budget math, bounded decompression, false Content-Length aggregation, proactive pending-task limits, stale revalidation limits and single-flight COLD cleanup. `tools/checks/memory_contracts.py` independently verifies the source-level bounds above when Cargo is unavailable and is part of `./dev.sh test`.
|
||||
|
||||
## Release-host acceptance gate
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ The dedicated Transform dashboard also shows current process-wide reserved bytes
|
||||
- local atomic inflight reservation obeys a runtime concurrency ceiling;
|
||||
- SQLite close/reopen preserves transform preset, memory budget and concurrency limit;
|
||||
- cache identity ignores resource-only changes but rotates for transform representation/eligibility changes;
|
||||
- `scripts/memory_contracts.py` verifies the new dynamic memory/concurrency bounds without Rust;
|
||||
- `tools/checks/memory_contracts.py` verifies the new dynamic memory/concurrency bounds without Rust;
|
||||
- source/release smoke checks verify the Transform UI, OpenAPI fields and release identity.
|
||||
- source/release smoke checks reject `anyhow::Context` on the boxed bounded-body collection error and require explicit `anyhow::Error` mapping.
|
||||
|
||||
|
||||
@@ -97,12 +97,12 @@ The Reader initially embedded a generated `OUT_DIR/docs-content.json`. A clean/i
|
||||
|
||||
## Verification performed in this workspace
|
||||
|
||||
- `python3 scripts/check_source.py` - PASS.
|
||||
- `python3 scripts/release_smoke.py` - PASS.
|
||||
- `python3 scripts/memory_contracts.py` - PASS.
|
||||
- `python3 scripts/web_server_contracts.py` - PASS.
|
||||
- `python3 scripts/docs_check.py` - PASS.
|
||||
- `python3 scripts/langs_check.py` - PASS.
|
||||
- `python3 tools/checks/check_source.py` - PASS.
|
||||
- `python3 tools/checks/release_smoke.py` - PASS.
|
||||
- `python3 tools/checks/memory_contracts.py` - PASS.
|
||||
- `python3 tools/checks/web_server_contracts.py` - PASS.
|
||||
- `python3 tools/checks/docs_check.py` - PASS.
|
||||
- `python3 tools/checks/langs_check.py` - PASS.
|
||||
- `node --check` for app, Settings, Docs Reader, Web Server and vhost administration JavaScript - PASS.
|
||||
- OpenAPI and both language JSON files parse - PASS.
|
||||
- `bash -n dev.sh` - PASS.
|
||||
|
||||
@@ -23,15 +23,15 @@ The reference/generated systemd units were also aligned with the stronger Debian
|
||||
|
||||
Passed in the audit environment:
|
||||
|
||||
- `python3 scripts/check_source.py`
|
||||
- `python3 scripts/web_server_contracts.py`
|
||||
- `python3 scripts/security_contracts.py`
|
||||
- `python3 scripts/security_dependency_contracts.py` (offline minimum-version gates for RustSec items reviewed on 2026-10-04)
|
||||
- `node scripts/web_service_ui_test.mjs` (preset selection + Save serialization regression)
|
||||
- `python3 scripts/memory_contracts.py`
|
||||
- `python3 scripts/docs_check.py`
|
||||
- `python3 scripts/langs_check.py`
|
||||
- `python3 scripts/release_smoke.py`
|
||||
- `python3 tools/checks/check_source.py`
|
||||
- `python3 tools/checks/web_server_contracts.py`
|
||||
- `python3 tools/checks/security_contracts.py`
|
||||
- `python3 tools/checks/security_dependency_contracts.py` (offline minimum-version gates for RustSec items reviewed on 2026-10-04)
|
||||
- `node tools/checks/web_service_ui_test.mjs` (preset selection + Save serialization regression)
|
||||
- `python3 tools/checks/memory_contracts.py`
|
||||
- `python3 tools/checks/docs_check.py`
|
||||
- `python3 tools/checks/langs_check.py`
|
||||
- `python3 tools/checks/release_smoke.py`
|
||||
- `node --check` for all administration JavaScript
|
||||
- `bash -n` for managed shell scripts
|
||||
- `go test ./...` for `docker-agent`
|
||||
@@ -41,7 +41,7 @@ Passed in the audit environment:
|
||||
- hard-coded secret scan for common private-key/token patterns: no production secret found; documentation placeholders only
|
||||
- manual review of the locked major network/security dependencies against current RustSec advisories, plus an offline regression deny-list for the reviewed 2026 malicious-crate campaign
|
||||
|
||||
`./dev.sh test` runs every non-Rust phase successfully and then stops because `cargo/rustc` are unavailable. `scripts/admin_audit.py` was also attempted, but no compiled/running RustProxy administration listener exists in this workspace, so its live probes are **blocked/unexecuted**, not passed.
|
||||
`./dev.sh test` runs every non-Rust phase successfully and then stops because `cargo/rustc` are unavailable. `tools/audit/admin_audit.py` was also attempted, but no compiled/running RustProxy administration listener exists in this workspace, so its live probes are **blocked/unexecuted**, not passed.
|
||||
|
||||
## Dependency review
|
||||
|
||||
@@ -119,7 +119,7 @@ Do not treat this audit as production approval until all of these pass on the ex
|
||||
|
||||
1. Install stable Rust/Cargo and run `./dev.sh doctor`, `./dev.sh check`, `./dev.sh test`, `cargo test --locked` and a release build.
|
||||
2. Run `cargo audit` (and preferably OSV/Trivy or equivalent) against the exact `Cargo.lock`; resolve vulnerabilities and review unmaintained/yanked transitive crates.
|
||||
3. Start the exact release binary under the target systemd unit and run `scripts/admin_audit.py` against loopback.
|
||||
3. Start the exact release binary under the target systemd unit and run `tools/audit/admin_audit.py` against loopback.
|
||||
4. Run active malformed HTTP tests for duplicate/ambiguous framing, oversized headers, slow headers/bodies, oversized request bodies, H2/H3 stream floods, WebSocket idle/connection exhaustion and Range edge cases.
|
||||
5. Fuzz/property-test `routing_path`, rewrite/`try_files`, `.htaccess`, CGI header parsing and backup restore parsers.
|
||||
6. Run filesystem escape tests using symlink races, nested links, renames and mount/bind-mount edge cases on the production kernel/filesystem.
|
||||
|
||||
+11
-11
@@ -25,23 +25,23 @@ The current source tree contains the intended corrections:
|
||||
- the split Web Server response-header fragment imports sibling `htaccess` explicitly and no longer retains the stale `ACCEPT_ENCODING`/`FromStr` imports;
|
||||
- split proxy/config/Prometheus fragments no longer export unnecessary `mut` bindings or unused values from their `include!` tuples.
|
||||
|
||||
`python3 scripts/rust_module_contracts.py` checks these conditions without a compiler. A real `cargo check --locked --all-targets` remains mandatory on the release host.
|
||||
`python3 tools/checks/rust_module_contracts.py` checks these conditions without a compiler. A real `cargo check --locked --all-targets` remains mandatory on the release host.
|
||||
|
||||
## Verification gates
|
||||
|
||||
Rust-independent acceptance for this package includes:
|
||||
|
||||
```text
|
||||
python3 scripts/rust_module_contracts.py
|
||||
python3 scripts/source_module_contracts.py
|
||||
python3 scripts/check_source.py
|
||||
python3 scripts/release_smoke.py
|
||||
python3 scripts/memory_contracts.py
|
||||
python3 scripts/web_server_contracts.py
|
||||
python3 scripts/security_contracts.py
|
||||
python3 scripts/security_dependency_contracts.py
|
||||
python3 scripts/docs_check.py
|
||||
python3 scripts/langs_check.py
|
||||
python3 tools/checks/rust_module_contracts.py
|
||||
python3 tools/checks/source_module_contracts.py
|
||||
python3 tools/checks/check_source.py
|
||||
python3 tools/checks/release_smoke.py
|
||||
python3 tools/checks/memory_contracts.py
|
||||
python3 tools/checks/web_server_contracts.py
|
||||
python3 tools/checks/security_contracts.py
|
||||
python3 tools/checks/security_dependency_contracts.py
|
||||
python3 tools/checks/docs_check.py
|
||||
python3 tools/checks/langs_check.py
|
||||
go test ./... # from docker-agent/
|
||||
```
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ After `/api/acme/issue` accepts an issuance request, the UI remembers that job I
|
||||
|
||||
## NPM migration helper
|
||||
|
||||
`scripts/migrate_npm.py` imports sibling modules `scripts/migrate_npm_core.py` and `scripts/migrate_npm_api.py`. They use the Python standard library and require no third-party package installation, but all three files must stay together. The documented container command now mounts the complete `scripts` directory.
|
||||
`scripts/migration/migrate_npm.py` imports sibling modules `scripts/migration/migrate_npm_core.py` and `scripts/migration/migrate_npm_api.py`. They use the Python standard library and require no third-party package installation, but all three files must stay together. The current documented container command mounts the dedicated `scripts/migration` directory.
|
||||
|
||||
## ACL policy composition
|
||||
|
||||
|
||||
@@ -25,3 +25,10 @@ The existing system/distribution Certbot fallback continues to execute its disco
|
||||
## Upgrade behavior
|
||||
|
||||
No ACME profile, account, certificate or credential migration is required. An `acme-python` environment created by 0.27.1 can be reused as-is because 0.27.2 bypasses the stale console-script shebang and imports Certbot from the environment's installed Python modules.
|
||||
|
||||
|
||||
## 0.27.3 correction
|
||||
|
||||
The module-based workaround described above was invalid for current Certbot packages: Certbot 5.8.0 installs a `certbot` console entry point but does not expose a runnable `certbot.__main__`, so `python -m certbot` fails even when installation and plugin imports are valid.
|
||||
|
||||
0.27.3 no longer relocates a freshly built managed environment after pip creates its console scripts. The environment is created/rebuilt directly at `<data-dir>/acme-python`, validation executes `<data-dir>/acme-python/bin/certbot --version`, and issuance/renewal use that same final console entry point. An older environment with a stale relocated shebang fails validation and is rebuilt at the final path.
|
||||
@@ -0,0 +1,58 @@
|
||||
# RustProxy 0.27.3 implementation note
|
||||
|
||||
## Scope
|
||||
|
||||
0.27.3 aligns HTTP/3 `HEAD` cache handling with HTTP/2, reduces long-lived cache/rate-limit memory, excludes the rebuildable managed Python runtime from backups, and promotes package repositories as the normal installation path. SQLite schema 8, saved configuration compatibility and the COLD cache on-disk format remain unchanged.
|
||||
|
||||
## HTTP/3 HEAD cache parity
|
||||
|
||||
HTTP semantics do not make `HEAD` meaningfully different between HTTP/2 and HTTP/3. RustProxy already allows `GET` and `HEAD` in cache policy, but the forwarding path actively probed an initially unknown request-body stream only for `GET`.
|
||||
|
||||
The HTTP/3 receive body starts with an unknown end-of-stream state until it is polled. A body-less `HEAD` could therefore reach cache policy as `body_empty=false` and be bypassed with `request_body`. HTTP/2 happened to expose end-of-stream immediately for the same curl request.
|
||||
|
||||
0.27.3 runs the existing bounded `empty_for_cache` probe for both `GET` and `HEAD`. A genuinely body-bearing request is still bypassed, while a body-less H3 `HEAD` follows the same cache lookup path as H2.
|
||||
|
||||
## COLD cache RAM
|
||||
|
||||
The COLD tier stores bodies on disk, but its old in-memory index retained a complete response `HeaderMap`, origin validators, a duplicate 32-byte cache key and a 64-character SHA-256 string for every object. With many small COLD objects, these metadata allocations could become a material RSS component even though body bytes were no longer resident.
|
||||
|
||||
0.27.3 keeps the fields needed for matching, invalidation, dashboard rows, LRU and freshness in the COLD index, but removes the persistent header/validator copies. On a real COLD read RustProxy reads and validates the existing metadata JSON, materializes headers/validators for that request, verifies the body digest and then promotes/serves the object as before. The in-memory digest is stored as 32 raw bytes and the map-owned cache key is no longer duplicated inside `ColdEntry`.
|
||||
|
||||
This trades one metadata-file read on a COLD hit for substantially lower long-lived metadata RAM. HOT behavior, COLD disk format, invalidation fields and response semantics are unchanged.
|
||||
|
||||
## Rate-limit/IP retention
|
||||
|
||||
The previous limiter keyed every client bucket by `(revision, vhost String, IP)`, duplicating the vhost allocation for each IP. Expired buckets were normally retained until the global 65,536-entry bound caused cleanup.
|
||||
|
||||
0.27.3 groups client-IP buckets below a single vhost key, stores the active revision once and removes buckets whose fixed window has expired. Cleanup runs opportunistically during requests and from the existing periodic runtime-maintenance loop, so idle traffic no longer leaves expired IP state resident indefinitely. Sparse client/vhost hash tables are shrunk after reclamation and the allocator trim follows the periodic sweep. Removing an expired bucket is behavior-equivalent to the existing next-request reset: the next request starts a new fixed window with count zero. The global client-bucket bound remains 65,536.
|
||||
|
||||
## Compression RAM assessment
|
||||
|
||||
Downstream compression remains streaming through `tower_http::compression::Compression`. It does not collect the complete response body before encoding, and `CompressionLevel::Fastest` remains selected. The long-lived cache does not keep encoder state. Compression memory therefore scales primarily with the number and codec type of concurrently active compressed responses rather than the number of cached objects or historical requests.
|
||||
|
||||
No compression algorithm or negotiation behavior is changed in 0.27.3 because the existing implementation is already bounded by streaming response lifetime. Brotli and Zstandard can have larger per-stream codec state than gzip/deflate, so concurrency remains the main compression-RAM factor under high load.
|
||||
|
||||
## Backup scope
|
||||
|
||||
`acme-python` is a managed/rebuildable Python virtual environment, not authoritative application state. Backups now skip both `acme-python` and the underscore spelling `acme_python`, while certificate/configuration/secret state remains covered by the existing backup logic.
|
||||
|
||||
## Installation paths
|
||||
|
||||
The documented normal installation/update paths are:
|
||||
|
||||
- DEB/RPM packages: `https://rustproxy.linuxiarz.pl/`
|
||||
- OPNsense plugin: `https://rustproxy-opn.linuxiarz.pl/`
|
||||
|
||||
The Debian 13+ source bootstrap remains available as an optional source/development path.
|
||||
|
||||
## Managed ACME bootstrap diagnostics
|
||||
|
||||
The managed ACME runtime now distinguishes private-environment creation, pip preparation, Certbot package installation and final plugin validation failures instead of collapsing all of them into one generic setup error. The selected stage is also emitted as a warning when no distribution Certbot fallback is available.
|
||||
|
||||
On distributions enforcing PEP 668, the application-local `virtualenv` bootstrap first uses normal `pip --target`; if the distribution rejects that operation, RustProxy retries with `--break-system-packages` while still writing exclusively into the private bootstrap directory under the RustProxy data tree. This does not install or modify packages in the distribution Python environment.
|
||||
|
||||
## Source-tool separation
|
||||
|
||||
0.27.3 also separates application-coupled scripts from auxiliary tooling without changing proxy behavior. `scripts/runtime`, `scripts/build`, `scripts/deploy` and `scripts/migration` contain code directly tied to application/build/deployment workflows. Compiler-independent checks, mocks, audit probes and the retired Python backup helper moved to `tools/`. OPNsense and RouterOS helpers moved to `integrations/`.
|
||||
|
||||
The shell entry points, `build.rs`, embedded ACME source path, source upgrader, deterministic source archive and release checks were updated together so the relocation is part of the same 0.27.3 development release.
|
||||
Reference in new issue
Block a user