This commit is contained in:
Mateusz Gruszczyński committed 2026-10-05 12:22:41 +02:00
1 parent e1a59f6e56
commit d168ee2afa
49 files changed
+5608 -4680

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
# Administration API access - 0.25.6
# Administration API access - 0.25.7
## Sign-in boundary
+1 -1
View File
@@ -1,4 +1,4 @@
# Installing and updating RustProxy 0.25.6
# Installing and updating RustProxy 0.25.7
The scripts prepare a Linux/systemd installation. This source archive is **not a
verified production build**: Rust/Cargo, real CA operations, live systemd startup
+4
View File
@@ -1,5 +1,9 @@
# Deployment and configuration migration history
## 0.25.6 -> 0.25.7
There is no SQLite schema or saved-configuration migration. Version 0.25.7 reuses the existing `admin_preferences` document to persist backend-table visible columns and sort order per administrator account; search text remains transient. It also adds vhost enable/disable UI actions, themed scrollbars and additional Prometheus/Grafana observability. Existing vhost `enabled` values and backend configuration remain unchanged until an administrator explicitly uses the new action.
## 0.25.5 -> 0.25.6
There is no SQLite schema or saved-configuration migration. Version 0.25.6 adds the already-exposed upstream client generation/rotation diagnostics to the live Backends table and keeps the 0.25.5 backend client recycling defaults unchanged.
+15 -3
View File
@@ -56,7 +56,7 @@ Only `GET` on the exact configured path without a query string is accepted. A
wrong path is `404`, wrong method `405`, disallowed peer `403`, invalid/missing
required bearer `401`, and exporter concurrency exhaustion `429`.
## Coverage audit in 0.19.1
## Coverage audit in 0.25.7
The exporter represents all scalar fields currently sampled by `diagnostics::View` when available. The per-interface `network_interfaces` list added in 0.18.6 is intentionally dashboard-only so kernel-created interface names cannot create an uncontrolled Prometheus label set. RustProxy also exports the bounded operational data already available from traffic metrics, cache, vhosts, backend pools, streams, logging, GeoIP and ACME renewal observations.
@@ -72,8 +72,8 @@ The exporter represents all scalar fields currently sampled by `diagnostics::Vie
| Traffic analytics | independent live collector (`include_traffic`): capture-state gauges, per-vhost request/error/body-byte/duration totals; approximate bounded top countries; fixed User-Agent families; fixed HTTP method families; status classes; cache outcomes; serving source (`web_server`, `reverse_proxy`, `local_response`, `unresolved`); and currently configured route IDs |
| Built-in Web Server | configured Web Service count/info, PHP and directory-listing flags, vhost/route source metadata, plus actual request traffic through the shared vhost counters and Traffic serving-source metrics |
| Redirect/404 hosts | desired enable state, domain/rule counts and local-response status |
| Backends | pool readiness/policy info, bounded backend status, health/drain/backup, active work and configured request-concurrency/queue limits, requests/errors/bytes, weight, separate active/passive failure state, active/passive successes and health-failure totals, unconditional HTTP-5xx/timeout/connect/I/O/slow-response observation counters, DNS/TLS/header-timeout/read-timeout/send-timeout diagnostics, capacity rejection/queue-timeout counters, plus `passive_http_5xx_total`, `passive_timeouts_total`, `passive_connect_errors_total`, `passive_io_errors_total` and `passive_slow_total` aliases, health transitions, last status, current/EWMA latency, last-probe/failure/ejection/recovery timestamps, traffic rate, and retry attempt/success totals for ordinary vhosts |
| Docker vhosts | separate `rust_proxy_docker_vhost_*` and `rust_proxy_docker_backend_*` families: configured agents/assignments/domains, vhost traffic/status/duration plus backend readiness, health, requests/errors/bytes, latency/EWMA, separate active/passive failure state, unconditional observation counters and matching passive-health aliases, transitions and probe results |
| Backends | pool readiness/policy info, bounded backend status, health/drain/backup, active work and configured request-concurrency/queue limits, requests/errors/bytes, weight, separate active/passive failure state, active/passive successes and health-failure totals, unconditional HTTP-5xx/timeout/connect/I/O/slow-response observation counters, DNS/TLS/header-timeout/read-timeout/send-timeout diagnostics, capacity rejection/queue-timeout counters, retry attempt/success totals, upstream-client generation/current-generation requests/generation age/rotation totals, plus `passive_http_5xx_total`, `passive_timeouts_total`, `passive_connect_errors_total`, `passive_io_errors_total` and `passive_slow_total` aliases, health transitions, last status, current/EWMA latency, last-probe/failure/ejection/recovery timestamps and traffic rate for ordinary vhosts |
| Docker vhosts | separate `rust_proxy_docker_vhost_*` and `rust_proxy_docker_backend_*` families: configured agents/assignments/domains, vhost traffic/status/duration plus backend readiness, health, requests/errors/bytes, latency/EWMA, separate active/passive failure state, unconditional observation counters and matching passive-health aliases, retry attempt/success totals, upstream-client generation/current-generation requests/generation age/rotation totals, transitions and probe results |
| Streams | desired enable state, active/session/reject/error counters, bytes/packets and max connections |
| Logging | structured sink queue capacity, sent/error/drop counters plus the global live-log contention drop counter |
| TLS/ACME | configured certificate count, auto-renew flag, bounded issuer metadata, latest ACME job state, renewal check/expiry timestamps, failure count and status |
@@ -157,6 +157,18 @@ rust_proxy_docker_backend_up
rust_proxy_docker_backend_ewma_latency_seconds
```
Backend client lifecycle and retry diagnostics:
```promql
rust_proxy_backend_upstream_client_generation_requests
rust_proxy_backend_upstream_client_generation_age_seconds
rate(rust_proxy_backend_upstream_client_rotations_total[5m])
rate(rust_proxy_backend_retry_attempts_total[5m])
rate(rust_proxy_backend_retry_successes_total[5m])
```
The same fields are exported for Docker-discovered backends under the `rust_proxy_docker_backend_*` prefix.
Certificate expiry window:
```promql
+24 -78
View File
@@ -1,78 +1,27 @@
# Verification report - RustProxy 0.25.6
# Verification report - RustProxy 0.25.7
## Scope
RustProxy 0.25.6 is a patch release that keeps the bounded upstream-client memory controls from 0.25.5 and makes their runtime state visible in the main Backends diagnostics table. Each row now shows client generation, requests in the current generation, generation age and total rotations. Those values come from the same backend-pool status object delivered through `/api/events` and `/api/status`, so the dashboard refreshes them with the existing live diagnostics path. The defaults remain 25,000 requests, 3,600 seconds and a 131,072-byte upstream HTTP/1 adaptive read-buffer ceiling. Recycling remains local to the backend client and does not reload the vhost or purge cache. SQLite remains schema 8 and no saved-configuration migration is introduced.
RustProxy 0.25.7 is a patch release focused on vhost operations and backend observability. Vhost cards now expose a direct revision-protected enable/disable action, the main Backends diagnostics table supports account-scoped persisted sort/column visibility preferences plus transient search, and the vhost editor gives the Enabled setting a distinct state treatment. Dashboard scrollbars follow the active theme. Prometheus now exports backend retry attempt/success counters and upstream-client generation, generation-request, generation-age and rotation metrics for both ordinary and Docker-discovered backends; the bundled Grafana dashboard adds matching lifecycle/retry panels. SQLite remains schema 8 and no saved-configuration migration is introduced.
## Source contracts reviewed
- Revision History now uses the shared dashboard dialog rule with square corners; the dedicated history dialog retains only layout dimensions/overflow and no longer duplicates color, background, border, shadow or backdrop appearance declarations. Calendar/diff sub-panels no longer add local rounded corners.
- Dashboard widths up to 850 px now hide the main section list behind an accessible `aria-expanded` Menu control. Opening shows a two-column section grid; selecting a section, pressing Escape or clicking outside closes it. Desktop navigation keeps the existing sidebar behavior.
- The authenticated top bar exposes an About dialog with author Mateusz Griszczynski, an Open Source notice and the canonical Git repository link; the documentation action is labeled Documentation. The About dialog uses the same square-corner modal styling and adds no new server route.
- Cloudflare client-IP mode still requires the direct transport peer to match the built-in Cloudflare edge CIDRs. After a successful verified `CF-Connecting-IP` override, one valid two-letter `CF-IPCountry` value is normalized and preferred for country policy/logging/Traffic; missing, duplicate, malformed and `XX` values fall back to local GeoIP of the verified effective client IP.
- Prometheus `include_traffic` defaults on and exports bounded per-vhost Traffic totals, country top values, fixed User-Agent families, fixed method families, status classes, cache outcomes, serving source and configured route IDs. Raw effective client IPs, raw request paths and full User-Agent strings remain excluded from exporter labels.
- Traffic serving source is recorded as one fixed value (`web_server`, `reverse_proxy`, `local_response`, `unresolved`) and the exporter adds configured Web Service inventory plus vhost/route source metadata. This makes pure Web Server traffic explicit while preserving the existing shared vhost request/status/byte/duration counters.
- The bundled Grafana dashboard adds a Traffic vhost variable and panels for Web Server request rate, queue drops, countries, User-Agent families, source rates, methods, status classes, cache outcomes, capture-state gauges and configured-route traffic.
- Vhost and location `method_policy` values validate and normalize HTTP methods; host and selected-location policies are cumulative and deny with 405 before upstream work. Allow-list denial includes `Allow`.
- Custom locations can select an `acl_profile_id` and add inline IP ACL plus country access policy. Profile and inline rules are compiled with the route and checked before authentication/backend selection; a location cannot weaken a vhost denial.
- Every observed exchange receives a fresh 64-hex SHA-256 `request_id`, overwrites inbound `X-Request-ID` before forwarding, and reuses the same value for diagnostics/logging. Custom header rules continue to protect `X-Request-ID`.
- SQLite schema 8 stores revision/time/actor/document in bounded `configuration_history`; successful CAS writes record history transactionally and retain the newest 512 revisions. The session-protected `/api/config/history` API supports metadata listing and one-revision detail with the previous retained document.
- `POST /api/config/history/restore` accepts an older retained revision plus the currently observed `expected_revision`. It rejects stale or non-older targets, reloads the retained document and passes it through the same startup-lock, certificate-removal, compile, cache-invalidation, persistence and hot-publish path as a normal configuration update.
- Restore persistence uses the existing storage CAS and appends the restored document as the next monotonic revision. The same transaction records `config.restore` with `source_revision=<old> revision=<new>`; the selected historical row is never overwritten.
- The Manual config history UI groups retained revisions by month/day, lists revisions for a selected day and renders a bounded recursive path-level before/after diff using text-only DOM operations. An older selected revision exposes a confirmation-gated restore action; success refreshes the active envelope and history.
- `Config.web_services` is a separate persisted collection; vhost/location `source` defaults to Reverse Proxy for old documents and Web Server stores only `web_service_id`.
- Full configuration compilation validates Web Service IDs, absolute/existing document roots, index names, duplicate IDs and every active Web Service reference. A pure static vhost does not require a backend pool; mixed Web Server and Reverse Proxy locations do.
- Web Server dispatch occurs after normal frontend routing, ACL and Basic/Tinyauth authorization and before backend selection/DNS/cache/upstream work. Static responses continue through the existing custom error-page, response-header/security, compression and transport pipeline.
- Static files use streamed Tokio file bodies with explicit lengths rather than whole-file buffering.
- Files support metadata-based ETag/Last-Modified, If-None-Match/If-Modified-Since, one Range/If-Range and 304/206/416 behavior.
- Directory requests redirect to a slash path, then search the optional ordered index list (which may be empty), then optionally render an HTML-escaped and URL-encoded RustProxy-styled listing without exposing filesystem paths.
- Root directory listing opens a fresh directory file description per request rather than a `dup` sharing the persistent root descriptor offset; a regression test requests the same listing twice. Nested directories independently apply index lookup first and listing fallback only when no index exists. Generated listings send `Cache-Control: no-store`.
- A directory with no matching index and directory listing disabled returns the built-in generic 403 page (or the configured vhost/global 403 replacement in the outer response pass), not a Web Server implementation-detail string. HEAD keeps an empty body.
- Web Services support up to 64 normalized MIME overrides, a validated fallback MIME header and an optional validated default `Cache-Control` header. Static files remain backed by the filesystem/OS page cache; existing vhost/location response-header rules run later and can override the source-level cache policy.
- Web Services additionally support ordered `ext:`/`mime:` Cache-Control rules, validated fixed response headers, ordered `try_files`, regex internal/redirect rewrites, precompressed `.br`/`.gz` sidecars and attachment extensions. Protected framing/transport headers cannot be overridden by the source header map.
- Optional `.htaccess` compatibility compiles a bounded root/subdirectory set at Web Service Apply time rather than parsing per request. It supports common RewriteRule/RewriteCond front controllers, DirectoryIndex/Indexes, AddType, Header, Expires, PHP AddHandler and simple Require all granted/denied. Unsupported access/handler scopes fail closed, `.ht*` control files are never served, and PHP AddHandler requires PHP-FPM.
- Web Service presets are UI-only generators: they populate ordinary configuration fields and do not persist a hidden CMS mode. ID/name/document root and PHP-FPM endpoint/tuning remain operator-owned. Optional hardening is persisted explicitly and defaults off for compatibility.
- `block_common_attacks` rejects TRACE/CONNECT/TRACK, sensitive dot/control/backup paths and a bounded set of high-confidence exploit probes; it also suppresses FastCGI `HTTP_PROXY` derivation from the inbound `Proxy` header. It does not claim generic WAF/SQLi/XSS filtering.
- `strip_unnecessary_headers` removes common source/PHP fingerprint headers after Web Service and `.htaccess` response handling while leaving the later vhost/location response-header pipeline authoritative.
- Optional PHP handling executes configured extensions through a bounded FastCGI connector over Unix socket or loopback TCP. PHP concurrency uses a fixed semaphore without an unbounded wait queue, request/response bodies use bounded streaming, and connection failure cannot fall back to serving PHP source. Advanced configuration adds Authorization forwarding control, a streaming request-body ceiling, bounded CGI response headers/stderr, trusted custom FastCGI parameters and validated `PHP_VALUE` overrides that cannot replace core CGI/HTTP fields or `PHP_ADMIN_VALUE`.
- Web Service symlink policy defaults to `deny`/`O_NOFOLLOW`; Linux-only `inside_root` verifies opened descriptors through `/proc/self/fd` against the canonical root. PHP-FPM is intentionally limited to `deny` because the external worker reopens `SCRIPT_FILENAME`.
- Routing rejects malformed/ambiguous encoded paths before filesystem lookup. Unix filesystem lookup walks from an opened root descriptor; `deny` uses `openat` + `O_NOFOLLOW`, while Linux-only `inside_root` verifies every opened descriptor against the canonical root. PHP-FPM requires `deny`. The secure Web Server compile path remains Unix-only.
- No second URL router, custom-error subsystem or object cache was introduced. Reverse Proxy remains the default source for existing configuration.
- Dashboard CRUD, source selectors, English/Polish strings and OpenAPI schemas expose the new model.
- Web Service index files are optional (0..16). An empty list skips index lookup, allowing directory-listing-only services without synthetic index names.
- Generated directory listings use a self-contained RustProxy panel-style layout (matching palette/typography, responsive light/dark treatment and RustProxy footer) while preserving HTML escaping, URL encoding and filesystem-path secrecy.
- Pure Web Server vhosts no longer present backend diagnostics as though an origin pool existed; their Backends summary identifies `Web Server`, while mixed static/proxy vhosts retain backend diagnostics.
- Status payloads expose fixed-cardinality per-vhost metrics independently of backend pools. The Vhosts dashboard uses those counters for Web Server-only request/active/error values, EWMA latency and byte-rate traffic while retaining backend health details for reverse-proxy sources.
- Logging settings are split into Outputs, JSON format and Error log sub-tabs inside one card, matching the Cache subsection layout. `route`, `cache_effective_enabled` and `transform_effective_enabled` are accepted by the same backend validator that saves custom JSON mappings, and the regression test validates then renders those fields.
- Structured logging exposes `user_agent` and `country`. User-Agent capture defaults on; country capture defaults off. Country resolution is skipped unless capture or an existing country ACL/rate-limit needs it; verified Cloudflare mode prefers trusted `CF-IPCountry`, otherwise local GeoIP is used.
- The authenticated Traffic workspace uses a bounded 2048-sample non-blocking queue, at most 64 vhost buckets and 32-entry approximate top tables for countries, User-Agents, effective client IPs, paths, routes, methods, status classes and cache outcomes. It never writes per-request analytics to SQLite. The Traffic UI is split into Overview, Clients, Requests and Delivery sub-tabs. Countries/methods/status/cache use donut summaries; User-Agent, effective client IP, path, route and request/response byte volume use bounded horizontal bar charts from the same in-memory TOP state.
- Sustained-traffic memory maintenance calls `malloc_trim(0)` every 60 seconds on Linux/glibc to release already-free allocator pages and trims HOT objects only when above the configured waterline and idle past the configured age. Backend Hyper clients additionally recycle their connection-pool generation after 25,000 requests or 3,600 seconds by default; both triggers are configurable/disableable per vhost, and HTTP/1 upstream adaptive read buffers default to a 128 KiB ceiling. Recycling does not publish a new vhost snapshot or purge cache.
- The live Backends table renders `upstream_client_generation`, `upstream_client_generation_requests`, `upstream_client_generation_age_seconds` and `upstream_client_rotations_total` in the same row as Active/Requests/Errors/Latency/Traffic. `app/core.js` feeds the table from the existing `/api/events` `snapshot.status` payload, so the new fields do not introduce another polling loop or control-plane query.
- Cache compatibility currently includes vhost configuration, so a cache-affecting vhost save can purge cache during snapshot publication; replacing the compiled snapshot also retires its upstream clients after outstanding references drain. These mechanisms explain why a manual vhost save can visibly reduce RSS without implying that reloads are required for steady-state operation.
- The Web Server list now uses the same vhost card/detail-cell visual structure as the Vhosts list. Reverse Proxy vhost creation reports a dedicated “at least one backend” validation error instead of the generic paths/ACL/headers JSON error.
- Web Service cards use only the shared `el(...)` DOM helper; a regression contract rejects the previous undefined `text(...)` call that aborted list rendering. Authenticated-shell startup now verifies `/api/auth/session` first and never reveals the legacy embedded sign-in form for non-authentication JavaScript/API failures, preventing F5 from falsely presenting the user as logged out.
- The Web Server UI module performs a catch-up render when it registers after `app.js`; this closes the race where a very fast `/api/config` response could finish before `web-server.js` existed and leave the Web Service list blank until a later render.
- The Web Service editor now builds its configuration tabs with the same `vh-tabs` + `quiet` button pattern and active/ARIA state handling as the Vhost editor; the source contract also checks this shared modal-tab pattern and invalid-field navigation switches to the owning tab.
- Static dispatch clones only `Method`, `HeaderMap` and `Uri` before awaiting the filesystem source; it does not hold `&Request<Body>` across an await, keeping the Axum 0.8 fallback handler future `Send`. This addresses the reported `Handler<_, _>` / E0277 failure at `.fallback(forward)`.
- `/docs` is an authenticated documentation surface with a Markdown Reader, searchable embedded docs bundle and a separate API/OpenAPI tab. Reader Markdown files are direct `include_str!` compiler inputs and no longer depend on a generated `OUT_DIR/docs-content.json`, preventing clean/incremental builds from failing on a missing documentation artifact.
- Documentation cleanup keeps README and the active ROADMAP current-only; operator release history, developer-level changelog history and completed roadmap milestones are separated into CHANGELOG/audit/archive documents.
Backend-table visible columns and sort order are presentation-only fields in the existing account-scoped `admin_preferences` document; search text is not persisted and none of these view settings alter RustProxy configuration. The quick vhost action changes only the selected vhost `enabled` flag through the same `saveSection("vhosts", ...)` revision/CSRF path as other vhost edits. Existing backend client recycling defaults remain unchanged.
## Implemented automated coverage
Rust unit tests in `src/web_server/tests.rs` cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, `try_files`, rewrite redirect/internal behavior, `.htaccess` WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. Upstream tests cover request-budget client generation recycling and disabled recycling; balancing tests cover the new keepalive defaults and validation bounds. `src/traffic/tests.rs` includes bounded-table, effective-client-IP view and fixed Prometheus User-Agent/method family coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. Vhost tests cover method-policy normalization/allow/block behavior, database tests cover retained configuration revision documents, actor metadata and previous-revision lookup, and admin tests cover restoring revision 1 as revision 3 while preserving the previous document and emitting `config.restore`. ACL tests include encoded traversal/separator/malformed-encoding cases.
Rust unit tests in `src/web_server/tests.rs` cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, `try_files`, rewrite redirect/internal behavior, `.htaccess` WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. Upstream tests cover request-budget client generation recycling and disabled recycling; balancing tests cover the new keepalive defaults and validation bounds. `src/traffic/tests.rs` includes bounded-table, effective-client-IP view and fixed Prometheus User-Agent/method family coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. Vhost tests cover method-policy normalization/allow/block behavior, database tests cover retained configuration revision documents, actor metadata and previous-revision lookup, and admin tests cover account-scoped/CSRF-protected view preferences including legacy preference defaults, backend-table columns/sort persistence and invalid-column rejection, plus restoring revision 1 as revision 3 while preserving the previous document and emitting `config.restore`. ACL tests include encoded traversal/separator/malformed-encoding cases.
Rust-independent release checks additionally validate UI/JSON/language/source contracts and reproducible packaging.
During the prior 0.25.4 compiler gate, an external build exposed one module-privacy error in the history split (`CONFIG_HISTORY_CAPACITY` was private to `db::history`) and one unused `country_resolved` assignment in the location GeoIP branch. Both were corrected before the 0.25.5 baseline: the capacity is exposed to its parent module with `pub(super)`, referenced through `history::CONFIG_HISTORY_CAPACITY`, and the dead assignment is removed. This workspace still has no Rust/Cargo toolchain, so compiler confirmation of the 0.25.6 tree remains a release-host gate.
During the prior 0.25.4 compiler gate, an external build exposed one module-privacy error in the history split (`CONFIG_HISTORY_CAPACITY` was private to `db::history`) and one unused `country_resolved` assignment in the location GeoIP branch. Both were corrected before the 0.25.5 baseline: the capacity is exposed to its parent module with `pub(super)`, referenced through `history::CONFIG_HISTORY_CAPACITY`, and the dead assignment is removed. This workspace still has no Rust/Cargo toolchain, so compiler confirmation of the 0.25.7 tree remains a release-host gate.
### Modular source-tree verification
- The new upstream client implementation is split into `src/upstream/client.rs` with test bodies in `src/upstream/client_tests.rs`; both stay below the 500-line module limit, and `src/upstream.rs` remains below that limit after moving client construction out.
- `python3 scripts/source_module_contracts.py`: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational deploy/NPM-migration Python modules remain within their source-size contracts.
- `python3 scripts/rust_module_contracts.py` is BLOCKED by a pre-existing source-tree issue in the supplied 0.25.5 baseline archive: `src/admin/documentation.rs` is 554 lines while the contract limit is 500. The same failure reproduces on the unmodified 0.25.5 baseline archive.
- `python3 scripts/docs_check.py` is also BLOCKED by a pre-existing supplied-archive issue: the Reader does not embed `docs/ACME_PROVIDERS.md`. This also reproduces on the unmodified input archive.
- Rust unit-test bodies added for this change are isolated in a test include file; the implementation module contains only the guarded include declaration.
- Cargo parsing/type checking remains a release-host requirement because this workspace has no Rust toolchain.
- `src/admin/documentation.rs` was split so the embedded Reader document catalog lives in `src/admin/documentation/documents.rs`; both files now stay below the 500-line Rust module limit without changing Reader behavior.
- The Rust module contract now recognizes the existing `*_tests.rs` naming convention, and the documentation contract validates embedded documents independently of `include_str!` line wrapping.
- `python3 scripts/rust_module_contracts.py`: PASS.
- `python3 scripts/source_module_contracts.py`: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational Python modules remain within their source-size contracts.
- `python3 scripts/docs_check.py`: PASS. The documentation index, authenticated Reader/API split and local Markdown links are consistent.
- Cargo parsing/type checking remains a release-host requirement because this workspace has no Rust/Cargo toolchain.
## Verification status in this workspace
@@ -80,26 +29,23 @@ During the prior 0.25.4 compiler gate, an external build exposed one module-priv
|---|---|
| `python3 scripts/langs_check.py` | PASS |
| `node --check src/admin/web/vhosts/render.js` | PASS |
| Backend live-table source contract | PASS: four client-generation diagnostics are rendered from backend member status fields |
| `python3 scripts/memory_contracts.py` | PASS, including upstream generation-recycle/buffer-cap source contracts |
| `node --check src/admin/web/vhosts/editor.js` | PASS |
| 0.25.7 vhost/dashboard source contracts | PASS: quick enable/disable, backend search/sort/column controls, account-scoped backend table preferences, themed scrollbars and distinct Enabled editor control are present |
| 0.25.7 Prometheus/Grafana source contracts | PASS: retry/client-lifecycle families exist for ordinary and Docker backends and matching dashboard queries are present |
| `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 |
| `node --check src/admin/web/vhosts/editor.js` | PASS |
| `python3 scripts/rust_module_contracts.py` | PASS |
| `python3 scripts/docs_check.py` | PASS |
| `node scripts/web_service_ui_test.mjs` | PASS |
| OpenAPI/language JSON parse | PASS |
| OpenAPI/language/Grafana JSON parse | PASS |
| `go test ./...` in `docker-agent` | PASS |
| SQL migration/backup smoke (`release_smoke.sql_and_backup_smoke`) | PASS |
| Stopped-source upgrade smoke (`release_smoke.upgrade_smoke`) | PASS |
| `python3 scripts/rust_module_contracts.py` | BLOCKED by pre-existing `src/admin/documentation.rs` 554-line baseline failure |
| `python3 scripts/docs_check.py` | BLOCKED by pre-existing missing `docs/ACME_PROVIDERS.md` Reader embed |
| `python3 scripts/check_source.py` | BLOCKED because it invokes the same pre-existing Rust module-size gate |
| `python3 scripts/release_smoke.py` | BLOCKED because it invokes the same pre-existing Rust module-size gate; its SQL/upgrade smoke functions pass when run directly |
| `./dev.sh test` | BLOCKED at the same pre-existing Rust module-size gate before reaching Cargo |
| `cargo fmt --all` / `./dev.sh fmt` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
| `cargo check --locked --all-targets` / `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
| `cargo test --locked --all-targets` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
| Live sustained HTTPS/HTTP/1.1 RSS acceptance | release-host acceptance gate; verify RSS plateau and `upstream_client_rotations_total` under representative traffic |
| `python3 scripts/check_source.py` | PASS; explicitly reports Rust parsing/types/runtime not verified |
| `python3 scripts/release_smoke.py` | PASS, including SQLite/backup/upgrade, Debian/Grafana and reproducible source-archive contracts |
| `./dev.sh test` | Static/security/UI/smoke gates PASS; exits 127 when it reaches Rust because Cargo is unavailable |
| `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
| `cargo fmt --all`, `cargo check --locked --all-targets`, `cargo test --locked --all-targets` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
The new source-level memory bounds and UI/config contracts pass the available targeted checks. Compiler-enabled and sustained-traffic runtime acceptance remain required before production release; two unrelated static gates are already failing in the supplied 0.25.5 baseline as described above.
All Rust-independent release gates available in this workspace pass. Compiler formatting, parsing, type checking, linking and Rust unit/integration tests still require a Rust-enabled release host before treating the archive as compiler-verified production output.