0.27.2
This commit is contained in:
1 parent
e0194fbaff
commit
a631068cbe
39 files changed
+246
-138
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.27.1.
|
||||
compatibility. Current source version: 0.27.2.
|
||||
|
||||
## Delivery
|
||||
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
> test-only changes and packaging implementation notes were moved to
|
||||
> [`docs/CHANGELOG_TECHNICAL_ARCHIVE.md`](docs/CHANGELOG_TECHNICAL_ARCHIVE.md).
|
||||
|
||||
## 0.27.2
|
||||
|
||||
- Fix managed ACME issuance/renewal after the 0.27.1 private-Python change: Certbot is now launched through the final managed interpreter (`acme-python/bin/python -m certbot`) instead of the pip console script whose absolute shebang still referenced the temporary `acme-python.installing` path after the atomic directory rename.
|
||||
- Validate managed Certbot through the same module-based launch path, so already-created 0.27.1 environments recover immediately after upgrade without deleting or rebuilding `/var/lib/rustproxy/acme-python`.
|
||||
- Keep the distribution Certbot fallback unchanged for systems where the managed environment cannot be used.
|
||||
- Keep SQLite schema 8 and the saved configuration format unchanged.
|
||||
|
||||
## 0.27.1
|
||||
|
||||
- Show ready-to-run first-administrator setup-token commands instead of requiring a `$DATA_DIR` placeholder substitution.
|
||||
|
||||
Generated
+1
-1
@@ -1688,7 +1688,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-proxy"
|
||||
version = "0.27.1"
|
||||
version = "0.27.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rust-proxy"
|
||||
version = "0.27.1"
|
||||
version = "0.27.2"
|
||||
edition = "2021"
|
||||
rust-version = "1.88"
|
||||
description = "RustProxy - independent reverse proxy with local administration"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# RustProxy 0.27.1
|
||||
# RustProxy 0.27.2
|
||||
|
||||
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.27.1 release source.**
|
||||
**0.27.2 release source.**
|
||||
|
||||
## Layer-4 streams
|
||||
|
||||
@@ -11,16 +11,14 @@ 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.27.1
|
||||
## What changed in 0.27.2
|
||||
|
||||
- Show a complete first-administrator setup-token command for the default `./data` path during first launch, plus a standard service-installation example using `/var/lib/rustproxy`.
|
||||
- Manage Certbot in a RustProxy-owned Python environment under `<data-dir>/acme-python`. Missing environments are initialized automatically with `venv`/`pip`; when `venv` is split out by a distribution, RustProxy can bootstrap `virtualenv` into its own data directory.
|
||||
- Fall back to a runnable distribution `certbot` when the managed environment cannot be prepared. The Certificates panel reports preparing/managed/system/unavailable state and explicitly reports missing Python/pip while keeping PEM import and existing-certificate workflows available.
|
||||
- Add account-scoped column + direction sorting for ordinary vhosts, Docker vhosts, redirects, 404 hosts and streams, with tab-specific sort columns matching each feature. Redirects and 404 hosts use the same search/sort/action toolbar presentation as Vhosts.
|
||||
- Use the installed production RustProxy binary (not `dev.sh`) in the Certbot deploy-hook example. The startup banner and About/runtime views now show the official source repository (`https://git.linuxiarz.pl/gru/RustProxy`), package repository (`https://rustproxy.linuxiarz.pl/`) and Python/pip/Certbot certificate-runtime state.
|
||||
- Keep SQLite schema 8. The new list-sort preferences are additive/defaulted and require no database migration.
|
||||
- Fix ACME issuance and renewal with the RustProxy-managed Python environment introduced in 0.27.1.
|
||||
- Run managed Certbot through the final venv interpreter (`acme-python/bin/python -m certbot`) instead of the pip console script whose shebang still points at the temporary `acme-python.installing` directory after the atomic rename.
|
||||
- Validate the managed runtime through the same module launch path, so an existing 0.27.1 `acme-python` directory starts working immediately after upgrade; no manual venv deletion/rebuild is required.
|
||||
- Keep the distribution Certbot fallback, SQLite schema 8 and saved configuration format unchanged.
|
||||
|
||||
0.27.1 retains the 0.27.0 proxy/compression and Docker-publication behavior. Historical details are in [CHANGELOG.md](CHANGELOG.md).
|
||||
0.27.2 retains the 0.27.1 first-admin, managed-runtime UI and route-list sorting changes plus the 0.27.0 proxy/compression and Docker-publication behavior. Historical details are in [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
### Historical 0.26.7 release notes
|
||||
|
||||
@@ -88,7 +86,7 @@ Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost
|
||||
- Replace backend sort text (`A-Z` / `Z-A`) with direction arrows (`↑` / `↓`).
|
||||
- Keep SQLite schema 8 and the saved proxy configuration format unchanged; upgrading from 0.26.1 requires no data migration.
|
||||
|
||||
The detailed 0.25.5 implementation audit remains available as historical baseline evidence. Current 0.27.1 verification status is maintained in [docs/TEST_REPORT.md](docs/TEST_REPORT.md).
|
||||
The detailed 0.25.5 implementation audit remains available as historical baseline evidence. Current 0.27.2 verification status is maintained in [docs/TEST_REPORT.md](docs/TEST_REPORT.md).
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -168,7 +166,7 @@ CARGO_BUILD_JOBS=1 CARGO_PROFILE_RELEASE_LTO=false \
|
||||
|
||||
Ready Debian packages are published separately at `https://rustproxy.linuxiarz.pl`; Debian package-build metadata is intentionally not shipped in this source tree.
|
||||
|
||||
The 0.27.1 source archive preserves the resolved `Cargo.lock` supplied with the source tree and
|
||||
The 0.27.2 source archive preserves the resolved `Cargo.lock` supplied with the source tree and
|
||||
updates only this package's own version entry. This packaging environment has no Cargo, so the
|
||||
dependency graph was not re-resolved here. On the compiler-enabled deployment host, run the
|
||||
locked check/test/release gates below and retain the verified lockfile. `dev.sh` can generate a
|
||||
@@ -414,7 +412,7 @@ python3 scripts/release_smoke.py
|
||||
# Runs those checks first, then the Rust suite when Cargo is available:
|
||||
bash dev.sh test
|
||||
# Source-only package, with no Git checkout required:
|
||||
python3 make_zip.py /tmp/RustProxy-0.27.1.zip
|
||||
python3 make_zip.py /tmp/RustProxy-0.27.2.zip
|
||||
```
|
||||
|
||||
## New management and test-origin guide
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# RustProxy roadmap
|
||||
|
||||
## 0.27.2 - Managed ACME renewal repair
|
||||
|
||||
Current direction: 0.27.1 -> 0.27.2
|
||||
|
||||
- Make the managed Certbot runtime independent of pip console-script shebang relocation.
|
||||
- Reuse existing 0.27.1 `acme-python` environments without operator cleanup.
|
||||
- Preserve the system Certbot fallback and schema/config compatibility.
|
||||
|
||||
## 0.27.1 - Portable certificate runtime and list sorting
|
||||
|
||||
Current direction: 0.27.0 -> 0.27.1
|
||||
|
||||
+40
-39
@@ -1,18 +1,18 @@
|
||||
61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore
|
||||
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
||||
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
||||
6479dfef0344de33714f8503944876a3641c8381e9a7ccaaa4faed06b65e67c6 AGENTS.md
|
||||
59ff94da1b39a85b9738c8265ed3b871f483451871182d73c8a678509ee222c1 CHANGELOG.md
|
||||
0b0ed48165c10747c1a2f524fbdb27488f3edc7ff0e6fdccc845625d885ef61c Cargo.lock
|
||||
f6d19f4e9b1453cc3b80d47f6cb27870b205f9aa4592f82a872c53da44e1308d Cargo.toml
|
||||
4595fb01446f9e9e08a459085dea96c2b27a9f0aff0fab1f40c8a62e95761902 AGENTS.md
|
||||
49f5f9b0490a8b411f16f8a1a2477e96f832d6d21155727bb80c4895f9877ea1 CHANGELOG.md
|
||||
3002fea4dac2c78c11003b6ef669e53415702337062ab737958ac48471e24422 Cargo.lock
|
||||
5823157f89f6d8576a038866ff5bc2be8733f226e345f4ff9be68d1b59d1d34c Cargo.toml
|
||||
75b008f237b2226c62a7721b7901018ce83bfc2726f047a83a17c66fcb799f3b Dockerfile
|
||||
37da924319eef96622afb996a528989780a3733cc44eda7944e4f914a81eb70e README.md
|
||||
fbeb203b4ca4f02c9d35c02561cd9c098bdd2bf58688ea7039e987e24ee8e8e1 ROADMAP.md
|
||||
3ef21bb67c050fb7189a032e55e4794c4e07a1b20bcdc3f2f6222f5a37fa8fb5 README.md
|
||||
e62a31c08cc123b39031e95d10d149d36dbccf73a78a18a7578bb88521c89983 ROADMAP.md
|
||||
da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml
|
||||
928ba6a504bc431ae100c6e587861e5088b28822d2cb19da5d437b39d26c864a build.rs
|
||||
385ac7970fa94f043d0bcf04a91184e6e2c807587b85e55517ed064bb4bddba6 deploy/README.md
|
||||
31d4e0cd454060b46f359fdb84a14b16a5fe0d3baabb387dd584d76e555558bb deploy/rustproxy.service
|
||||
18121e6fb922fb0e8d8b582486cb029256b305bd0f14bb989f9a16484b619674 dev.sh
|
||||
c90c8a484ff15bb516a810c01e19260ba941b652d5d67afc4405f444ab3b06ab dev.sh
|
||||
5f51efe621f45512a466fa7f2656867c6502a135ca040f4bfeec06a6919b39b6 docker-agent/README.md
|
||||
7fee7d51a7deb67e73e53a0bdff3aa4630aea9bab9b23a0f9b8001b2169892b1 docker-agent/certificate.go
|
||||
5e4f565c3c9de4dba897af2e801ea646a83395e72eae4717a6d502dff2fcec10 docker-agent/docker-agent.env.example
|
||||
@@ -21,25 +21,25 @@ bf687a851374d8f1fa59d050f3f76532f7c12f16a6daa7d3c36102c2d9a8ec9c docker-agent/d
|
||||
9d77c90767fa929ee8338734d72ce83284d3d965673270f62cb2b1613d587a33 docker-agent/install.sh
|
||||
b68234472bec5cedd67c7cfe1de7d8806a965dfd4101f944aa6320132f18c14e docker-agent/main.go
|
||||
3d4051a1f805d145df3877476e4b87773e74be8e123045065955a5133afdc68c docker-agent/main_test.go
|
||||
dcd840bb3fd542379d3554ddc78e597c64bff22a4bd832b466f0db867840c17e docker-agent/model.go
|
||||
4e9eb90294d936e0e4f63618bbadd54b8063ec73d4beda9aa4d70d768b16ab97 docker-agent/model.go
|
||||
e52b31d0abf65ae3034f6cb367cca113633014ce8d1d799ad4dd5624d2c7b8bb docker-agent/network.go
|
||||
634790f35ff4627df2a78cec2ed371f6e9ec9df00afb386075595fc7f3ed72eb docker-agent/rustproxy-docker-agent.service
|
||||
5220d669171ec3ad65f50e0bc8de5178dadaa4904def8e1a4f61002aa9e9a55b docker-agent/server.go
|
||||
875faa3969df9409d79f050a84b4183496f557edda3d34aaec19fe556cf8c471 docs/ACME_PROVIDERS.md
|
||||
ec15163f5f51c9212003b7edd1fc380321311c2496fbaa9b45c838281b9af475 docs/ACME_RFC2136.md
|
||||
c7b75ed137094cade2b2047c1c8d304e936e0fe1121ff91a858f77c2e969fa39 docs/API.md
|
||||
386d1d9b120e05b8b776af87237294d1674ac6f37c6ca4fbd74368014d09c0d7 docs/API_ACCESS.md
|
||||
d7b224425930cf06cf34d0547e445e0363f6ac4aced43e182d1d88faa2d28cdb docs/API_ACCESS.md
|
||||
0f7f159ad5b4b5277f80c19f3c47f4e7823ea439ef02e5913e1391f1b34d129f docs/ARCHITECTURE.md
|
||||
86469d17f9786c3e6f20c66791b47e10e11695d2f1a88c66c9ded157a585c85f docs/CACHE.md
|
||||
6266163e17d2921468abdae92c1620266af8351321530e2c9b7dca6f3dd89c88 docs/CACHE_DIAGNOSTICS.md
|
||||
c6003dcbc0b95e2cfa9523b7017186cc8b4826248b588af77111ac5eb15174f9 docs/CHANGELOG_TECHNICAL_ARCHIVE.md
|
||||
0031861b52c00fc1cffc73df1410c9dee5838d445699326deddc2488ad1193ad docs/CONTAINER.md
|
||||
0a92a2d4ee88d02e9b460c680305680227c3ef82cf6b57d6f92b1ef5a6433154 docs/CONTAINER.md
|
||||
9538a52d508d8d7053c1387c42eef60e6d5dc1879c300b6fe951b3374c16884c docs/CUSTOM_LOCATIONS.md
|
||||
16d8f59908c66e595d6003495cbf5c068c68b10aa9495eb8612c38b2de0e4a7c docs/DOCKER_DISCOVERY.md
|
||||
9ea8db4d034ecb573976dd323da29f044538525c230df9f43a47be1ac867b24c docs/ERROR_LOGGING.md
|
||||
adb4c6c43023f09d291eee1027944453eb7667b4c702339346a75aa23c986b5a docs/FILE_LOGS.md
|
||||
5c46b311f48e143a3e43e61a69c8bc3cfad7748c7dfef87bd76df333b64023bd docs/FILE_LOGS.md
|
||||
df6ecd4a50796640243676ad4b3a87789f6e5d20cbebea6255e92fbfff1c7131 docs/HTTP3.md
|
||||
69b7ede915818a52bb68f94983f0fcefe77ff6c58d776c92758e2f7007678eab docs/INSTALL.md
|
||||
10f378674dced022f063bfc1b15dc9a5cfc0afd03639deb4db5de091c139288c docs/INSTALL.md
|
||||
3b5c31c805e5aee0dc2100b81246a9b631b5abb996faa598ae94f87ba39305f3 docs/INTEGRATIONS_040.md
|
||||
4bb56add544f15d54695cf797cd16a51c09024360cdeef803a88988f4a54b3a5 docs/LIVE_LOGS.md
|
||||
7c35c4cdbe7bbb81d94f3bf6aeb22b8a866af3e7f0d62bbedc299e4d6f264e0d docs/MANAGEMENT.md
|
||||
@@ -50,7 +50,7 @@ e7516646dfb107d6240370f4e7460b1189f2eb21f398740381d5d102847bbfe6 docs/NOT_FOUND
|
||||
0c2241828e01b12f749562e2ac206a4519908fff63f46eba207b1cffa932dc5b docs/NPM_MIGRATION.md
|
||||
712cb1cbf84515384b081fd2929e86e40af7c10f65bc69919b78b7b3e2fd12b5 docs/PHP_FPM.md
|
||||
572c70fbd2f61fecd80a8ff9fa5de4a94c4f158de5e90da8e920f99b051241fa docs/PROMETHEUS.md
|
||||
72a1cfc792f4cc35d3463c312a88bf0053689df0bb52d89889bb7ed15e35462b docs/README.md
|
||||
a5faed54574e23cc5940205883a9731aa1572c2499783ecba138a621fcfb4a42 docs/README.md
|
||||
6e46a137b9c88dac8cb9e3fdca877430092392de9913d746278dbff8652460c2 docs/REDIRECTS.md
|
||||
0dfd0d431c5aedc67abac1ce5de040ffa790ec9578fd7d6f91a987c333d73358 docs/REFERENCES.md
|
||||
be661dbf81af840d4d8aeeb5347c24c7faecdecc73a8cf0f6f09053f1abe04c1 docs/RENEWAL.md
|
||||
@@ -60,7 +60,7 @@ be661dbf81af840d4d8aeeb5347c24c7faecdecc73a8cf0f6f09053f1abe04c1 docs/RENEWAL.m
|
||||
620b69e566d27af04f0604f4ca3f88cf95cdfea7fbc6ae9dd92446d2b2b5d9be docs/SECURITY_AUDIT.md
|
||||
632976125cbd9e96e91d1771331c73d1ac5adaa796476a20f8546971787c2529 docs/SETTINGS.md
|
||||
3611defd206cde107e75cac006159856d12cd8f15df7ae2eb9ec3592ed2b4abd docs/STREAMS.md
|
||||
6f1d1ced81d32c2efae10b0743e6fbd45648734439ce1adbc4a62baa07341dd8 docs/TEST_REPORT.md
|
||||
6a6f48614fcf64b675ef0b7efb49f65878da3f42a6ee110f0d608c70e737be2a docs/TEST_REPORT.md
|
||||
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
|
||||
8ee6187a5460ca45643b7fd789e27bffd264449e3a92ff70e9359edee011bbbb docs/TRANSFORM.md
|
||||
a1e9c6d38d21067d1ce7115ca3395ae8ff1f6a4c40fb0ebf00a6940ef79df439 docs/TRANSPORT.md
|
||||
@@ -97,6 +97,7 @@ dd9b5dcdbd53a04fd32458caaf03b56aa335f0153b1a0e332fdf230fec12680e docs/V0.26.6_I
|
||||
f9667fe81b31762e64d36126a7e94b609316dfa856de8f8e3b96661dd2a918c6 docs/V0.26.7_IMPLEMENTATION.md
|
||||
efd5935852d4cfd09758bf67c70e437490cfce2baade46c8733201e506dbcc42 docs/V0.27.0_IMPLEMENTATION.md
|
||||
9ba6417417a0eb293879b26b019449f143e773d1482434bee88f5eaf1fe34b90 docs/V0.27.1_IMPLEMENTATION.md
|
||||
6aafee24d7badabe00e23554c8c1ec868f586e09f2d915e9f48422639a7348fb docs/V0.27.2_IMPLEMENTATION.md
|
||||
bc2ac0117528ed4616c68cf7fe05cb1d9bbd36ecaa8573828cb3b3136923f265 docs/VHOSTS.md
|
||||
09b60fb7b40db4d0139fa2a9e69a2aa9f28d4e61b8643521cfc7e936d7df8774 docs/VHOST_ACCESS.md
|
||||
4026a4adeee70f98a96cc7aa8d8be16cda42ffb2e5890d38f1ba638134ab0675 docs/WEB_SERVER.md
|
||||
@@ -111,14 +112,14 @@ b26833cb4251f9390a44192ecc827ff7f052fd19016a5ccf7498c94503ab4ce3 examples/mock-
|
||||
5a8f3a8a054abc89c6e78896b9fe2f903212199a24dc3d2d2bcbd0696a31bcde examples/transport.json
|
||||
d242de9614fbb52933b4accd32f4715ca94107abe4a3b1d7e088362b07a6ba60 examples/vhosts-balanced.json
|
||||
af2bdb1343a8141069e94ccd2c7f92574ad848437e2f9fdb5c7576a9a18ef4a5 examples/vhosts-private.json
|
||||
9cab73d7de1f54bc9e9e8b889a6eeaf2c293ab454c93ce904e9f7f5c6b7c588c grafana/README.md
|
||||
2e23d77477bd3eea895c2afe8c5e836559f435419c066e995dec9910c5bbb942 grafana/rustproxy-overview.json
|
||||
cc99b14927c696adc17c9d0689041798f0a99cbc372b35a81652d6e38af69311 grafana/README.md
|
||||
b6401012c55a9cdf7ca7ac5f90b4142c623230903877309e427142de1a81f9d0 grafana/rustproxy-overview.json
|
||||
fe1fc76bcb639cac0609a8969cd92725cfd77d87f1d8519756ef16825e04914a install-debian13.sh
|
||||
858b39fa6886b71d20690bf369e76580922364b3cc7f0cf6ba9b040df9cd76e3 install.sh
|
||||
29cada0936762f26495064d1524a668262ed729b21f20aebddc8b6e5cfea363b langs/README.md
|
||||
55a50c4071a05e4c24fef7fe9da10c0d9a3d5aaf19bafdb39fbacfbaa0b953e8 langs/en_US.json
|
||||
41707ded727ff98fc3672f69f7cb16e7950eca8efa248fd328108ca1b262c22e langs/pl_pl.json
|
||||
95f980b8420d14addf02c4c0139986ba317239426a3c91a1a821df410147c2c4 make_zip.py
|
||||
917efd1646d06ac34c5729ce5a569482d7512cf285dfc603bca24b3608d36e7c langs/en_US.json
|
||||
bab5f124ee1e1e823fe310217560c2abaff8a07c9c23a4daf7ab0f60d766eb4b langs/pl_pl.json
|
||||
300b8cbb49e44d6ce11a4445df01b1a7467b81acfafa9c2d2ba62b5a611501e4 make_zip.py
|
||||
e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql
|
||||
20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql
|
||||
5c62da30fa9db594a4d656c77ae676d3c388072b6a85f91170ec7d911d7cde43 migrations/0004_admin_preferences.sql
|
||||
@@ -133,15 +134,15 @@ ee50f38c037765fab742e888d4b9fc4d874c31c785c6064d4eca3d2c4d24d944 nagios/check_r
|
||||
1465396cf1358067e9fe48b3d61f28fd4ac65c577b67c502950ce6b42ecbe3b3 nagios/check_rustproxy_latency
|
||||
6e036f736a2b40feb78eec17bf34871771524190f283591d1c89e48e6d2271e6 nagios/check_rustproxy_queues
|
||||
7458b2d74495e6fb1c1edeea4d5a793705476431dadb60627187111f91441e13 rust-toolchain.toml
|
||||
edb6ee1445b01cd6f3a74a3a607f39fb107d411b49df028d2e0f4679e093de31 scripts/acme_provider.py
|
||||
5d4ae015f1c8199c2ed02b34576b74ec6f2b3b7a90c8d7178e5070a850bb6e72 scripts/acme_provider.py
|
||||
e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/acme_rfc2136.py
|
||||
a5b4451e45ce975685772aa8409b64a57a20a7548466584c3ea7fb975e64729c scripts/admin_audit.py
|
||||
20e83f8b6347b819d1d1ea3de5c691c36f0816954a4210b0d3f39557fefe1931 scripts/backup.py
|
||||
4ab1fc13e7447e752c476bc8bfd15ad4745900bf2a40fc5469174aacbc3aaef6 scripts/check_source.py
|
||||
6e656850ca0bafae0aeb2fdf3b8f7e9342b027830df8e4ca19190a8b1cfeb7a9 scripts/check_source.py
|
||||
187ee92c8029cdd59e89b4447cf4d170e856017a2091ceb85ae7c22dd1a79c72 scripts/deploy.py
|
||||
11321aa4c5744dd2a3322123c00182e9565891e3b2742cda5bf3fc437b3d0c60 scripts/deploy_core.py
|
||||
6960ff75a235289d270a9d8e7205a4432b51d3bca83e2c599bd20bcc90caac81 scripts/deploy_core.py
|
||||
f014472588e889488976970dbaa95a8745b6907516aa81a7cca21d0f81eaaad3 scripts/deploy_runtime.py
|
||||
f818039f8a2e35922596122cde671a5e1af264b03d48938a3ca8261ec3c8e431 scripts/docs_check.py
|
||||
fc1a74246478cb477b3892812634cb28f8b8ad45604a098327f7a14a60f25c96 scripts/docs_check.py
|
||||
d391681dc3f6786552ca44929979286a5c76a2b86785635871b59d2eb4d73389 scripts/langs_check.py
|
||||
2e35b7c78887fd56f83ca9017caa168630963a9f47da71dfc53b1a8f9ad436c2 scripts/memory_contracts.py
|
||||
2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migrate_npm.py
|
||||
@@ -151,8 +152,8 @@ d1418f8e574a7390fd45a2aa879bdf5720b773162d65e295ab0350506aa5220a scripts/mock_a
|
||||
2d3ff92300b09ce9cecbbaaa9309b4d33160fa4b2291c9952b784e8cfb599ab5 scripts/mock_server.py
|
||||
2d4c859aae5ba357a6d30024c8487ae8f59f01b192711f13f9c2f8fee0f48b50 scripts/os-acme-client/README.md
|
||||
c73b814a42bb4ff703441dbd177ee625055eeb115f9b5bb0c2150aede573a159 scripts/os-acme-client/opnsense-rustproxy-cert-deploy.sh
|
||||
f7474501b9ab7102d9f9b51c6d62c83dac3e6111e982f12e13480bcfd0b1c909 scripts/preflight.py
|
||||
3019322686f3eccb141a9587b5bff78aabf46fb2ef766d3ddf1de274fea4dc8e scripts/release_smoke.py
|
||||
65ee67092955aae5216c304453f88066ad9f51dc27e682f36866540eebbf621b scripts/preflight.py
|
||||
1df736690e3de94f1ddc363ecef9e0e86acee4e98a78c30b82936324f4747484 scripts/release_smoke.py
|
||||
45be151cd85fc2ef2f1fdc3003ace63381af262e73af8a685ab48cb697cc0de1 scripts/routeros-oci-build/.env.routeros.example
|
||||
3b48cff8506e5a6ae7d3876f47721f5de7d63e2e02264a78cf5b6ddd52d9fbc6 scripts/routeros-oci-build/Dockerfile.routeros
|
||||
7c7a3e51f43b43e1c962a4b0bb591f99c1f06977bf77f23719f7f867dfe7eb8e scripts/routeros-oci-build/Dockerfile.routeros.dockerignore
|
||||
@@ -164,11 +165,11 @@ ecfe0bb21a7549225a19b0846bb6de8c99cbfbbf5a706d33cf84db2c7146abed scripts/rust_s
|
||||
1c83054336b3508d7ad72cd259f039394682642439877fe69639c0b76be09154 scripts/security_contracts.py
|
||||
295b6f2625b1875950ea3eecccd142f49be327afdd00c92641286e6de530ec51 scripts/security_dependency_contracts.py
|
||||
6fefb5c459aacdef3dcabe9c5e6e7718a2145a0190b165c29d7a46216ac53bad scripts/source_module_contracts.py
|
||||
6c1b64db378fd6ab351882ecf91d7be3db7114b6650a88d402408b34794260cc scripts/swagger_assets.py
|
||||
df2bffcd729a998c5c7ec5452235cc07e834d8f86017d65ccd0b1754d91d11b0 scripts/swagger_assets.py
|
||||
538b5f6cfa738355a729940ee3d92e7ab3dc25ca69ae330ddaa08f831775b8ba scripts/test_compression.py
|
||||
19bfa4dca422cebe8b41d9374f2e5ad480a34228995eddcf12acfc21e0ebed6f scripts/upgrade.py
|
||||
45a6a4cca69419da94b2389d73d3f1eb42ccc4aafa5825da14242eb236bdd963 scripts/upgrade.py
|
||||
0aaa80453e25aae7ea953fadb91b3ae3eaff627977c81c9ab5a2779f9a93582f scripts/web_assets.py
|
||||
71bc04c6d71ce14362c7668e6798e0f13f2fda052a081ae52d04d7845e208adb scripts/web_server_contracts.py
|
||||
12d2e324b2685f2d20d7bde4b68d2cb1565a3b5aff49e30850238e05d57bff9f scripts/web_server_contracts.py
|
||||
c245f8f832bd2c36a3fbd5e66fe98e7367c70a8db840c79e6b640f1d9d74f2ac scripts/web_service_ui_test.mjs
|
||||
ad62f73bb42906d617cc1b479f02d4648c7324cb89fc11d2c6aa6bf13774eec9 src/acl.rs
|
||||
ea272433e7f92e983509a8ab1aa54242440abef21df526c2f99944ef279e09b9 src/acl/tests.rs
|
||||
@@ -177,20 +178,20 @@ ea272433e7f92e983509a8ab1aa54242440abef21df526c2f99944ef279e09b9 src/acl/tests.
|
||||
3f158f46e80b403b658b4e9b1e3710e38c70e47b2d476b8223d9c394ffeeba95 src/acme/model.rs
|
||||
c5334de6c732d76b2bea7bfc17b3ac305a250bbaad31a5420d6a7d7abb200449 src/acme/providers.rs
|
||||
b9e57db4bd80ef37564dfc533a96897d8a494671d53acea9fb4bf28d23ba370d src/acme/providers/tests.rs
|
||||
a5dad04694780f0c6da3c277a110930f3c2ed925fc122d4be770678055931017 src/acme/runtime_env.rs
|
||||
f8c4bb96814f669be8be40d013a6217c32f66943de0961ad827a184be6879645 src/acme/runtime_env.rs
|
||||
7acbaf34e7b953b753ab074893e47b5024f0cd756dc4c7a1074067dd936c2e8e src/acme/tests.rs
|
||||
55ef7ceb44c25c7a8ddcbfd5e0d4b647526f9bdcde901ee08db5314e4d055b39 src/admin/access.rs
|
||||
d18efa3f797f62b3916265e30ba546725a41e7ccfd9b123965ff9f522e3baa88 src/admin/certificates.rs
|
||||
1de4c7c116eeab2452ccccbaba3f2b7b63c6eb1c1e146ab870d19c5a5ca16f80 src/admin/documentation.rs
|
||||
9cac4393318cd34afcfdd02527291aaeb8eb373d38f9b219f71cb963c6d8e883 src/admin/documentation/documents.rs
|
||||
e8892cca11b3d686d1e5f6ef091a01d7b28cf4289993876a0a4d91bedb751ec4 src/admin/documentation/documents.rs
|
||||
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
|
||||
002922c91aa07cbea17cb0ee11127bb6e7e015de108ee032761b34507dcfa06d src/admin/file_log_search.rs
|
||||
d3210e037481e1f95e840550428e088ffd83ec9a42f1810e4c976298fb555a9a src/admin/file_logs.rs
|
||||
beb8be241e4f1a8cea7b6c4e02b42f0359fb1fff10ab5ce2c70ccd0e63a554b0 src/admin/logging_api.rs
|
||||
58802528128f53e493f7339063433a747b605007a8842b5efc670132d897d6f7 src/admin/mod.rs
|
||||
dd40e2e8f1cac463532b113f91b4474a97a118fcd96aa27ee9f26bd78821064b src/admin/openapi.json
|
||||
01bde7e69062ad85449a03c05188c8af4299952921993e9828f9c03439cff104 src/admin/openapi.json
|
||||
a53309daf118381031122ca70764f7a2f92adc44af3fc91df5f946e6856f76ae src/admin/operations.rs
|
||||
a01160fd4f6743a9e8c1aa2e03ddf1514ff68a192ac9523c25be09252d2ac7a4 src/admin/preferences.rs
|
||||
5287fff6b3ad436ac695e9b66feb1b0b5705b744a9f00cec7ea6a3e951e5eebf src/admin/preferences.rs
|
||||
b4fa393b780b2676b5d72e0f90cd7290292f424b8062d4b5983e722d6ca72c32 src/admin/public.rs
|
||||
684d5d28e0d2b10fb2baf2a56857b226d6334cc3346e1ca86de173ff914bee73 src/admin/router.rs
|
||||
333d5f9f4c27941c535ac689e5826264ffa2bb86b00832b597a9bb9f811f01e8 src/admin/session.rs
|
||||
@@ -226,7 +227,7 @@ e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/
|
||||
0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg
|
||||
af6e7a2e890df2fb7385a374bcb3fba52fb5a53dbe18adc1fb7865660fcba842 src/admin/web/file-logs.js
|
||||
b14e7b3578322f309627f6fe965cc16abcf85da3437c9070be6caecae1908743 src/admin/web/host404.js
|
||||
8f306bfa5635dd126a965125e11179f5475b2feec3471f36b460eb67c571bb19 src/admin/web/index.html
|
||||
9e236b9a2e9505a0eda738e4cec92efb57b1db60288499e0bf797cb67df7eecf src/admin/web/index.html
|
||||
24db88842707f764064657712d3660c6ac129fbfb47d188c0903925cf8244ce5 src/admin/web/integrations.js
|
||||
7a12f020fc587205694978ab41b660e9a80487d413fbf6e34fc525eabc58308f src/admin/web/login-keys.json
|
||||
af0fbd94d9b88ce1cce28e39dfd2c35de031adcba412dd4a9a17d9b416c256dd src/admin/web/login.html
|
||||
@@ -235,7 +236,7 @@ e169d77359785ba604ce1a728420571fdc9b491fc1c0088642399466fbed8c1b src/admin/web/
|
||||
90d9a0836662135b79fb6f183c4f3eff60f8a64392d6c5795ccf1d8ef6862263 src/admin/web/redirects.js
|
||||
20670b3167a56e0c79b061ea1b9af74a0d1e4dedb4b57cb8c211463610df28eb src/admin/web/settings.js
|
||||
bb67e77af5514478485cfb69f339d63d7eb0cbadd093fa054814a416260ccc1d src/admin/web/streams.js
|
||||
2a2543859506ac69b41e706c3e2eeb4b500b054c7302a902f71e598cc67d9007 src/admin/web/style.css
|
||||
625702e6e58ef6d78615909d02a0a236eee1a8b22cce451ca811ed30bb35967e src/admin/web/style.css
|
||||
a8a73a4fa849ae49391fcd6143e900c515c8b577f71b55cbae9701fa9f5bbe47 src/admin/web/traffic-panel.js
|
||||
e686d68fd6a368110a85dc4c5dc64e8093950d20d63e9aa44790c03dea6fc193 src/admin/web/transform-panel.js
|
||||
f746b0aa758c1f9fbf5e656ab269f3ffe32675b90c83f0ed5b1e398322095e34 src/admin/web/vhosts/core.js
|
||||
@@ -345,11 +346,11 @@ a16613114273c54b6d2a16a94fa8748550e91468585469642622bd2c86087baa src/logging/fo
|
||||
17425ebbca6bbbb0dcaeb65ebc44b1e51488a4092b7b6add556e764c6d486d6a src/logging/tests.rs
|
||||
3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs
|
||||
c66a9803e43bdd87101825e8c71ab33f890ac4c3428467ba5d43c17fdfa1439e src/main/admin_runtime.rs
|
||||
0cc35b47d2264816009160e2416a4052d0118fee4c41c35d428dc088ee68a352 src/main/bootstrap.rs
|
||||
04084e87167a8c47a24d5a4e89e0bde0f30398ea95c38fe34c057a1149ac33e8 src/main/bootstrap.rs
|
||||
5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs
|
||||
4dd7c1084a6214c0f2513ebf86fe8ef144470695557772bfe25979edd64491ab src/main/shutdown.rs
|
||||
0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs
|
||||
a72eb4ae7ffecd5e1e566fbece270a7956bb3393d3fc18be108de959e65a99c0 src/main/tasks.rs
|
||||
7e97938fd9209f2335af5d6304abcb4193e80bb33e4ccf480938e8c3ab4644d6 src/main/tasks.rs
|
||||
49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs
|
||||
201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs
|
||||
49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs
|
||||
@@ -456,7 +457,7 @@ ff4980f0a091da9ff1722d6b9f6662529cbd7c5e2ac68dcd22a507ce6aaf3011 src/vhost/vali
|
||||
c1fef6dfb79275479c15097b211cd5f063ad7e0852a0767b0145cf4f32f751da src/web_server/config/model.rs
|
||||
f1d3e427c53f8b5be5768d85e69ead746d83647fcd3b355acc98e3f9d5e217e0 src/web_server/config/validation.rs
|
||||
86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs
|
||||
fbc035f68621ac6f3c31e363712c4e06f9bc4382d94511bf93f0fdba39b627b2 src/web_server/fastcgi/protocol.rs
|
||||
be75d0bf057a9b17d8c4a1cab67a1cbf349f542c8e57e4a822ebb9192b1c9582 src/web_server/fastcgi/protocol.rs
|
||||
134c4998f6a0aa27e121af1ae3355b7e335488b2ae867ac0a934c58b4eb77191 src/web_server/fastcgi/response.rs
|
||||
8186363315bd998919c6c783e6f7501528f257a5c0da77c5d60f423e8670db5e src/web_server/filesystem.rs
|
||||
0aafd7f37c4fe784b047646e4ce5ddcb5fe821231a41ed0a9f519529385288a8 src/web_server/htaccess.rs
|
||||
@@ -466,14 +467,14 @@ fbc035f68621ac6f3c31e363712c4e06f9bc4382d94511bf93f0fdba39b627b2 src/web_server
|
||||
80f946570c14c8915fd21bfdb1a84dfb6a14c633ab6060acb828fab4c7c21daa src/web_server/mod.rs
|
||||
67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs
|
||||
c5cb561b0f276e8082f904b9446fa5885f6b3c0608f25ea2ef425061e9f7f6b4 src/web_server/response.rs
|
||||
bbd66ca7e3cab7b5a8b42402567b99fe060f19d513bb2de9f4423aaa14513d18 src/web_server/response/file.rs
|
||||
51b0878fcf6e8ef2458f1b8ded65f843951c122f0ff0afe2854f467c5e192273 src/web_server/response/file.rs
|
||||
9aa68251a5f549f4ce3b1bda88d4abb9efc629caf444989381b4117c9488e37b src/web_server/response/headers.rs
|
||||
2268a6aeed2f565f9791af33e1cd21c56c228c8873b031725b39a6c57184f2d1 src/web_server/routing.rs
|
||||
400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs
|
||||
3e0b4e92600a7d5abcec92efed532b3a01e0781cb4f2681daac6d6ae13b0a6e9 src/web_server/serve.rs
|
||||
cf86c4692080723bbdf8f4105e1abfae33d7fcf020d2ad9e13ebae3943bd0cbe src/web_server/tests.rs
|
||||
c62752fe2fa6b74ddc9d94d36f8d191376b1575b15d21fc434c5a5da4c932692 src/web_server/tests/part_01.rs
|
||||
bb09d550a0dacb6169ffabe2877f510e3a1b7ebd5a6bf527c0f19395c77b753e src/web_server/tests/part_02.rs
|
||||
ef49a4230a1cb46c51866c4c0a49eae8c711377245df50c4f36a86693c040c1e src/web_server/tests/part_02.rs
|
||||
e54f44f6ca1ed2c41e620de9195d32c4f8bb6936c3881745316a07160f87b4fa src/web_server/tests/part_03.rs
|
||||
f00743af2cf4a5952caef7a1dcf68e7817b5599a252a9973e1c22045517c0b0e tests/fixtures/argon2id.json
|
||||
1725c10331745dc04a07675784d385260da7b14567b8dba3cbae5e891eb5dadf tests/http2.rs
|
||||
|
||||
@@ -18,7 +18,7 @@ if [[ $# -gt 0 ]]; then shift; fi
|
||||
case "$mode" in
|
||||
help|-h|--help)
|
||||
cat <<'HELP'
|
||||
RustProxy 0.27.1
|
||||
RustProxy 0.27.2
|
||||
./dev.sh Build and start proxy + local panel
|
||||
./dev.sh run [serve flags] Same, with extra server options
|
||||
./dev.sh admin setup-token Generate/print a one-time setup capability before first login
|
||||
@@ -139,7 +139,7 @@ if [[ "$mode" == "test" ]]; then
|
||||
printf 'Checking all Rust targets before tests...\n' >&2
|
||||
cargo check --locked --all-targets
|
||||
fi
|
||||
printf 'Building RustProxy 0.27.1...\n' >&2
|
||||
printf 'Building RustProxy 0.27.2...\n' >&2
|
||||
cargo build --locked
|
||||
BIN="$CARGO_TARGET_DIR/debug/rust-proxy"
|
||||
case "$mode" in
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package main
|
||||
|
||||
const version = "0.27.1"
|
||||
const version = "0.27.2"
|
||||
|
||||
type config struct {
|
||||
Listen string
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Administration API access - 0.27.1
|
||||
# Administration API access - 0.27.2
|
||||
|
||||
## Sign-in boundary
|
||||
|
||||
|
||||
+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.1 .
|
||||
docker build -t rustproxy:0.27.2 .
|
||||
```
|
||||
|
||||
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.1
|
||||
rustproxy:0.27.2
|
||||
|
||||
docker exec rustproxy rust-proxy admin setup-token
|
||||
```
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Stored log explorer
|
||||
|
||||
RustProxy 0.27.1 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.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.
|
||||
|
||||
## Separation from Live Logs
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Installing and updating RustProxy 0.27.1
|
||||
# Installing and updating RustProxy 0.27.2
|
||||
|
||||
The scripts prepare a Linux/systemd installation. This source archive is **not a
|
||||
verified production build**: Rust/Cargo, real CA operations, live systemd startup
|
||||
|
||||
+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.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.
|
||||
- [0.26.7 implementation note](V0.26.7_IMPLEMENTATION.md) - HOT/COLD occupancy meters, backend rotation continuity and container Certbot packaging.
|
||||
@@ -69,7 +70,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.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md); [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.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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
+8
-7
@@ -1,18 +1,18 @@
|
||||
# Verification report - RustProxy 0.27.1
|
||||
# Verification report - RustProxy 0.27.2
|
||||
|
||||
## Scope
|
||||
|
||||
RustProxy 0.27.1 changes first-administrator onboarding, ACME/Certbot runtime preparation and account-scoped sorting for vhosts, Docker vhosts, redirects, 404 hosts and streams while keeping SQLite schema 8.
|
||||
RustProxy 0.27.2 is a focused repair for managed ACME/Certbot execution while keeping SQLite schema 8 and the saved configuration format unchanged.
|
||||
|
||||
The first-run administrator screen now presents a complete command using the default `./data` directory and a second standard-service example using `/var/lib/rustproxy`.
|
||||
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.
|
||||
|
||||
Certificate automation now prefers a RustProxy-owned Python environment at `<data-dir>/acme-python`. Missing environments are prepared with `venv` and pip; when a distribution omits the stdlib `venv` module but provides pip, RustProxy can bootstrap `virtualenv` into its own data directory rather than changing distribution site-packages. Certbot 5.8.0 and the Cloudflare, OVH and RFC2136 plugins are installed into that managed environment. A runnable distribution Certbot remains the fallback. The Certificates panel reports managed/system/preparing/unavailable state and missing Python/pip diagnostics; manual PEM import and existing-file workflows do not depend on ACME runtime availability.
|
||||
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 route/list pages gain feature-specific sort-column and sort-direction controls. Their values are saved in the existing account-scoped administrator preferences and default safely when absent. Redirects and 404 hosts use the same search/sort/action toolbar structure as Vhosts.
|
||||
The 0.27.1 first-administrator, runtime-status and route/list sorting behavior remains unchanged.
|
||||
|
||||
## Regression coverage
|
||||
|
||||
Static/source contracts cover the new first-run commands, ACME runtime status UI/API, managed environment path and pinned package set, distro fallback markers, preference fields and list-specific sort controls. They also reject the development-only `./dev.sh tls deploy` UI hook and require the production binary/data-directory example, both official repository links and Python/pip/Certbot runtime metadata in the startup banner and authenticated application information. Existing release-smoke, language/OpenAPI, source-module, security, web-server, browser-service and Docker-agent gates remain part of the Rust-independent verification set.
|
||||
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.
|
||||
|
||||
## Verification status in this workspace
|
||||
|
||||
@@ -20,6 +20,7 @@ Rust/Cargo is not installed in this workspace. Rust-independent checks are run h
|
||||
|
||||
| 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 |
|
||||
@@ -41,4 +42,4 @@ Rust/Cargo is not installed in this workspace. Rust-independent checks are run h
|
||||
| `cargo test --all-targets --all-features` | BLOCKED: Rust/Cargo toolchain unavailable |
|
||||
| complete release build | BLOCKED at Rust compilation: Rust/Cargo toolchain unavailable |
|
||||
|
||||
The 0.27.1 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.
|
||||
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.
|
||||
@@ -0,0 +1,27 @@
|
||||
# RustProxy 0.27.2 implementation note
|
||||
|
||||
## Scope
|
||||
|
||||
0.27.2 is a focused ACME runtime repair. It keeps SQLite schema 8 and the saved configuration format unchanged.
|
||||
|
||||
## Managed Certbot relocation bug
|
||||
|
||||
0.27.1 creates the private environment under `<data-dir>/acme-python.installing`, installs Certbot and its DNS plugins there, validates it, and then atomically renames the directory to `<data-dir>/acme-python`.
|
||||
|
||||
Python virtual-environment console scripts created by pip contain an absolute interpreter path in their shebang. After the directory rename, `bin/certbot` can still point at the removed `acme-python.installing/bin/python`. Executing that console script can therefore fail with a local `OSError`; the private worker intentionally reduced such errors to `acme.local_io_or_json_error`, which hid the relocation detail from the UI.
|
||||
|
||||
## Repair
|
||||
|
||||
Managed-environment validation now runs Certbot as:
|
||||
|
||||
```text
|
||||
<data-dir>/acme-python/bin/python -I -m certbot --version
|
||||
```
|
||||
|
||||
ACME issuance and renewal use the same final interpreter with `-m certbot`. The provider worker receives the managed interpreter path from RustProxy and no longer depends on the relocated pip console-script shebang.
|
||||
|
||||
The existing system/distribution Certbot fallback continues to execute its discovered `certbot` program normally.
|
||||
|
||||
## 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.
|
||||
+1
-1
@@ -19,7 +19,7 @@ classes, cache outcomes, capture-state gauges and configured-route traffic. Raw
|
||||
are intentionally absent from Prometheus labels.
|
||||
|
||||
Import the JSON in Grafana and select a Prometheus datasource when prompted. The
|
||||
dashboard expects RustProxy 0.27.1 metric names and a scrape interval around 15s.
|
||||
dashboard expects RustProxy 0.27.2 metric names and a scrape interval around 15s.
|
||||
Collectors can be disabled in RustProxy settings; panels for disabled collectors
|
||||
will simply show no series.
|
||||
|
||||
|
||||
@@ -4529,9 +4529,9 @@
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "RustProxy 0.27.1 - Operations",
|
||||
"title": "RustProxy 0.27.2 - Operations",
|
||||
"uid": "rustproxy-0170",
|
||||
"version": 5,
|
||||
"weekStart": "",
|
||||
"description": "RustProxy 0.27.1 operations dashboard including backend client lifecycle/retry diagnostics, bounded Traffic analytics, country and User-Agent-family visibility, and built-in Web Server traffic."
|
||||
"description": "RustProxy 0.27.2 operations dashboard including backend client lifecycle/retry diagnostics, bounded Traffic analytics, country and User-Agent-family visibility, and built-in Web Server traffic."
|
||||
}
|
||||
+1
-1
@@ -183,7 +183,7 @@
|
||||
"saveCertificate": "Apply certificate",
|
||||
"reloadCertificates": "Reload certificate files",
|
||||
"certificateHelp": "Upload a PEM pair, reference files already in data/certs, or deploy an externally issued certificate with the installed RustProxy binary. Reload re-reads configured files without changing the configuration revision.",
|
||||
"certificateHint": "External Certbot hook (standard service install): rust-proxyopt/rustproxy/current/ --data-dir /var/lib/rustproxy tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem",
|
||||
"certificateHint": "External Certbot hook (standard service install): /opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem",
|
||||
"emptyCertificates": "No explicit SNI bindings. The generated default certificate is used while the TLS listener is enabled.",
|
||||
"certificateSafety": "Certificates secure TLS connections, not routing. Assign a certificate to a vhost. Changes affect new handshakes.",
|
||||
"wsActive": "WebSocket tunnels",
|
||||
|
||||
+1
-1
@@ -183,7 +183,7 @@
|
||||
"saveCertificate": "Zastosuj certyfikat",
|
||||
"reloadCertificates": "Wczytaj pliki certyfikatów",
|
||||
"certificateHelp": "Wgraj parę PEM, wskaż pliki w data/certs albo wdrażaj certyfikat z zewnętrznego wystawcy zainstalowaną binarką RustProxy. Ponowne wczytanie odczytuje skonfigurowane pliki bez zmiany rewizji.",
|
||||
"certificateHint": "Hook Certbota (standardowa instalacja usługi): rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem",
|
||||
"certificateHint": "Hook Certbota (standardowa instalacja usługi): /opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem",
|
||||
"emptyCertificates": "Brak jawnych powiązań SNI. Aktywny listener TLS używa wygenerowanego certyfikatu domyślnego.",
|
||||
"certificateSafety": "Certyfikaty samopodpisane służą do testów. Certyfikat nie tworzy trasy. Zmiana dotyczy nowych połączeń TLS.",
|
||||
"wsActive": "Tunele WebSocket",
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ def add_file(archive: zipfile.ZipFile, rel: Path, data: bytes, timestamp: tuple[
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('output', nargs='?', type=Path, default=ROOT.parent / 'RustProxy-0.27.1.zip')
|
||||
parser.add_argument('output', nargs='?', type=Path, default=ROOT.parent / 'RustProxy-0.27.2.zip')
|
||||
output = parser.parse_args().output.resolve()
|
||||
paths = files()
|
||||
checksum = ROOT / 'SHA256SUMS'
|
||||
|
||||
+18
-10
@@ -165,8 +165,20 @@ def credentials(value: dict) -> bytes:
|
||||
return "".join(f"dns_rfc2136_{k} = {v}\n" for k, v in lines.items()).encode("ascii")
|
||||
|
||||
|
||||
def certbot_command(value: dict, work: Path, credential_file: Path, executable: str) -> list[str]:
|
||||
args = [executable, "certonly", "--non-interactive", "--agree-tos", "--no-eff-email",
|
||||
def certbot_prefix(executable: str | None = None) -> list[str]:
|
||||
if executable:
|
||||
return [executable]
|
||||
managed_python = os.environ.get("RUSTPROXY_CERTBOT_PYTHON")
|
||||
if managed_python:
|
||||
return [managed_python, "-I", "-m", "certbot"]
|
||||
discovered = shutil.which("certbot")
|
||||
if discovered:
|
||||
return [discovered]
|
||||
raise AcmeError("acme.certbot_not_installed")
|
||||
|
||||
|
||||
def certbot_command(value: dict, work: Path, credential_file: Path, command_prefix: list[str]) -> list[str]:
|
||||
args = [*command_prefix, "certonly", "--non-interactive", "--agree-tos", "--no-eff-email",
|
||||
"--email", value["email"], "--server", DIRECTORIES[value["environment"]],
|
||||
"--cert-name", "rustproxy", "--keep-until-expiring", "--key-type", "ecdsa",
|
||||
"--config-dir", str(work / "config"), "--work-dir", str(work / "work"),
|
||||
@@ -203,9 +215,7 @@ def read_generated(work: Path, name: str) -> bytes:
|
||||
|
||||
def issue(raw: dict, certificate_directory: Path, executable: str | None = None) -> dict:
|
||||
value = validate(raw)
|
||||
executable = executable or shutil.which("certbot")
|
||||
if not executable:
|
||||
raise AcmeError("acme.certbot_not_installed")
|
||||
command_prefix = certbot_prefix(executable)
|
||||
certificate_directory = certificate_directory.absolute()
|
||||
private_directory(certificate_directory)
|
||||
root = certificate_directory / "acme"
|
||||
@@ -242,7 +252,7 @@ def issue(raw: dict, certificate_directory: Path, executable: str | None = None)
|
||||
temporary = work / ("profile-" + uuid.uuid4().hex)
|
||||
write_new(temporary, json.dumps(profile).encode())
|
||||
os.replace(temporary, work / "profile.json")
|
||||
args = certbot_command(value, work, credential_file, executable)
|
||||
args = certbot_command(value, work, credential_file, command_prefix)
|
||||
try:
|
||||
result = subprocess.run(args, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL, timeout=1200 + value["propagation_seconds"], check=False)
|
||||
@@ -354,9 +364,7 @@ def renew(raw: dict, certificate_directory: Path, executable: str | None = None)
|
||||
Dry-run validates challenge access but never stages/deploys its test output.
|
||||
"""
|
||||
value = renewal_request(raw)
|
||||
executable = executable or shutil.which("certbot")
|
||||
if not executable:
|
||||
raise AcmeError("acme.certbot_not_installed")
|
||||
command_prefix = certbot_prefix(executable)
|
||||
certificate_directory = certificate_directory.absolute()
|
||||
private_directory(certificate_directory)
|
||||
work = profile_directory(certificate_directory, value["provider"], value["environment"], value["certificate_id"])
|
||||
@@ -400,7 +408,7 @@ def renew(raw: dict, certificate_directory: Path, executable: str | None = None)
|
||||
installed_key = read_private(certificate_directory / value["key_file"], MAX_PEM)
|
||||
# Check dependencies/installed PEM before invoking a CA operation.
|
||||
old_dates = certificate_dates(installed_cert)
|
||||
args = [executable, "renew", "--cert-name", "rustproxy", "--non-interactive",
|
||||
args = [*command_prefix, "renew", "--cert-name", "rustproxy", "--non-interactive",
|
||||
"--no-random-sleep-on-renew", "--no-directory-hooks",
|
||||
"--config-dir", str(work / "config"), "--work-dir", str(work / "work"), "--logs-dir", str(work / "logs")]
|
||||
if value["dry_run"]:
|
||||
|
||||
+15
-11
@@ -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.27.1"
|
||||
assert manifest["package"]["version"] == "0.27.2"
|
||||
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.27.1"' in lock
|
||||
assert 'name = "rust-proxy"\nversion = "0.27.2"' 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.27.1",
|
||||
"CHANGELOG.md": "## 0.27.1",
|
||||
"ROADMAP.md": "## 0.27.1",
|
||||
"AGENTS.md": "Current source version: 0.27.1.",
|
||||
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.27.1",
|
||||
"README.md": "# RustProxy 0.27.2",
|
||||
"CHANGELOG.md": "## 0.27.2",
|
||||
"ROADMAP.md": "## 0.27.2",
|
||||
"AGENTS.md": "Current source version: 0.27.2.",
|
||||
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.27.2",
|
||||
}.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"
|
||||
@@ -287,7 +287,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.27.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']:
|
||||
for marker in ['"version": "0.27.2"', '"/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
|
||||
@@ -613,12 +613,16 @@ assert 'runtime_setup_once' in acme_source
|
||||
assert 'include!("acme/runtime_env.rs")' in (root / "src/acme.rs").read_text(encoding="utf-8")
|
||||
for marker in ['CERTBOT_PACKAGES', 'certbot==5.8.0', 'certbot-dns-cloudflare==5.8.0', 'certbot-dns-ovh==5.8.0', 'certbot-dns-rfc2136==5.8.0', 'join("acme-python")', 'virtualenv>=20,<21', 'system_has_pip', 'distro_certbot_available', 'acme.runtime_python_missing', 'acme.runtime_pip_missing']:
|
||||
assert marker in acme_runtime_source, marker
|
||||
for marker in ['"-I", "-m", "certbot", "--version"', 'RUSTPROXY_CERTBOT_PYTHON', 'managed_certbot_python']:
|
||||
assert marker in acme_runtime_source, marker
|
||||
main_source = rust_source(root, "src/main.rs")
|
||||
logging_source = rust_source(root, "src/logging.rs")
|
||||
secret_store_source = rust_source(root, "src/secret_store.rs")
|
||||
backup_source = rust_source(root, "src/backup.rs")
|
||||
config_source = rust_source(root, "src/config.rs")
|
||||
acme_worker_source = (root / "scripts/acme_provider.py").read_text()
|
||||
for marker in ['def certbot_prefix', 'RUSTPROXY_CERTBOT_PYTHON', '"-I", "-m", "certbot"', '[*command_prefix, "renew"', 'certbot_command(value, work, credential_file, command_prefix)']:
|
||||
assert marker in acme_worker_source, marker
|
||||
for feature_marker in [
|
||||
"AES_256_GCM", "master.key", "O_NOFOLLOW", "migrate_acme_credentials",
|
||||
"secret_store", "SecretMetadata",
|
||||
@@ -816,7 +820,7 @@ assert any(variable.get('name') == 'traffic_vhost' for variable in grafana['temp
|
||||
assert any(panel.get('title') == 'Traffic analytics and Web Server' for panel in grafana['panels'])
|
||||
assert any(panel.get('title') == 'Traffic capture state' for panel in grafana['panels'])
|
||||
assert any(panel.get('title') == 'Top configured routes' for panel in grafana['panels'])
|
||||
# 0.27.1 compression/protocol/dashboard UX regressions.
|
||||
# 0.27.2 compression/protocol/dashboard UX regressions.
|
||||
compression_source = rust_source(root, "src/compression.rs")
|
||||
metrics_source = rust_source(root, "src/metrics.rs")
|
||||
admin_source = rust_source(root, "src/admin/mod.rs")
|
||||
@@ -1373,7 +1377,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.27.1"' in openapi
|
||||
assert '"RuntimeInformation"' in openapi and '"version": "0.27.2"' in openapi
|
||||
|
||||
# 0.24.1 compiler and hostname-cardinality regressions.
|
||||
tls_0241 = rust_source(root, "src/tls.rs")
|
||||
@@ -1418,5 +1422,5 @@ for schema_name in ["RedirectHost", "NotFoundHost"]:
|
||||
node = openapi_0241["components"]["schemas"][schema_name]["properties"]["frontend"]["properties"]["hosts"]
|
||||
assert "maxItems" not in node, schema_name
|
||||
|
||||
print("PASS: 0.27.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-v8 migrations.")
|
||||
print("PASS: 0.27.2 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-v8 migrations.")
|
||||
print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.")
|
||||
@@ -97,7 +97,7 @@ def digest(path: Path) -> str:
|
||||
def fetch_https(url: str, max_bytes: int) -> bytes:
|
||||
if urllib.parse.urlparse(url).scheme != 'https':
|
||||
raise ValueError('GeoIP downloads require HTTPS.')
|
||||
request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer/0.27.1'})
|
||||
request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer/0.27.2'})
|
||||
with urllib.request.urlopen(request, timeout=30) as response:
|
||||
if urllib.parse.urlparse(response.geturl()).scheme != 'https':
|
||||
raise ValueError('GeoIP download redirected away from HTTPS.')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Rust-independent documentation/Reader consistency checks for the 0.27.1 release."""
|
||||
"""Rust-independent documentation/Reader consistency checks for the 0.27.2 release."""
|
||||
from pathlib import Path
|
||||
import re
|
||||
from rust_source import rust_source
|
||||
@@ -14,6 +14,7 @@ required = [
|
||||
DOCS / "README.md",
|
||||
DOCS / "WEB_SERVER.md",
|
||||
DOCS / "TODO.md",
|
||||
DOCS / "V0.27.2_IMPLEMENTATION.md",
|
||||
DOCS / "V0.27.1_IMPLEMENTATION.md",
|
||||
DOCS / "V0.27.0_IMPLEMENTATION.md",
|
||||
DOCS / "V0.26.7_IMPLEMENTATION.md",
|
||||
@@ -58,16 +59,16 @@ 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.27.1")
|
||||
assert readme.startswith("# RustProxy 0.27.2")
|
||||
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
|
||||
assert roadmap.startswith("# RustProxy roadmap") and "## 0.27.1" in roadmap and "## 0.27.0" in roadmap and "## 0.26.7" in roadmap and "## 0.26.6" in roadmap and "## 0.26.5" in roadmap and "## 0.26.4" in roadmap and "## 0.26.0" in roadmap and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap
|
||||
assert roadmap.startswith("# RustProxy roadmap") and "## 0.27.2" in roadmap and "## 0.27.1" in roadmap and "## 0.27.0" in roadmap and "## 0.26.7" in roadmap and "## 0.26.6" in roadmap and "## 0.26.5" in roadmap and "## 0.26.4" in roadmap and "## 0.26.0" in roadmap and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap
|
||||
assert "## 0.24." not in roadmap and "## Web Server follow-up" in roadmap and "docs/ROADMAP_HISTORY.md" in roadmap
|
||||
assert changelog.startswith("# Changelog\n")
|
||||
for release in ["0.27.1", "0.27.0", "0.26.7", "0.26.6", "0.26.5", "0.26.4", "0.26.1", "0.26.0", "0.25.6", "0.25.5", "0.25.4", "0.25.3"]:
|
||||
for release in ["0.27.2", "0.27.1", "0.27.0", "0.26.7", "0.26.6", "0.26.5", "0.26.4", "0.26.1", "0.26.0", "0.25.6", "0.25.5", "0.25.4", "0.25.3"]:
|
||||
assert f"## {release}" in changelog, release
|
||||
assert changelog.index("## 0.27.1") < changelog.index("## 0.27.0") < changelog.index("## 0.26.7") < changelog.index("## 0.26.6") < changelog.index("## 0.26.5") < changelog.index("## 0.26.4") < changelog.index("## 0.26.1") < changelog.index("## 0.26.0") < changelog.index("## 0.25.6") < changelog.index("## 0.25.5")
|
||||
assert changelog.index("## 0.27.2") < changelog.index("## 0.27.1") < changelog.index("## 0.27.0") < changelog.index("## 0.26.7") < changelog.index("## 0.26.6") < changelog.index("## 0.26.5") < changelog.index("## 0.26.4") < changelog.index("## 0.26.1") < changelog.index("## 0.26.0") < changelog.index("## 0.25.6") < changelog.index("## 0.25.5")
|
||||
assert "CHANGELOG_TECHNICAL_ARCHIVE.md" in changelog
|
||||
for developer_only in ["Clean the remaining compiler warnings", "Update package/source/UI/OpenAPI/release identity", "source regressions and update release identity"]:
|
||||
assert developer_only not in changelog, f"developer-only CHANGELOG detail: {developer_only}"
|
||||
|
||||
@@ -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/proxy/websocket.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/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/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", "scripts/mock_server.py", "scripts/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", "scripts/docs_check.py", "scripts/web_server_contracts.py", "scripts/rust_source.py", "scripts/rust_module_contracts.py", "scripts/source_module_contracts.py", "scripts/acme_provider.py", "src/basic_auth.rs", "scripts/deploy.py", "scripts/deploy_core.py", "scripts/deploy_runtime.py", "scripts/migrate_npm.py", "scripts/migrate_npm_core.py", "scripts/migrate_npm_api.py", "docs/NPM_MIGRATION.md", "docs/STREAMS.md", "install.sh", "install-debian13.sh", "update.sh", "build.rs", "scripts/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.27.1 source tree: missing {path}")
|
||||
raise ValueError(f"Incomplete RustProxy 0.27.2 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.27.1 entry point; extract the complete package, not individual files.")
|
||||
raise ValueError("src/lib.rs is not the 0.27.2 entry point; extract the complete package, not individual files.")
|
||||
return messages
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ then checks the 0.24.1 shared-statistics/runtime/settings contracts and retained
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
@@ -123,7 +124,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.27.1"' in (target / "Cargo.toml").read_text(encoding="utf-8")
|
||||
assert 'version = "0.27.2"' 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()
|
||||
@@ -134,7 +135,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.27.1"
|
||||
assert manifest["to_version"] == "0.27.2"
|
||||
assert manifest["removed_obsolete_runtime_state"] is True
|
||||
assert not legacy.exists()
|
||||
assert not (backup / "legacy-data").exists()
|
||||
@@ -604,7 +605,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.27.1"' in openapi_0241
|
||||
assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.27.2"' 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
|
||||
@@ -1087,7 +1088,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.27.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"']:
|
||||
for marker in ['"version": "0.27.2"', '"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"']:
|
||||
@@ -1238,6 +1239,52 @@ def reproducible_archive_smoke(tmp: Path) -> None:
|
||||
assert len(timestamps) == 1
|
||||
|
||||
|
||||
def managed_acme_relocation_smoke(tmp: Path) -> None:
|
||||
"""Reproduce the 0.27.1 relocated console-script shebang failure."""
|
||||
stage = tmp / "acme-python.installing"
|
||||
final = tmp / "acme-python"
|
||||
bindir = stage / "bin"
|
||||
bindir.mkdir(parents=True)
|
||||
python = bindir / "python"
|
||||
python.write_text(
|
||||
"#!/bin/sh\n"
|
||||
"test \"$1\" = -I && test \"$2\" = -m && test \"$3\" = certbot && test \"$4\" = --version || exit 2\n"
|
||||
"echo 'certbot 5.8.0'\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
python.chmod(0o755)
|
||||
console = bindir / "certbot"
|
||||
console.write_text(f"#!{python}\necho 'certbot 5.8.0'\n", encoding="utf-8")
|
||||
console.chmod(0o755)
|
||||
stage.rename(final)
|
||||
|
||||
relocated_console = final / "bin/certbot"
|
||||
try:
|
||||
subprocess.run([str(relocated_console), "--version"], check=True, capture_output=True, text=True)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("relocated pip console script unexpectedly kept a valid staging shebang")
|
||||
|
||||
worker_path = ROOT / "scripts/acme_provider.py"
|
||||
spec = importlib.util.spec_from_file_location("rustproxy_acme_provider", worker_path)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
old = os.environ.get("RUSTPROXY_CERTBOT_PYTHON")
|
||||
os.environ["RUSTPROXY_CERTBOT_PYTHON"] = str(final / "bin/python")
|
||||
try:
|
||||
spec.loader.exec_module(module)
|
||||
prefix = module.certbot_prefix()
|
||||
assert prefix == [str(final / "bin/python"), "-I", "-m", "certbot"]
|
||||
result = subprocess.run(prefix + ["--version"], check=True, capture_output=True, text=True)
|
||||
assert result.stdout.strip() == "certbot 5.8.0"
|
||||
finally:
|
||||
if old is None:
|
||||
os.environ.pop("RUSTPROXY_CERTBOT_PYTHON", None)
|
||||
else:
|
||||
os.environ["RUSTPROXY_CERTBOT_PYTHON"] = old
|
||||
|
||||
|
||||
def main() -> None:
|
||||
subprocess.run(["python3", str(ROOT / "scripts/rust_module_contracts.py")], check=True)
|
||||
subprocess.run(["python3", str(ROOT / "scripts/source_module_contracts.py")], check=True)
|
||||
@@ -1245,6 +1292,7 @@ def main() -> None:
|
||||
tmp = Path(directory)
|
||||
sql_and_backup_smoke(tmp / "sql")
|
||||
upgrade_smoke(tmp / "upgrade")
|
||||
managed_acme_relocation_smoke(tmp / "acme-relocation")
|
||||
reproducible_archive_smoke(tmp / "archives")
|
||||
deployment_gate_smoke(tmp)
|
||||
npm_migration_smoke(tmp)
|
||||
@@ -1252,7 +1300,7 @@ def main() -> None:
|
||||
source_contract_smoke()
|
||||
container_contract_smoke()
|
||||
grafana_contract_smoke()
|
||||
print("PASS: 0.27.1 SQLite/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.27.2 SQLite/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__":
|
||||
|
||||
@@ -85,7 +85,7 @@ def download(destination: Path) -> None:
|
||||
"""TLS verification uses Python's default trust store; never executes a shell."""
|
||||
started = time.monotonic()
|
||||
opener = build_opener(HttpsRedirects())
|
||||
request = Request(DOWNLOAD_URL, headers={"User-Agent": "RustProxy-build/0.27.1"})
|
||||
request = Request(DOWNLOAD_URL, headers={"User-Agent": "RustProxy-build/0.27.2"})
|
||||
with opener.open(request, timeout=30) as response, destination.open("wb") as output:
|
||||
length = response.headers.get("Content-Length")
|
||||
if length and int(length) > MAX_ARCHIVE:
|
||||
|
||||
+3
-3
@@ -46,7 +46,7 @@ def upgrade(source: Path, target: Path, *, stopped: bool, data_dir: Path | None
|
||||
for name in MANAGED:
|
||||
if (target / name).is_symlink():
|
||||
raise ValueError(f"Managed target {name} is a symlink; refusing to replace it.")
|
||||
backup = target / ".upgrade-backup" / ("before-0.27.1-" + uuid.uuid4().hex[:12])
|
||||
backup = target / ".upgrade-backup" / ("before-0.27.2-" + uuid.uuid4().hex[:12])
|
||||
backup.mkdir(parents=True, mode=0o700)
|
||||
installed: list[str] = []
|
||||
moved: list[str] = []
|
||||
@@ -84,7 +84,7 @@ def upgrade(source: Path, target: Path, *, stopped: bool, data_dir: Path | None
|
||||
remove_legacy = legacy.exists()
|
||||
if remove_legacy and (legacy.is_symlink() or not legacy.is_file()):
|
||||
raise ValueError("Obsolete renewal observation sidecar must be a regular file.")
|
||||
(backup / "upgrade.json").write_text(json.dumps({"from_directory":str(target), "to_version":"0.27.1", "managed_paths":MANAGED, "removed_obsolete_runtime_state": remove_legacy}, indent=2)+"\n", encoding="utf-8")
|
||||
(backup / "upgrade.json").write_text(json.dumps({"from_directory":str(target), "to_version":"0.27.2", "managed_paths":MANAGED, "removed_obsolete_runtime_state": remove_legacy}, indent=2)+"\n", encoding="utf-8")
|
||||
if remove_legacy:
|
||||
legacy.unlink()
|
||||
except BaseException:
|
||||
@@ -115,7 +115,7 @@ def main() -> None:
|
||||
backup = upgrade(Path(__file__).resolve().parents[1], args.target, stopped=args.stopped, data_dir=data_dir)
|
||||
except (OSError, ValueError) as error:
|
||||
parser.exit(2, f"Upgrade refused or rolled back: {error}\n")
|
||||
print(f"Installed RustProxy 0.27.1. Previous managed source files: {backup}")
|
||||
print(f"Installed RustProxy 0.27.2. Previous managed source files: {backup}")
|
||||
print("Preserved data, .env, .git, target and other unmanaged files. No database migration was run.")
|
||||
print(f"Next: cd {args.target}; ./dev.sh test; ./dev.sh")
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ need(web,
|
||||
'HeaderValue::from_static("no-store")',
|
||||
"builtin_error_response(StatusCode::FORBIDDEN, &method)",
|
||||
"empty_index_can_go_directly_to_directory_listing",
|
||||
"RustProxy <b>0.27.1</b>",
|
||||
"RustProxy <b>0.27.2</b>",
|
||||
"traversal_and_symlink_escape_are_not_served",
|
||||
"try_files_rewrites_cache_rules_headers_and_downloads_work",
|
||||
"precompressed_sidecars_keep_mime_validators_and_range_semantics",
|
||||
|
||||
+16
-13
@@ -60,6 +60,7 @@ impl Manager {
|
||||
struct RuntimeLaunch {
|
||||
python: PathBuf,
|
||||
prepend_path: Option<PathBuf>,
|
||||
managed_certbot_python: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn find_on_path(name: &str) -> Option<PathBuf> {
|
||||
@@ -96,15 +97,6 @@ fn venv_python(directory: &Path) -> PathBuf {
|
||||
venv_bin(directory).join("python")
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn venv_certbot(directory: &Path) -> PathBuf {
|
||||
venv_bin(directory).join("certbot.exe")
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
fn venv_certbot(directory: &Path) -> PathBuf {
|
||||
venv_bin(directory).join("certbot")
|
||||
}
|
||||
|
||||
async fn command_success(
|
||||
mut command: Command,
|
||||
timeout: Duration,
|
||||
@@ -131,8 +123,7 @@ async fn managed_environment_valid(
|
||||
shutdown: &tokio_util::sync::CancellationToken,
|
||||
) -> bool {
|
||||
let python = venv_python(directory);
|
||||
let certbot = venv_certbot(directory);
|
||||
if !python.is_file() || !certbot.is_file() {
|
||||
if !python.is_file() {
|
||||
return false;
|
||||
}
|
||||
let mut imports = Command::new(&python);
|
||||
@@ -144,8 +135,13 @@ async fn managed_environment_valid(
|
||||
if !command_success(imports, Duration::from_secs(20), shutdown).await {
|
||||
return false;
|
||||
}
|
||||
let mut version = Command::new(&certbot);
|
||||
version.arg("--version");
|
||||
// A venv is created under an atomic staging directory and then renamed
|
||||
// into place. pip-generated console scripts contain an absolute shebang,
|
||||
// so the staged `bin/certbot` is not relocatable after that rename. Invoke
|
||||
// Certbot as a module through the final venv interpreter instead. This also
|
||||
// makes existing 0.27.1 environments immediately usable after upgrade.
|
||||
let mut version = Command::new(&python);
|
||||
version.args(["-I", "-m", "certbot", "--version"]);
|
||||
command_success(version, Duration::from_secs(20), shutdown).await
|
||||
}
|
||||
|
||||
@@ -307,6 +303,7 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
|
||||
return Ok(RuntimeLaunch {
|
||||
python: venv_python(&managed),
|
||||
prepend_path: Some(venv_bin(&managed)),
|
||||
managed_certbot_python: Some(venv_python(&managed)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -355,6 +352,7 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
|
||||
return Ok(RuntimeLaunch {
|
||||
python: venv_python(&managed),
|
||||
prepend_path: Some(venv_bin(&managed)),
|
||||
managed_certbot_python: Some(venv_python(&managed)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -371,6 +369,7 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
|
||||
return Ok(RuntimeLaunch {
|
||||
python,
|
||||
prepend_path: None,
|
||||
managed_certbot_python: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -434,9 +433,13 @@ async fn worker(state: &App, directory: PathBuf, raw: Zeroizing<String>) -> Resu
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
.kill_on_drop(true);
|
||||
command.env_remove("RUSTPROXY_CERTBOT_PYTHON");
|
||||
if let Some(prepend) = launch.prepend_path.as_deref() {
|
||||
command.env("PATH", merged_path(prepend)?);
|
||||
}
|
||||
if let Some(python) = launch.managed_certbot_python.as_deref() {
|
||||
command.env("RUSTPROXY_CERTBOT_PYTHON", python);
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
||||
@@ -409,7 +409,8 @@ pub(super) static READER_DOCUMENTS: &[(&str, &str, &str)] = &[
|
||||
"/docs/V0.25.1_AUDIT.md"
|
||||
)),
|
||||
),
|
||||
reader_doc!("docs/V0.27.1_IMPLEMENTATION.md", "technical"),
|
||||
reader_doc!("docs/V0.27.2_IMPLEMENTATION.md", "technical"),
|
||||
reader_doc!("docs/V0.27.1_IMPLEMENTATION.md", "historical"),
|
||||
reader_doc!("docs/V0.27.0_IMPLEMENTATION.md", "technical"),
|
||||
reader_doc!("docs/V0.26.7_IMPLEMENTATION.md", "technical"),
|
||||
reader_doc!("docs/V0.26.6_IMPLEMENTATION.md", "technical"),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "RustProxy Administration API",
|
||||
"version": "0.27.1",
|
||||
"version": "0.27.2",
|
||||
"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": [
|
||||
|
||||
@@ -2823,7 +2823,7 @@
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<footer class="page-footer"><span>RustProxy <b>0.27.1</b></span><span id="footer-status">API - /
|
||||
<footer class="page-footer"><span>RustProxy <b>0.27.2</b></span><span id="footer-status">API - /
|
||||
dropped: 0</span></footer>
|
||||
</div>
|
||||
</main>
|
||||
@@ -3567,7 +3567,7 @@ max_execution_time = 30</code></pre>
|
||||
<article class="card about-card">
|
||||
<div class="about-product">
|
||||
<span aria-hidden="true" class="brand-mark">r<span>/</span>p</span>
|
||||
<div><span class="small-label">RustProxy</span><strong>0.27.1</strong></div>
|
||||
<div><span class="small-label">RustProxy</span><strong>0.27.2</strong></div>
|
||||
</div>
|
||||
<dl class="about-meta">
|
||||
<div>
|
||||
|
||||
@@ -41,7 +41,7 @@ use zeroize::Zeroizing;
|
||||
#[command(
|
||||
name = "rust-proxy",
|
||||
version,
|
||||
about = "RustProxy - independent Rust reverse proxy and static Web Server 0.27.1"
|
||||
about = "RustProxy - independent Rust reverse proxy and static Web Server 0.27.2"
|
||||
)]
|
||||
struct Cli {
|
||||
#[arg(
|
||||
|
||||
+1
-1
@@ -239,7 +239,7 @@ async fn live_logs_command(dir: PathBuf, addr: SocketAddr) -> Result<()> {
|
||||
}
|
||||
});
|
||||
let interactive = io::stdin().is_terminal() && io::stdout().is_terminal();
|
||||
println!("RustProxy live logs 0.27.1 - all vhosts. Type 'help' for interactive filters; Ctrl-C or 'quit' exits.");
|
||||
println!("RustProxy live logs 0.27.2 - all vhosts. Type 'help' for interactive filters; Ctrl-C or 'quit' exits.");
|
||||
if interactive { print!("> "); io::stdout().flush()?; }
|
||||
let mut filters = LiveLogFilters::default();
|
||||
let mut history = std::collections::BTreeMap::<u64, serde_json::Value>::new();
|
||||
|
||||
@@ -159,7 +159,7 @@ pub(super) fn fastcgi_params(
|
||||
if context.tls { "on" } else { "off" }.into(),
|
||||
);
|
||||
params.insert("GATEWAY_INTERFACE".into(), "CGI/1.1".into());
|
||||
params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.27.1".into());
|
||||
params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.27.2".into());
|
||||
params.insert("REDIRECT_STATUS".into(), "200".into());
|
||||
if let Some(value) = headers
|
||||
.get(CONTENT_TYPE)
|
||||
|
||||
@@ -185,7 +185,7 @@ pub(super) fn directory_listing(path: &str, entries: &[DirectoryEntry]) -> Vec<u
|
||||
"<a class=\"{class}\" href=\"{href}\"><span class=\"type\">{type_label}</span><span class=\"name\">{label}{slash}</span><span class=\"kind\">{kind}</span></a>"
|
||||
));
|
||||
}
|
||||
html.push_str(r#"</div></section><footer class="page-footer"><span>RustProxy <b>0.27.1</b></span><span>Web Server · Directory listing</span></footer></main></body></html>"#);
|
||||
html.push_str(r#"</div></section><footer class="page-footer"><span>RustProxy <b>0.27.2</b></span><span>Web Server · Directory listing</span></footer></main></body></html>"#);
|
||||
html.into_bytes()
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ async fn empty_index_can_go_directly_to_directory_listing() {
|
||||
let body = std::str::from_utf8(&body).unwrap();
|
||||
assert!(body.contains("file.txt"));
|
||||
assert!(body.contains("DIRECTORY LISTING"));
|
||||
assert!(body.contains("RustProxy <b>0.27.1</b>"));
|
||||
assert!(body.contains("RustProxy <b>0.27.2</b>"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in new issue
Block a user