new_version

This commit is contained in:
Mateusz Gruszczyński committed 2026-10-19 11:09:13 +02:00
1 parent 910bb563f0
commit a946c38194
32 files changed
+809 -65

No files matched your search

+81 -18
View File
@@ -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
```
+2
View File
@@ -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
+9
View File
@@ -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;
}
View File
File mode changed.
View File
File mode changed.
+37 -1
View File
@@ -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
+19
View File
@@ -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
+4
View File
@@ -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
+5
View File
@@ -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
+135
View File
@@ -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"
+118
View File
@@ -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"
+7 -3
View File
@@ -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"/
+2 -2
View File
@@ -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
+19 -4
View File
@@ -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
View File
@@ -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"
+6 -2
View File
@@ -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"
+29
View File
@@ -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
+1
View File
@@ -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">
+4
View File
@@ -39,6 +39,10 @@ code{{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}}
<p><strong>OPNsense series:</strong> {h(series)} &nbsp; <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 &gt; /usr/local/etc/pkg/repos/RustProxy.conf &lt;&lt;'REPO'
+1 -1
View File
@@ -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:
+2 -1
View File
@@ -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
View File
@@ -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')" "$*"
+103
View File
@@ -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"
+33 -2
View 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
+1
View File
@@ -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"
+13 -12
View File
@@ -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'
+96
View File
@@ -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'
+3
View File
@@ -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"
+28 -2
View File
@@ -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
View File
@@ -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.