cleanup
This commit is contained in:
1 parent
feb9d91a3d
commit
1f0daa0679
25 files changed
+174
-1035
No files matched your search
@@ -1,17 +1,21 @@
|
||||
# RustProxy unified package builder
|
||||
|
||||
Wydanie wdrożeniowe (odchudzone): zawiera panel, konfigurację Nginx oraz wszystkie skrypty budowania Linux, OPNsense i FreeBSD. Nie zawiera pustych szkieletów projektów ani testów developerskich. Istniejące katalogi `data/`, `gpg/` i plik `.env` pozostają nienaruszone podczas rozpakowywania.
|
||||
|
||||
Jeden kontener buildera buduje z jednego commita RustProxy:
|
||||
|
||||
- Linux x86_64: DEB + podpisane repo APT (`rustproxy` **oraz osobny** `rustproxy-docker-agent`),
|
||||
- Linux x86_64: RPM + podpisane repo DNF/YUM (`rustproxy` **oraz osobny** `rustproxy-docker-agent`),
|
||||
- FreeBSD x86_64: cross-build bez VM FreeBSD,
|
||||
- OPNsense: `os-rustproxy-<version>_<revision>.pkg` + statyczne repo `pkg`,
|
||||
- **natywne FreeBSD** (opcjonalnie): `rustproxy-<version>_<revision>.pkg` + osobny katalog repo `pkg` pod `/freebsd/` (bez zależności OPNsense).
|
||||
- **natywne FreeBSD** (domyślnie włączone): `rustproxy-<version>_<revision>.pkg` + osobny katalog repo `pkg` pod `/freebsd/` (bez zależności OPNsense).
|
||||
|
||||
**Agent Docker jest pakowany wyłącznie na Linux (DEB/RPM); brak paczki FreeBSD pkg dla agenta.** Nie ma Docker-in-Docker, SCP ani osobnego watchera repo OPNsense. FreeBSD sysroot, clang/lld i Rust target są częścią głównego obrazu buildera. OPNsense dostaje osobny publiczny adres. Gałąź Linux, gałąź OPNsense i opcjonalna gałąź natywnego FreeBSD są budowane oraz publikowane niezależnie, więc błąd testów Linux nie blokuje pakietu FreeBSD.
|
||||
**Agent Docker jest pakowany wyłącznie na Linux (DEB/RPM); brak paczki FreeBSD pkg dla agenta.** Nie ma Docker-in-Docker, SCP ani osobnego watchera repo OPNsense. FreeBSD sysroot, clang/lld i Rust target są częścią głównego obrazu buildera. OPNsense dostaje osobny publiczny adres. Gałąź Linux, gałąź OPNsense i gałąź natywnego FreeBSD są budowane oraz publikowane niezależnie, więc błąd testów Linux nie blokuje pakietu FreeBSD.
|
||||
|
||||
## Panel repozytorium (RustProxy Package Registry)
|
||||
|
||||
The dashboard interface defaults to **English (`en-GB`)**, including its dates, navigation, notifications, and installation instructions. The **Docker discovery agent** installation card is shown only for **Linux (DEB/RPM)**, never for OPNsense or native FreeBSD. Package listings/API also omit any stray agent PKG files for the FreeBSD channels.
|
||||
|
||||
Strony startowe wszystkich trzech repozytoriów działają teraz jako **lekka aplikacja Python** (`dashboard/`) za istniejącym Nginx. Wygląd nawiązuje do panelu RustProxy 0.34.6 (ciemny, jasny i kremowy motyw). **APT, RPM i pkg są nadal obsługiwane bezpośrednio przez Nginx**, więc mechanizm aktualizacji paczek, ścieżki plików, podpisy GPG i atomowe przełączanie `current` nie zmieniają się.
|
||||
|
||||
Panel udostępnia:
|
||||
@@ -26,7 +30,7 @@ Adresy paneli (bez zmian domen i portów):
|
||||
```text
|
||||
REPOSITORY_URL/ Linux DEB + RPM
|
||||
OPNSENSE_REPOSITORY_URL/ OPNsense pkg
|
||||
OPNSENSE_REPOSITORY_URL/freebsd/ Native FreeBSD pkg (opcjonalnie)
|
||||
OPNSENSE_REPOSITORY_URL/freebsd/ Native FreeBSD pkg
|
||||
```
|
||||
|
||||
Publiczne API, np. `https://twoje-repo.example/api/v1/packages`, zwraca JSON z `builds`, `packages` i `summary`. API jest dostępne na obu hostach. Panel nie zapisuje nic w repo; odczytuje wyłącznie opublikowany snapshot `data/repository/current`. Kontener Python nie publikuje portu hosta i ma dostęp **tylko do odczytu**.
|
||||
@@ -45,8 +49,6 @@ docker compose --env-file .env up -d repository-dashboard repository-http
|
||||
curl -fsS http://127.0.0.1:18765/api/v1/packages
|
||||
curl -fsS http://127.0.0.1:18765/healthz
|
||||
|
||||
# testy komponentu Python (bez Dockera)
|
||||
python3 -m unittest discover -s tests -p 'test_dashboard.py' -v
|
||||
```
|
||||
|
||||
Panel zależy wyłącznie od biblioteki standardowej Pythona, bez dodatkowych pakietów pip. Jeżeli nie ma jeszcze buildów, pokaże komunikat **brak paczek**, a nie fikcyjne wersje.
|
||||
@@ -102,7 +104,7 @@ opn-rustproxy.linuxiarz.pl -> http://builder:18766
|
||||
publikacja Linux os-rustproxy rustproxy.pkg
|
||||
pkg repo pkg repo
|
||||
|
||||
* FreeBSD native: FREEBSD_NATIVE_ENABLED=1
|
||||
* FreeBSD native: enabled by default; FREEBSD_NATIVE_ENABLED=0 disables it
|
||||
```
|
||||
|
||||
`cargo test` i `go test ./...` (agenta) należą tylko do gałęzi Linux. Jeśli testy nie przejdą, DEB/RPM nie są publikowane, ale builder nadal uruchamia cross-build FreeBSD i może opublikować repo OPNsense. Stan jest śledzony osobno w `last_linux_commit`, `last_opnsense_commit` i (jeśli włączone) `last_freebsd_commit`; kolejny cykl ponawia tylko brakującą gałąź.
|
||||
@@ -208,7 +210,7 @@ APPLY_FREEBSD_PATCHES=1
|
||||
|
||||
`OPNSENSE_RETENTION=10` zachowuje ostatnie 10 wersji pakietu dla danej serii/architektury OPNsense. `0` wyłącza usuwanie starych wersji.
|
||||
|
||||
`FREEBSD_NATIVE_ENABLED=0` wyłącza natywny pakiet FreeBSD (domyślnie, bez zmian istniejącej instalacji). Włączenie `1` tworzy oddzielny kanał publikacji i dodaje go do cyklicznego buildera. `FREEBSD_NATIVE_RETENTION=10` ogranicza liczbę zachowanych wersji. Repo używa tego samego publicznego hosta/portu co OPNsense, ale pod oddzielnym prefiksem `OPNSENSE_REPOSITORY_URL/freebsd/`.
|
||||
`FREEBSD_NATIVE_ENABLED=1` (domyślnie) włącza natywny pakiet FreeBSD i oddzielny kanał publikacji. `0` wyłącza budowanie natywnego FreeBSD. **Uwaga przy aktualizacji:** istniejący plik `.env` z `FREEBSD_NATIVE_ENABLED=0` ma pierwszeństwo przed nową wartością domyślną — zmień go ręcznie na `1`, inaczej pakiet FreeBSD nadal nie powstanie. `FREEBSD_NATIVE_RETENTION=10` ogranicza liczbę zachowanych wersji. Repo używa tego samego publicznego hosta/portu co OPNsense, ale pod oddzielnym prefiksem `OPNSENSE_REPOSITORY_URL/freebsd/`.
|
||||
|
||||
## Automatyczny Rust toolchain podczas budowania
|
||||
|
||||
@@ -290,7 +292,7 @@ configctl rustproxy start
|
||||
```
|
||||
|
||||
Obsługa miękkiego przeładowania zwiększa `OPNSENSE_PACKAGING_REVISION` do `4`.
|
||||
Pakowanie Linux ma `PACKAGING_REVISION=5`, a natywne FreeBSD `FREEBSD_NATIVE_PACKAGING_REVISION=1`. Każdy kanał otrzymuje osobną aktualizację przy zmianie swojej rewizji.
|
||||
Pakowanie Linux ma `PACKAGING_REVISION=5`, a natywne FreeBSD `FREEBSD_NATIVE_PACKAGING_REVISION=2`. Każdy kanał otrzymuje osobną aktualizację przy zmianie swojej rewizji.
|
||||
|
||||
## DEB/RPM: dostęp do plików strony i zewnętrznych certyfikatów
|
||||
|
||||
@@ -312,11 +314,7 @@ zewnętrzne PEM wymagają zaufanych katalogów właściciela `root`/`rustproxy`.
|
||||
Pakiet nie przypisuje automatycznie szerokich grup do użytkownika usługi,
|
||||
nie zmienia uprawnień witryn ani nie nadpisuje istniejących drop-inów.
|
||||
|
||||
Test pakowania, bez podpisywania i kompilacji Rust:
|
||||
|
||||
```sh
|
||||
./tests/linux-path-access.sh
|
||||
```
|
||||
Test pakowania jest dostępny w pełnym repozytorium developerskim (nie jest dołączony do archiwum wdrożeniowego).
|
||||
|
||||
## Rotacja logów RustProxy
|
||||
|
||||
@@ -325,7 +323,7 @@ Test pakowania, bez podpisywania i kompilacji Rust:
|
||||
|
||||
**Uwaga FreeBSD:** `newsyslog` działa przez zmianę nazwy pliku, nie ma `copytruncate`. Pliki JSONL i inne logi otwarte bezpośrednio przez aplikację muszą być przez nią ponownie otwierane po rotacji. W przeciwnym razie proces może pisać do poprzedniego (przeniesionego) pliku; zachowanie nie jest identyczne z Linux. Reguły są instalowane, ale na działającym OPNsense należy zweryfikować sposób otwierania plików przez RustProxy.
|
||||
|
||||
Bieżąca rewizja pakowania Linux wynosi `PACKAGING_REVISION=5` i `OPNSENSE_PACKAGING_REVISION=4`; nowy kanał używa `FREEBSD_NATIVE_PACKAGING_REVISION=1`. `check-and-build.sh` sprawdza osobno rewizje pakowania Linux, OPNsense i FreeBSD native; nowa wersja samej wtyczki przebudowuje **tylko OPNsense**, nawet przy niezmienionym SHA aplikacji. Rewizja pakietu PKG zwiększy się automatycznie. W przypadku zmiany rewizji Linux analogicznie odświeżane są DEB/RPM. Konfiguracja w `/etc/logrotate.d/rustproxy` jest oznaczona jako `noreplace`, więc lokalna wersja zmodyfikowana przez administratora może zostać zachowana (zależnie od menedżera pakietów).
|
||||
Bieżąca rewizja pakowania Linux wynosi `PACKAGING_REVISION=5` i `OPNSENSE_PACKAGING_REVISION=4`; nowy kanał używa `FREEBSD_NATIVE_PACKAGING_REVISION=2`. `check-and-build.sh` sprawdza osobno rewizje pakowania Linux, OPNsense i FreeBSD native; nowa wersja samej wtyczki przebudowuje **tylko OPNsense**, nawet przy niezmienionym SHA aplikacji. Rewizja pakietu PKG zwiększy się automatycznie. W przypadku zmiany rewizji Linux analogicznie odświeżane są DEB/RPM. Konfiguracja w `/etc/logrotate.d/rustproxy` jest oznaczona jako `noreplace`, więc lokalna wersja zmodyfikowana przez administratora może zostać zachowana (zależnie od menedżera pakietów).
|
||||
|
||||
Kontrola po zainstalowaniu:
|
||||
|
||||
@@ -337,11 +335,7 @@ logrotate -d /etc/logrotate.d/rustproxy
|
||||
newsyslog -n -v -f /usr/local/etc/newsyslog.conf.d/rustproxy.conf
|
||||
```
|
||||
|
||||
Pakietowe testy integracyjne (lokalnie, bez budowy aplikacji):
|
||||
|
||||
```sh
|
||||
./tests/log-rotation.sh
|
||||
```
|
||||
Testy integracyjne są dostępne w pełnym repozytorium developerskim.
|
||||
|
||||
## Dane
|
||||
|
||||
@@ -379,11 +373,7 @@ curl -f http://127.0.0.1:18766/healthz
|
||||
|
||||
## Testy statyczne
|
||||
|
||||
```bash
|
||||
./tests/static.sh
|
||||
./tests/linux-path-access.sh
|
||||
./tests/check-rustproxy-source.sh /sciezka/do/RustProxy
|
||||
```
|
||||
Skrypty diagnostyczne są dostępne w pełnym repozytorium developerskim; wydanie wdrożeniowe zawiera tylko pliki potrzebne do uruchomienia.
|
||||
|
||||
## Klucz GPG
|
||||
|
||||
@@ -425,16 +415,16 @@ Ustawienia środowiskowe: `CLEAN_TARGET_AFTER_BUILD=0` wyłącza czyszczenie;
|
||||
|
||||
**Ważne:** CLI `reload` wymaga uruchomionego RustProxy, zainicjalizowanego administratora i API osiągalnego przez adres loopback. Zmiana adresów/portów nasłuchujących wymaga `restart`, a nie `reload`.
|
||||
|
||||
## Natywne repo FreeBSD — wersja developerska
|
||||
## Natywne repo FreeBSD — włączone domyślnie
|
||||
|
||||
W pliku `.env` ustaw:
|
||||
Dla nowej instalacji FreeBSD native włącza się automatycznie. Jeśli masz już `.env`, **sprawdź**, czy ma:
|
||||
|
||||
```env
|
||||
FREEBSD_NATIVE_ENABLED=1
|
||||
FREEBSD_NATIVE_RETENTION=10
|
||||
```
|
||||
|
||||
Następnie `./start.sh`. Automatyczna publikacja katalogu `pkg` pojawi się pod:
|
||||
Następnie `./start.sh` (przebudowa kontenerów buildera i panelu). Natywna paczka pojawi się pod:
|
||||
|
||||
```text
|
||||
${OPNSENSE_REPOSITORY_URL}/freebsd/
|
||||
@@ -461,15 +451,17 @@ service rustproxy reload
|
||||
|
||||
To osobny pakiet od `os-rustproxy`: nie należy instalować obu pakietów naraz, bo oba używają nazwy usługi i ścieżek RustProxy.
|
||||
|
||||
**Bezpieczeństwo repo:** aktualnie katalog `pkg` jest **niesygnowany**, analogicznie do istniejącego repo OPNsense (`signature_type: none`). To nadaje się do testów DEV na zaufanej infrastrukturze. Przed produkcyjnym wdrożeniem należy dodać podpis katalogu `pkg`, bezpieczną dystrybucję klucza publicznego i wykonać instalację oraz aktualizację na rzeczywistym FreeBSD. Generator katalogu i testy offline nie zastępują testu klienta `pkg` na FreeBSD.
|
||||
**Bezpieczeństwo repo:** aktualnie katalog `pkg` jest **niesygnowany**, analogicznie do istniejącego repo OPNsense (`signature_type: none`). To nadaje się do testów DEV na zaufanej infrastrukturze. Przed produkcyjnym wdrożeniem należy dodać podpis katalogu `pkg`, bezpieczną dystrybucję klucza publicznego i wykonać instalację oraz aktualizację na rzeczywistym FreeBSD. Generator katalogu korzysta z formatu repozytorium `pkg` w wersji **2** dla FreeBSD 15 (OPNsense zachowuje dotychczasowy format), ale testy offline nie zastępują testu klienta `pkg` na prawdziwym FreeBSD.
|
||||
|
||||
Pakietowe testy offline:
|
||||
Pakietowe testy offline są dostępne w pełnym repozytorium developerskim (nie w wydaniu wdrożeniowym).
|
||||
|
||||
```sh
|
||||
./tests/static.sh
|
||||
./tests/linux-path-access.sh
|
||||
./tests/opnsense-plugin.sh
|
||||
./tests/log-rotation.sh
|
||||
./tests/freebsd-native.sh
|
||||
./tests/toolchains.sh
|
||||
```
|
||||
|
||||
## Troubleshooting: no native FreeBSD build
|
||||
|
||||
1. Ensure `.env` contains `FREEBSD_NATIVE_ENABLED=1` (older installations often set `0`).
|
||||
2. Rebuild/start: `docker compose --env-file .env up -d --build rust-package-builder repository-dashboard`.
|
||||
3. Follow the builder logs: `docker compose --env-file .env logs -f rust-package-builder`.
|
||||
4. Look for `build plan: ... freebsd=1` and then `FreeBSD native publication completed:`. If compilation fails, inspect the **first** `error:` in the same log. The OPNsense package uses the same FreeBSD cross-compiled executable but native FreeBSD publishes independently.
|
||||
5. Check `data/repository/current/freebsd/BUILD-INFO.txt` and `data/repository/current/freebsd/meta.conf` (`version: 2;`). The API `/api/v1/packages` then shows the published FreeBSD package/version/build time.
|
||||
|
||||
The development test `tests/freebsd-release.sh` uses a simulated ELF to verify packaging/catalog/atomic publication without Docker. It **does not prove Rust compilation or installation on real FreeBSD**. For end-to-end validation, run `pkg update -f` and `pkg install rustproxy` on FreeBSD 15.1 amd64 against the published URL. The catalog is **not signed**, so only use a trusted HTTPS source during testing.
|
||||
+16
-27
@@ -1,16 +1,14 @@
|
||||
516d7009f920efa26f60acbd859fa62cd3c7e23953c805173150145b1428a033 .env.example
|
||||
c92255b37b57e5356a10e88a8be14c856e9ef4372379c48423d69db7a1365625 .env.example
|
||||
17298e7669ed82b4c98abfce803e1a3f0a265b0abdc2567bf1316aa15e98aad3 Dockerfile
|
||||
ef47c4a3fad51d17ad690b0d6aa440d6ef3e355c5e9bd1824368f5450b4b7957 README.md
|
||||
16821f51ece84db491da19b64f1129710fb46288e9807abe31e1000fe33f72df README.md
|
||||
862263fa1f46c20f0d1e4dac5ffcc75abd55c08211b2c3864c5f8764b9d87793 dashboard/.dockerignore
|
||||
ced0339cb93478c2faf7b7b74215fe03375086e11ca957bd8892b52802fbbd3a dashboard/Dockerfile
|
||||
4bd84a56b756d6109a4fde23c6fcb2fef1b290302312a55046b8487cb9c36d74 dashboard/app.py
|
||||
345dbb2c4293405092445e159ce23053894d0c2335457f7299622ca42382dc05 dashboard/web/app.js
|
||||
bd2ba3a11ee715ba41a94f3301bec4ce83d7177489190a755e165112df50f112 dashboard/app.py
|
||||
6447c64295ac62dd88d03fc796344f8702d6af54586720bb3e1240eb4f16db42 dashboard/web/app.js
|
||||
f1ac0fb5c4da97db09ff328cb86f4bc763fbdd84d7310d6e8e713be1c8707bb9 dashboard/web/favicon.svg
|
||||
c7427bf31438cbbec9152c93674088bb2a16ea1d9a499b3c5c85beee2c543dda dashboard/web/index.html
|
||||
a3834770bcc9c0548bf387fb52795f3f6cb15b253f7d3819df9be147b04ebb8e dashboard/web/style.css
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 data/.gitkeep
|
||||
328b8b8075208e0c92793cf70c6d8999775faf94abf5d839101e6d3ba35597cf docker-compose.yml
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 gpg/.gitkeep
|
||||
df2483e63e8559f41da83712e94b5f216faff38f4786fd2c804eac4576645c23 dashboard/web/index.html
|
||||
2b5a34085be972372401abc9af16e2c14cc4e682fac448afb7c6f364d61b8649 dashboard/web/style.css
|
||||
ebb5e6eefe375ca1357d96f6a7344424c43df0bc51bc01ee66a459e54ef4b3c7 docker-compose.yml
|
||||
7da761300aef6cf22ce28c1c7a55414b692814023e4d540a3f3ec4111c62926c http/nginx.conf
|
||||
77e898aebb54f8acf39d3eb1fb348e7f41532da1b0a9e1820a717fdcde406f71 opnsense/patches/0.20.0/0001-opnsense-build.patch
|
||||
80bb419b980793f3a57b4fda0dc132a872186b3a07e0e6db2585c6057ab4f882 opnsense/plugin/+POST_INSTALL.pre
|
||||
@@ -43,32 +41,23 @@ c8dde46217c008bfc31420c19ecbd31e3db6d71ee48f99be856ad40ca3c7f490 packaging/free
|
||||
79122afbd5964a87c0d933abe8b34745d4189e2a586d5918a82efbb9b2f50864 packaging/rustproxy-filesystem-access.md
|
||||
0f7970888117b4bc810ad3f6abc6796f189d34e4863875b2501785e689471be6 packaging/rustproxy.logrotate
|
||||
eee3cb8959cb90cd1b5b320ec4674892e5d1a987049d1028dae39c3bdc9f3dc7 scripts/apply-freebsd-patches.sh
|
||||
5751d1e6fd0a5b0347ae6f80fb906e4ae306a34b51f0cf6837f2c062b6729f22 scripts/build-freebsd-release.sh
|
||||
a869ece6aef358abd5901474c5c2201e74bfc56d24bfe9931ad5cc3837aea215 scripts/build-freebsd-release.sh
|
||||
d197c25fd346a2cd2a516434a8d9fab304ae6fbf3b215e4f9ea35e6efbc4f417 scripts/build-linux-release.sh
|
||||
01aaa5ecd63e15f3a5436ca394d26308f7616117233dcac8a74a6db73ab68142 scripts/build-opnsense-release.sh
|
||||
5db9f6e5c782bb9afcf455688dea7c1de1d6070c510bbedc9408af5b0fe509b1 scripts/build-opnsense.sh
|
||||
b795c04884f75cae9154af80dfa5ec418b95c8991ed2927b8953c39e3f01a4e8 scripts/build-release.sh
|
||||
1e43a0e6706c0457ab04b155fa566edd509fc52bc4023eb8c44d4271a944e62c scripts/check-and-build.sh
|
||||
16bafbba1eb2000b42c754bae92fee43301e57e0859e2cef17be2550006ab111 scripts/build-opnsense.sh
|
||||
ed581639a606323d4e91e632bc40a9be7037570f91cdef4264e4db0ca130ee8e scripts/build-release.sh
|
||||
62fc5506b3786a1c943299a3d8107224dadb1b5bdee068acbbd4f649e7edc13b scripts/check-and-build.sh
|
||||
cba164bde8967045bfb76de7eff46d4407dfb7ed2bc861fbc600782551d1629e scripts/ensure-rust-toolchain.sh
|
||||
62d45e193b06c8fae02705b5214092f13a916cf0c637bbc793b4c46eac6a39fd scripts/entrypoint.sh
|
||||
621bc5e0bba15cba16271d7a02e7d34ea3652b88fb481a46b134f2dac01b7f4f scripts/generate-freebsd-index.sh
|
||||
6cc8f506dd72189af34ed22334467e9af022690860edcc902e80b2ae976384ea scripts/entrypoint.sh
|
||||
c8402314cbcf87c30eb521a273a13628eccb78112acb85e0e85c9a7679550cca scripts/generate-freebsd-index.sh
|
||||
4220710396d0670d5c9ebcc31c6c4d59073d2b1c192f08268a3ea49164d1dcbd scripts/generate-index.sh
|
||||
80f49932346268f2cd63cbfe4814c666cd665661e82c25f2e99883929ecae0c0 scripts/generate-opnsense-index.sh
|
||||
a21afa240ca0869c2f92af7a73899f270361b2b8677b897646479452185196fe scripts/generate-opnsense-repo.py
|
||||
094c603f30f6a41bddeedfefa9e2c260dc97f849f0a690475ebe128ce4b49475 scripts/generate-opnsense-repo.py
|
||||
40186599540f6886188abda5dac72bc85d15b9b71ce20788061131bfcd519cb7 scripts/init-storage.sh
|
||||
d078c62c54464095e7ddd2071c58a2ac3abd972f3aaa5b4bad0596735eca170c scripts/lib.sh
|
||||
4fdb7f98e83a262e9ad22f08fd5dd776993009f7b22623dfa9b04f554e48ac3c scripts/lib.sh
|
||||
de4fbbb973d9cddb170ef1e9f4f6f7896018ed5e6184594c9636c0215adf5233 scripts/normalize-systemd-unit.py
|
||||
0eca8ef60f15dce0c5651fc8a55de10e0d9a11f3816f04153608abcbe2e2e1d8 scripts/package-freebsd.sh
|
||||
b098fa629f9fcc1a54baab3d46b28721eb582c314e084b3210259bf157c124a6 scripts/package-opnsense.sh
|
||||
4ad289bc2c0e400b39a8d1bcf86395d7576c88e71b678ba8b893ccb72ac35465 scripts/prepare-agent-package.sh
|
||||
46908bfac309688340be72edded60efaecd765aa151f520a2491952619f53a43 scripts/prepare-package.sh
|
||||
57aae30a7ace2253e80f454e542bccf932e081457482718d7a4822e796b0c882 start.sh
|
||||
f0bde843d75330bc49e3ab5547e739d8fbda8d74d0b12dfdbdb7648847e91e88 tests/check-rustproxy-source.sh
|
||||
a55cc19cba2729ea3e8d82e8e5e90d734ba77c0e0d3f56a1b432e2e7e5316dc5 tests/docker-agent-linux.sh
|
||||
e82c52ef15183a539e96909a39e44db68c8301543950e145008b563524b0b9b9 tests/freebsd-native.sh
|
||||
84e9822fe9bbf87dd574b32fc2df5eebf317d3f26677a46035a49eb16044a4c1 tests/linux-path-access.sh
|
||||
c5781dd2335cc85e72daffe807c7ba24481b6c2e8bc95f4012be4ea1baeac9a8 tests/log-rotation.sh
|
||||
aab57cd66dc157dc2359d8d57612c174570a7ea09fe753428dce8faad231ba3c tests/opnsense-plugin.sh
|
||||
1227d503f784f7765c5950b603e4258ea155c2fdc3779886a7b0c403320be2a8 tests/static.sh
|
||||
ff0fe09dcd33124644a9babdf951193ebb358015997b302c7e3775a6c7a4d762 tests/test_dashboard.py
|
||||
c8de9ebbf51e017643d0735f27b960a6cf3c9b7122f6de32858f6b7dcc7ba9e9 tests/toolchains.sh
|
||||
2b6d2dc393be6dd5ba5184e6ccd068a8faf193bcd280f349a4b1da890187a79f start.sh
|
||||
@@ -138,6 +138,9 @@ def package_entry(path: Path, current: Path, site: str, kind: str, channel: str,
|
||||
if not parsed or not path.is_file():
|
||||
return None
|
||||
name, version, arch = parsed
|
||||
# Discovery agent is packaged for Linux DEB/RPM only; never advertise it as FreeBSD pkg.
|
||||
if channel in ('opnsense', 'freebsd') and name == 'rustproxy-docker-agent':
|
||||
return None
|
||||
try:
|
||||
stat = path.stat()
|
||||
except OSError:
|
||||
|
||||
+45
-41
@@ -5,10 +5,10 @@
|
||||
const el = (id) => document.getElementById(id);
|
||||
const CHANNEL_LABELS = {linux:'Linux',opnsense:'OPNsense',freebsd:'FreeBSD'};
|
||||
const INSTALL_NAMES = {deb:'Debian / Ubuntu',rpm:'RHEL / Rocky / Alma / Fedora',opnsense:'OPNsense',freebsd:'FreeBSD native'};
|
||||
const SECTION_LABELS = {overview:'Przegląd',packages:'Paczki i wersje',install:'Instalacja',repository:'Repozytoria'};
|
||||
const SECTION_LABELS = {overview:'Overview',packages:'Packages & versions',install:'Installation',repository:'Repositories'};
|
||||
const esc = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char]));
|
||||
const collator = new Intl.Collator('pl', {numeric:true,sensitivity:'base'});
|
||||
const formatNumber = new Intl.NumberFormat('pl-PL');
|
||||
const collator = new Intl.Collator('en', {numeric:true,sensitivity:'base'});
|
||||
const formatNumber = new Intl.NumberFormat('en-GB');
|
||||
const site = ['linux','opnsense','freebsd'].includes(document.body.dataset.site) ? document.body.dataset.site : 'linux';
|
||||
const state = {
|
||||
site, catalog:null, section:'overview', installing:site === 'linux' ? 'deb' : site,
|
||||
@@ -20,13 +20,13 @@
|
||||
if (!value) return '—';
|
||||
const time = new Date(value);
|
||||
if (Number.isNaN(time.valueOf())) return '—';
|
||||
return new Intl.DateTimeFormat('pl-PL', {year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'}).format(time);
|
||||
return new Intl.DateTimeFormat('en-GB', {year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'}).format(time);
|
||||
};
|
||||
const formatShortDate = (value) => {
|
||||
if (!value) return '—';
|
||||
const time = new Date(value);
|
||||
if (Number.isNaN(time.valueOf())) return '—';
|
||||
return new Intl.DateTimeFormat('pl-PL', {day:'2-digit',month:'short',year:'numeric'}).format(time);
|
||||
return new Intl.DateTimeFormat('en-GB', {day:'2-digit',month:'short',year:'numeric'}).format(time);
|
||||
};
|
||||
const formatSize = (value) => {
|
||||
const size = Number(value);
|
||||
@@ -43,7 +43,7 @@
|
||||
return '#';
|
||||
};
|
||||
const origin = (url) => typeof url === 'string' ? url.replace(/\/$/, '') : '';
|
||||
const dateLabel = (kind) => kind === 'build' ? 'Data zapisana przez builder' : 'Data pliku (starsze buildy bez znacznika czasu)';
|
||||
const dateLabel = (kind) => kind === 'build' ? 'Build timestamp recorded by the builder' : 'File modification time (older builds without a build timestamp)';
|
||||
const setText = (id, value) => {const node = el(id);if (node) node.textContent = value;};
|
||||
const versionText = (b) => b?.app_version ? `v${b.app_version}` : '—';
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
? `PKG · ${build?.opnsense_series || 'FreeBSD'}` : `PKG · ${build?.freebsd_abi || 'Native'}`;
|
||||
const version = build?.package_version || (live ? build?.app_version : '') || '—';
|
||||
return `<article class="build-card${live ? '' : ' off'}">
|
||||
<div class="build-card-top"><span>${esc(CHANNEL_LABELS[channel].toUpperCase())} / ${channel === 'linux' ? 'SIGNED' : 'PKG'}</span><span class="pill ${live ? 'live' : 'missing'}">${live ? 'PUBLISHED' : 'BRAK BUILDU'}</span></div>
|
||||
<div class="build-card-top"><span>${esc(CHANNEL_LABELS[channel].toUpperCase())} / ${channel === 'linux' ? 'SIGNED' : 'PKG'}</span><span class="pill ${live ? 'live' : 'missing'}">${live ? 'PUBLISHED' : 'NOT BUILT'}</span></div>
|
||||
<div class="build-card-version">${esc(version)}</div><div class="build-card-sub">${esc(subtitle)}</div>
|
||||
<div class="build-card-details"><div><small>BUILD DATE</small><strong title="${esc(dateLabel(build?.date_source))}">${esc(formatDate(build?.built_at))}</strong></div><div><small>COMMIT</small><strong class="commit">${esc(commit)}</strong></div></div>
|
||||
</article>`;
|
||||
@@ -92,7 +92,7 @@
|
||||
return `<span class="format-label${pkg.format === 'PKG' ? ' pkg' : ''}">${esc(pkg.format)}</span>`;
|
||||
}
|
||||
function tableRow(pkg, compact = false) {
|
||||
const download = `<a class="download-link" href="${esc(safeLink(pkg.download_url))}" target="_blank" rel="noopener noreferrer" download title="Pobierz ${esc(pkg.name)} ${esc(pkg.version)}">${compact ? 'Pobierz' : 'Pobierz plik'} <span>↗</span></a>`;
|
||||
const download = `<a class="download-link" href="${esc(safeLink(pkg.download_url))}" target="_blank" rel="noopener noreferrer" download title="Download ${esc(pkg.name)} ${esc(pkg.version)}">${compact ? 'Download' : 'Download file'} <span>↗</span></a>`;
|
||||
const first = `<span class="artifact-name" title="${esc(pkg.name)}">${esc(pkg.name)}</span><span class="artifact-arch">${esc(pkg.architecture)}</span>`;
|
||||
const format = `${formatBadge(pkg)}<span class="channel-tag ${pkg.format === 'PKG' ? 'pkg' : ''}">${esc(CHANNEL_LABELS[pkg.channel] || pkg.channel)}</span>`;
|
||||
const date = `<span class="date-cell" title="${esc(dateLabel(pkg.date_source))}">${esc(formatDate(pkg.built_at))}</span>`;
|
||||
@@ -112,29 +112,29 @@
|
||||
setText('stat-channels', `${data.summary?.channels_published || 0} / 3`);
|
||||
setText('stat-date', formatShortDate(data.summary?.latest_build_at));
|
||||
setText('stat-version', heroVersion);
|
||||
setText('stat-release', main?.package_version ? `Pakiet: ${main.package_version}` : 'Brak opublikowanej wersji');
|
||||
setText('stat-date-sub', 'Data ostatniej publikacji');
|
||||
setText('stat-release', main?.package_version ? `Package: ${main.package_version}` : 'No release published yet');
|
||||
setText('stat-date-sub', 'Latest publication date');
|
||||
setText('pipeline-updated', formatDate(data.generated_at));
|
||||
const ready = !!data.ready;
|
||||
el('hero-status').innerHTML = `<span class="pulse-dot"></span> ${ready ? 'REPOZYTORIUM AKTYWNE' : 'OCZEKIWANIE NA BUILD'}`;
|
||||
el('hero-status').innerHTML = `<span class="pulse-dot"></span> ${ready ? 'REPOSITORY ONLINE' : 'WAITING FOR BUILD'}`;
|
||||
el('hero-status').classList.toggle('waiting', !ready);
|
||||
el('sidebar-status').classList.toggle('waiting', !ready);
|
||||
el('sidebar-status').querySelector('span').textContent = ready ? 'REPOSITORY ONLINE' : 'OCZEKIWANIE NA DANE';
|
||||
el('sidebar-status').querySelector('span').textContent = ready ? 'REPOSITORY ONLINE' : 'WAITING FOR DATA';
|
||||
const side = el('side-channels');
|
||||
side.innerHTML = ['linux','opnsense','freebsd'].map((channel) => `<span class="side-channel${data.builds[channel]?.published ? '' : ' disabled'}"><i class="tiny-dot"></i>${esc(CHANNEL_LABELS[channel])}<small>${channel === 'linux' ? 'APT / DNF' : 'PKG'}</small></span>`).join('');
|
||||
el('build-grid').innerHTML = ['linux','opnsense','freebsd'].map((channel) => buildCard(data.builds[channel],channel)).join('');
|
||||
const recent = data.packages.slice(0,6);
|
||||
el('recent-rows').innerHTML = recent.length ? recent.map((pkg) => tableRow(pkg,true)).join('') : '<tr><td colspan="5" class="empty-table">Nie opublikowano jeszcze żadnych paczek. Katalog zapełni się po pierwszym buildzie.</td></tr>';
|
||||
const recent = data.packages.filter((pkg) => state.site === 'linux' || pkg.channel === state.site).slice(0,6);
|
||||
el('recent-rows').innerHTML = recent.length ? recent.map((pkg) => tableRow(pkg,true)).join('') : '<tr><td colspan="5" class="empty-table">No packages published yet. The catalog will populate after the first build.</td></tr>';
|
||||
}
|
||||
|
||||
function filteredPackages() {
|
||||
const arr = state.catalog?.packages || [];
|
||||
const search = state.search.trim().toLocaleLowerCase('pl-PL');
|
||||
const search = state.search.trim().toLocaleLowerCase('en-GB');
|
||||
const filtered = arr.filter((pkg) => {
|
||||
if (state.channel !== 'all' && pkg.channel !== state.channel) return false;
|
||||
if (state.format !== 'all' && pkg.format !== state.format) return false;
|
||||
if (!search) return true;
|
||||
return [pkg.name,pkg.version,pkg.channel,pkg.format,pkg.architecture].some((field) => String(field ?? '').toLocaleLowerCase('pl-PL').includes(search));
|
||||
return [pkg.name,pkg.version,pkg.channel,pkg.format,pkg.architecture].some((field) => String(field ?? '').toLocaleLowerCase('en-GB').includes(search));
|
||||
});
|
||||
if (state.sort === 'name') filtered.sort((a,b) => collator.compare(a.name,b.name) || collator.compare(b.version,a.version));
|
||||
if (state.sort === 'version') filtered.sort((a,b) => collator.compare(b.version,a.version) || collator.compare(a.name,b.name));
|
||||
@@ -147,10 +147,10 @@
|
||||
if (!data) return;
|
||||
const all = filteredPackages();
|
||||
const shown = all.slice(0,state.rows);
|
||||
setText('packages-total', `${formatNumber.format(data.summary.packages_count)} paczek`);
|
||||
setText('filter-count', `${formatNumber.format(all.length)} ${all.length === 1 ? 'wynik' : 'wyników'}`);
|
||||
setText('result-range', all.length ? `Wyświetlono ${shown.length} z ${all.length}` : 'Brak pasujących paczek');
|
||||
el('catalog-rows').innerHTML = shown.length ? shown.map((pkg) => tableRow(pkg)).join('') : '<tr><td colspan="6" class="empty-table">Brak paczek spełniających kryteria. Zmień filtry lub poczekaj na publikację.</td></tr>';
|
||||
setText('packages-total', `${formatNumber.format(data.summary.packages_count)} packages`);
|
||||
setText('filter-count', `${formatNumber.format(all.length)} ${all.length === 1 ? 'result' : 'results'}`);
|
||||
setText('result-range', all.length ? `Showing ${shown.length} of ${all.length}` : 'No matching packages');
|
||||
el('catalog-rows').innerHTML = shown.length ? shown.map((pkg) => tableRow(pkg)).join('') : '<tr><td colspan="6" class="empty-table">No packages match these filters. Adjust your search or check back after a new release.</td></tr>';
|
||||
el('show-more').hidden = shown.length >= all.length;
|
||||
}
|
||||
|
||||
@@ -163,9 +163,9 @@
|
||||
const component = data.apt_component || 'main';
|
||||
if (kind === 'deb') {
|
||||
return {
|
||||
description:'Dodaj podpisane repozytorium APT, odśwież listę pakietów i zainstaluj RustProxy.',
|
||||
description:'Add the signed APT repository, update the package list, and install RustProxy.',
|
||||
signature:'GPG SIGNED',
|
||||
note:'Obsługiwane: Debian / Ubuntu · architektura amd64.',
|
||||
note:'Supported: Debian / Ubuntu · amd64 architecture.',
|
||||
reference:`${linux}/apt/dists/${encodeURIComponent(distribution)}/InRelease`,
|
||||
agent:'sudo apt install rustproxy-docker-agent',
|
||||
code:[
|
||||
@@ -182,9 +182,9 @@
|
||||
}
|
||||
if (kind === 'rpm') {
|
||||
return {
|
||||
description:'Dodaj podpisane repozytorium DNF/YUM i zainstaluj serwer RustProxy.',
|
||||
description:'Add the signed DNF/YUM repository and install the RustProxy server.',
|
||||
signature:'GPG SIGNED',
|
||||
note:'Obsługiwane: RHEL / Rocky / Alma / Fedora · architektura x86_64.',
|
||||
note:'Supported: RHEL / Rocky / Alma / Fedora · x86_64 architecture.',
|
||||
reference:`${linux}/rpm/x86_64/repodata/repomd.xml`,
|
||||
agent:'sudo dnf install rustproxy-docker-agent',
|
||||
code:[
|
||||
@@ -206,11 +206,11 @@
|
||||
}
|
||||
if (kind === 'opnsense') {
|
||||
return {
|
||||
description:'Pobierz konfigurację repozytorium pkg i zainstaluj plugin os-rustproxy.',
|
||||
description:'Fetch the pkg repository configuration and install the os-rustproxy plugin.',
|
||||
signature:'UNSIGNED PKG',
|
||||
note:'Repozytorium pkg nie ma podpisanego katalogu. Korzystaj tylko z zaufanego hosta HTTPS.',
|
||||
note:'The pkg repository index is unsigned. Only use a trusted HTTPS host.',
|
||||
reference:`${opnsense}/RustProxy.conf`,
|
||||
agent:'sudo apt install rustproxy-docker-agent',
|
||||
agent:null,
|
||||
code:[
|
||||
'mkdir -p /usr/local/etc/pkg/repos',
|
||||
`fetch -o /usr/local/etc/pkg/repos/RustProxy.conf ${opnsense}/RustProxy.conf`,
|
||||
@@ -220,11 +220,11 @@
|
||||
};
|
||||
}
|
||||
return {
|
||||
description:'Zainstaluj natywny pakiet rustproxy i włącz usługę rc.d.',
|
||||
description:'Install the native rustproxy package and enable its rc.d service.',
|
||||
signature:'UNSIGNED PKG',
|
||||
note:'Dostępne po ustawieniu FREEBSD_NATIVE_ENABLED=1. Katalog pkg jest niesygnowany.',
|
||||
note:'The FreeBSD pkg index is unsigned. Only use a trusted HTTPS source.',
|
||||
reference:`${freebsd}/RustProxy-FreeBSD.conf`,
|
||||
agent:'sudo dnf install rustproxy-docker-agent',
|
||||
agent:null,
|
||||
code:[
|
||||
'mkdir -p /usr/local/etc/pkg/repos',
|
||||
`fetch -o /usr/local/etc/pkg/repos/RustProxy-FreeBSD.conf ${freebsd}/RustProxy-FreeBSD.conf`,
|
||||
@@ -251,7 +251,12 @@
|
||||
el('install-signature').classList.toggle('live', instructionsData.signature === 'GPG SIGNED');
|
||||
setText('install-command', instructionsData.code);
|
||||
setText('install-note', instructionsData.note);
|
||||
setText('agent-command', instructionsData.agent);
|
||||
// Docker discovery agent is only built for Linux DEB/RPM.
|
||||
const hasDockerAgent = (kind === 'deb' || kind === 'rpm') && !!instructionsData.agent;
|
||||
el('agent-card').hidden = !hasDockerAgent;
|
||||
el('install-extra-grid').classList.toggle('single-card', !hasDockerAgent);
|
||||
setText('trust-index', hasDockerAgent ? '02' : '01');
|
||||
setText('agent-command', hasDockerAgent ? instructionsData.agent : '');
|
||||
el('install-reference').href = safeLink(instructionsData.reference);
|
||||
}
|
||||
|
||||
@@ -269,7 +274,7 @@
|
||||
const distribution = encodeURIComponent(data.apt_distribution || 'stable');
|
||||
el('endpoints-grid').innerHTML = [
|
||||
endpointsCard('Linux','GPG SIGNED',url.linux,[
|
||||
{name:'Klucz publiczny GPG',url:`${url.linux}/repo-key.gpg`},
|
||||
{name:'GPG public key',url:`${url.linux}/repo-key.gpg`},
|
||||
{name:'APT InRelease',url:`${url.linux}/apt/dists/${distribution}/InRelease`},
|
||||
{name:'RPM repomd.xml',url:`${url.linux}/rpm/x86_64/repodata/repomd.xml`},
|
||||
{name:'Build info',url:`${url.linux}/LINUX-BUILD-INFO.txt`},
|
||||
@@ -290,13 +295,13 @@
|
||||
el('metadata-table').innerHTML = ['linux','opnsense','freebsd'].map((channel) => {
|
||||
const b = data.builds[channel] || {};
|
||||
const rows = [
|
||||
['WERSJA APLIKACJI',b.app_version || '—','latest-value'],
|
||||
['WERSJA PACZKI',b.package_version || '—',''],
|
||||
['DATA BUILDU',formatDate(b.built_at),''],
|
||||
['APPLICATION VERSION',b.app_version || '—','latest-value'],
|
||||
['PACKAGE VERSION',b.package_version || '—',''],
|
||||
['BUILD DATE',formatDate(b.built_at),''],
|
||||
['SOURCE COMMIT',b.source_commit || '—',''],
|
||||
['REWIZJA PAKOWANIA',b.packaging_revision || '—',''],
|
||||
['PACKAGING REVISION',b.packaging_revision || '—',''],
|
||||
];
|
||||
return `<div class="meta-block"><h3>${esc(CHANNEL_LABELS[channel])}</h3>${rows.map(([label,value,klass]) => `<div class="meta-row"><small>${esc(label)}</small><strong class="${klass}"${label === 'DATA BUILDU' ? ` title="${esc(dateLabel(b.date_source))}"` : ''}>${esc(value)}</strong></div>`).join('')}</div>`;
|
||||
return `<div class="meta-block"><h3>${esc(CHANNEL_LABELS[channel])}</h3>${rows.map(([label,value,klass]) => `<div class="meta-row"><small>${esc(label)}</small><strong class="${klass}"${label === 'BUILD DATE' ? ` title="${esc(dateLabel(b.date_source))}"` : ''}>${esc(value)}</strong></div>`).join('')}</div>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
@@ -307,7 +312,6 @@
|
||||
renderInstall();
|
||||
renderRepositories();
|
||||
setText('last-sync', formatDate(data.generated_at));
|
||||
setText('footer-time', formatDate(data.generated_at));
|
||||
el('last-sync').innerHTML = `<i></i> ${esc(formatDate(data.generated_at))}`;
|
||||
}
|
||||
|
||||
@@ -325,7 +329,7 @@
|
||||
el('error-banner').hidden = true;
|
||||
} catch (err) {
|
||||
el('error-banner').hidden = false;
|
||||
setText('last-sync','Błąd odczytu');
|
||||
setText('last-sync','Load failed');
|
||||
console.error('RustProxy repository:',err);
|
||||
} finally {
|
||||
state.refreshing = false;
|
||||
@@ -349,8 +353,8 @@
|
||||
input.remove();
|
||||
if (!copied) throw new Error('Clipboard unsupported');
|
||||
}
|
||||
toast('Skopiowano do schowka');
|
||||
} catch (_) { toast('Nie udało się skopiować — zaznacz polecenia ręcznie'); }
|
||||
toast('Copied to clipboard');
|
||||
} catch (_) { toast('Copy failed. Select and copy the command manually.'); }
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
+44
-49
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="pl" data-theme="dark">
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
@@ -18,14 +18,13 @@
|
||||
<span class="brand-text">RustProxy <small>PACKAGE REGISTRY</small></span>
|
||||
</a>
|
||||
<div class="edition">INDEPENDENT BY DESIGN <span>BUILD DISTRIBUTION</span></div>
|
||||
<div class="sidebar-label">WORKSPACE / 01</div>
|
||||
<nav class="main-navigation" aria-label="Nawigacja panelu">
|
||||
<button class="nav active" data-section="overview" aria-current="page"><span>01</span><b>Przegląd</b><span class="nav-arrow">↗</span></button>
|
||||
<button class="nav" data-section="packages"><span>02</span><b>Paczki i wersje</b><span class="nav-arrow">↗</span></button>
|
||||
<button class="nav" data-section="install"><span>03</span><b>Instalacja</b><span class="nav-arrow">↗</span></button>
|
||||
<button class="nav" data-section="repository"><span>04</span><b>Repozytoria</b><span class="nav-arrow">↗</span></button>
|
||||
<nav class="main-navigation" aria-label="Dashboard navigation">
|
||||
<button class="nav active" data-section="overview" aria-current="page"><span>01</span><b>Overview</b><span class="nav-arrow">↗</span></button>
|
||||
<button class="nav" data-section="packages"><span>02</span><b>Packages & versions</b><span class="nav-arrow">↗</span></button>
|
||||
<button class="nav" data-section="install"><span>03</span><b>Installation</b><span class="nav-arrow">↗</span></button>
|
||||
<button class="nav" data-section="repository"><span>04</span><b>Repositories</b><span class="nav-arrow">↗</span></button>
|
||||
</nav>
|
||||
<div class="sidebar-label sidebar-label--second">DOSTĘPNE KANAŁY</div>
|
||||
<div class="sidebar-label sidebar-label--second">AVAILABLE CHANNELS</div>
|
||||
<div class="side-channels" id="side-channels">
|
||||
<span class="side-channel"><i class="tiny-dot"></i> Linux <small>APT / DNF</small></span>
|
||||
<span class="side-channel"><i class="tiny-dot"></i> OPNsense <small>PKG</small></span>
|
||||
@@ -34,100 +33,96 @@
|
||||
<div class="sidebar-bottom">
|
||||
<div class="small-label">REPOSITORY ENGINE</div>
|
||||
<p>Python / HTTP API<br>Nginx / Signed APT + RPM<br>FreeBSD pkg catalog</p>
|
||||
<div class="local-tag" id="sidebar-status"><i></i><span>OCZEKIWANIE NA DANE</span></div>
|
||||
<div class="local-tag" id="sidebar-status"><i></i><span>WAITING FOR DATA</span></div>
|
||||
<div class="copyright">© RustProxy <span id="year"></span></div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="workspace">
|
||||
<header class="topbar">
|
||||
<div class="crumb"><span>RUSTPROXY</span><b>/</b><span>REPOSITORY</span><b>/</b><strong id="crumb-section">Przegląd</strong></div>
|
||||
<div class="crumb"><span>RUSTPROXY</span><b>/</b><span>REPOSITORY</span><b>/</b><strong id="crumb-section">Overview</strong></div>
|
||||
<div class="top-actions">
|
||||
<span class="live-sync" id="last-sync"><i></i> Odczyt danych…</span>
|
||||
<button class="quiet icon-button" id="refresh" title="Odśwież listę paczek" aria-label="Odśwież dane">
|
||||
<span class="live-sync" id="last-sync"><i></i> Loading data…</span>
|
||||
<button class="quiet icon-button" id="refresh" title="Refresh package list" aria-label="Refresh data">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 7v5h-5M4 17v-5h5"/><path d="M5 9a8 8 0 0 1 13.4-2.2L20 12M4 12l1.6 5.2A8 8 0 0 0 19 15"/></svg>
|
||||
</button>
|
||||
<button class="quiet theme-switch" id="theme-toggle" title="Zmień motyw" aria-label="Zmień motyw"><span class="theme-glyph">◐</span><span id="theme-name">Dark</span></button>
|
||||
<button class="quiet theme-switch" id="theme-toggle" title="Change theme" aria-label="Change theme"><span class="theme-glyph">◐</span><span id="theme-name">Dark</span></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-content">
|
||||
<div class="error-banner" id="error-banner" hidden role="status">Nie można pobrać katalogu. Automatyczna próba ponowienia za minutę. <button id="retry-inline">Spróbuj teraz</button></div>
|
||||
<div class="error-banner" id="error-banner" hidden role="status">Could not load the catalog. Retrying automatically in one minute. <button id="retry-inline">Retry now</button></div>
|
||||
|
||||
<section class="view" id="view-overview" aria-labelledby="overview-title">
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<div class="eyebrow"><span class="eyebrow-line"></span> DISTRIBUTION CONTROL ROOM <span class="eyebrow-separator">/</span> LIVE CATALOG</div>
|
||||
<h1 id="overview-title">Pakiety. Wersje.<br><em>Pełna kontrola.</em></h1>
|
||||
<p class="lead">Jedno miejsce dla wydań RustProxy na Linux, OPNsense i FreeBSD. Aktualne buildy, daty publikacji i gotowe instrukcje instalacji.</p>
|
||||
</div>
|
||||
<div class="page-head-side"><div class="subtle-label">STATUS / LIVE DATA</div><span class="active-status" id="hero-status"><span class="pulse-dot"></span> ODCZYTYWANIE</span><div class="muted-detail">Odświeżanie automatyczne co 60 sekund</div></div>
|
||||
<section class="view" id="view-overview" aria-label="Overview">
|
||||
<div class="overview-statusbar">
|
||||
<span class="active-status" id="hero-status"><span class="pulse-dot"></span> LOADING</span>
|
||||
<span class="muted-detail">Refreshes every 60 seconds</span>
|
||||
</div>
|
||||
|
||||
<div class="hero-grid">
|
||||
<div class="hero-release">
|
||||
<div class="hero-header"><span><span class="dot-amber"></span> NAJNOWSZE WYDANIE <span id="hero-channel">LINUX</span></span><span class="hero-corner">R / P — 01</span></div>
|
||||
<div class="hero-header"><span><span class="dot-amber"></span> LATEST RELEASE <span id="hero-channel">LINUX</span></span><span class="hero-corner">R / P — 01</span></div>
|
||||
<div class="hero-version-label">RUSTPROXY / APPLICATION VERSION</div>
|
||||
<div class="hero-version" id="hero-version">—</div>
|
||||
<div class="hero-foot">
|
||||
<div><small>ZBUDOWANO / OPUBLIKOWANO</small><strong id="hero-date">Brak informacji</strong></div>
|
||||
<div><small>BUILT / PUBLISHED</small><strong id="hero-date">Not available</strong></div>
|
||||
<div><small>SOURCE COMMIT</small><strong class="mono" id="hero-commit">—</strong></div>
|
||||
<button class="hero-link" data-go-section="packages">Pokaż wydania <span aria-hidden="true">↗</span></button>
|
||||
<button class="hero-link" data-go-section="packages">View releases <span aria-hidden="true">↗</span></button>
|
||||
</div>
|
||||
<div class="hero-background-rings" aria-hidden="true"></div>
|
||||
</div>
|
||||
<div class="pipeline-panel">
|
||||
<div class="pipeline-head"><span class="small-label">BUILD PIPELINE</span><span class="pipeline-live"><i class="tiny-dot"></i> READ ONLY</span></div>
|
||||
<p>Od źródeł do gotowych paczek.</p>
|
||||
<p>From source code to installable packages.</p>
|
||||
<div class="pipeline-list">
|
||||
<div class="pipeline-step"><span class="step-index">01</span><span class="step-info"><b>Git / source</b><small>RustProxy upstream</small></span><span class="step-right">GIT <span>↗</span></span></div>
|
||||
<div class="pipeline-connector"></div>
|
||||
<div class="pipeline-step"><span class="step-index">02</span><span class="step-info"><b>Build / package</b><small>Rust + Go + FreeBSD</small></span><span class="step-right">CI <span>↗</span></span></div>
|
||||
<div class="pipeline-connector"></div>
|
||||
<div class="pipeline-step"><span class="step-index">03</span><span class="step-info"><b>Signed repository</b><small>APT / RPM / PKG</small></span><span class="step-right step-success">LIVE <span>●</span></span></div>
|
||||
<div class="pipeline-step"><span class="step-index">03</span><span class="step-info"><b>Repository publish</b><small>APT / RPM / PKG</small></span><span class="step-right step-success">LIVE <span>●</span></span></div>
|
||||
</div>
|
||||
<div class="pipeline-footer">Ostatni odczyt <span id="pipeline-updated">—</span></div>
|
||||
<div class="pipeline-footer">Last sync <span id="pipeline-updated">—</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid" aria-label="Statystyki repozytorium">
|
||||
<div class="stat"><span>01 / PACZEK W KATALOGU</span><strong id="stat-packages">—</strong><small>Wszystkie opublikowane artefakty</small></div>
|
||||
<div class="stat"><span>02 / AKTYWNE KANAŁY</span><strong id="stat-channels">—</strong><small>Linux · OPNsense · FreeBSD</small></div>
|
||||
<div class="stat"><span>03 / OSTATNI BUILD</span><strong class="stat-date" id="stat-date">—</strong><small id="stat-date-sub">UTC / czas publikacji</small></div>
|
||||
<div class="stat"><span>04 / AKTUALNA WERSJA</span><strong id="stat-version">—</strong><small id="stat-release">Wersja aplikacji</small></div>
|
||||
<div class="stats-grid" aria-label="Repository statistics">
|
||||
<div class="stat"><span>01 / CATALOG PACKAGES</span><strong id="stat-packages">—</strong><small>All published artifacts</small></div>
|
||||
<div class="stat"><span>02 / ACTIVE CHANNELS</span><strong id="stat-channels">—</strong><small>Linux · OPNsense · FreeBSD</small></div>
|
||||
<div class="stat"><span>03 / LATEST BUILD</span><strong class="stat-date" id="stat-date">—</strong><small id="stat-date-sub">Latest publication time</small></div>
|
||||
<div class="stat"><span>04 / CURRENT VERSION</span><strong id="stat-version">—</strong><small id="stat-release">Application version</small></div>
|
||||
</div>
|
||||
|
||||
<div class="section-heading"><div><span class="section-index">01 / RELEASE CHANNELS</span><h2>Ostatnie buildy</h2></div><button class="text-link" data-go-section="packages">Cały katalog <span>↗</span></button></div>
|
||||
<div class="build-grid" id="build-grid"><div class="skeleton-card">Ładowanie kanałów…</div></div>
|
||||
<div class="section-heading"><div><span class="section-index">01 / RELEASE CHANNELS</span><h2>Latest builds</h2></div><button class="text-link" data-go-section="packages">View catalog <span>↗</span></button></div>
|
||||
<div class="build-grid" id="build-grid"><div class="skeleton-card">Loading channels…</div></div>
|
||||
|
||||
<div class="section-heading section-heading--second"><div><span class="section-index">02 / RECENT ARTIFACTS</span><h2>Najnowsze paczki</h2></div><button class="text-link" data-go-section="packages">Przeglądaj paczki <span>↗</span></button></div>
|
||||
<div class="section-heading section-heading--second"><div><span class="section-index">02 / RECENT ARTIFACTS</span><h2>Recent packages</h2></div><button class="text-link" data-go-section="packages">Browse packages <span>↗</span></button></div>
|
||||
<div class="card recent-card">
|
||||
<div class="table-scroller"><table class="data-table"><thead><tr><th>PAKIET</th><th>FORMAT / KANAŁ</th><th>WERSJA PACZKI</th><th>DATA BUILDU</th><th class="table-action-col">PLIK</th></tr></thead><tbody id="recent-rows"><tr><td colspan="5" class="empty-table">Ładowanie danych…</td></tr></tbody></table></div>
|
||||
<div class="table-scroller"><table class="data-table"><thead><tr><th>PACKAGE</th><th>FORMAT / CHANNEL</th><th>PACKAGE VERSION</th><th>BUILD DATE</th><th class="table-action-col">FILE</th></tr></thead><tbody id="recent-rows"><tr><td colspan="5" class="empty-table">Loading data…</td></tr></tbody></table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-packages" aria-labelledby="packages-title" hidden>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> ARTIFACT EXPLORER <span class="eyebrow-separator">/</span> VERSIONS</div><h1 id="packages-title">Katalog <em>paczek.</em></h1><p class="lead">Wyszukuj, filtruj, sortuj i pobieraj opublikowane pliki. Wszystkie dane są odczytywane bezpośrednio z aktualnego repozytorium.</p></div><div class="count-pill" id="packages-total">0 paczek</div></div>
|
||||
<div class="filter-panel"><div class="search-field"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m16.5 16.5 4 4"/></svg><input id="search-input" type="search" placeholder="Szukaj nazwy, wersji, architektury..." aria-label="Szukaj paczek" autocomplete="off"></div><label class="filter-input">KANAŁ<select id="filter-channel"><option value="all">Wszystkie</option><option value="linux">Linux</option><option value="opnsense">OPNsense</option><option value="freebsd">FreeBSD</option></select></label><label class="filter-input">FORMAT<select id="filter-format"><option value="all">Wszystkie</option><option value="DEB">DEB</option><option value="RPM">RPM</option><option value="PKG">PKG</option></select></label><label class="filter-input">SORTOWANIE<select id="filter-sort"><option value="date">Najnowsze</option><option value="version">Wersja ↓</option><option value="name">Nazwa A–Z</option><option value="size">Rozmiar ↓</option></select></label></div>
|
||||
<div class="result-topline"><span id="filter-count">Ładowanie…</span><span>Wersje i daty pochodzą z paczek i metadanych buildu</span></div>
|
||||
<div class="card catalog-card"><div class="table-scroller"><table class="data-table data-table--catalog"><thead><tr><th>PAKIET</th><th>KANAŁ</th><th>WERSJA</th><th>DATA BUILDU</th><th>ROZMIAR</th><th>POBIERZ</th></tr></thead><tbody id="catalog-rows"><tr><td colspan="6" class="empty-table">Ładowanie danych…</td></tr></tbody></table></div><div class="catalog-bottom"><span id="result-range">—</span><button class="quiet show-more" id="show-more" hidden>Załaduj kolejne 25 ↓</button></div></div>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> ARTIFACT EXPLORER <span class="eyebrow-separator">/</span> VERSIONS</div><h1 id="packages-title">Package <em>catalog.</em></h1><p class="lead">Search, filter, sort, and download published files. All details are read directly from the current repository.</p></div><div class="count-pill" id="packages-total">0 packages</div></div>
|
||||
<div class="filter-panel"><div class="search-field"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m16.5 16.5 4 4"/></svg><input id="search-input" type="search" placeholder="Search by name, version, architecture..." aria-label="Search packages" autocomplete="off"></div><label class="filter-input">CHANNEL<select id="filter-channel"><option value="all">All</option><option value="linux">Linux</option><option value="opnsense">OPNsense</option><option value="freebsd">FreeBSD</option></select></label><label class="filter-input">FORMAT<select id="filter-format"><option value="all">All</option><option value="DEB">DEB</option><option value="RPM">RPM</option><option value="PKG">PKG</option></select></label><label class="filter-input">SORT BY<select id="filter-sort"><option value="date">Newest first</option><option value="version">Version ↓</option><option value="name">Name A–Z</option><option value="size">Size ↓</option></select></label></div>
|
||||
<div class="result-topline"><span id="filter-count">Loading…</span><span>Versions and dates are read from packages and build metadata</span></div>
|
||||
<div class="card catalog-card"><div class="table-scroller"><table class="data-table data-table--catalog"><thead><tr><th>PACKAGE</th><th>CHANNEL</th><th>VERSION</th><th>BUILD DATE</th><th>SIZE</th><th>DOWNLOAD</th></tr></thead><tbody id="catalog-rows"><tr><td colspan="6" class="empty-table">Loading data…</td></tr></tbody></table></div><div class="catalog-bottom"><span id="result-range">—</span><button class="quiet show-more" id="show-more" hidden>Load 25 more ↓</button></div></div>
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-install" aria-labelledby="install-title" hidden>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> GET STARTED <span class="eyebrow-separator">/</span> INSTALLATION</div><h1 id="install-title">Zainstaluj <em>RustProxy.</em></h1><p class="lead">Gotowe polecenia dodania repozytorium i instalacji. Wybierz platformę, skopiuj komendy do terminala.</p></div></div>
|
||||
<div class="install-tabs" role="tablist" aria-label="Wybór systemu"><button role="tab" aria-selected="true" data-install="deb" class="install-tab active">Debian / Ubuntu <small>APT · amd64</small></button><button role="tab" aria-selected="false" data-install="rpm" class="install-tab">RHEL / Rocky <small>DNF · x86_64</small></button><button role="tab" aria-selected="false" data-install="opnsense" class="install-tab">OPNsense <small>FreeBSD pkg</small></button><button role="tab" aria-selected="false" data-install="freebsd" class="install-tab">FreeBSD <small>Native pkg</small></button></div>
|
||||
<div class="install-card card"><div class="install-card-head"><div><span class="section-index">TERMINAL / INSTALL</span><h2 id="install-tab-title">Debian / Ubuntu</h2><p id="install-description">Dodanie podpisanego repo APT i instalacja serwera.</p></div><span class="pill" id="install-signature">GPG SIGNED</span></div><div class="code-window"><div class="code-topbar"><span><i class="tiny-dot"></i><i class="tiny-dot"></i><i class="tiny-dot"></i> <b>install.sh</b></span><button class="copy-code" id="copy-install" data-copy-target="install-command">Kopiuj <span>↗</span></button></div><pre><code id="install-command">Przygotowywanie poleceń…</code></pre></div><div class="install-foot"><span id="install-note">Wymagane uprawnienia sudo.</span><a id="install-reference" class="text-link" href="#">Pliki repozytorium ↗</a></div></div>
|
||||
<div class="install-extra-grid"><div class="card hint-card"><span class="hint-icon">01</span><h3>Docker discovery agent</h3><p>Linux ma również osobną paczkę <code>rustproxy-docker-agent</code>. Instalujesz ją niezależnie od głównego serwera.</p><div class="inline-command"><code id="agent-command">sudo apt install rustproxy-docker-agent</code><button data-copy-target="agent-command" class="quiet">Kopiuj</button></div></div><div class="card hint-card"><span class="hint-icon">02</span><h3>Podpisy i zaufanie</h3><p>Repozytoria APT i DNF w builderze są podpisane GPG. Repozytoria OPNsense i natywnego FreeBSD używają obecnie katalogów <code>signature_type: none</code>; korzystaj z zaufanego źródła HTTPS.</p></div></div>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> GET STARTED <span class="eyebrow-separator">/</span> INSTALLATION</div><h1 id="install-title">Install <em>RustProxy.</em></h1><p class="lead">Ready-to-run commands to add the repository and install RustProxy. Select a platform and copy the commands to your terminal.</p></div></div>
|
||||
<div class="install-tabs" role="tablist" aria-label="Choose operating system"><button role="tab" aria-selected="true" data-install="deb" class="install-tab active">Debian / Ubuntu <small>APT · amd64</small></button><button role="tab" aria-selected="false" data-install="rpm" class="install-tab">RHEL / Rocky <small>DNF · x86_64</small></button><button role="tab" aria-selected="false" data-install="opnsense" class="install-tab">OPNsense <small>FreeBSD pkg</small></button><button role="tab" aria-selected="false" data-install="freebsd" class="install-tab">FreeBSD <small>Native pkg</small></button></div>
|
||||
<div class="install-card card"><div class="install-card-head"><div><span class="section-index">TERMINAL / INSTALL</span><h2 id="install-tab-title">Debian / Ubuntu</h2><p id="install-description">Add the signed APT repository and install the server.</p></div><span class="pill" id="install-signature">GPG SIGNED</span></div><div class="code-window"><div class="code-topbar"><span><i class="tiny-dot"></i><i class="tiny-dot"></i><i class="tiny-dot"></i> <b>install.sh</b></span><button class="copy-code" id="copy-install" data-copy-target="install-command">Copy <span>↗</span></button></div><pre><code id="install-command">Preparing commands…</code></pre></div><div class="install-foot"><span id="install-note">Requires sudo privileges.</span><a id="install-reference" class="text-link" href="#">Repository files ↗</a></div></div>
|
||||
<div class="install-extra-grid single-card" id="install-extra-grid"><div class="card hint-card" id="agent-card" hidden><span class="hint-icon">01</span><h3>Docker discovery agent</h3><p>Linux also provides a separate <code>rustproxy-docker-agent</code> package. Install it separately from the main server.</p><div class="inline-command"><code id="agent-command">sudo apt install rustproxy-docker-agent</code><button data-copy-target="agent-command" class="quiet">Copy</button></div></div><div class="card hint-card"><span class="hint-icon" id="trust-index">01</span><h3>Signatures and trust</h3><p>APT and DNF repositories are GPG-signed. OPNsense and native FreeBSD currently use <code>signature_type: none</code> catalogs; use a trusted HTTPS source.</p></div></div>
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-repository" aria-labelledby="repository-title" hidden>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> REPOSITORY ENDPOINTS <span class="eyebrow-separator">/</span> METADATA</div><h1 id="repository-title">Źródła <em>pakietów.</em></h1><p class="lead">Adresy publicznych repozytoriów, podpisów i katalogów paczek. Aktualne metadane pochodzą z opublikowanych buildów.</p></div></div>
|
||||
<div class="page-head compact-head"><div><div class="eyebrow"><span class="eyebrow-line"></span> REPOSITORY ENDPOINTS <span class="eyebrow-separator">/</span> METADATA</div><h1 id="repository-title">Package <em>sources.</em></h1><p class="lead">Public repository URLs, signatures, and package indexes. Current metadata comes from published builds.</p></div></div>
|
||||
<div class="endpoints-grid" id="endpoints-grid"></div>
|
||||
<div class="section-heading section-heading--second"><div><span class="section-index">SOURCE TRACE</span><h2>Informacje o wydaniach</h2></div></div>
|
||||
<div class="card metadata-card"><div class="meta-table" id="metadata-table"><span>Wczytywanie…</span></div></div>
|
||||
<div class="section-heading section-heading--second"><div><span class="section-index">SOURCE TRACE</span><h2>Release metadata</h2></div></div>
|
||||
<div class="card metadata-card"><div class="meta-table" id="metadata-table"><span>Loading…</span></div></div>
|
||||
</section>
|
||||
|
||||
<footer class="page-footer"><span>RUSTPROXY <b>/</b> PACKAGE REGISTRY</span><span>Live catalog · Python / Nginx <b>·</b> <span id="footer-time">—</span></span></footer>
|
||||
<footer class="page-footer"><span>RUSTPROXY <b>/</b> PACKAGE REGISTRY</span></footer>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -246,6 +246,7 @@ h3{font-size:16px;font-weight:575;letter-spacing:-.3px}
|
||||
.code-window pre{color:var(--text);font:12px/1.9 var(--mono);overflow:auto;margin:0;padding:21px 24px;min-height:170px;tab-size:2;white-space:pre}
|
||||
.install-foot{display:flex;justify-content:space-between;gap:15px;margin-top:17px;color:var(--muted);font-size:11px}
|
||||
.install-extra-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px}
|
||||
.install-extra-grid.single-card{grid-template-columns:1fr}
|
||||
.hint-card{padding:24px 26px}
|
||||
.hint-icon{display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--pill-live-line);color:var(--green);font:11px var(--mono);margin-bottom:18px}
|
||||
.hint-card h3{margin-bottom:10px}
|
||||
@@ -388,3 +389,8 @@ h3{font-size:16px;font-weight:575;letter-spacing:-.3px}
|
||||
.page-footer{flex-direction:column;gap:7px}
|
||||
}
|
||||
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
||||
|
||||
/* Compact overview: no decorative marketing hero. */
|
||||
.overview-statusbar{display:flex;gap:15px;align-items:center;justify-content:flex-end;flex-wrap:wrap;margin:0 0 18px}
|
||||
.overview-statusbar .muted-detail{margin-top:0}
|
||||
.main-navigation{margin-top:26px}
|
||||
+1
-1
@@ -25,7 +25,7 @@ services:
|
||||
FREEBSD_RUST_TOOLCHAIN: "${FREEBSD_RUST_TOOLCHAIN:-1.88.0}"
|
||||
APPLY_FREEBSD_PATCHES: "${APPLY_FREEBSD_PATCHES:-1}"
|
||||
RUN_LINUX_TESTS: "${RUN_LINUX_TESTS:-1}"
|
||||
FREEBSD_NATIVE_ENABLED: "${FREEBSD_NATIVE_ENABLED:-0}"
|
||||
FREEBSD_NATIVE_ENABLED: "${FREEBSD_NATIVE_ENABLED:-1}"
|
||||
FREEBSD_NATIVE_RETENTION: "${FREEBSD_NATIVE_RETENTION:-10}"
|
||||
volumes:
|
||||
- ./data:/var/lib/package-builder
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
BUILDER_ROOT=${BUILDER_ROOT:-/opt/rust-package-builder}
|
||||
source "$BUILDER_ROOT/scripts/lib.sh"
|
||||
|
||||
: "${SHA:?SHA required}"
|
||||
: "${SRC:?SRC required}"
|
||||
@@ -22,7 +23,7 @@ trap cleanup_freebsd_release EXIT
|
||||
FREEBSD_BINARY="$OUT/rust-proxy-freebsd"
|
||||
if [[ ! -x "$FREEBSD_BINARY" ]]; then
|
||||
# Reuse the same FreeBSD cross-build as OPNsense if it succeeded first.
|
||||
/opt/rust-package-builder/scripts/build-opnsense.sh "$SRC" "$FREEBSD_BINARY" "$BINARY_NAME" "$WORK"
|
||||
"$BUILDER_ROOT/scripts/build-opnsense.sh" "$SRC" "$FREEBSD_BINARY" "$BINARY_NAME" "$WORK"
|
||||
fi
|
||||
|
||||
FREEBSD_PACKAGE_REVISION=$SOURCE_REVISION
|
||||
@@ -43,7 +44,7 @@ if (( FREEBSD_PACKAGE_REVISION == 0 )); then
|
||||
fi
|
||||
FREEBSD_PACKAGE_VERSION="${VERSION}_${FREEBSD_PACKAGE_REVISION}"
|
||||
FREEBSD_PACKAGE_FILE="$OUT/rustproxy-${FREEBSD_PACKAGE_VERSION}.pkg"
|
||||
/opt/rust-package-builder/scripts/package-freebsd.sh \
|
||||
"$BUILDER_ROOT/scripts/package-freebsd.sh" \
|
||||
"$SRC" "$FREEBSD_BINARY" "$FREEBSD_PACKAGE_FILE" "$FREEBSD_PACKAGE_VERSION"
|
||||
|
||||
mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense" "$RELEASE_DIR/freebsd"
|
||||
@@ -70,7 +71,7 @@ fi
|
||||
FREEBSD_PACKAGE_DIR="$RELEASE_DIR/freebsd/$FREEBSD_ABI"
|
||||
mkdir -p "$FREEBSD_PACKAGE_DIR"
|
||||
cp -f "$FREEBSD_PACKAGE_FILE" "$FREEBSD_PACKAGE_DIR/"
|
||||
/opt/rust-package-builder/scripts/generate-opnsense-repo.py "$RELEASE_DIR/freebsd" --retention "$FREEBSD_NATIVE_RETENTION"
|
||||
"$BUILDER_ROOT/scripts/generate-opnsense-repo.py" "$RELEASE_DIR/freebsd" --retention "$FREEBSD_NATIVE_RETENTION" --repo-version 2
|
||||
NATIVE_URL="${OPNSENSE_REPOSITORY_URL%/}/freebsd"
|
||||
cat > "$RELEASE_DIR/freebsd/RustProxy-FreeBSD.conf" <<CONF
|
||||
RustProxyNative: {
|
||||
@@ -97,15 +98,18 @@ freebsd_abi=$FREEBSD_ABI
|
||||
freebsd_arch=$FREEBSD_ARCH
|
||||
package=$FREEBSD_ABI/$(basename "$FREEBSD_PACKAGE_FILE")
|
||||
INFO
|
||||
/opt/rust-package-builder/scripts/generate-freebsd-index.sh "$RELEASE_DIR/freebsd/index.html"
|
||||
"$BUILDER_ROOT/scripts/generate-freebsd-index.sh" "$RELEASE_DIR/freebsd/index.html"
|
||||
|
||||
[[ -s "$RELEASE_DIR/freebsd/index.html" ]]
|
||||
[[ -s "$RELEASE_DIR/freebsd/meta.conf" ]]
|
||||
[[ -s "$RELEASE_DIR/freebsd/packagesite.pkg" ]]
|
||||
[[ -s "$RELEASE_DIR/freebsd/data.pkg" ]]
|
||||
grep -Fqx "version: 2;" "$RELEASE_DIR/freebsd/meta.conf" || fatal "unexpected FreeBSD pkg repository format"
|
||||
[[ -s "$RELEASE_DIR/freebsd/rustproxy-latest.pkg" ]]
|
||||
bsdtar -tf "$RELEASE_DIR/freebsd/packagesite.pkg" | grep -Fx 'packagesite.yaml' >/dev/null || fatal 'invalid FreeBSD packagesite.pkg'
|
||||
bsdtar -xOf "$FREEBSD_PACKAGE_DIR/$(basename "$FREEBSD_PACKAGE_FILE")" +COMPACT_MANIFEST >/dev/null || fatal 'invalid FreeBSD package manifest'
|
||||
# Fail before switching the live repository if the public package is missing or empty.
|
||||
[[ -s "$FREEBSD_PACKAGE_DIR/$(basename "$FREEBSD_PACKAGE_FILE")" ]] || fatal 'missing FreeBSD native package artifact'
|
||||
|
||||
log 'publishing native FreeBSD repository branch'
|
||||
rm -f "$REPOSITORY/current.new"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
BUILDER_ROOT=${BUILDER_ROOT:-/opt/rust-package-builder}
|
||||
source "$BUILDER_ROOT/scripts/lib.sh"
|
||||
|
||||
SOURCE_DIR=${1:?source path required}
|
||||
OUTPUT_BINARY=${2:?output binary required}
|
||||
@@ -17,7 +18,7 @@ rsync -a --delete \
|
||||
"$SOURCE_DIR/" "$BUILD_SOURCE/"
|
||||
|
||||
if [[ "${APPLY_FREEBSD_PATCHES:-1}" == "1" ]]; then
|
||||
/opt/rust-package-builder/scripts/apply-freebsd-patches.sh "$BUILD_SOURCE"
|
||||
"$BUILDER_ROOT/scripts/apply-freebsd-patches.sh" "$BUILD_SOURCE"
|
||||
else
|
||||
log "FreeBSD/OPNsense source patches disabled"
|
||||
fi
|
||||
@@ -29,7 +30,7 @@ export CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_RUSTFLAGS="-C link-arg=--target=x86_6
|
||||
|
||||
log "cross-compiling $BINARY_NAME for x86_64-unknown-freebsd${FREEBSD_TARGET_VERSION}"
|
||||
cd "$BUILD_SOURCE"
|
||||
FREEBSD_RUST_TOOLCHAIN=$(/opt/rust-package-builder/scripts/ensure-rust-toolchain.sh "$BUILD_SOURCE" freebsd)
|
||||
FREEBSD_RUST_TOOLCHAIN=$("$BUILDER_ROOT/scripts/ensure-rust-toolchain.sh" "$BUILD_SOURCE" freebsd)
|
||||
if [[ -f Cargo.lock ]]; then
|
||||
cargo "+$FREEBSD_RUST_TOOLCHAIN" build --release --locked --target x86_64-unknown-freebsd
|
||||
else
|
||||
|
||||
@@ -146,7 +146,7 @@ FREEBSD_STATE=""
|
||||
[[ -r "$DATA_DIR/state/last_linux_commit" ]] && LINUX_STATE=$(cat "$DATA_DIR/state/last_linux_commit")
|
||||
[[ -r "$DATA_DIR/state/last_opnsense_commit" ]] && OPNSENSE_STATE=$(cat "$DATA_DIR/state/last_opnsense_commit")
|
||||
[[ -r "$DATA_DIR/state/last_freebsd_commit" ]] && FREEBSD_STATE=$(cat "$DATA_DIR/state/last_freebsd_commit")
|
||||
if [[ "$LINUX_STATE" == "$SHA" && "$OPNSENSE_STATE" == "$SHA" && ( "${FREEBSD_NATIVE_ENABLED:-0}" != "1" || "$FREEBSD_STATE" == "$SHA" ) ]]; then
|
||||
if [[ "$LINUX_STATE" == "$SHA" && "$OPNSENSE_STATE" == "$SHA" && ( "${FREEBSD_NATIVE_ENABLED:-1}" != "1" || "$FREEBSD_STATE" == "$SHA" ) ]]; then
|
||||
printf '%s\n' "$SHA" | atomic_write "$DATA_DIR/state/last_commit"
|
||||
log "all branches complete for $SHA"
|
||||
fi
|
||||
|
||||
@@ -87,7 +87,7 @@ if opnsense_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
printf '%s\n' "$REMOTE_SHA" | atomic_write "$DATA_DIR/state/last_opnsense_commit"
|
||||
fi
|
||||
|
||||
if [[ "${FREEBSD_NATIVE_ENABLED:-0}" == "1" ]]; then
|
||||
if [[ "${FREEBSD_NATIVE_ENABLED:-1}" == "1" ]]; then
|
||||
BUILD_FREEBSD=1
|
||||
if freebsd_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
BUILD_FREEBSD=0
|
||||
|
||||
@@ -16,7 +16,7 @@ FREEBSD_ARCH=${FREEBSD_ARCH:-freebsd:15:x86:64}
|
||||
FREEBSD_RUST_TOOLCHAIN=${FREEBSD_RUST_TOOLCHAIN:-1.88.0}
|
||||
APPLY_FREEBSD_PATCHES=${APPLY_FREEBSD_PATCHES:-1}
|
||||
RUN_LINUX_TESTS=${RUN_LINUX_TESTS:-1}
|
||||
FREEBSD_NATIVE_ENABLED=${FREEBSD_NATIVE_ENABLED:-0}
|
||||
FREEBSD_NATIVE_ENABLED=${FREEBSD_NATIVE_ENABLED:-1}
|
||||
FREEBSD_NATIVE_RETENTION=${FREEBSD_NATIVE_RETENTION:-10}
|
||||
|
||||
[[ "$POLL_INTERVAL" =~ ^[0-9]+$ ]] || fatal "POLL_INTERVAL must be an integer"
|
||||
@@ -27,6 +27,9 @@ FREEBSD_NATIVE_RETENTION=${FREEBSD_NATIVE_RETENTION:-10}
|
||||
[[ "$RUN_LINUX_TESTS" =~ ^[01]$ ]] || fatal "RUN_LINUX_TESTS must be 0 or 1"
|
||||
[[ "$FREEBSD_NATIVE_ENABLED" =~ ^[01]$ ]] || fatal "FREEBSD_NATIVE_ENABLED must be 0 or 1"
|
||||
[[ "$FREEBSD_NATIVE_RETENTION" =~ ^[0-9]+$ ]] || fatal "FREEBSD_NATIVE_RETENTION must be a nonnegative integer"
|
||||
if [[ "$FREEBSD_NATIVE_ENABLED" != "1" ]]; then
|
||||
log 'WARNING: native FreeBSD build is disabled (FREEBSD_NATIVE_ENABLED=0); no FreeBSD packages will be published'
|
||||
fi
|
||||
|
||||
export DATA_DIR=${DATA_DIR:-/var/lib/package-builder}
|
||||
export SOURCE_REPO SOURCE_BRANCH REPOSITORY_URL OPNSENSE_REPOSITORY_URL POLL_INTERVAL
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
BUILDER_ROOT=${BUILDER_ROOT:-/opt/rust-package-builder}
|
||||
source "$BUILDER_ROOT/scripts/lib.sh"
|
||||
OUT=${1:?output file required}
|
||||
URL="${OPNSENSE_REPOSITORY_URL%/}/freebsd"
|
||||
export OUT URL FREEBSD_ABI
|
||||
|
||||
@@ -91,7 +91,7 @@ def make_tar(dst: Path, member_name: str, payload: bytes):
|
||||
os.replace(tmp, dst)
|
||||
|
||||
|
||||
def rebuild(repo: Path, retention: int):
|
||||
def rebuild(repo: Path, retention: int, repo_version: int = 1):
|
||||
packages = collect_packages(repo)
|
||||
if enforce_retention(packages, retention):
|
||||
packages = collect_packages(repo)
|
||||
@@ -111,7 +111,7 @@ def rebuild(repo: Path, retention: int):
|
||||
make_tar(repo / "data.pkg", "data", data)
|
||||
|
||||
meta = (
|
||||
'version: 1;\n'
|
||||
f'version: {repo_version};\n'
|
||||
'packing_format: "tar";\n'
|
||||
'manifests: "packagesite.yaml";\n'
|
||||
'manifests_archive: "packagesite";\n'
|
||||
@@ -130,11 +130,12 @@ def main():
|
||||
parser = argparse.ArgumentParser(description="Build a static FreeBSD pkg repository catalogue")
|
||||
parser.add_argument("repo", type=Path, help="repository root")
|
||||
parser.add_argument("--retention", type=int, default=10, help="versions kept per package/ABI; 0 disables pruning")
|
||||
parser.add_argument("--repo-version", type=int, choices=(1, 2), default=1, help="pkg repository format; 2 for native FreeBSD 15")
|
||||
args = parser.parse_args()
|
||||
|
||||
repo = args.repo.resolve()
|
||||
repo.mkdir(parents=True, exist_ok=True)
|
||||
rebuild(repo, args.retention)
|
||||
rebuild(repo, args.retention, args.repo_version)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ set -Eeuo pipefail
|
||||
# Increment when package payload/installation semantics change without a source commit.
|
||||
PACKAGING_REVISION=5
|
||||
OPNSENSE_PACKAGING_REVISION=4
|
||||
FREEBSD_NATIVE_PACKAGING_REVISION=1
|
||||
FREEBSD_NATIVE_PACKAGING_REVISION=2
|
||||
|
||||
log() {
|
||||
printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*"
|
||||
|
||||
@@ -104,6 +104,9 @@ fi
|
||||
|
||||
[[ -f "$ENV_FILE" ]] || write_env_file
|
||||
load_env_file
|
||||
if [[ "${FREEBSD_NATIVE_ENABLED:-1}" == "0" ]]; then
|
||||
warn "Native FreeBSD builds are DISABLED by existing .env; set FREEBSD_NATIVE_ENABLED=1 and rerun ./start.sh to publish native PKG"
|
||||
fi
|
||||
|
||||
: "${SOURCE_REPO:?Uzupelnij SOURCE_REPO w .env albo ustaw zmienna przed uruchomieniem start.sh}"
|
||||
: "${REPOSITORY_URL:?Uzupelnij REPOSITORY_URL dla APT/RPM}"
|
||||
@@ -185,7 +188,7 @@ printf 'APT/RPM URL: %s/\n' "${REPOSITORY_URL%/}"
|
||||
printf 'APT/RPM local HTTP port: %s\n' "$HTTP_PORT"
|
||||
printf 'OPNsense pkg URL: %s/\n' "${OPNSENSE_REPOSITORY_URL%/}"
|
||||
printf 'OPNsense local HTTP port: %s\n' "$OPNSENSE_HTTP_PORT"
|
||||
[[ "${FREEBSD_NATIVE_ENABLED:-0}" == "1" ]] && printf 'Native FreeBSD pkg URL: %s/freebsd/\n' "${OPNSENSE_REPOSITORY_URL%/}"
|
||||
[[ "${FREEBSD_NATIVE_ENABLED:-1}" == "1" ]] && printf 'Native FreeBSD pkg URL: %s/freebsd/\n' "${OPNSENSE_REPOSITORY_URL%/}"
|
||||
[[ -n "$fingerprint" ]] && printf 'GPG fingerprint: %s\n' "$fingerprint"
|
||||
printf 'Publiczny katalog: %s\n\n' "$DATA_DIR/repository"
|
||||
printf 'Health Linux: http://127.0.0.1:%s/healthz\n' "$HTTP_PORT"
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
SRC=${1:?usage: check-rustproxy-source.sh /path/to/RustProxy}
|
||||
|
||||
for f in Cargo.toml grafana/rustproxy-overview.json src/main/bootstrap.rs; do
|
||||
[[ -f "$SRC/$f" ]] || { echo "missing: $f" >&2; exit 1; }
|
||||
done
|
||||
grep -q '^name = "rust-proxy"' "$SRC/Cargo.toml"
|
||||
grep -q 'RUST_PROXY_CONFIG' "$SRC/src/main/bootstrap.rs"
|
||||
grep -q 'Reload,' "$SRC/src/main/bootstrap.rs"
|
||||
|
||||
# Old RustProxy releases shipped full Debian metadata. The 0.34.x source
|
||||
# archive no longer does; the builder's own nFPM fallback is authoritative.
|
||||
if [[ -f "$SRC/debian/rustproxy.service" ]]; then
|
||||
grep -q 'ExecStart=' "$SRC/debian/rustproxy.service"
|
||||
else
|
||||
[[ -f "$SRC/deploy/rustproxy.service" ]] || { echo 'no reference systemd unit found' >&2; exit 1; }
|
||||
grep -q '^ExecReload=' "$SRC/deploy/rustproxy.service"
|
||||
fi
|
||||
|
||||
echo 'RustProxy source supports --config and soft reload: OK'
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Offline verification of the agent-specific nFPM packaging pipeline.
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
SRC=${1:-}
|
||||
if [[ ! -d "${SRC:-}/docker-agent" ]]; then
|
||||
SRC="$WORK/source"
|
||||
mkdir -p "$SRC/docker-agent"
|
||||
cat > "$SRC/docker-agent/rustproxy-docker-agent.service" <<'UNIT'
|
||||
[Service]
|
||||
User=rustproxy-docker-agent
|
||||
Group=docker
|
||||
EnvironmentFile=/etc/rustproxy/docker-agent.env
|
||||
ExecStart=/usr/local/bin/rustproxy-docker-agent
|
||||
StateDirectory=rustproxy-docker-agent
|
||||
UNIT
|
||||
cat > "$SRC/docker-agent/docker-agent.env.example" <<'ENV'
|
||||
RUSTPROXY_DOCKER_AGENT_TOKEN=replace-with-at-least-24-random-characters
|
||||
ENV
|
||||
echo '# Docker Agent' > "$SRC/docker-agent/README.md"
|
||||
fi
|
||||
if [[ -f "$SRC/docker-agent/go.mod" && $(command -v go || true) ]]; then
|
||||
(cd "$SRC/docker-agent" && GOWORK=off CGO_ENABLED=0 go test ./... && \
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -o "$WORK/agent" .)
|
||||
else
|
||||
cat > "$WORK/agent" <<'MOCK'
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
MOCK
|
||||
chmod 0755 "$WORK/agent"
|
||||
fi
|
||||
export BUILDER_ROOT="$ROOT" VERSION=0.34.2 PACKAGE_RELEASE=4
|
||||
export MAINTAINER='Package QA <qa@example.invalid>' HOMEPAGE=https://example.invalid
|
||||
export GPG_PRIVATE_KEY_FILE="$WORK/test-key.asc"
|
||||
"$ROOT/scripts/prepare-agent-package.sh" "$SRC" "$WORK/package" "$WORK/agent"
|
||||
PKG="$WORK/package"
|
||||
test -x "$PKG/payload/usr/bin/rustproxy-docker-agent"
|
||||
grep -Fqx 'ExecStart=/usr/bin/rustproxy-docker-agent' "$PKG/payload/usr/lib/systemd/system/rustproxy-docker-agent.service"
|
||||
grep -Fq 'config|noreplace' "$PKG/nfpm-deb.yaml"
|
||||
grep -Fq 'config|noreplace' "$PKG/nfpm-rpm.yaml"
|
||||
grep -q 'type: origin' "$PKG/nfpm-deb.yaml"
|
||||
grep -q 'signature:' "$PKG/nfpm-rpm.yaml"
|
||||
! grep -q '\.pkg' "$PKG/nfpm-deb.yaml"
|
||||
for script in "$PKG"/scripts/*; do sh -n "$script"; done
|
||||
for script in "$PKG"/scripts/*postinstall.sh; do
|
||||
grep -Fq '/usr/bin/rustproxy-docker-agent init' "$script"
|
||||
grep -Fq 'systemctl enable rustproxy-docker-agent.service' "$script"
|
||||
done
|
||||
if python3 -c 'import yaml' >/dev/null 2>&1; then
|
||||
python3 - "$PKG" <<'PY_YAML'
|
||||
import yaml, pathlib, sys
|
||||
pkg=pathlib.Path(sys.argv[1])
|
||||
for kind in ('deb','rpm'):
|
||||
x=yaml.safe_load((pkg/f'nfpm-{kind}.yaml').read_text())
|
||||
assert x['name']=='rustproxy-docker-agent'
|
||||
assert x['version']=='0.34.2'
|
||||
assert x['arch']=='amd64'
|
||||
assert len(x['contents'])==4
|
||||
assert x['scripts']['postinstall']
|
||||
assert any(c['dst']=='/etc/rustproxy/docker-agent.env' and c['type']=='config|noreplace' for c in x['contents'])
|
||||
PY_YAML
|
||||
fi
|
||||
echo 'Docker Agent package manifests, service layout and lifecycle scripts: OK'
|
||||
@@ -1,96 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
SLEEP_PID=""
|
||||
cleanup() {
|
||||
[[ -z "$SLEEP_PID" ]] || kill "$SLEEP_PID" 2>/dev/null || true
|
||||
rm -rf "$WORK"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
for tool in file zstd tar python3; do
|
||||
command -v "$tool" >/dev/null 2>&1 || { echo "SKIP FreeBSD native packaging: missing $tool"; exit 0; }
|
||||
done
|
||||
mkdir -p "$WORK/source" "$WORK/repo/FreeBSD:15:amd64" "$WORK/run"
|
||||
printf '[package]\nname = "rust-proxy"\nversion = "0.34.1"\n' > "$WORK/source/Cargo.toml"
|
||||
python3 - "$WORK/bin" <<'PY'
|
||||
from pathlib import Path
|
||||
import struct,sys
|
||||
p=Path(sys.argv[1]); p.write_bytes(b'\x7fELF\x02\x01\x01\x09'+bytes(8)+struct.pack('<HHIQQQIHHHHHH',2,62,1,0,0,0,0,64,56,0,64,0,0));p.chmod(0o755)
|
||||
PY
|
||||
export BUILDER_ROOT="$ROOT" FREEBSD_ABI=FreeBSD:15:amd64 FREEBSD_ARCH=freebsd:15:x86:64
|
||||
"$ROOT/scripts/package-freebsd.sh" "$WORK/source" "$WORK/bin" "$WORK/rustproxy-0.34.1_2.pkg" 0.34.1_2
|
||||
zstd -dc "$WORK/rustproxy-0.34.1_2.pkg" | tar -xOf - +MANIFEST > "$WORK/manifest.json"
|
||||
python3 - "$WORK/manifest.json" <<'PY'
|
||||
import json,sys
|
||||
m=json.load(open(sys.argv[1])); names=set(m['files'])
|
||||
assert m['name']=='rustproxy'
|
||||
assert m['origin']=='www/rustproxy'
|
||||
assert m['version']=='0.34.1_2'
|
||||
assert m['abi']=='FreeBSD:15:amd64'
|
||||
assert '/usr/local/sbin/rust-proxy' in names
|
||||
assert '/usr/local/etc/rc.d/rustproxy' in names
|
||||
assert '/usr/local/etc/newsyslog.conf.d/rustproxy.conf' in names
|
||||
assert len(names)==3
|
||||
assert not any('/opnsense/' in n or 'syshook' in n for n in names)
|
||||
assert 'post-install' in m['scripts'] and 'pre-deinstall' in m['scripts']
|
||||
PY
|
||||
|
||||
# Test the actual rc.d reload command without a running FreeBSD machine.
|
||||
cat > "$WORK/rc.subr" <<'SH'
|
||||
load_rc_config() { :; }
|
||||
checkyesno() { eval 'v=${'"$1"'-NO}'; [ "$v" = YES ]; }
|
||||
run_rc_command() { case "$1" in reload) "$reload_cmd" ;; *) return 1 ;; esac; }
|
||||
SH
|
||||
cat > "$WORK/su" <<'SH'
|
||||
#!/bin/sh
|
||||
printf '%s\n' "$*" > "$TEST_ARGS"
|
||||
SH
|
||||
chmod +x "$WORK/su"
|
||||
python3 - "$ROOT/packaging/freebsd/rustproxy.rc" "$WORK/rc" "$WORK" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
src=Path(sys.argv[1]).read_text();w=Path(sys.argv[3]);
|
||||
src=src.replace('. /etc/rc.subr', f'. "{w}/rc.subr"')
|
||||
src=src.replace('/usr/bin/su -m', f'"{w}/su" -m')
|
||||
Path(sys.argv[2]).write_text(src)
|
||||
PY
|
||||
sleep 120 & SLEEP_PID=$!
|
||||
printf '%s\n' "$SLEEP_PID" > "$WORK/run/rustproxy.pid"
|
||||
export TEST_ARGS="$WORK/cli-args" rustproxy_run_dir="$WORK/run"
|
||||
export rustproxy_config=/usr/local/etc/rustproxy/config.json rustproxy_enable=YES
|
||||
sh "$WORK/rc" reload
|
||||
rg_args=$(cat "$TEST_ARGS")
|
||||
[[ "$rg_args" == *'--data-dir /var/db/rustproxy'* ]]
|
||||
[[ "$rg_args" == *'--config /usr/local/etc/rustproxy/config.json'* ]]
|
||||
[[ "$rg_args" == *'--admin-listen 127.0.0.1:9090 reload'* ]]
|
||||
export rustproxy_config='/usr/local/etc/rustproxy/config.json;touch /tmp/bad'
|
||||
if sh "$WORK/rc" reload >/dev/null 2>&1; then
|
||||
echo 'unsafe config path was accepted' >&2; exit 1
|
||||
fi
|
||||
unset rustproxy_config
|
||||
|
||||
# Catalog generation: mock FreeBSD bsdtar on Linux using zstd + tar.
|
||||
mkdir -p "$WORK/mockbin"
|
||||
cat > "$WORK/mockbin/bsdtar" <<'SH'
|
||||
#!/bin/sh
|
||||
case "$1" in
|
||||
-xOf) zstd -dc "$2" | tar -xOf - "$3" ;;
|
||||
*) exit 2 ;;
|
||||
esac
|
||||
SH
|
||||
chmod +x "$WORK/mockbin/bsdtar"
|
||||
cp "$WORK/rustproxy-0.34.1_2.pkg" "$WORK/repo/FreeBSD:15:amd64/"
|
||||
cp "$WORK/rustproxy-0.34.1_2.pkg" "$WORK/repo/rustproxy-latest.pkg"
|
||||
PATH="$WORK/mockbin:$PATH" python3 "$ROOT/scripts/generate-opnsense-repo.py" "$WORK/repo" --retention 10
|
||||
python3 - "$WORK/repo/packagesite.pkg" <<'PY'
|
||||
import json,tarfile,sys
|
||||
with tarfile.open(sys.argv[1]) as archive:
|
||||
content=archive.extractfile('packagesite.yaml').read().decode().splitlines()
|
||||
assert len(content)==1,content
|
||||
pkg=json.loads(content[0]);assert pkg['name']=='rustproxy'
|
||||
assert pkg['path']=='FreeBSD:15:amd64/rustproxy-0.34.1_2.pkg',pkg['path']
|
||||
PY
|
||||
|
||||
echo 'FreeBSD native package, rc.d reload and repository catalog: OK'
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$WORK/source"
|
||||
printf '#!/bin/sh\nexit 0\n' > "$WORK/rust-proxy"
|
||||
chmod 0755 "$WORK/rust-proxy"
|
||||
|
||||
export BUILDER_ROOT="$ROOT" PACKAGE_NAME=rustproxy BINARY_NAME=rust-proxy
|
||||
export VERSION=1.0.0 PACKAGE_RELEASE=1 DESCRIPTION=RustProxy LICENSE=UNKNOWN
|
||||
export MAINTAINER=test@example.invalid HOMEPAGE=https://example.invalid
|
||||
export GPG_PRIVATE_KEY_FILE=/nonexistent/test.gpg
|
||||
|
||||
check_unit() {
|
||||
local unit=$1
|
||||
# A read-only home does not conceal /home, unlike ProtectHome=true/tmpfs.
|
||||
[[ $(grep -c '^ProtectHome=read-only$' "$unit") -eq 1 ]]
|
||||
! grep -Eq '^ProtectHome=(true|yes|tmpfs|false|no)$' "$unit"
|
||||
grep -Fxq 'ProtectSystem=strict' "$unit"
|
||||
grep -Fxq 'User=rustproxy' "$unit"
|
||||
grep -Fxq 'Group=rustproxy' "$unit"
|
||||
grep -Fxq 'NoNewPrivileges=true' "$unit"
|
||||
grep -Fxq 'CapabilityBoundingSet=CAP_NET_BIND_SERVICE' "$unit"
|
||||
grep -Fq 'ReadWritePaths=-/etc/rustproxy' "$unit"
|
||||
grep -Fxq 'ExecReload=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 reload' "$unit"
|
||||
}
|
||||
|
||||
# Current RustProxy archive has no debian unit; both nFPM targets use fallback.
|
||||
"$ROOT/scripts/prepare-package.sh" "$WORK/source" "$WORK/fallback" "$WORK/rust-proxy"
|
||||
check_unit "$WORK/fallback/payload/usr/lib/systemd/system/rustproxy.service"
|
||||
for platform in deb rpm; do
|
||||
grep -Fq '/usr/lib/systemd/system/rustproxy.service' "$WORK/fallback/nfpm-$platform.yaml"
|
||||
grep -Fq '/usr/share/doc/rustproxy/FILESYSTEM_ACCESS.md' "$WORK/fallback/nfpm-$platform.yaml"
|
||||
done
|
||||
cmp "$ROOT/packaging/rustproxy-filesystem-access.md" \
|
||||
"$WORK/fallback/payload/usr/share/doc/rustproxy/FILESYSTEM_ACCESS.md"
|
||||
|
||||
# Some source releases ship their own unit. Normalize its outdated home policy
|
||||
# rather than letting it override the new package default.
|
||||
mkdir -p "$WORK/source/debian"
|
||||
cat > "$WORK/source/debian/rustproxy.service" <<'UNIT'
|
||||
[Unit]
|
||||
Description=RustProxy unit supplied with a source release
|
||||
|
||||
[Service]
|
||||
User=rustproxy
|
||||
Group=rustproxy
|
||||
ExecStart=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy serve
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/lib/rustproxy /var/log/rustproxy
|
||||
ProtectHome=true
|
||||
NoNewPrivileges=true
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
UNIT
|
||||
python3 "$ROOT/scripts/normalize-systemd-unit.py" "$WORK/source/debian/rustproxy.service" rust-proxy
|
||||
check_unit "$WORK/source/debian/rustproxy.service"
|
||||
|
||||
# A custom unit without ProtectHome must also get the new safe policy.
|
||||
sed -i '/^ProtectHome=/d' "$WORK/source/debian/rustproxy.service"
|
||||
python3 "$ROOT/scripts/normalize-systemd-unit.py" "$WORK/source/debian/rustproxy.service" rust-proxy
|
||||
check_unit "$WORK/source/debian/rustproxy.service"
|
||||
|
||||
echo 'Linux DEB/RPM external path access policy: OK'
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
|
||||
# The bundled Linux rules must match the expected user-provided settings.
|
||||
diff -u "$ROOT/packaging/rustproxy.logrotate" - <<'CONFIG'
|
||||
/var/log/rustproxy/*.jsonl /var/log/rustproxy/*.log /var/log/rustproxy/vhosts/*.jsonl {
|
||||
daily
|
||||
maxsize 512M
|
||||
rotate 14
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
copytruncate
|
||||
su rustproxy rustproxy
|
||||
}
|
||||
CONFIG
|
||||
|
||||
# All three log groups must also be tracked by native FreeBSD newsyslog.
|
||||
OPNSENSE_CONF="$ROOT/opnsense/plugin/src/etc/newsyslog.conf.d/rustproxy.conf"
|
||||
for pattern in '/var/log/rustproxy/*.jsonl' '/var/log/rustproxy/*.log' '/var/log/rustproxy/vhosts/*.jsonl'; do
|
||||
grep -Fq "$pattern " "$OPNSENSE_CONF"
|
||||
done
|
||||
[[ $(grep -c '^/var/log/rustproxy/' "$OPNSENSE_CONF") == 3 ]]
|
||||
grep -Fq '14 100M $D0 GBEZPN' "$OPNSENSE_CONF"
|
||||
grep -Fq '14 100M $D0 GBEZP /var/run/rustproxy/daemon.pid SIGHUP' "$OPNSENSE_CONF"
|
||||
grep -Fq ' -H -P ${pidfile}' "$ROOT/opnsense/plugin/src/etc/rc.d/rustproxy"
|
||||
grep -Fq 'COPY packaging/ /opt/rust-package-builder/packaging/' "$ROOT/Dockerfile"
|
||||
grep -Fq 'packaging_revision=$PACKAGING_REVISION' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'packaging_revision=$OPNSENSE_PACKAGING_REVISION' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
|
||||
# Test staging and native PKG manifest without compiling Rust or signing RPM/DEB.
|
||||
for tool in file zstd tar sha256sum python3; do
|
||||
command -v "$tool" >/dev/null 2>&1 || { echo "SKIP packaging integration: missing $tool"; exit 0; }
|
||||
done
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$WORK/source" "$WORK/linux"
|
||||
|
||||
if command -v logrotate >/dev/null 2>&1; then
|
||||
# Test parser compatibility even if the local test machine has no rustproxy user.
|
||||
sed 's/su rustproxy rustproxy/su root root/' "$ROOT/packaging/rustproxy.logrotate" > "$WORK/logrotate-test.conf"
|
||||
logrotate -d -s "$WORK/logrotate.state" "$WORK/logrotate-test.conf" > "$WORK/logrotate-output" 2>&1
|
||||
grep -Fq 'reading config file' "$WORK/logrotate-output"
|
||||
fi
|
||||
printf '[package]\nname = "rust-proxy"\nversion = "1.0.0"\n' > "$WORK/source/Cargo.toml"
|
||||
python3 - "$WORK/bin" <<'PY'
|
||||
from pathlib import Path
|
||||
import struct, sys
|
||||
p = Path(sys.argv[1])
|
||||
# ELF header with FreeBSD OSABI is enough to check the OPNsense packaging path.
|
||||
e_ident = b'\x7fELF\x02\x01\x01\x09' + bytes(8)
|
||||
header = struct.pack('<HHIQQQIHHHHHH', 2, 62, 1, 0, 0, 0, 0, 64, 56, 0, 64, 0, 0)
|
||||
p.write_bytes(e_ident + header)
|
||||
p.chmod(0o755)
|
||||
PY
|
||||
|
||||
export BUILDER_ROOT="$ROOT" PACKAGE_NAME=rustproxy BINARY_NAME=rust-proxy
|
||||
export VERSION=1.0.0 PACKAGE_RELEASE=2 DESCRIPTION=RustProxy LICENSE=UNKNOWN
|
||||
export MAINTAINER=test@example.invalid HOMEPAGE=https://example.invalid
|
||||
export GPG_PRIVATE_KEY_FILE=/nonexistent/test.gpg
|
||||
"$ROOT/scripts/prepare-package.sh" "$WORK/source" "$WORK/linux" "$WORK/bin"
|
||||
cmp "$ROOT/packaging/rustproxy.logrotate" "$WORK/linux/payload/etc/logrotate.d/rustproxy"
|
||||
UNIT="$WORK/linux/payload/usr/lib/systemd/system/rustproxy.service"
|
||||
grep -Fq 'ExecReload=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 reload' "$UNIT"
|
||||
grep -Fq 'ReadWritePaths=-/etc/rustproxy' "$UNIT"
|
||||
grep -Fxq 'ProtectHome=read-only' "$UNIT"
|
||||
grep -Fxq 'ProtectSystem=strict' "$UNIT"
|
||||
for metadata in nfpm-deb.yaml nfpm-rpm.yaml; do
|
||||
grep -Fq '/etc/logrotate.d/rustproxy' "$WORK/linux/$metadata"
|
||||
grep -Fq 'config|noreplace' "$WORK/linux/$metadata"
|
||||
grep -Fq ' - logrotate' "$WORK/linux/$metadata"
|
||||
done
|
||||
|
||||
"$ROOT/scripts/package-opnsense.sh" "$WORK/source" "$WORK/bin" "$WORK/os-rustproxy.pkg" '1.0.0_20'
|
||||
zstd -dc "$WORK/os-rustproxy.pkg" | tar -xOf - +MANIFEST > "$WORK/manifest.json"
|
||||
python3 - "$WORK/manifest.json" <<'PY'
|
||||
import json, sys
|
||||
with open(sys.argv[1]) as f:
|
||||
manifest=json.load(f)
|
||||
path='/usr/local/etc/newsyslog.conf.d/rustproxy.conf'
|
||||
assert path in manifest['files'], f'{path} missing from PKG manifest'
|
||||
assert path in manifest['files'] and len(manifest['files'][path]) == 64
|
||||
assert '/usr/local/etc/rc.d/rustproxy' in manifest['files']
|
||||
assert '/usr/local/etc/rc.syshook.d/start/50-rustproxy.start' in manifest['files']
|
||||
assert '/usr/local/etc/rc.syshook.d/10-rustproxy.start' not in manifest['files']
|
||||
PY
|
||||
zstd -dc "$WORK/os-rustproxy.pkg" | tar -xOf - /usr/local/etc/newsyslog.conf.d/rustproxy.conf > "$WORK/packaged-newsyslog.conf"
|
||||
cmp "$OPNSENSE_CONF" "$WORK/packaged-newsyslog.conf"
|
||||
echo 'log rotation package integration: OK'
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
SRC="$ROOT/opnsense/plugin/src"
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
RC="$SRC/etc/rc.d/rustproxy"
|
||||
HOOK="$SRC/etc/rc.syshook.d/start/50-rustproxy.start"
|
||||
SERVICE="$SRC/opnsense/scripts/rustproxy/service.sh"
|
||||
MODEL="$SRC/opnsense/mvc/app/models/OPNsense/RustProxy/RustProxy.xml"
|
||||
FORM="$SRC/opnsense/mvc/app/controllers/OPNsense/RustProxy/forms/general.xml"
|
||||
TEMPLATE="$SRC/opnsense/service/templates/OPNsense/RustProxy/rustproxy.conf"
|
||||
|
||||
[[ -f "$HOOK" && -x "$HOOK" ]] || { echo 'Boot syshook must exist and be executable' >&2; exit 1; }
|
||||
[[ ! -e "$SRC/etc/rc.syshook.d/10-rustproxy.start" ]] || { echo 'Old hook path still exists' >&2; exit 1; }
|
||||
for script in "$RC" "$HOOK" "$SERVICE"; do
|
||||
sh -n "$script"
|
||||
done
|
||||
php -l "$SRC/opnsense/mvc/app/models/OPNsense/RustProxy/Migrations/M1_5_0.php" >/dev/null
|
||||
|
||||
# Ensure GUI, model and Jinja template agree about the new setting.
|
||||
python3 - "$MODEL" "$FORM" "$TEMPLATE" <<'PY'
|
||||
import pathlib, sys, xml.etree.ElementTree as ET
|
||||
model = ET.parse(sys.argv[1]).getroot()
|
||||
form = ET.parse(sys.argv[2]).getroot()
|
||||
template = pathlib.Path(sys.argv[3]).read_text()
|
||||
assert model.find('version').text == '1.5.0'
|
||||
field = model.find('./items/general/updateCheckIntervalSecs')
|
||||
assert field is not None and field.attrib['type'] == 'IntegerField'
|
||||
assert field.findtext('Default') == '3600'
|
||||
assert field.findtext('MinimumValue') == '60'
|
||||
assert field.findtext('MaximumValue') == '604800'
|
||||
assert 'rustproxy.general.updateCheckIntervalSecs' in [e.text for e in form.iter('id')]
|
||||
assert 'rustproxy_update_check_interval_secs=' in template
|
||||
assert 'OPNsense.rustproxy.general.updateCheckIntervalSecs' in template
|
||||
PY
|
||||
|
||||
# Isolate the rc.d argument composition without running FreeBSD-only commands.
|
||||
cat > "$WORK/rc.subr" <<'EOF'
|
||||
load_rc_config() { :; }
|
||||
run_rc_command() {
|
||||
if [ "$1" = reload ]; then "$reload_cmd"; else printf '%s\n' "$command_args"; fi
|
||||
}
|
||||
EOF
|
||||
python3 - "$RC" "$WORK/rc-test" "$WORK" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
src = Path(sys.argv[1]).read_text()
|
||||
work = Path(sys.argv[3])
|
||||
src = src.replace('. /etc/rc.subr', '. "'+str(work/'rc.subr')+'"')
|
||||
src = src.replace('config_file="/usr/local/etc/rustproxy/opnsense.conf"', 'config_file="'+str(work/'opnsense.conf')+'"')
|
||||
Path(sys.argv[2]).write_text(src)
|
||||
PY
|
||||
|
||||
assert_interval() {
|
||||
local val=$1
|
||||
printf 'enabled="1"\nrustproxy_update_check_interval_secs="%s"\n' "$val" > "$WORK/opnsense.conf"
|
||||
local args
|
||||
args=$(sh "$WORK/rc-test" start)
|
||||
[[ "$args" == *"--update-check-interval-secs $val serve"* ]] || {
|
||||
echo "Wrong update interval arguments: $args" >&2; exit 1;
|
||||
}
|
||||
}
|
||||
assert_interval 3600
|
||||
assert_interval 7200
|
||||
assert_interval 60
|
||||
assert_interval 604800
|
||||
printf 'enabled="1"\n' > "$WORK/opnsense.conf"
|
||||
args=$(sh "$WORK/rc-test" start)
|
||||
[[ "$args" == *'--update-check-interval-secs 3600 serve'* ]] || exit 1
|
||||
# Exercise the rc.d soft reload itself with a live mock child and CLI.
|
||||
mkdir -p "$WORK/bin"
|
||||
cat > "$WORK/bin/mock-cli" <<'EOF'
|
||||
#!/bin/sh
|
||||
printf '%s\n' "$*" > "$TEST_CLI_ARGS"
|
||||
EOF
|
||||
chmod +x "$WORK/bin/mock-cli"
|
||||
printf 'enabled="1"\nrustproxy_config_path="/usr/local/etc/rustproxy/config.json"\n' > "$WORK/opnsense.conf"
|
||||
echo "$$" > "$WORK/rustproxy.pid"
|
||||
export TEST_CLI_ARGS="$WORK/cli-args"
|
||||
rustproxy_run_dir="$WORK" rustproxy_command="$WORK/bin/mock-cli" sh "$WORK/rc-test" reload
|
||||
args=$(cat "$TEST_CLI_ARGS")
|
||||
[[ "$args" == *'--data-dir /var/db/rustproxy'* ]]
|
||||
[[ "$args" == *'--config /usr/local/etc/rustproxy/config.json'* ]]
|
||||
[[ "$args" == *'--admin-listen 127.0.0.1:9090 reload'* ]]
|
||||
printf 'enabled="1"\nrustproxy_config_path="/usr/local/etc/rustproxy/config.json;touch /tmp/bad"\n' > "$WORK/opnsense.conf"
|
||||
if rustproxy_run_dir="$WORK" rustproxy_command="$WORK/bin/mock-cli" sh "$WORK/rc-test" reload >/dev/null 2>&1; then
|
||||
echo 'Unsafe OPNsense config path was accepted' >&2; exit 1
|
||||
fi
|
||||
|
||||
for invalid in 0 59 604801 nope '1;touch /tmp/pwn'; do
|
||||
printf 'enabled="1"\nrustproxy_update_check_interval_secs="%s"\n' "$invalid" > "$WORK/opnsense.conf"
|
||||
if sh "$WORK/rc-test" start >/dev/null 2>&1; then
|
||||
echo "Interval '$invalid' should have failed" >&2; exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Mock configd + rc.d so we can exercise the actual hook and service wrapper.
|
||||
mkdir -p "$WORK/bin"
|
||||
cat > "$WORK/bin/configctl" <<'EOF'
|
||||
#!/bin/sh
|
||||
printf 'template %s\n' "$*" >> "$TEST_LOG"
|
||||
if [ "${FAIL_RENDER:-0}" = 1 ]; then
|
||||
exit 2
|
||||
fi
|
||||
printf 'enabled="%s"\n' "${ENABLED:-1}" > "$TEST_CONFIG"
|
||||
EOF
|
||||
cat > "$WORK/bin/rustproxy-rc" <<'EOF'
|
||||
#!/bin/sh
|
||||
case "$1" in
|
||||
status) [ -f "$TEST_PID" ] ;;
|
||||
onestart) printf 'start\n' >> "$TEST_LOG"; touch "$TEST_PID" ;;
|
||||
onestop) printf 'stop\n' >> "$TEST_LOG"; rm -f "$TEST_PID" ;;
|
||||
reload) printf 'reload\n' >> "$TEST_LOG" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$WORK/bin/configctl" "$WORK/bin/rustproxy-rc"
|
||||
python3 - "$HOOK" "$SERVICE" "$WORK" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
hook = Path(sys.argv[1]).read_text()
|
||||
service = Path(sys.argv[2]).read_text()
|
||||
w = Path(sys.argv[3])
|
||||
hook = hook.replace('/usr/local/sbin/configctl', str(w/'bin/configctl'))
|
||||
hook = hook.replace('/usr/local/opnsense/scripts/rustproxy/service.sh', str(w/'service-test'))
|
||||
service = service.replace('/usr/local/etc/rustproxy/opnsense.conf', str(w/'opnsense.conf'))
|
||||
service = service.replace('/usr/local/etc/rc.d/rustproxy', str(w/'bin/rustproxy-rc'))
|
||||
(w/'hook-test').write_text(hook)
|
||||
(w/'service-test').write_text(service)
|
||||
PY
|
||||
chmod +x "$WORK/hook-test" "$WORK/service-test"
|
||||
export TEST_LOG="$WORK/actions.log" TEST_CONFIG="$WORK/opnsense.conf" TEST_PID="$WORK/pidfile"
|
||||
: > "$TEST_LOG"
|
||||
ENABLED=1 "$WORK/hook-test"
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Boot did not start service' >&2; exit 1; }
|
||||
ENABLED=1 "$WORK/hook-test"
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Duplicate supervisor start' >&2; exit 1; }
|
||||
ENABLED=1 "$WORK/service-test" reload
|
||||
[[ $(grep -cx reload "$TEST_LOG") == 1 ]] || { echo 'Soft reload not passed through' >&2; exit 1; }
|
||||
[[ $(grep -cx stop "$TEST_LOG" || true) == 0 ]] || { echo 'Soft reload restarted service' >&2; exit 1; }
|
||||
rm -f "$TEST_PID"
|
||||
ENABLED=0 "$WORK/hook-test"
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Disabled service started' >&2; exit 1; }
|
||||
if FAIL_RENDER=1 ENABLED=1 "$WORK/hook-test" >/dev/null 2>&1; then
|
||||
echo 'Broken configuration reload was not reported' >&2; exit 1
|
||||
fi
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Started despite failed template rendering' >&2; exit 1; }
|
||||
|
||||
echo 'OPNsense boot / update interval / soft reload checks: OK'
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
|
||||
for f in "$ROOT"/start.sh "$ROOT"/scripts/*.sh "$ROOT"/tests/*.sh; do
|
||||
bash -n "$f"
|
||||
done
|
||||
python3 -m py_compile "$ROOT/scripts/generate-opnsense-repo.py"
|
||||
|
||||
# Main image/build dependencies.
|
||||
grep -q 'FROM rockylinux:9' "$ROOT/Dockerfile"
|
||||
grep -q 'FREEBSD_RELEASE=15.1-RELEASE' "$ROOT/Dockerfile"
|
||||
grep -q 'x86_64-unknown-freebsd' "$ROOT/Dockerfile"
|
||||
grep -q '/opt/freebsd-sysroot' "$ROOT/Dockerfile"
|
||||
|
||||
# Coordinator uses one checkout but independent branches.
|
||||
grep -q 'build-linux-release.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'build-opnsense-release.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'build-freebsd-release.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'package-freebsd.sh' "$ROOT/scripts/build-freebsd-release.sh"
|
||||
grep -q 'FREEBSD_NATIVE_PACKAGING_REVISION=1' "$ROOT/scripts/lib.sh"
|
||||
grep -Fq 'FREEBSD_NATIVE_ENABLED: "${FREEBSD_NATIVE_ENABLED:-0}"' "$ROOT/docker-compose.yml"
|
||||
grep -Fq 'location /freebsd/' "$ROOT/http/nginx.conf"
|
||||
grep -Fq 'FREEBSD_NATIVE_ENABLED=0' "$ROOT/.env.example"
|
||||
grep -Fq 'ExecReload=/usr/bin/' "$ROOT/scripts/normalize-systemd-unit.py"
|
||||
grep -q 'OPNsense branch will still run' "$ROOT/scripts/build-release.sh"
|
||||
|
||||
# Linux tests gate Linux packaging only.
|
||||
grep -Fq 'cargo "+$LINUX_RUST_TOOLCHAIN" test --release' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'CGO_ENABLED=0 go test ./...' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'prepare-agent-package.sh' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'AGENT_DEB_FILE=' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'AGENT_RPM_FILE=' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'rustproxy-docker-agent' "$ROOT/scripts/generate-index.sh"
|
||||
grep -Fq 'COPY --from=go-toolchain' "$ROOT/Dockerfile"
|
||||
grep -q 'PACKAGING_REVISION=5' "$ROOT/scripts/lib.sh"
|
||||
grep -Fq 'ensure-rust-toolchain.sh' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'ensure-rust-toolchain.sh' "$ROOT/scripts/build-opnsense.sh"
|
||||
grep -Fq 'nfpm package' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -q 'aptly .*publish' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -q 'createrepo_c' "$ROOT/scripts/build-linux-release.sh"
|
||||
[[ -x "$ROOT/tests/linux-path-access.sh" ]]
|
||||
! grep -q 'cargo test' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
! grep -q 'cargo test' "$ROOT/scripts/build-opnsense.sh"
|
||||
|
||||
# FreeBSD/OPNsense branch.
|
||||
grep -q 'build-opnsense.sh' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
grep -q 'package-opnsense.sh' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
grep -q 'generate-opnsense-repo.py' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
grep -q 'last_opnsense_commit' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
test -f "$ROOT/opnsense/plugin/src/etc/rc.d/rustproxy"
|
||||
test -x "$ROOT/opnsense/plugin/src/etc/rc.syshook.d/start/50-rustproxy.start"
|
||||
[[ ! -e "$ROOT/opnsense/plugin/src/etc/rc.syshook.d/10-rustproxy.start" ]]
|
||||
grep -q 'OPNSENSE_PACKAGING_REVISION=4' "$ROOT/scripts/lib.sh"
|
||||
test -f "$ROOT/opnsense/patches/0.20.0/0001-opnsense-build.patch"
|
||||
|
||||
# Per-branch state/retry logic.
|
||||
grep -q 'last_linux_commit' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'last_opnsense_commit' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'BUILD_LINUX' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'BUILD_OPNSENSE' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'RUN_LINUX_TESTS=${RUN_LINUX_TESTS:-1}' "$ROOT/scripts/entrypoint.sh"
|
||||
grep -Fq 'RUN_LINUX_TESTS: "${RUN_LINUX_TESTS:-1}"' "$ROOT/docker-compose.yml"
|
||||
|
||||
# Two public endpoints from one nginx container.
|
||||
grep -Fq '${REPOSITORY_URL:?REPOSITORY_URL is required}' "$ROOT/docker-compose.yml"
|
||||
grep -Fq '${OPNSENSE_REPOSITORY_URL:?OPNSENSE_REPOSITORY_URL is required}' "$ROOT/docker-compose.yml"
|
||||
grep -Fq '0.0.0.0:${HTTP_PORT:-18765}:8080' "$ROOT/docker-compose.yml"
|
||||
grep -Fq '0.0.0.0:${OPNSENSE_HTTP_PORT:-18766}:8081' "$ROOT/docker-compose.yml"
|
||||
grep -q 'listen 8080' "$ROOT/http/nginx.conf"
|
||||
grep -q 'listen 8081' "$ROOT/http/nginx.conf"
|
||||
grep -q 'root /srv/repository/opnsense' "$ROOT/http/nginx.conf"
|
||||
|
||||
grep -q 'DEFAULT_HTTP_PORT=18765' "$ROOT/start.sh"
|
||||
grep -q 'DEFAULT_OPNSENSE_HTTP_PORT=18766' "$ROOT/start.sh"
|
||||
grep -q 'OPNSENSE_REPOSITORY_URL=https://opn-rustproxy.linuxiarz.pl' "$ROOT/.env.example"
|
||||
grep -q 'RUN_LINUX_TESTS=1' "$ROOT/.env.example"
|
||||
|
||||
echo 'static checks: OK'
|
||||
@@ -1,157 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run: python3 -m unittest discover -s tests -p 'test_dashboard.py' -v"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
from datetime import datetime, timezone
|
||||
from http.server import ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
spec = importlib.util.spec_from_file_location("dashboard_app", ROOT / "dashboard" / "app.py")
|
||||
app = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(app)
|
||||
|
||||
|
||||
class RepoFixture:
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.repo = Path(self.temp.name) / "repository"
|
||||
self.r1 = self.repo / "releases" / "r1"
|
||||
self.r1.mkdir(parents=True)
|
||||
(self.repo / "current").symlink_to("releases/r1")
|
||||
|
||||
def make_file(self, name, *, contents="package-bytes", timestamp=1735853760):
|
||||
path = self.r1 / name
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
path.write_text(contents,encoding="utf-8")
|
||||
os.utime(path,(timestamp,timestamp))
|
||||
return path
|
||||
|
||||
def make_catalog(self):
|
||||
self.make_file("apt/pool/r/rustproxy/rustproxy_0.34.6-2_amd64.deb")
|
||||
self.make_file("apt/pool/r/rustproxy/rustproxy-docker-agent_0.34.6-2_amd64.deb")
|
||||
self.make_file("rpm/x86_64/rustproxy-0.34.6-2.x86_64.rpm")
|
||||
self.make_file("rpm/x86_64/rustproxy-docker-agent-0.34.6-2.x86_64.rpm")
|
||||
self.make_file("opnsense/26.7/amd64/os-rustproxy-0.34.6_123.pkg")
|
||||
self.make_file("opnsense/packagesite.pkg",contents="index")
|
||||
self.make_file("opnsense/os-rustproxy-latest.pkg",contents="duplicate")
|
||||
self.make_file("freebsd/FreeBSD:15:amd64/rustproxy-0.34.6_123.pkg")
|
||||
self.make_file("freebsd/rustproxy-latest.pkg",contents="duplicate")
|
||||
self.make_file("LINUX-BUILD-INFO.txt",contents="app_version=0.34.6\npackage_release=2\nsource_commit=abc123\nbuilt_at=2026-10-22T08:41:00Z\n")
|
||||
self.make_file("opnsense/BUILD-INFO.txt",contents="app_version=0.34.6\npackage_version=0.34.6_123\nsource_commit=abc123\nbuilt_at=2026-10-22T08:43:00Z\n")
|
||||
self.make_file("freebsd/BUILD-INFO.txt",contents="app_version=0.34.6\npackage_version=0.34.6_123\nsource_commit=abc123\nbuilt_at=2026-10-22T08:45:00Z\n")
|
||||
|
||||
class CatalogTests(RepoFixture, unittest.TestCase):
|
||||
def test_scans_real_file_layout_without_index_duplicates(self):
|
||||
self.make_catalog()
|
||||
catalog = app.generate_catalog(self.repo)
|
||||
self.assertEqual(6, catalog["summary"]["packages_count"])
|
||||
self.assertEqual(3, catalog["summary"]["channels_published"])
|
||||
self.assertEqual(4, catalog["summary"]["channel_counts"]["linux"])
|
||||
self.assertEqual(1, catalog["summary"]["channel_counts"]["opnsense"])
|
||||
self.assertEqual(1, catalog["summary"]["channel_counts"]["freebsd"])
|
||||
self.assertEqual("0.34.6-2",catalog["builds"]["linux"]["package_version"])
|
||||
self.assertEqual("2026-10-22T08:45:00Z",catalog["summary"]["latest_build_at"])
|
||||
linux = [p for p in catalog["packages"] if p["format"] == "RPM"]
|
||||
self.assertEqual({"rustproxy","rustproxy-docker-agent"}, {p["name"] for p in linux})
|
||||
self.assertEqual("2026-10-22T08:41:00Z", linux[0]["built_at"])
|
||||
self.assertEqual("build",linux[0]["date_source"])
|
||||
opnsense = next(p for p in catalog["packages"] if p["channel"] == "opnsense")
|
||||
self.assertTrue(opnsense["download_url"].endswith("/26.7/amd64/os-rustproxy-0.34.6_123.pkg"))
|
||||
freebsd = next(p for p in catalog["packages"] if p["channel"] == "freebsd")
|
||||
self.assertIn("/freebsd/FreeBSD%3A15%3Aamd64/",freebsd["download_url"])
|
||||
self.assertEqual("2026-10-22T08:45:00Z",freebsd["built_at"])
|
||||
|
||||
def test_mtime_backwards_compatibility(self):
|
||||
self.make_file("LINUX-BUILD-INFO.txt",contents="app_version=0.21.0\npackage_release=5\n")
|
||||
self.make_file("rpm/x86_64/rustproxy-0.21.0-5.x86_64.rpm")
|
||||
catalog = app.generate_catalog(self.repo)
|
||||
self.assertEqual("file", catalog["builds"]["linux"]["date_source"])
|
||||
self.assertEqual("file", catalog["packages"][0]["date_source"])
|
||||
self.assertEqual("0.21.0-5",catalog["packages"][0]["version"])
|
||||
self.assertTrue(catalog["packages"][0]["built_at"].endswith("Z"))
|
||||
|
||||
def test_symlink_rotation_gives_current_packages(self):
|
||||
self.make_file("rpm/x86_64/rustproxy-0.1.0-1.x86_64.rpm")
|
||||
v2 = self.repo / "releases" / "r2"
|
||||
v2.mkdir()
|
||||
(v2 / "rpm/x86_64").mkdir(parents=True)
|
||||
(v2 / "rpm/x86_64/rustproxy-0.2.0-1.x86_64.rpm").write_bytes(b"new package")
|
||||
before = app.generate_catalog(self.repo)
|
||||
self.assertEqual("0.1.0-1",before["packages"][0]["version"])
|
||||
(self.repo / "current.new").symlink_to("releases/r2")
|
||||
os.replace(self.repo / "current.new",self.repo / "current")
|
||||
after = app.generate_catalog(self.repo)
|
||||
self.assertEqual("0.2.0-1",after["packages"][0]["version"])
|
||||
|
||||
def test_empty_repo_and_untrusted_symlink(self):
|
||||
first = app.generate_catalog(self.repo)
|
||||
self.assertFalse(first["ready"])
|
||||
self.assertEqual([],first["packages"])
|
||||
(self.repo / "current").unlink()
|
||||
(self.repo / "current").symlink_to(self.temp.name) # outside repo root
|
||||
second = app.generate_catalog(self.repo)
|
||||
self.assertFalse(second["ready"])
|
||||
self.assertEqual([],second["packages"])
|
||||
|
||||
def test_regexes_and_metadata_parser(self):
|
||||
self.assertEqual(("rustproxy-docker-agent","0.34.6-2","x86_64"),app.parse_filename("rustproxy-docker-agent-0.34.6-2.x86_64.rpm","rpm"))
|
||||
self.assertEqual(("os-rustproxy","0.34.6_123","amd64"),app.parse_filename("os-rustproxy-0.34.6_123.pkg","pkg"))
|
||||
self.assertIsNone(app.parse_filename("packagesite.pkg","pkg"))
|
||||
self.assertIsNone(app.parse_filename("rustproxy-latest.pkg","pkg"))
|
||||
self.assertIsNone(app.parse_filename("repomd.xml","rpm"))
|
||||
self.assertEqual({},app.parse_metadata(self.repo/"missing-info.txt"))
|
||||
|
||||
|
||||
class HttpTests(RepoFixture, unittest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.make_catalog()
|
||||
original_cache = app.CACHE
|
||||
app.CACHE = app.CatalogCache(self.repo,ttl=1)
|
||||
self.addCleanup(lambda: setattr(app,"CACHE",original_cache))
|
||||
self.server = ThreadingHTTPServer(("127.0.0.1",0),app.DashboardHandler)
|
||||
self.thread = threading.Thread(target=self.server.serve_forever,daemon=True)
|
||||
self.thread.start()
|
||||
self.addCleanup(self.server.server_close)
|
||||
self.addCleanup(self.server.shutdown)
|
||||
self.base = f"http://127.0.0.1:{self.server.server_port}"
|
||||
|
||||
def test_http_catalog_page_assets_head(self):
|
||||
with urlopen(self.base + "/api/v1/packages") as response:
|
||||
self.assertIn("no-store",response.headers["Cache-Control"])
|
||||
catalog = json.load(response)
|
||||
self.assertEqual(6,len(catalog["packages"]))
|
||||
request = Request(self.base + "/",headers={"X-Repo-Site":"opnsense"})
|
||||
with urlopen(request) as response:
|
||||
html = response.read().decode()
|
||||
self.assertIn('data-site="opnsense"',html)
|
||||
self.assertIn("Package Registry",html)
|
||||
self.assertIn("Content-Security-Policy",response.headers)
|
||||
with urlopen(self.base + "/freebsd/") as response:
|
||||
self.assertIn('data-site="freebsd"',response.read().decode())
|
||||
with urlopen(self.base + "/ui/style.css") as response:
|
||||
self.assertIn("text/css",response.headers["Content-Type"])
|
||||
self.assertIn("--accent:#f69b74",response.read().decode())
|
||||
request = Request(self.base + "/ui/app.js", method="HEAD")
|
||||
with urlopen(request) as response:
|
||||
self.assertEqual(200,response.status)
|
||||
self.assertEqual(b"",response.read())
|
||||
with self.assertRaises(HTTPError) as raised:
|
||||
urlopen(self.base + "/../something")
|
||||
self.assertEqual(404,raised.exception.code)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,136 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Offline simulation of rustup installation/selection; no Rust or network required.
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$WORK/bin" "$WORK/source" "$WORK/state"
|
||||
cat > "$WORK/bin/rustup" <<'MOCK'
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
state=${MOCK_RUSTUP_STATE:?}
|
||||
case "$1" in
|
||||
run)
|
||||
channel=$2
|
||||
[[ -r "$state/$channel.version" ]] || exit 1
|
||||
printf 'rustc %s (mock)\n' "$(cat "$state/$channel.version")"
|
||||
;;
|
||||
toolchain)
|
||||
[[ "$2" == install ]] || exit 7
|
||||
channel=$3
|
||||
[[ ${MOCK_INSTALL_FAIL:-0} != 1 ]] || exit 9
|
||||
case "$channel" in
|
||||
stable) version=${MOCK_NEW_STABLE:-1.100.0} ;;
|
||||
*) case "$channel" in *.*.*) version=$channel ;; *) version=${channel}.0 ;; esac ;;
|
||||
esac
|
||||
echo "$version" > "$state/$channel.version"
|
||||
printf 'install %s\n' "$channel" >> "$state/calls"
|
||||
;;
|
||||
target)
|
||||
action=$2
|
||||
if [[ "$action" == list ]]; then
|
||||
[[ "$3" == --toolchain && "$5" == --installed ]] || exit 7
|
||||
[[ -f "$state/$4.target" ]] && cat "$state/$4.target"
|
||||
elif [[ "$action" == add ]]; then
|
||||
[[ "$4" == --toolchain ]] || exit 7
|
||||
echo "$3" > "$state/$5.target"
|
||||
printf 'target %s %s\n' "$5" "$3" >> "$state/calls"
|
||||
else exit 7
|
||||
fi
|
||||
;;
|
||||
*) printf 'Unexpected rustup arguments: %s\n' "$*" >&2; exit 7 ;;
|
||||
esac
|
||||
MOCK
|
||||
chmod +x "$WORK/bin/rustup"
|
||||
export PATH="$WORK/bin:$PATH" MOCK_RUSTUP_STATE="$WORK/state" TOML_PYTHON=python3
|
||||
TOOL="$ROOT/scripts/ensure-rust-toolchain.sh"
|
||||
reset_state() { rm -f "$WORK/state/"*; }
|
||||
manifest() { printf '[package]\nname = "rust-proxy"\nversion = "0.31.2"\nrust-version = "%s"\n' "$1" > "$WORK/source/Cargo.toml"; rm -f "$WORK/source/rust-toolchain" "$WORK/source/rust-toolchain.toml"; }
|
||||
|
||||
# No update or download when installed stable already satisfies the manifest.
|
||||
reset_state
|
||||
manifest 1.99
|
||||
printf '1.100.0\n' > "$WORK/state/stable.version"
|
||||
result=$($TOOL "$WORK/source" linux)
|
||||
[[ "$result" == stable ]]
|
||||
[[ ! -e "$WORK/state/calls" ]]
|
||||
|
||||
# Upgrade stable only when too old, then reuse it on subsequent checks.
|
||||
reset_state
|
||||
printf '1.98.1\n' > "$WORK/state/stable.version"
|
||||
result=$($TOOL "$WORK/source" linux)
|
||||
[[ "$result" == stable ]]
|
||||
grep -Fqx 'install stable' "$WORK/state/calls"
|
||||
[[ $($TOOL "$WORK/source" linux) == stable ]]
|
||||
[[ $(wc -l < "$WORK/state/calls") == 1 ]]
|
||||
|
||||
# FreeBSD default 1.88 is auto raised to the project's 1.99 MSRV with its own target.
|
||||
reset_state
|
||||
result=$(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd)
|
||||
[[ "$result" == 1.99 ]]
|
||||
grep -Fqx 'install 1.99' "$WORK/state/calls"
|
||||
grep -Fqx 'target 1.99 x86_64-unknown-freebsd' "$WORK/state/calls"
|
||||
[[ $(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) == 1.99 ]]
|
||||
[[ $(wc -l < "$WORK/state/calls") == 2 ]]
|
||||
|
||||
# A deliberate rust-toolchain.toml pin is respected; do not silently override it.
|
||||
reset_state
|
||||
cat > "$WORK/source/rust-toolchain.toml" <<'PIN'
|
||||
[toolchain]
|
||||
channel = "1.98.0"
|
||||
PIN
|
||||
if "$TOOL" "$WORK/source" linux >/dev/null 2>&1; then
|
||||
printf 'An incompatible explicit pin should have failed\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -e "$WORK/state/calls" ]] || { echo 'Should not install an incompatible pin' >&2; exit 1; }
|
||||
rm "$WORK/source/rust-toolchain.toml"
|
||||
|
||||
# Pin that meets the project requirement is installed without changing stable.
|
||||
reset_state
|
||||
cat > "$WORK/source/rust-toolchain.toml" <<'PIN'
|
||||
[toolchain]
|
||||
channel = "1.99.0"
|
||||
PIN
|
||||
[[ $($TOOL "$WORK/source" linux) == 1.99.0 ]]
|
||||
grep -Fqx 'install 1.99.0' "$WORK/state/calls"
|
||||
rm "$WORK/source/rust-toolchain.toml"
|
||||
|
||||
# RustProxy-like rust-toolchain.toml (stable) also upgrades stale stable for FreeBSD.
|
||||
reset_state
|
||||
manifest 1.99
|
||||
cat > "$WORK/source/rust-toolchain.toml" <<'PIN'
|
||||
[toolchain]
|
||||
channel = "stable"
|
||||
profile = "minimal"
|
||||
components = ["rustfmt", "clippy"]
|
||||
PIN
|
||||
printf '1.98.1\n' > "$WORK/state/stable.version"
|
||||
[[ $(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) == stable ]]
|
||||
grep -Fqx 'install stable' "$WORK/state/calls"
|
||||
grep -Fqx 'target stable x86_64-unknown-freebsd' "$WORK/state/calls"
|
||||
rm "$WORK/source/rust-toolchain.toml"
|
||||
|
||||
# Workspace-inherited rust-version is resolved through TOML, not grep.
|
||||
reset_state
|
||||
cat > "$WORK/source/Cargo.toml" <<'MANIFEST'
|
||||
[workspace.package]
|
||||
rust-version = "1.99"
|
||||
[package]
|
||||
name = "rust-proxy"
|
||||
version = "0.31.2"
|
||||
rust-version = { workspace = true }
|
||||
MANIFEST
|
||||
printf '1.100.0\n' > "$WORK/state/stable.version"
|
||||
[[ $($TOOL "$WORK/source" linux) == stable ]]
|
||||
|
||||
# An unavailable upgrade must be a hard failure.
|
||||
reset_state
|
||||
manifest 1.99
|
||||
printf '1.98.1\n' > "$WORK/state/stable.version"
|
||||
if MOCK_INSTALL_FAIL=1 "$TOOL" "$WORK/source" linux >/dev/null 2>&1; then
|
||||
printf 'A failed rustup update should abort the build\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 'Rust toolchain selection: 8 offline scenarios OK'
|
||||
Reference in new issue
Block a user