new_version
This commit is contained in:
1 parent
910bb563f0
commit
a946c38194
32 files changed
+809
-65
No files matched your search
@@ -5,9 +5,10 @@ Jeden kontener buildera buduje z jednego commita RustProxy:
|
||||
- Linux x86_64: DEB + podpisane repo APT,
|
||||
- Linux x86_64: RPM + podpisane repo DNF/YUM,
|
||||
- FreeBSD x86_64: cross-build bez VM FreeBSD,
|
||||
- OPNsense: `os-rustproxy-<version>_<revision>.pkg` + statyczne repo `pkg`.
|
||||
- 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).
|
||||
|
||||
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 i gałąź OPNsense są budowane oraz publikowane niezależnie, więc błąd testów Linux nie blokuje pakietu FreeBSD.
|
||||
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.
|
||||
|
||||
## Szybki start
|
||||
|
||||
@@ -49,17 +50,20 @@ opn-rustproxy.linuxiarz.pl -> http://builder:18766
|
||||
wspólny checkout
|
||||
/ \
|
||||
/ \
|
||||
Linux branch OPNsense branch
|
||||
cargo test izolowana kopia źródła
|
||||
cargo build poprawki FreeBSD
|
||||
DEB + RPM cross-build FreeBSD
|
||||
APT + DNF os-rustproxy.pkg
|
||||
| |
|
||||
v v
|
||||
publikacja Linux publikacja OPNsense
|
||||
Linux branch FreeBSD cross-build
|
||||
cargo test |
|
||||
cargo build +---+---+
|
||||
DEB + RPM | |
|
||||
APT + DNF OPNsense FreeBSD native*
|
||||
| | |
|
||||
v v v
|
||||
publikacja Linux os-rustproxy rustproxy.pkg
|
||||
pkg repo pkg repo
|
||||
|
||||
* FreeBSD native: FREEBSD_NATIVE_ENABLED=1
|
||||
```
|
||||
|
||||
`cargo test` należy 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` i `last_opnsense_commit`, więc kolejny cykl ponawia tylko brakującą gałąź.
|
||||
`cargo test` należy 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łąź.
|
||||
|
||||
## OPNsense repo
|
||||
|
||||
@@ -124,6 +128,8 @@ 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/`.
|
||||
|
||||
## Automatyczny Rust toolchain podczas budowania
|
||||
|
||||
Builder sprawdza `rust-version` w `Cargo.toml` **pobranego commita** i opcjonalny
|
||||
@@ -203,17 +209,17 @@ configctl template reload OPNsense/RustProxy
|
||||
configctl rustproxy start
|
||||
```
|
||||
|
||||
Zmiana wtyczki zwiększa tylko `OPNSENSE_PACKAGING_REVISION` do `3`.
|
||||
Rewizja pakowania Linux (`PACKAGING_REVISION=2`) pozostaje bez zmian.
|
||||
Obsługa miękkiego przeładowania zwiększa `OPNSENSE_PACKAGING_REVISION` do `4`.
|
||||
Pakowanie Linux ma `PACKAGING_REVISION=3`, a natywne FreeBSD `FREEBSD_NATIVE_PACKAGING_REVISION=1`. Każdy kanał otrzymuje osobną aktualizację przy zmianie swojej rewizji.
|
||||
|
||||
## Rotacja logów RustProxy
|
||||
|
||||
- **DEB/RPM:** builder zawsze umieszcza `packaging/rustproxy.logrotate` w `/etc/logrotate.d/rustproxy` (nFPM: `config|noreplace`). Logrotate jest zależnością obu pakietów. Reguła obejmuje `/var/log/rustproxy/*.jsonl`, `*.log` i `vhosts/*.jsonl`, z rotacją codzienną lub po przekroczeniu 100 MiB, 14 archiwami, gzip z opóźnioną kompresją, `copytruncate` oraz `su rustproxy rustproxy`.
|
||||
- **OPNsense/FreeBSD PKG:** pakiet dostarcza `/usr/local/etc/newsyslog.conf.d/rustproxy.conf` dla tych samych ścieżek; `newsyslog` wykonuje rotację codziennie lub przy rozmiarze 100 MiB, przechowuje 14 archiwów, pomija puste pliki i używa gzip z niekompresowanym najnowszym archiwum. Plik `*.log` jest ponownie otwierany przez `daemon(8)` po `SIGHUP` (opcja `-H` w skrypcie rc.d). OPNsense uruchamia usługę jako `root`, dlatego `newsyslog` używa `root:wheel`.
|
||||
- **OPNsense / natywne FreeBSD PKG:** pakiet dostarcza `/usr/local/etc/newsyslog.conf.d/rustproxy.conf` dla tych samych ścieżek; `newsyslog` wykonuje rotację codziennie lub przy rozmiarze 100 MiB, przechowuje 14 archiwów, pomija puste pliki i używa gzip z niekompresowanym najnowszym archiwum. Plik `*.log` jest ponownie otwierany przez `daemon(8)` po `SIGHUP` (opcja `-H` w skrypcie rc.d). OPNsense uruchamia usługę jako `root` (`root:wheel` w `newsyslog`); natywne FreeBSD działa jako `rustproxy` (`rustproxy:rustproxy` w `newsyslog`).
|
||||
|
||||
**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.
|
||||
|
||||
Poprzednia zmiana rotacji logów ustawiła `PACKAGING_REVISION=2`. `check-and-build.sh` sprawdza osobno rewizję pakowania Linux i OPNsense; 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).
|
||||
Wersja buildera z obsługą reload zwiększa `PACKAGING_REVISION=3` 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).
|
||||
|
||||
Kontrola po zainstalowaniu:
|
||||
|
||||
@@ -245,16 +251,17 @@ data/
|
||||
│ ├── apt -> current/apt
|
||||
│ ├── rpm -> current/rpm
|
||||
│ ├── opnsense -> current/opnsense
|
||||
│ ├── freebsd -> current/freebsd
|
||||
│ └── releases/
|
||||
├── state/
|
||||
└── work/
|
||||
```
|
||||
|
||||
Każda publikacja tworzy nowy snapshot `repository/releases/...` i atomowo przełącza `current`. Przy publikacji Linux poprzedni katalog OPNsense jest zachowywany, a przy publikacji OPNsense zachowywane są aktualne APT/RPM. Dzięki temu obie gałęzie są niezależne, ale nginx nadal serwuje jeden spójny snapshot katalogu.
|
||||
Każda publikacja tworzy nowy snapshot `repository/releases/...` i atomowo przełącza `current`. Przy publikacji jednego kanału poprzednie katalogi pozostałych kanałów są zachowywane. Dzięki temu wszystkie aktywne kanały są niezależne, ale nginx nadal serwuje jeden spójny snapshot katalogu.
|
||||
|
||||
## HTTP i logi
|
||||
|
||||
Jeden kontener nginx obsługuje oba repozytoria na dwóch lokalnych portach:
|
||||
Jeden kontener nginx obsługuje repo Linux i repo OPNsense na dwóch lokalnych portach; natywne FreeBSD jest serwowane jako `/freebsd/` na porcie OPNsense:
|
||||
|
||||
```bash
|
||||
docker compose logs -f rust-package-builder
|
||||
@@ -292,7 +299,7 @@ The OPNsense branch reuses the Cargo package `VERSION` already detected by the m
|
||||
|
||||
### Czyszczenie cache Cargo
|
||||
|
||||
Po **udanym opublikowaniu pakietów** każdej gałęzi (Linux/OPNsense) builder
|
||||
Po **udanym opublikowaniu pakietów** każdej gałęzi (Linux/OPNsense/FreeBSD native) builder
|
||||
usuwa `target/**/incremental` i `target/debug`, a także pliki starsze
|
||||
niż 30 dni z `target/release/deps` oraz
|
||||
`target/x86_64-unknown-freebsd/release/deps`. Zachowuje aktualne artefakty
|
||||
@@ -302,3 +309,59 @@ od zera. Starsze usunięte zależności mogą wymagać pojedynczej rekompilacji.
|
||||
Ustawienia środowiskowe: `CLEAN_TARGET_AFTER_BUILD=0` wyłącza czyszczenie;
|
||||
`TARGET_CACHE_MAX_AGE_DAYS=30` określa wiek nieużywanych plików.
|
||||
|
||||
|
||||
## RustProxy 0.34.x: plik `--config` i miękki reload
|
||||
|
||||
- **Linux DEB/RPM:** gdy usługa systemd nie ma własnego `ExecReload`, builder dodaje wywołanie `rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 reload`. `systemctl reload rustproxy` wykonuje przeładowanie przez administracyjne API, nie restartuje procesu. Usługi z `ProtectSystem=strict` otrzymują dodatkowo zapis do `-/etc/rustproxy`. Aby panel mógł zapisywać wskazany `--config`, plik i jego katalog muszą być własnością użytkownika usługi. Przykładowo można ustawić `RUST_PROXY_CONFIG=/etc/rustproxy/config.json` w `/etc/rustproxy/environment`, po uprzednim utworzeniu poprawnego pliku JSON.
|
||||
- **OPNsense:** `configctl rustproxy reload` wykonuje miękkie przeładowanie z CLI. Skrypt `service.sh` nie robi już stop/start dla `reload`. Listener GUI po zmianie adresu/portu wymaga nadal `restart`, ponieważ samo przeładowanie nie zmienia gniazd nasłuchujących. Opcjonalna ścieżka `rustproxy_config_path` w `rc.conf` (absolutna, bez spacji) jest przekazywana jako `--config`; panel OPNsense nie ma jeszcze osobnego pola do jej edycji. CLI wymaga osiągalnego adresu administratora na loopback.
|
||||
- **Czystemu FreeBSD** służy osobna paczka `rustproxy`, bez modeli MVC, configd, syshooków i pluginu OPNsense. Jej natywne `rc.d` uruchamia usługę na koncie `rustproxy`, domyślnie nasłuchuje na HTTP `8080`, admin na `127.0.0.1:9090`, a TLS jest domyślnie wyłączony. Po `sysrc rustproxy_enable=YES` można wykonać `service rustproxy start`, `service rustproxy reload` i `service rustproxy restart`. Ścieżkę JSON można przekazać przez `sysrc rustproxy_config=/usr/local/etc/rustproxy/config.json` po przygotowaniu prawidłowego pliku z uprawnieniami użytkownika `rustproxy`.
|
||||
|
||||
**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
|
||||
|
||||
W pliku `.env` ustaw:
|
||||
|
||||
```env
|
||||
FREEBSD_NATIVE_ENABLED=1
|
||||
FREEBSD_NATIVE_RETENTION=10
|
||||
```
|
||||
|
||||
Następnie `./start.sh`. Automatyczna publikacja katalogu `pkg` pojawi się pod:
|
||||
|
||||
```text
|
||||
${OPNSENSE_REPOSITORY_URL}/freebsd/
|
||||
RustProxy-FreeBSD.conf
|
||||
meta.conf
|
||||
packagesite.pkg
|
||||
data.pkg
|
||||
rustproxy-latest.pkg
|
||||
FreeBSD:15:amd64/rustproxy-<wersja>_<revision>.pkg
|
||||
```
|
||||
|
||||
Na **czystym FreeBSD 15 amd64**:
|
||||
|
||||
```sh
|
||||
mkdir -p /usr/local/etc/pkg/repos
|
||||
fetch -o /usr/local/etc/pkg/repos/RustProxy-FreeBSD.conf \
|
||||
https://YOUR-OPNSENSE-REPO-HOST/freebsd/RustProxy-FreeBSD.conf
|
||||
pkg update -f
|
||||
pkg install rustproxy
|
||||
sysrc rustproxy_enable=YES
|
||||
service rustproxy start
|
||||
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.
|
||||
|
||||
Pakietowe testy offline:
|
||||
|
||||
```sh
|
||||
./tests/static.sh
|
||||
./tests/opnsense-plugin.sh
|
||||
./tests/log-rotation.sh
|
||||
./tests/freebsd-native.sh
|
||||
./tests/toolchains.sh
|
||||
```
|
||||
@@ -25,6 +25,8 @@ 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_RETENTION: "${FREEBSD_NATIVE_RETENTION:-10}"
|
||||
volumes:
|
||||
- ./data:/var/lib/package-builder
|
||||
- ./gpg:/run/secrets/gpg:ro
|
||||
|
||||
@@ -88,6 +88,15 @@ http {
|
||||
return 200 "ok\n";
|
||||
}
|
||||
|
||||
# Native FreeBSD package repo at <OPNSENSE_REPOSITORY_URL>/freebsd/.
|
||||
# Keep a distinct catalog so clients never see the OPNsense plugin.
|
||||
location = /freebsd { return 301 /freebsd/; }
|
||||
location /freebsd/ {
|
||||
alias /srv/repository/freebsd/;
|
||||
index index.html;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location = / {
|
||||
try_files /index.html @opnsense_initializing;
|
||||
}
|
||||
|
||||
Executable → Regular
File mode changed.
Executable → Regular
File mode changed.
@@ -18,6 +18,8 @@ load_rc_config "$name"
|
||||
: ${rustproxy_user:="root"}
|
||||
: ${rustproxy_group:="wheel"}
|
||||
: ${rustproxy_data_dir:="/var/db/rustproxy"}
|
||||
# Optional external canonical JSON (absolute path without spaces).
|
||||
: ${rustproxy_config_path:=""}
|
||||
: ${rustproxy_log_dir:="/var/log/rustproxy"}
|
||||
: ${rustproxy_log_file:="${rustproxy_log_dir}/rustproxy.log"}
|
||||
: ${rustproxy_run_dir:="/var/run/rustproxy"}
|
||||
@@ -163,7 +165,20 @@ if ! rustproxy_valid_update_interval "$rustproxy_update_check_interval_secs"; th
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rustproxy_runtime_args="--data-dir ${rustproxy_data_dir} --admin-listen ${rustproxy_admin_listen_resolved} --update-check-interval-secs ${rustproxy_update_check_interval_secs} serve --proxy-listen ${rustproxy_proxy_listen_resolved}"
|
||||
# Restrict to shell-safe absolute paths because rc.subr expands command_args.
|
||||
rustproxy_config_arg=""
|
||||
if [ -n "${rustproxy_config_path}" ]; then
|
||||
case "${rustproxy_config_path}" in
|
||||
/*) ;;
|
||||
*) echo "rustproxy_config_path must be an absolute path" >&2; exit 1 ;;
|
||||
esac
|
||||
case "${rustproxy_config_path}" in
|
||||
*[!a-zA-Z0-9_./-]*) echo "rustproxy_config_path contains unsupported characters" >&2; exit 1 ;;
|
||||
esac
|
||||
rustproxy_config_arg="--config ${rustproxy_config_path}"
|
||||
fi
|
||||
|
||||
rustproxy_runtime_args="--data-dir ${rustproxy_data_dir} ${rustproxy_config_arg} --admin-listen ${rustproxy_admin_listen_resolved} --update-check-interval-secs ${rustproxy_update_check_interval_secs} serve --proxy-listen ${rustproxy_proxy_listen_resolved}"
|
||||
if [ "$rustproxy_tls_enabled" = "1" ]; then
|
||||
rustproxy_runtime_args="${rustproxy_runtime_args} --tls-listen ${rustproxy_tls_listen_resolved}"
|
||||
fi
|
||||
@@ -186,6 +201,8 @@ start_precmd="rustproxy_prestart"
|
||||
start_postcmd="rustproxy_poststart"
|
||||
stop_postcmd="rustproxy_poststop"
|
||||
status_cmd="rustproxy_status"
|
||||
extra_commands="reload"
|
||||
reload_cmd="rustproxy_reload"
|
||||
|
||||
rustproxy_prestart()
|
||||
{
|
||||
@@ -286,6 +303,25 @@ rustproxy_status()
|
||||
return 1
|
||||
}
|
||||
|
||||
rustproxy_reload()
|
||||
{
|
||||
# rust-proxy reload authenticates locally via SQLite; it must run as the
|
||||
# same account as the daemon and address the listener through loopback.
|
||||
rustproxy_child_pid >/dev/null || {
|
||||
echo "RustProxy is not running; nothing to reload" >&2
|
||||
return 1
|
||||
}
|
||||
_rp_port="${rustproxy_admin_listen_resolved##*:}"
|
||||
case "${rustproxy_admin_listen_resolved}" in
|
||||
\[*\]:*) _rp_local_admin="[::1]:${_rp_port}" ;;
|
||||
*:*) _rp_local_admin="127.0.0.1:${_rp_port}" ;;
|
||||
*) echo "Invalid RustProxy administration listen address" >&2; return 1 ;;
|
||||
esac
|
||||
# The optional path is already checked for safe characters above.
|
||||
${rustproxy_command} --data-dir "${rustproxy_data_dir}" ${rustproxy_config_arg} \
|
||||
--admin-listen "${_rp_local_admin}" reload
|
||||
}
|
||||
|
||||
rustproxy_poststop()
|
||||
{
|
||||
/bin/rm -f "${child_pidfile}" "${pidfile}"
|
||||
|
||||
@@ -36,10 +36,19 @@ case "${1:-}" in
|
||||
stop)
|
||||
stop_service
|
||||
;;
|
||||
restart|reload)
|
||||
restart)
|
||||
stop_service
|
||||
start_service
|
||||
;;
|
||||
reload)
|
||||
if [ "$enabled" != "1" ]; then
|
||||
echo "RustProxy is disabled in OPNsense configuration" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Soft reload is performed by rust-proxy CLI through the live admin API.
|
||||
# Listener changes from the GUI still require the explicit restart action.
|
||||
"$RC_SCRIPT" reload
|
||||
;;
|
||||
status)
|
||||
"$RC_SCRIPT" status
|
||||
;;
|
||||
|
||||
@@ -20,7 +20,7 @@ message:restarting RustProxy
|
||||
allowed_groups:wheel,wwwonly
|
||||
|
||||
[reload]
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh restart
|
||||
command:/usr/local/opnsense/scripts/rustproxy/service.sh reload
|
||||
parameters:
|
||||
type:script
|
||||
message:reloading RustProxy
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
# Do not start the service by default on fresh installation.
|
||||
if ! /usr/sbin/pw groupshow rustproxy >/dev/null 2>&1; then
|
||||
/usr/sbin/pw groupadd rustproxy
|
||||
fi
|
||||
if ! /usr/sbin/pw usershow rustproxy >/dev/null 2>&1; then
|
||||
/usr/sbin/pw useradd rustproxy -g rustproxy -c 'RustProxy reverse proxy' -d /var/db/rustproxy -s /usr/sbin/nologin
|
||||
fi
|
||||
/usr/bin/install -d -m 0700 -o rustproxy -g rustproxy /var/db/rustproxy
|
||||
/usr/bin/install -d -m 0750 -o rustproxy -g rustproxy /var/log/rustproxy
|
||||
/usr/bin/install -d -m 0700 -o rustproxy -g rustproxy /usr/local/etc/rustproxy
|
||||
# On upgrades pkg executes the former pre-deinstall hook first.
|
||||
if /usr/sbin/service rustproxy enabled >/dev/null 2>&1; then
|
||||
/usr/sbin/service rustproxy start || echo 'Warning: RustProxy requires attention; see /var/log/rustproxy/rustproxy.log' >&2
|
||||
else
|
||||
echo 'Enable RustProxy with: sysrc rustproxy_enable=YES && service rustproxy start'
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# Also stop on upgrade, before the old executable is replaced.
|
||||
/usr/sbin/service rustproxy onestop >/dev/null 2>&1 || true
|
||||
exit 0
|
||||
@@ -0,0 +1,5 @@
|
||||
# Native FreeBSD RustProxy logs; daemon(8) -H reopens supervised stdout.
|
||||
# For application-written JSONL, verify that the writer reopens rotated files.
|
||||
/var/log/rustproxy/*.jsonl rustproxy:rustproxy 0640 14 100M $D0 GBEZPN
|
||||
/var/log/rustproxy/*.log rustproxy:rustproxy 0640 14 100M $D0 GBEZP /var/run/rustproxy/daemon.pid SIGHUP
|
||||
/var/log/rustproxy/vhosts/*.jsonl rustproxy:rustproxy 0640 14 100M $D0 GBEZPN
|
||||
@@ -0,0 +1,135 @@
|
||||
#!/bin/sh
|
||||
# PROVIDE: rustproxy
|
||||
# REQUIRE: LOGIN NETWORKING
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
name=rustproxy
|
||||
rcvar=rustproxy_enable
|
||||
load_rc_config "$name"
|
||||
|
||||
: ${rustproxy_enable:="NO"}
|
||||
: ${rustproxy_user:="rustproxy"}
|
||||
: ${rustproxy_group:="rustproxy"}
|
||||
: ${rustproxy_data_dir:="/var/db/rustproxy"}
|
||||
: ${rustproxy_log_dir:="/var/log/rustproxy"}
|
||||
: ${rustproxy_run_dir:="/var/run/rustproxy"}
|
||||
: ${rustproxy_config:=""}
|
||||
: ${rustproxy_proxy_listen:="0.0.0.0:8080"}
|
||||
: ${rustproxy_tls_listen:=""}
|
||||
: ${rustproxy_admin_listen:="127.0.0.1:9090"}
|
||||
: ${rustproxy_allow_remote_admin:="NO"}
|
||||
: ${rustproxy_update_check_interval_secs:="3600"}
|
||||
|
||||
# rc.subr expands command_args; permit only simple shell-safe paths and
|
||||
# IPv4 socket addresses to avoid command injection from rc.conf settings.
|
||||
rustproxy_safe_path()
|
||||
{
|
||||
case "$1" in
|
||||
/*) ;;
|
||||
*) echo "RustProxy requires absolute paths: $1" >&2; return 1 ;;
|
||||
esac
|
||||
case "$1" in
|
||||
*[!a-zA-Z0-9_./-]*) echo "Unsupported path characters: $1" >&2; return 1 ;;
|
||||
esac
|
||||
}
|
||||
rustproxy_safe_listen()
|
||||
{
|
||||
case "$1" in
|
||||
*[!0-9.:]*|''|*::*) echo "Only IPv4 host:port listeners are supported by this rc.d script: $1" >&2; return 1 ;;
|
||||
*:*) ;;
|
||||
*) echo "Missing listener port: $1" >&2; return 1 ;;
|
||||
esac
|
||||
}
|
||||
case "${rustproxy_user}:${rustproxy_group}" in
|
||||
*[!a-zA-Z0-9_:-]*) echo 'Unsupported user/group name' >&2; exit 1 ;;
|
||||
esac
|
||||
for rp_path in "$rustproxy_data_dir" "$rustproxy_log_dir" "$rustproxy_run_dir"; do
|
||||
rustproxy_safe_path "$rp_path" || exit 1
|
||||
done
|
||||
if [ -n "$rustproxy_config" ]; then
|
||||
rustproxy_safe_path "$rustproxy_config" || exit 1
|
||||
fi
|
||||
rustproxy_safe_listen "$rustproxy_proxy_listen" || exit 1
|
||||
rustproxy_safe_listen "$rustproxy_admin_listen" || exit 1
|
||||
if [ -n "$rustproxy_tls_listen" ]; then
|
||||
rustproxy_safe_listen "$rustproxy_tls_listen" || exit 1
|
||||
fi
|
||||
case "$rustproxy_update_check_interval_secs" in
|
||||
''|*[!0-9]*) echo 'Invalid update interval' >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
rustproxy_bin="/usr/local/sbin/rust-proxy"
|
||||
rustproxy_config_arg=""
|
||||
if [ -n "$rustproxy_config" ]; then
|
||||
rustproxy_config_arg="--config ${rustproxy_config}"
|
||||
fi
|
||||
rustproxy_args="--data-dir ${rustproxy_data_dir} ${rustproxy_config_arg} --admin-listen ${rustproxy_admin_listen} --update-check-interval-secs ${rustproxy_update_check_interval_secs} serve --proxy-listen ${rustproxy_proxy_listen}"
|
||||
if [ -n "$rustproxy_tls_listen" ]; then
|
||||
rustproxy_args="${rustproxy_args} --tls-listen ${rustproxy_tls_listen}"
|
||||
fi
|
||||
if checkyesno rustproxy_allow_remote_admin; then
|
||||
rustproxy_args="${rustproxy_args} --allow-remote-admin"
|
||||
fi
|
||||
|
||||
pidfile="${rustproxy_run_dir}/daemon.pid"
|
||||
child_pidfile="${rustproxy_run_dir}/rustproxy.pid"
|
||||
command="/usr/sbin/daemon"
|
||||
command_args="-r -R 5 -H -P ${pidfile} -p ${child_pidfile} -u ${rustproxy_user} -o ${rustproxy_log_dir}/rustproxy.log ${rustproxy_bin} ${rustproxy_args}"
|
||||
required_files="${rustproxy_bin}"
|
||||
start_precmd="rustproxy_prestart"
|
||||
stop_postcmd="rustproxy_poststop"
|
||||
status_cmd="rustproxy_status"
|
||||
extra_commands="reload"
|
||||
reload_cmd="rustproxy_reload"
|
||||
|
||||
rustproxy_prestart()
|
||||
{
|
||||
/usr/bin/install -d -m 0750 -o "${rustproxy_user}" -g "${rustproxy_group}" "${rustproxy_run_dir}"
|
||||
/usr/bin/install -d -m 0700 -o "${rustproxy_user}" -g "${rustproxy_group}" "${rustproxy_data_dir}"
|
||||
/usr/bin/install -d -m 0750 -o "${rustproxy_user}" -g "${rustproxy_group}" "${rustproxy_log_dir}"
|
||||
/usr/bin/touch "${rustproxy_log_dir}/rustproxy.log"
|
||||
/usr/sbin/chown "${rustproxy_user}:${rustproxy_group}" "${rustproxy_log_dir}/rustproxy.log"
|
||||
/bin/chmod 0640 "${rustproxy_log_dir}/rustproxy.log"
|
||||
}
|
||||
|
||||
rustproxy_child_pid()
|
||||
{
|
||||
[ -r "$child_pidfile" ] || return 1
|
||||
rp_pid=$(/bin/cat "$child_pidfile" 2>/dev/null)
|
||||
case "$rp_pid" in
|
||||
''|*[!0-9]*) return 1 ;;
|
||||
esac
|
||||
/bin/kill -0 "$rp_pid" 2>/dev/null || return 1
|
||||
printf '%s\n' "$rp_pid"
|
||||
}
|
||||
|
||||
rustproxy_status()
|
||||
{
|
||||
if rp_pid=$(rustproxy_child_pid); then
|
||||
echo "rustproxy is running as pid $rp_pid"
|
||||
return 0
|
||||
fi
|
||||
echo 'rustproxy is not running'
|
||||
return 1
|
||||
}
|
||||
|
||||
rustproxy_reload()
|
||||
{
|
||||
rustproxy_child_pid >/dev/null || {
|
||||
echo 'RustProxy is not running; cannot reload' >&2
|
||||
return 1
|
||||
}
|
||||
# Change to the daemon's UID. Reload creates a short-lived SQLite session.
|
||||
# A root-owned SQLite WAL would make the next reload/save fail.
|
||||
rp_port="${rustproxy_admin_listen##*:}"
|
||||
rp_command="${rustproxy_bin} --data-dir ${rustproxy_data_dir} ${rustproxy_config_arg} --admin-listen 127.0.0.1:${rp_port} reload"
|
||||
/usr/bin/su -m "${rustproxy_user}" -c "exec ${rp_command}"
|
||||
}
|
||||
|
||||
rustproxy_poststop()
|
||||
{
|
||||
/bin/rm -f "$child_pidfile" "$pidfile"
|
||||
}
|
||||
|
||||
run_rc_command "$1"
|
||||
Executable
+118
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
|
||||
: "${SHA:?SHA required}"
|
||||
: "${SRC:?SRC required}"
|
||||
: "${OUT:?OUT required}"
|
||||
: "${VERSION:?VERSION required}"
|
||||
: "${SOURCE_REVISION:?SOURCE_REVISION required}"
|
||||
|
||||
REPOSITORY="$DATA_DIR/repository"
|
||||
BRANCH_RELEASE_ID="$(date -u '+%Y%m%dT%H%M%SZ')-${SHORT_SHA}-freebsd"
|
||||
RELEASE_DIR="$REPOSITORY/releases/$BRANCH_RELEASE_ID"
|
||||
PUBLISHED=0
|
||||
cleanup_freebsd_release() {
|
||||
if [[ "$PUBLISHED" != "1" && -d "$RELEASE_DIR" ]]; then
|
||||
rm -rf "$RELEASE_DIR"
|
||||
fi
|
||||
}
|
||||
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"
|
||||
fi
|
||||
|
||||
FREEBSD_PACKAGE_REVISION=$SOURCE_REVISION
|
||||
LAST_FREEBSD_PACKAGE_VERSION=""
|
||||
if [[ -r "$DATA_DIR/state/last_freebsd_package_version" ]]; then
|
||||
LAST_FREEBSD_PACKAGE_VERSION=$(cat "$DATA_DIR/state/last_freebsd_package_version")
|
||||
elif [[ -r "$REPOSITORY/current/freebsd/BUILD-INFO.txt" ]]; then
|
||||
LAST_FREEBSD_PACKAGE_VERSION=$(sed -n 's/^package_version=//p' "$REPOSITORY/current/freebsd/BUILD-INFO.txt" | head -n1)
|
||||
fi
|
||||
if [[ "$LAST_FREEBSD_PACKAGE_VERSION" == "${VERSION}_"* ]]; then
|
||||
LAST_FREEBSD_REVISION=${LAST_FREEBSD_PACKAGE_VERSION#"${VERSION}_"}
|
||||
if [[ "$LAST_FREEBSD_REVISION" =~ ^[0-9]+$ ]] && (( LAST_FREEBSD_REVISION >= FREEBSD_PACKAGE_REVISION )); then
|
||||
FREEBSD_PACKAGE_REVISION=$((LAST_FREEBSD_REVISION + 1))
|
||||
fi
|
||||
fi
|
||||
if (( FREEBSD_PACKAGE_REVISION == 0 )); then
|
||||
FREEBSD_PACKAGE_REVISION=1
|
||||
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 \
|
||||
"$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"
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "$REPOSITORY/current" ]]; then
|
||||
CURRENT_LINK=$(readlink "$REPOSITORY/current")
|
||||
CURRENT_TARGET="$REPOSITORY/$CURRENT_LINK"
|
||||
fi
|
||||
|
||||
log 'staging native FreeBSD repository snapshot'
|
||||
if [[ -n "$CURRENT_TARGET" ]]; then
|
||||
for component in apt rpm opnsense freebsd; do
|
||||
if [[ -d "$CURRENT_TARGET/$component" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/$component"/ "$CURRENT_TARGET/$component"/ "$RELEASE_DIR/$component"/
|
||||
fi
|
||||
done
|
||||
for copied in repo-key.gpg index.html LINUX-BUILD-INFO.txt; do
|
||||
if [[ -f "$CURRENT_TARGET/$copied" ]]; then
|
||||
cp -a "$CURRENT_TARGET/$copied" "$RELEASE_DIR/$copied"
|
||||
fi
|
||||
done
|
||||
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"
|
||||
NATIVE_URL="${OPNSENSE_REPOSITORY_URL%/}/freebsd"
|
||||
cat > "$RELEASE_DIR/freebsd/RustProxy-FreeBSD.conf" <<CONF
|
||||
RustProxyNative: {
|
||||
url: "${NATIVE_URL}",
|
||||
enabled: yes,
|
||||
mirror_type: "none",
|
||||
signature_type: "none"
|
||||
}
|
||||
CONF
|
||||
cp -f "$FREEBSD_PACKAGE_FILE" "$RELEASE_DIR/freebsd/rustproxy-latest.pkg"
|
||||
(cd "$RELEASE_DIR/freebsd" && sha256sum "$FREEBSD_ABI/$(basename "$FREEBSD_PACKAGE_FILE")") > "$RELEASE_DIR/freebsd/SHA256"
|
||||
cat > "$RELEASE_DIR/freebsd/BUILD-INFO.txt" <<INFO
|
||||
app_version=$VERSION
|
||||
package_version=$FREEBSD_PACKAGE_VERSION
|
||||
source_url=$SOURCE_REPO
|
||||
source_ref=$SOURCE_BRANCH
|
||||
source_commit=$SHA
|
||||
build_reason=$BUILD_REASON
|
||||
source_revision=$SOURCE_REVISION
|
||||
packaging_revision=$FREEBSD_NATIVE_PACKAGING_REVISION
|
||||
freebsd_release=$FREEBSD_RELEASE
|
||||
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"
|
||||
|
||||
[[ -s "$RELEASE_DIR/freebsd/index.html" ]]
|
||||
[[ -s "$RELEASE_DIR/freebsd/meta.conf" ]]
|
||||
[[ -s "$RELEASE_DIR/freebsd/packagesite.pkg" ]]
|
||||
[[ -s "$RELEASE_DIR/freebsd/data.pkg" ]]
|
||||
[[ -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'
|
||||
|
||||
log 'publishing native FreeBSD repository branch'
|
||||
rm -f "$REPOSITORY/current.new"
|
||||
ln -s "releases/$BRANCH_RELEASE_ID" "$REPOSITORY/current.new"
|
||||
mv -Tf "$REPOSITORY/current.new" "$REPOSITORY/current"
|
||||
PUBLISHED=1
|
||||
printf '%s\n' "$SHA" | atomic_write "$DATA_DIR/state/last_freebsd_commit"
|
||||
printf '%s\n' "$FREEBSD_PACKAGE_VERSION" | atomic_write "$DATA_DIR/state/last_freebsd_package_version"
|
||||
printf '%s\n' "$BRANCH_RELEASE_ID" | atomic_write "$DATA_DIR/state/last_freebsd_release"
|
||||
printf '%s\n' "$BRANCH_RELEASE_ID" | atomic_write "$DATA_DIR/state/last_release"
|
||||
log "FreeBSD native publication completed: package=$FREEBSD_PACKAGE_VERSION commit=$SHA"
|
||||
@@ -144,7 +144,7 @@ APT_PUBLIC="$DATA_DIR/aptly/public"
|
||||
gpg --batch --verify "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release.gpg" "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release" >/dev/null 2>&1 \
|
||||
|| fatal "APT Release signature verification failed"
|
||||
|
||||
mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense"
|
||||
mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense" "$RELEASE_DIR/freebsd"
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "$REPOSITORY/current" ]]; then
|
||||
CURRENT_LINK=$(readlink "$REPOSITORY/current")
|
||||
@@ -152,8 +152,12 @@ if [[ -L "$REPOSITORY/current" ]]; then
|
||||
fi
|
||||
|
||||
log "staging Linux repository snapshot"
|
||||
if [[ -n "$CURRENT_TARGET" && -d "$CURRENT_TARGET/opnsense" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/opnsense"/ "$CURRENT_TARGET/opnsense"/ "$RELEASE_DIR/opnsense"/
|
||||
if [[ -n "$CURRENT_TARGET" ]]; then
|
||||
for component in opnsense freebsd; do
|
||||
if [[ -d "$CURRENT_TARGET/$component" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/$component"/ "$CURRENT_TARGET/$component"/ "$RELEASE_DIR/$component"/
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
rsync -a --delete "$APT_PUBLIC"/ "$RELEASE_DIR/apt"/
|
||||
|
||||
@@ -50,7 +50,7 @@ OPNSENSE_PACKAGE_FILE="$OUT/os-rustproxy-${OPNSENSE_PACKAGE_VERSION}.pkg"
|
||||
/opt/rust-package-builder/scripts/package-opnsense.sh \
|
||||
"$SRC" "$FREEBSD_BINARY" "$OPNSENSE_PACKAGE_FILE" "$OPNSENSE_PACKAGE_VERSION"
|
||||
|
||||
mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense"
|
||||
mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense" "$RELEASE_DIR/freebsd"
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "$REPOSITORY/current" ]]; then
|
||||
CURRENT_LINK=$(readlink "$REPOSITORY/current")
|
||||
@@ -59,7 +59,7 @@ fi
|
||||
|
||||
log "staging OPNsense repository snapshot"
|
||||
if [[ -n "$CURRENT_TARGET" ]]; then
|
||||
for component in apt rpm opnsense; do
|
||||
for component in apt rpm opnsense freebsd; do
|
||||
if [[ -d "$CURRENT_TARGET/$component" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/$component"/ "$CURRENT_TARGET/$component"/ "$RELEASE_DIR/$component"/
|
||||
fi
|
||||
|
||||
@@ -6,10 +6,12 @@ SHA=${1:?commit SHA required}
|
||||
BUILD_REASON=${2:-new-commit}
|
||||
BUILD_LINUX=${3:-1}
|
||||
BUILD_OPNSENSE=${4:-1}
|
||||
BUILD_FREEBSD=${5:-0}
|
||||
|
||||
[[ "$BUILD_LINUX" =~ ^[01]$ ]] || fatal "BUILD_LINUX must be 0 or 1"
|
||||
[[ "$BUILD_OPNSENSE" =~ ^[01]$ ]] || fatal "BUILD_OPNSENSE must be 0 or 1"
|
||||
(( BUILD_LINUX == 1 || BUILD_OPNSENSE == 1 )) || { log "nothing to build for $SHA"; exit 0; }
|
||||
[[ "$BUILD_FREEBSD" =~ ^[01]$ ]] || fatal "BUILD_FREEBSD must be 0 or 1"
|
||||
(( BUILD_LINUX == 1 || BUILD_OPNSENSE == 1 || BUILD_FREEBSD == 1 )) || { log "nothing to build for $SHA"; exit 0; }
|
||||
|
||||
SHORT_SHA=${SHA:0:12}
|
||||
BUILD_ID="$(date -u '+%Y%m%dT%H%M%SZ')-${SHORT_SHA}"
|
||||
@@ -102,10 +104,11 @@ HOMEPAGE=${PACKAGE_HOMEPAGE:-${CARGO_HOMEPAGE:-${CARGO_REPOSITORY:-${CONTROL_HOM
|
||||
export SHA SHORT_SHA BUILD_ID BUILD_REASON SOURCE_REVISION WORK SRC PKG OUT
|
||||
export PACKAGE_NAME VERSION BINARY_NAME DESCRIPTION LICENSE HOMEPAGE MAINTAINER
|
||||
|
||||
log "build plan: commit=$SHA linux=$BUILD_LINUX opnsense=$BUILD_OPNSENSE version=$VERSION"
|
||||
log "build plan: commit=$SHA linux=$BUILD_LINUX opnsense=$BUILD_OPNSENSE freebsd=$BUILD_FREEBSD version=$VERSION"
|
||||
|
||||
LINUX_OK=1
|
||||
OPNSENSE_OK=1
|
||||
FREEBSD_OK=1
|
||||
|
||||
if [[ "$BUILD_LINUX" == "1" ]]; then
|
||||
if /opt/rust-package-builder/scripts/build-linux-release.sh; then
|
||||
@@ -127,15 +130,27 @@ if [[ "$BUILD_OPNSENSE" == "1" ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$BUILD_FREEBSD" == "1" ]]; then
|
||||
if /opt/rust-package-builder/scripts/build-freebsd-release.sh; then
|
||||
log "FreeBSD native branch completed for $SHA"
|
||||
cleanup_cargo_target
|
||||
else
|
||||
FREEBSD_OK=0
|
||||
log "ERROR: FreeBSD native branch failed for $SHA"
|
||||
fi
|
||||
fi
|
||||
|
||||
LINUX_STATE=""
|
||||
OPNSENSE_STATE=""
|
||||
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")
|
||||
if [[ "$LINUX_STATE" == "$SHA" && "$OPNSENSE_STATE" == "$SHA" ]]; then
|
||||
[[ -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
|
||||
printf '%s\n' "$SHA" | atomic_write "$DATA_DIR/state/last_commit"
|
||||
log "all branches complete for $SHA"
|
||||
fi
|
||||
|
||||
if [[ "$LINUX_OK" != "1" || "$OPNSENSE_OK" != "1" ]]; then
|
||||
if [[ "$LINUX_OK" != "1" || "$OPNSENSE_OK" != "1" || "$FREEBSD_OK" != "1" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
+29
-12
@@ -50,12 +50,28 @@ opnsense_release_complete_for_commit() {
|
||||
return 0
|
||||
}
|
||||
|
||||
freebsd_release_complete_for_commit() {
|
||||
local sha=$1
|
||||
local repo="$CURRENT/freebsd"
|
||||
[[ -d "$CURRENT" ]] || return 1
|
||||
for file in meta.conf packagesite.pkg data.pkg RustProxy-FreeBSD.conf BUILD-INFO.txt rustproxy-latest.pkg; do
|
||||
[[ -s "$repo/$file" ]] || return 1
|
||||
done
|
||||
grep -Fqx "source_commit=$sha" "$repo/BUILD-INFO.txt" || return 1
|
||||
grep -Fqx "packaging_revision=$FREEBSD_NATIVE_PACKAGING_REVISION" "$repo/BUILD-INFO.txt" || return 1
|
||||
grep -Fqx "freebsd_abi=$FREEBSD_ABI" "$repo/BUILD-INFO.txt" || return 1
|
||||
[[ -d "$repo/$FREEBSD_ABI" ]] || return 1
|
||||
find "$repo/$FREEBSD_ABI" -maxdepth 1 -type f -name 'rustproxy-*.pkg' -print -quit | grep -q . || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
log "checking repository"
|
||||
REMOTE_SHA=$(git ls-remote "$SOURCE_REPO" "refs/heads/$SOURCE_BRANCH" | awk 'NR == 1 {print $1}')
|
||||
[[ "$REMOTE_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || fatal "cannot resolve branch $SOURCE_BRANCH from $SOURCE_REPO"
|
||||
|
||||
BUILD_LINUX=1
|
||||
BUILD_OPNSENSE=1
|
||||
BUILD_FREEBSD=0
|
||||
if linux_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
BUILD_LINUX=0
|
||||
# Persist migrated per-branch state when an older installation already has
|
||||
@@ -67,19 +83,20 @@ if opnsense_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
printf '%s\n' "$REMOTE_SHA" | atomic_write "$DATA_DIR/state/last_opnsense_commit"
|
||||
fi
|
||||
|
||||
if [[ "$BUILD_LINUX" == "0" && "$BUILD_OPNSENSE" == "0" ]]; then
|
||||
if [[ "${FREEBSD_NATIVE_ENABLED:-0}" == "1" ]]; then
|
||||
BUILD_FREEBSD=1
|
||||
if freebsd_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
BUILD_FREEBSD=0
|
||||
printf '%s\n' "$REMOTE_SHA" | atomic_write "$DATA_DIR/state/last_freebsd_commit"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$BUILD_LINUX" == "0" && "$BUILD_OPNSENSE" == "0" && "$BUILD_FREEBSD" == "0" ]]; then
|
||||
printf '%s\n' "$REMOTE_SHA" | atomic_write "$DATA_DIR/state/last_commit"
|
||||
log "no changes: Linux and OPNsense are complete for $REMOTE_SHA"
|
||||
log "no changes: all enabled repositories are complete for $REMOTE_SHA"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$BUILD_LINUX" == "1" && "$BUILD_OPNSENSE" == "1" ]]; then
|
||||
REASON="new-or-missing-both"
|
||||
elif [[ "$BUILD_LINUX" == "1" ]]; then
|
||||
REASON="repair-linux"
|
||||
else
|
||||
REASON="repair-opnsense"
|
||||
fi
|
||||
|
||||
log "build required: commit=$REMOTE_SHA linux=$BUILD_LINUX opnsense=$BUILD_OPNSENSE reason=$REASON"
|
||||
/opt/rust-package-builder/scripts/build-release.sh "$REMOTE_SHA" "$REASON" "$BUILD_LINUX" "$BUILD_OPNSENSE"
|
||||
REASON="missing-or-outdated-channel"
|
||||
log "build required: commit=$REMOTE_SHA linux=$BUILD_LINUX opnsense=$BUILD_OPNSENSE freebsd=$BUILD_FREEBSD reason=$REASON"
|
||||
/opt/rust-package-builder/scripts/build-release.sh "$REMOTE_SHA" "$REASON" "$BUILD_LINUX" "$BUILD_OPNSENSE" "$BUILD_FREEBSD"
|
||||
@@ -16,6 +16,8 @@ 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_RETENTION=${FREEBSD_NATIVE_RETENTION:-10}
|
||||
|
||||
[[ "$POLL_INTERVAL" =~ ^[0-9]+$ ]] || fatal "POLL_INTERVAL must be an integer"
|
||||
(( POLL_INTERVAL >= 1 )) || fatal "POLL_INTERVAL must be >= 1"
|
||||
@@ -23,6 +25,8 @@ RUN_LINUX_TESTS=${RUN_LINUX_TESTS:-1}
|
||||
[[ "$OPNSENSE_RETENTION" =~ ^[0-9]+$ ]] || fatal "OPNSENSE_RETENTION must be >= 0"
|
||||
[[ "$APPLY_FREEBSD_PATCHES" =~ ^[01]$ ]] || fatal "APPLY_FREEBSD_PATCHES must be 0 or 1"
|
||||
[[ "$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"
|
||||
|
||||
export DATA_DIR=${DATA_DIR:-/var/lib/package-builder}
|
||||
export SOURCE_REPO SOURCE_BRANCH REPOSITORY_URL OPNSENSE_REPOSITORY_URL POLL_INTERVAL
|
||||
@@ -31,7 +35,7 @@ export REPO_COMPONENT=${REPO_COMPONENT:-main}
|
||||
export PACKAGE_RELEASE
|
||||
export OPNSENSE_ABI OPNSENSE_RETENTION
|
||||
export FREEBSD_RELEASE FREEBSD_ABI FREEBSD_ARCH FREEBSD_RUST_TOOLCHAIN
|
||||
export APPLY_FREEBSD_PATCHES RUN_LINUX_TESTS
|
||||
export APPLY_FREEBSD_PATCHES RUN_LINUX_TESTS FREEBSD_NATIVE_ENABLED FREEBSD_NATIVE_RETENTION
|
||||
export MAX_GLIBC_VERSION=${MAX_GLIBC_VERSION:-2.34}
|
||||
export GPG_PRIVATE_KEY_FILE=${GPG_PRIVATE_KEY_FILE:-/run/secrets/gpg/private-key.asc}
|
||||
export GPG_PASSPHRASE_FILE=${GPG_PASSPHRASE_FILE:-/run/secrets/gpg/passphrase}
|
||||
@@ -77,7 +81,7 @@ fi
|
||||
|
||||
/opt/rust-package-builder/scripts/init-storage.sh
|
||||
|
||||
log "builder started: branch=$SOURCE_BRANCH interval=${POLL_INTERVAL}s opnsense=$OPNSENSE_ABI freebsd=$FREEBSD_RELEASE"
|
||||
log "builder started: branch=$SOURCE_BRANCH interval=${POLL_INTERVAL}s opnsense=$OPNSENSE_ABI freebsd=$FREEBSD_RELEASE native_freebsd=$FREEBSD_NATIVE_ENABLED"
|
||||
while true; do
|
||||
if ! /opt/rust-package-builder/scripts/check-and-build.sh; then
|
||||
log "ERROR: one or more build branches failed; any successful branch was published independently"
|
||||
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
OUT=${1:?output file required}
|
||||
URL="${OPNSENSE_REPOSITORY_URL%/}/freebsd"
|
||||
export OUT URL FREEBSD_ABI
|
||||
python3 <<'PY'
|
||||
import html, os
|
||||
h=html.escape
|
||||
url=h(os.environ['URL']); abi=h(os.environ['FREEBSD_ABI'])
|
||||
page=f'''<!doctype html>
|
||||
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>RustProxy - native FreeBSD pkg</title>
|
||||
<style>body{{font:16px/1.55 system-ui,sans-serif;max-width:860px;margin:40px auto;padding:0 20px}}pre{{overflow:auto;background:#171717;color:#eee;padding:18px;border-radius:8px}}</style></head>
|
||||
<body><h1>RustProxy for native FreeBSD</h1>
|
||||
<p>This repository contains the <code>rustproxy</code> package and an rc.d service, without OPNsense plugin files. ABI: <code>{abi}</code>.</p>
|
||||
<p><strong>Development repository: unsigned pkg catalog.</strong> Use only in an environment where you trust the source and transport. Configure signing before production.</p>
|
||||
<pre><code>mkdir -p /usr/local/etc/pkg/repos
|
||||
fetch -o /usr/local/etc/pkg/repos/RustProxy-FreeBSD.conf {url}/RustProxy-FreeBSD.conf
|
||||
pkg update -f
|
||||
pkg install rustproxy
|
||||
sysrc rustproxy_enable=YES
|
||||
service rustproxy start
|
||||
service rustproxy reload</code></pre>
|
||||
<p>To use an external JSON configuration, set <code>rustproxy_config="/usr/local/etc/rustproxy/config.json"</code> in <code>/etc/rc.conf</code>. The file and parent directory must be writable by the service account.</p>
|
||||
<ul><li><a href="{url}/meta.conf">meta.conf</a></li><li><a href="{url}/packagesite.pkg">packagesite.pkg</a></li><li><a href="{url}/RustProxy-FreeBSD.conf">RustProxy-FreeBSD.conf</a></li><li><a href="{url}/rustproxy-latest.pkg">latest package</a></li></ul>
|
||||
</body></html>'''
|
||||
with open(os.environ['OUT'],'w',encoding='utf-8') as f:
|
||||
f.write(page)
|
||||
PY
|
||||
@@ -72,6 +72,7 @@ sudo dnf install {h(package)}</code></pre>
|
||||
<h2>OPNsense / FreeBSD pkg</h2>
|
||||
<p>The OPNsense plugin is published separately because it uses the FreeBSD pkg format.</p>
|
||||
<p><a href="{h(opn_url)}/">{h(opn_url)}/</a></p>
|
||||
<p>Native FreeBSD pkg (if enabled): <a href="{h(opn_url)}/freebsd/">{h(opn_url)}/freebsd/</a>.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
|
||||
@@ -39,6 +39,10 @@ code{{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}}
|
||||
<p><strong>OPNsense series:</strong> {h(series)} <strong>ABI:</strong> {h(abi)}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Native FreeBSD (without OPNsense)</h2>
|
||||
<p>The separate optional native FreeBSD pkg repository is available at <a href="{h(url)}/freebsd/">{h(url)}/freebsd/</a> when FREEBSD_NATIVE_ENABLED=1.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>pkg repository configuration</h2>
|
||||
<pre><code>mkdir -p /usr/local/etc/pkg/repos
|
||||
cat > /usr/local/etc/pkg/repos/RustProxy.conf <<'REPO'
|
||||
|
||||
@@ -11,7 +11,7 @@ from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
CATALOG_FILES = {"data.pkg", "packagesite.pkg"}
|
||||
LATEST_NAMES = {"latest.pkg", "os-rustproxy-latest.pkg"}
|
||||
LATEST_NAMES = {"latest.pkg", "os-rustproxy-latest.pkg", "rustproxy-latest.pkg"}
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
|
||||
@@ -34,7 +34,7 @@ if ! aptly -config="$APTLY_CONF" repo list -raw | grep -Fx package-builder >/dev
|
||||
package-builder >/dev/null
|
||||
fi
|
||||
|
||||
for item in apt rpm opnsense repo-key.gpg index.html LINUX-BUILD-INFO.txt; do
|
||||
for item in apt rpm opnsense freebsd repo-key.gpg index.html LINUX-BUILD-INFO.txt; do
|
||||
if [[ -e "$REPOSITORY/$item" && ! -L "$REPOSITORY/$item" ]]; then
|
||||
fatal "$REPOSITORY/$item exists and is not a symlink; refusing to overwrite"
|
||||
fi
|
||||
@@ -43,6 +43,7 @@ done
|
||||
ln -sfn current/apt "$REPOSITORY/apt"
|
||||
ln -sfn current/rpm "$REPOSITORY/rpm"
|
||||
ln -sfn current/opnsense "$REPOSITORY/opnsense"
|
||||
ln -sfn current/freebsd "$REPOSITORY/freebsd"
|
||||
ln -sfn current/repo-key.gpg "$REPOSITORY/repo-key.gpg"
|
||||
ln -sfn current/index.html "$REPOSITORY/index.html"
|
||||
ln -sfn current/LINUX-BUILD-INFO.txt "$REPOSITORY/LINUX-BUILD-INFO.txt"
|
||||
+3
-2
@@ -2,8 +2,9 @@
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Increment when package payload/installation semantics change without a source commit.
|
||||
PACKAGING_REVISION=2
|
||||
OPNSENSE_PACKAGING_REVISION=3
|
||||
PACKAGING_REVISION=3
|
||||
OPNSENSE_PACKAGING_REVISION=4
|
||||
FREEBSD_NATIVE_PACKAGING_REVISION=1
|
||||
|
||||
log() {
|
||||
printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*"
|
||||
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
BUILDER_ROOT=${BUILDER_ROOT:-/opt/rust-package-builder}
|
||||
source "$BUILDER_ROOT/scripts/lib.sh"
|
||||
|
||||
SOURCE_DIR=${1:?source path required}
|
||||
BINARY=${2:?FreeBSD binary required}
|
||||
PACKAGE_FILE=${3:?output package file required}
|
||||
PACKAGE_VERSION=${4:?FreeBSD package version required}
|
||||
FREEBSD_ABI=${FREEBSD_ABI:-FreeBSD:15:amd64}
|
||||
FREEBSD_ARCH=${FREEBSD_ARCH:-freebsd:15:x86:64}
|
||||
PACKAGING="$BUILDER_ROOT/packaging/freebsd"
|
||||
|
||||
for tool in python3 sha256sum tar zstd file; do
|
||||
require_cmd "$tool"
|
||||
done
|
||||
[[ -f "$SOURCE_DIR/Cargo.toml" ]] || fatal "missing Cargo.toml: $SOURCE_DIR"
|
||||
[[ -f "$BINARY" ]] || fatal "missing FreeBSD binary: $BINARY"
|
||||
[[ "$(file -b "$BINARY")" == *FreeBSD* ]] || fatal "refusing non-FreeBSD native package: $BINARY"
|
||||
|
||||
WORK=$(mktemp -d "${PACKAGE_FILE}.work.XXXXXX")
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
STAGE="$WORK/stage"
|
||||
META="$WORK/meta"
|
||||
ARCHIVE="$WORK/rustproxy.tar"
|
||||
mkdir -p "$META" "$(dirname "$PACKAGE_FILE")"
|
||||
install -D -m 0555 "$BINARY" "$STAGE/usr/local/sbin/rust-proxy"
|
||||
install -D -m 0555 "$PACKAGING/rustproxy.rc" "$STAGE/usr/local/etc/rc.d/rustproxy"
|
||||
install -D -m 0644 "$PACKAGING/rustproxy.newsyslog" "$STAGE/usr/local/etc/newsyslog.conf.d/rustproxy.conf"
|
||||
|
||||
python3 - "$STAGE" "$META" "$PACKAGE_VERSION" "$FREEBSD_ABI" "$FREEBSD_ARCH" \
|
||||
"$PACKAGING/+POST_INSTALL" "$PACKAGING/+PRE_DEINSTALL" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
stage, meta = map(Path, sys.argv[1:3])
|
||||
version, abi, arch = sys.argv[3:6]
|
||||
post_install = Path(sys.argv[6]).read_text(encoding='utf-8')
|
||||
pre_deinstall = Path(sys.argv[7]).read_text(encoding='utf-8')
|
||||
|
||||
files = {}
|
||||
flatsize = 0
|
||||
for path in sorted(stage.rglob('*')):
|
||||
if path.is_symlink():
|
||||
files['/' + path.relative_to(stage).as_posix()] = '-'
|
||||
elif path.is_file():
|
||||
files['/' + path.relative_to(stage).as_posix()] = hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
flatsize += path.stat().st_size
|
||||
common = {
|
||||
'name': 'rustproxy',
|
||||
'version': version,
|
||||
'origin': 'www/rustproxy',
|
||||
'comment': 'RustProxy reverse proxy for native FreeBSD',
|
||||
'desc': 'RustProxy daemon and rc.d service for FreeBSD (no OPNsense plugin or dependency).',
|
||||
'maintainer': 'local@localhost',
|
||||
'www': 'https://git.linuxiarz.pl/gru/RustProxy',
|
||||
'prefix': '/usr/local',
|
||||
'abi': abi,
|
||||
'arch': arch,
|
||||
'flatsize': flatsize,
|
||||
'licenselogic': 'single',
|
||||
'licenses': ['UNKNOWN'],
|
||||
'categories': ['www'],
|
||||
'deps': {},
|
||||
'options': {},
|
||||
}
|
||||
manifest = dict(common)
|
||||
manifest['files'] = files
|
||||
manifest['scripts'] = {'post-install': post_install, 'pre-deinstall': pre_deinstall}
|
||||
(meta / '+COMPACT_MANIFEST').write_text(json.dumps(common, separators=(',', ':')) + '\n')
|
||||
(meta / '+MANIFEST').write_text(json.dumps(manifest, separators=(',', ':')) + '\n')
|
||||
PY
|
||||
|
||||
(
|
||||
cd "$STAGE"
|
||||
find . \( -type f -o -type l \) -print | LC_ALL=C sort | sed 's#^\./##' > "$WORK/payload.list"
|
||||
)
|
||||
[[ -s "$WORK/payload.list" ]] || fatal 'FreeBSD package payload is empty'
|
||||
tar --format=ustar --owner=0 --group=0 --numeric-owner \
|
||||
-cf "$ARCHIVE" -C "$META" +COMPACT_MANIFEST +MANIFEST
|
||||
tar -P --format=ustar --owner=0 --group=0 --numeric-owner --no-recursion \
|
||||
--transform='s,^,/,S' \
|
||||
-rf "$ARCHIVE" -C "$STAGE" -T "$WORK/payload.list"
|
||||
python3 - "$ARCHIVE" "$META/+MANIFEST" <<'PY'
|
||||
from pathlib import Path
|
||||
import json
|
||||
import sys
|
||||
import tarfile
|
||||
pkg = Path(sys.argv[1])
|
||||
manifest = json.loads(Path(sys.argv[2]).read_text())
|
||||
with tarfile.open(pkg) as tf:
|
||||
members = tf.getmembers()
|
||||
assert [m.name for m in members[:2]] == ['+COMPACT_MANIFEST', '+MANIFEST']
|
||||
assert all(not m.isdir() for m in members[2:]), 'package contains directory records'
|
||||
actual = {m.name for m in members[2:] if m.isfile() or m.issym() or m.islnk()}
|
||||
assert actual == set(manifest['files']), 'payload differs from +MANIFEST'
|
||||
assert all(name.startswith('/') for name in actual), 'non-absolute native FreeBSD payload path'
|
||||
PY
|
||||
zstd -q -f -19 -T0 "$ARCHIVE" -o "$PACKAGE_FILE"
|
||||
zstd -dc "$PACKAGE_FILE" | tar -tf - >/dev/null
|
||||
log "created native FreeBSD package: $PACKAGE_FILE"
|
||||
@@ -69,6 +69,37 @@ WantedBy=multi-user.target
|
||||
UNIT
|
||||
fi
|
||||
|
||||
# Match the 0.34.x CLI. Avoid changing upstream units that already provide
|
||||
# their own ExecReload. Linux package revision forces rebuilding old binaries.
|
||||
python3 - "$PKG/payload/usr/lib/systemd/system/${PACKAGE_NAME}.service" "$BINARY_NAME" <<'PY_UNIT'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
path = Path(sys.argv[1])
|
||||
name = sys.argv[2]
|
||||
text = path.read_text()
|
||||
if not re.search(r'^ExecReload=', text, re.M):
|
||||
if not re.search(r'^ExecStart=', text, re.M):
|
||||
raise SystemExit('unit has no ExecStart; cannot attach reload')
|
||||
text = re.sub(
|
||||
r'^(ExecStart=[^\n]*\n)',
|
||||
lambda m: m.group(1) +
|
||||
f'ExecReload=/usr/bin/{name} --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 reload\n',
|
||||
text,
|
||||
count=1,
|
||||
flags=re.M,
|
||||
)
|
||||
if re.search(r'^ProtectSystem=strict\s*$', text, re.M) and not re.search(
|
||||
r'^ReadWritePaths=.*(?:^|[ \t])-?/etc/rustproxy(?:[ \t]|$)', text, re.M
|
||||
):
|
||||
text = re.sub(
|
||||
r'^(ProtectSystem=strict\s*\n)',
|
||||
lambda m: m.group(1) + 'ReadWritePaths=-/etc/rustproxy\n',
|
||||
text, count=1, flags=re.M,
|
||||
)
|
||||
path.write_text(text)
|
||||
PY_UNIT
|
||||
|
||||
if [[ -r "$ENV_SRC" ]]; then
|
||||
install -D -m 0640 "$ENV_SRC" "$PKG/payload/etc/${PACKAGE_NAME}/environment"
|
||||
fi
|
||||
@@ -104,7 +135,7 @@ if ! getent passwd "$PACKAGE_NAME" >/dev/null 2>&1; then
|
||||
adduser --system --ingroup "$PACKAGE_NAME" --home "/var/lib/$PACKAGE_NAME" --no-create-home \\
|
||||
--disabled-password --shell /usr/sbin/nologin "$PACKAGE_NAME" >/dev/null
|
||||
fi
|
||||
install -d -o "$PACKAGE_NAME" -g "$PACKAGE_NAME" -m 0700 "/var/lib/$PACKAGE_NAME" "/var/log/$PACKAGE_NAME"
|
||||
install -d -o "$PACKAGE_NAME" -g "$PACKAGE_NAME" -m 0700 "/var/lib/$PACKAGE_NAME" "/var/log/$PACKAGE_NAME" "/etc/$PACKAGE_NAME"
|
||||
SCRIPT
|
||||
fi
|
||||
cat >> "$PKG/scripts/deb-postinstall.sh" <<SCRIPT
|
||||
@@ -139,7 +170,7 @@ fi
|
||||
if ! getent passwd "$PACKAGE_NAME" >/dev/null 2>&1; then
|
||||
useradd --system --gid "$PACKAGE_NAME" --home-dir "/var/lib/$PACKAGE_NAME" --no-create-home --shell /sbin/nologin "$PACKAGE_NAME"
|
||||
fi
|
||||
install -d -o "$PACKAGE_NAME" -g "$PACKAGE_NAME" -m 0700 "/var/lib/$PACKAGE_NAME" "/var/log/$PACKAGE_NAME"
|
||||
install -d -o "$PACKAGE_NAME" -g "$PACKAGE_NAME" -m 0700 "/var/lib/$PACKAGE_NAME" "/var/log/$PACKAGE_NAME" "/etc/$PACKAGE_NAME"
|
||||
systemd-tmpfiles --create "/usr/lib/tmpfiles.d/${PACKAGE_NAME}.conf" >/dev/null 2>&1 || true
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
systemctl enable "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
|
||||
|
||||
@@ -185,6 +185,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%/}"
|
||||
[[ -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"
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
set -Eeuo pipefail
|
||||
SRC=${1:?usage: check-rustproxy-source.sh /path/to/RustProxy}
|
||||
|
||||
for f in \
|
||||
Cargo.toml \
|
||||
debian/rustproxy.service \
|
||||
debian/rustproxy.environment \
|
||||
debian/rustproxy.logrotate \
|
||||
debian/rustproxy.tmpfiles \
|
||||
debian/rustproxy.postinst \
|
||||
grafana/rustproxy-overview.json; do
|
||||
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 '^ExecStart=/usr/bin/rust-proxy serve' "$SRC/debian/rustproxy.service"
|
||||
grep -q '^RUST_PROXY_DATA_DIR=/var/lib/rustproxy' "$SRC/debian/rustproxy.environment"
|
||||
grep -q 'RUST_PROXY_CONFIG' "$SRC/src/main/bootstrap.rs"
|
||||
grep -q 'Reload,' "$SRC/src/main/bootstrap.rs"
|
||||
|
||||
echo 'RustProxy packaging layout: OK'
|
||||
# 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'
|
||||
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/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'
|
||||
@@ -62,6 +62,9 @@ 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"
|
||||
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"
|
||||
|
||||
@@ -39,7 +39,9 @@ PY
|
||||
# Isolate the rc.d argument composition without running FreeBSD-only commands.
|
||||
cat > "$WORK/rc.subr" <<'EOF'
|
||||
load_rc_config() { :; }
|
||||
run_rc_command() { printf '%s\n' "$command_args"; }
|
||||
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
|
||||
@@ -67,6 +69,26 @@ 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
|
||||
@@ -90,6 +112,7 @@ 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
|
||||
@@ -114,6 +137,9 @@ 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; }
|
||||
@@ -122,4 +148,4 @@ if FAIL_RENDER=1 ENABLED=1 "$WORK/hook-test" >/dev/null 2>&1; then
|
||||
fi
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Started despite failed template rendering' >&2; exit 1; }
|
||||
|
||||
echo 'OPNsense boot / update interval checks: OK'
|
||||
echo 'OPNsense boot / update interval / soft reload checks: OK'
|
||||
+8
-1
@@ -16,6 +16,13 @@ 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/prepare-package.sh"
|
||||
grep -q 'OPNsense branch will still run' "$ROOT/scripts/build-release.sh"
|
||||
|
||||
# Linux tests gate Linux packaging only.
|
||||
@@ -36,7 +43,7 @@ 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"
|
||||
! test -e "$ROOT/opnsense/plugin/src/etc/rc.syshook.d/10-rustproxy.start"
|
||||
grep -q 'OPNSENSE_PACKAGING_REVISION=3' "$ROOT/scripts/lib.sh"
|
||||
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.
|
||||
|
||||
Reference in new issue
Block a user