first commit
This commit is contained in:
commit
093e6a7c14
39 files changed
+1112
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
*.sh text eol=lf
|
||||||
|
*.php text eol=lf
|
||||||
|
*.xml text eol=lf
|
||||||
|
*.volt text eol=lf
|
||||||
|
Makefile text eol=lf
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
/dist/
|
||||||
|
/.build/
|
||||||
|
/.cache/
|
||||||
|
/app/
|
||||||
|
/opnsense-plugin/www/rustproxy/work/
|
||||||
|
/opnsense-plugin/www/rustproxy/src/sbin/rust-proxy
|
||||||
|
*.log
|
||||||
|
*.key
|
||||||
|
.env
|
||||||
|
builder.env
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# RustProxy OPNsense packaging repository
|
||||||
|
|
||||||
|
This repository contains only the OPNsense plugin and build/release automation. The RustProxy application source is **not vendored here**. The Debian scheduler downloads it dynamically from:
|
||||||
|
|
||||||
|
`https://git.linuxiarz.pl/gru/RustProxy`
|
||||||
|
|
||||||
|
## What is included
|
||||||
|
|
||||||
|
- `opnsense-plugin/www/rustproxy/` - OPNsense plugin source.
|
||||||
|
- `builder/debian/` - hourly scheduler and optional cross-build helper.
|
||||||
|
- `builder/freebsd/` - native FreeBSD release builder and repository signing helper.
|
||||||
|
- `ci/build-release.sh` - Debian-to-FreeBSD orchestration and publishing.
|
||||||
|
- `deploy/opnsense/` - custom package repository install/update helpers.
|
||||||
|
- `docs/` - setup and architecture notes.
|
||||||
|
|
||||||
|
## Source/update flow
|
||||||
|
|
||||||
|
```text
|
||||||
|
Packaging repository RustProxy upstream
|
||||||
|
(plugin + scripts) https://git.linuxiarz.pl/gru/RustProxy
|
||||||
|
| |
|
||||||
|
+------------------+-------------------+
|
||||||
|
v
|
||||||
|
Debian cron, hourly
|
||||||
|
|
|
||||||
|
detects either commit change
|
||||||
|
|
|
||||||
|
v
|
||||||
|
FreeBSD 15.1 amd64 builder
|
||||||
|
|
|
||||||
|
cargo test + cargo build
|
||||||
|
|
|
||||||
|
OPNsense make package
|
||||||
|
|
|
||||||
|
v
|
||||||
|
signed pkg repository
|
||||||
|
|
|
||||||
|
v
|
||||||
|
OPNsense
|
||||||
|
```
|
||||||
|
|
||||||
|
By default `APP_REPO_REF=HEAD`, so every cron run follows the current default branch of the RustProxy repository. You can instead pin a branch/tag/ref in `/etc/rustproxy-opnsense-builder.env`.
|
||||||
|
|
||||||
|
A release rebuild is triggered when either the packaging repository commit or the RustProxy upstream commit changes. The package version is read at build time from the dynamically downloaded `Cargo.toml`.
|
||||||
|
|
||||||
|
## Recommended release build
|
||||||
|
|
||||||
|
Use the Debian VM only as scheduler/orchestrator and a FreeBSD 15.1 amd64 VM as compiler/packager. The included Docker/cross path (`BUILD_MODE=cross-binary`) is for development validation only and does not publish production `.pkg` files.
|
||||||
|
|
||||||
|
## Quick validation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./scripts/check.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick setup
|
||||||
|
|
||||||
|
Read `docs/FIRST_RUN.md`, copy `builder.env.example` to `/etc/rustproxy-opnsense-builder.env` on Debian and fill in your packaging-repository, SSH and publication settings. `APP_REPO_URL` is already set to your RustProxy repository.
|
||||||
|
|
||||||
|
## OPNsense UI scope
|
||||||
|
|
||||||
|
The plugin currently exposes only Enabled / Disabled. RustProxy is supervised by FreeBSD `daemon(8)`, runs as user `rustproxy`, and uses `/var/db/rustproxy` as its private data directory.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
RustProxy's `Cargo.toml` currently does not declare a license and the supplied source snapshot did not contain LICENSE/COPYING, so the plugin manifest remains `UNKNOWN`. Set the correct license before public redistribution.
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# This repository: OPNsense plugin + packaging/build scripts.
|
||||||
|
# Push this generated repository to your own Git server and set its URL here.
|
||||||
|
PACKAGING_REPO_URL=git@github.com:YOUR_ORG/rustproxy-opnsense.git
|
||||||
|
PACKAGING_REPO_REF=main
|
||||||
|
PACKAGING_WORKDIR=/srv/rustproxy-opnsense/packaging
|
||||||
|
|
||||||
|
# RustProxy application source. This is fetched independently on every cron run.
|
||||||
|
APP_REPO_URL=https://git.linuxiarz.pl/gru/RustProxy
|
||||||
|
# HEAD follows the default branch of the upstream repository. You can pin a branch,
|
||||||
|
# tag or other fetchable ref instead, for example: main, stable, v0.21.0.
|
||||||
|
APP_REPO_REF=HEAD
|
||||||
|
APP_WORKDIR=/srv/rustproxy-opnsense/source/RustProxy
|
||||||
|
|
||||||
|
# Local Debian state.
|
||||||
|
STATE_DIR=/var/lib/rustproxy-opnsense-builder
|
||||||
|
|
||||||
|
# Release builder. Use a FreeBSD 15.1 amd64 host for production packages.
|
||||||
|
BUILD_MODE=native-freebsd
|
||||||
|
FREEBSD_HOST=freebsd-builder.example.net
|
||||||
|
FREEBSD_USER=builder
|
||||||
|
FREEBSD_SSH_KEY=/root/.ssh/rustproxy_freebsd_builder
|
||||||
|
FREEBSD_REMOTE_DIR=/usr/local/rustproxy-build/project
|
||||||
|
|
||||||
|
# OPNsense branch/ABI targeted by the plugin package.
|
||||||
|
OPNSENSE_PLUGINS_REF=stable/26.7
|
||||||
|
OPNSENSE_ABI=26.7
|
||||||
|
|
||||||
|
# Paths on the FreeBSD builder. Leave empty for an unsigned development repo.
|
||||||
|
PKG_REPO_SIGN_KEY=/usr/local/rustproxy-build/keys/rustproxy-repo.key
|
||||||
|
PKG_REPO_PUBLIC_KEY=/usr/local/rustproxy-build/keys/rustproxy-repo.pub
|
||||||
|
|
||||||
|
# Publish dist/ over SSH/rsync. This should be the document root for RustProxy packages.
|
||||||
|
PUBLISH_TARGET=repo-user@packages.example.net:/srv/www/rustproxy/
|
||||||
|
PUBLISH_SSH_KEY=/root/.ssh/rustproxy_package_publisher
|
||||||
|
|
||||||
|
# Optional automatic upgrade of explicitly listed TEST firewalls after a successful publish.
|
||||||
|
# Disabled by default. Space-separated SSH targets, for example: root@fw-test-01 root@fw-test-02
|
||||||
|
AUTO_DEPLOY_HOSTS=
|
||||||
|
AUTO_DEPLOY_SSH_KEY=/root/.ssh/rustproxy_opnsense_test
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
SOURCE_DIR="${RUSTPROXY_SOURCE_DIR:-$ROOT/app}"
|
||||||
|
TARGET="x86_64-unknown-freebsd"
|
||||||
|
|
||||||
|
if [[ ! -f "$SOURCE_DIR/Cargo.toml" ]]; then
|
||||||
|
echo "RustProxy source not found. Set RUSTPROXY_SOURCE_DIR to the dynamically fetched checkout." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "Docker is required for cross mode." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! command -v cross >/dev/null 2>&1; then
|
||||||
|
echo "cross is not installed. Install it with: cargo install cross --locked" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$SOURCE_DIR"
|
||||||
|
cross build --locked --release --target "$TARGET"
|
||||||
|
mkdir -p "$ROOT/dist/cross/$TARGET"
|
||||||
|
cp "target/$TARGET/release/rust-proxy" "$ROOT/dist/cross/$TARGET/rust-proxy"
|
||||||
|
|
||||||
|
echo "Cross-built binary: $ROOT/dist/cross/$TARGET/rust-proxy"
|
||||||
|
echo "Do not publish this as the production OPNsense package without validation on the target FreeBSD ABI."
|
||||||
Executable
+86
@@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONFIG_FILE="${RUSTPROXY_BUILDER_CONFIG:-/etc/rustproxy-opnsense-builder.env}"
|
||||||
|
if [[ ! -r "$CONFIG_FILE" ]]; then
|
||||||
|
echo "Missing builder config: $CONFIG_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
|
||||||
|
: "${PACKAGING_REPO_URL:?PACKAGING_REPO_URL is required}"
|
||||||
|
: "${PACKAGING_REPO_REF:=main}"
|
||||||
|
: "${PACKAGING_WORKDIR:=/srv/rustproxy-opnsense/packaging}"
|
||||||
|
: "${APP_REPO_URL:=https://git.linuxiarz.pl/gru/RustProxy}"
|
||||||
|
: "${APP_REPO_REF:=HEAD}"
|
||||||
|
: "${APP_WORKDIR:=/srv/rustproxy-opnsense/source/RustProxy}"
|
||||||
|
: "${STATE_DIR:=/var/lib/rustproxy-opnsense-builder}"
|
||||||
|
|
||||||
|
mkdir -p "$STATE_DIR" "$(dirname "$PACKAGING_WORKDIR")" "$(dirname "$APP_WORKDIR")"
|
||||||
|
exec 9>"$STATE_DIR/build.lock"
|
||||||
|
if ! flock -n 9; then
|
||||||
|
echo "Another build is running; exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
SYNC_COMMIT=""
|
||||||
|
sync_checkout()
|
||||||
|
{
|
||||||
|
local dir="$1"
|
||||||
|
local url="$2"
|
||||||
|
local ref="$3"
|
||||||
|
|
||||||
|
if [[ ! -d "$dir/.git" ]]; then
|
||||||
|
rm -rf "$dir"
|
||||||
|
mkdir -p "$dir"
|
||||||
|
git -C "$dir" init
|
||||||
|
git -C "$dir" remote add origin "$url"
|
||||||
|
else
|
||||||
|
git -C "$dir" remote set-url origin "$url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Fetching $url ($ref)" >&2
|
||||||
|
git -C "$dir" fetch --prune --tags origin "$ref" >&2
|
||||||
|
SYNC_COMMIT="$(git -C "$dir" rev-parse FETCH_HEAD)"
|
||||||
|
git -C "$dir" checkout --detach -f "$SYNC_COMMIT" >&2
|
||||||
|
git -C "$dir" reset --hard "$SYNC_COMMIT" >&2
|
||||||
|
git -C "$dir" clean -ffd >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Refresh the packaging repository first so the newest build logic is used.
|
||||||
|
sync_checkout "$PACKAGING_WORKDIR" "$PACKAGING_REPO_URL" "$PACKAGING_REPO_REF"
|
||||||
|
packaging_commit="$SYNC_COMMIT"
|
||||||
|
|
||||||
|
# RustProxy is intentionally NOT vendored in the packaging repository.
|
||||||
|
# Fetch the application directly from its upstream repository every run.
|
||||||
|
sync_checkout "$APP_WORKDIR" "$APP_REPO_URL" "$APP_REPO_REF"
|
||||||
|
app_commit="$SYNC_COMMIT"
|
||||||
|
app_revision="$(git -C "$APP_WORKDIR" rev-list --count "$app_commit")"
|
||||||
|
|
||||||
|
if [[ ! -f "$APP_WORKDIR/Cargo.toml" ]]; then
|
||||||
|
echo "Upstream checkout does not contain Cargo.toml: $APP_WORKDIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
state_file="$STATE_DIR/last-successful-build"
|
||||||
|
current_state="packaging=$packaging_commit app=$app_commit"
|
||||||
|
last_state="$(cat "$state_file" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [[ "$current_state" == "$last_state" ]]; then
|
||||||
|
echo "No changes. packaging=$packaging_commit app=$app_commit"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building RustProxy commit $app_commit (revision $app_revision)"
|
||||||
|
echo "Using packaging commit $packaging_commit"
|
||||||
|
|
||||||
|
RUSTPROXY_SOURCE_DIR="$APP_WORKDIR" \
|
||||||
|
RUSTPROXY_SOURCE_URL="$APP_REPO_URL" \
|
||||||
|
RUSTPROXY_SOURCE_REF="$APP_REPO_REF" \
|
||||||
|
RUSTPROXY_SOURCE_COMMIT="$app_commit" \
|
||||||
|
RUSTPROXY_SOURCE_REVISION="$app_revision" \
|
||||||
|
"$PACKAGING_WORKDIR/ci/build-release.sh"
|
||||||
|
|
||||||
|
printf '%s\n' "$current_state" > "$state_file"
|
||||||
|
echo "Build completed: $current_state"
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ ${EUID} -ne 0 ]]; then
|
||||||
|
echo "Run as root" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y docker.io rustup build-essential pkg-config
|
||||||
|
systemctl enable --now docker
|
||||||
|
|
||||||
|
TARGET_USER="${SUDO_USER:-root}"
|
||||||
|
if [[ "$TARGET_USER" == "root" ]]; then
|
||||||
|
rustup default stable
|
||||||
|
cargo install cross --locked
|
||||||
|
else
|
||||||
|
sudo -u "$TARGET_USER" -H sh -c 'rustup default stable && cargo install cross --locked'
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Docker + rustup + cross installed for $TARGET_USER."
|
||||||
|
echo "Use BUILD_MODE=cross-binary only for development validation."
|
||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ ${EUID} -ne 0 ]]; then
|
||||||
|
echo "Run as root" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||||
|
ca-certificates cron git openssh-client rsync util-linux curl jq
|
||||||
|
|
||||||
|
install -d -m 0755 /srv/rustproxy-opnsense
|
||||||
|
install -d -m 0755 /var/lib/rustproxy-opnsense-builder
|
||||||
|
install -m 0755 "$REPO_ROOT/builder/debian/hourly-build.sh" /usr/local/sbin/rustproxy-opnsense-hourly
|
||||||
|
install -m 0644 "$REPO_ROOT/builder/debian/rustproxy-opnsense.cron" /etc/cron.d/rustproxy-opnsense
|
||||||
|
|
||||||
|
if [[ ! -e /etc/rustproxy-opnsense-builder.env ]]; then
|
||||||
|
install -m 0600 "$REPO_ROOT/builder.env.example" /etc/rustproxy-opnsense-builder.env
|
||||||
|
echo "Created /etc/rustproxy-opnsense-builder.env. Edit it before the first cron run."
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch /var/log/rustproxy-opnsense-builder.log
|
||||||
|
chmod 0640 /var/log/rustproxy-opnsense-builder.log
|
||||||
|
systemctl enable --now cron
|
||||||
|
|
||||||
|
echo "Debian scheduler installed."
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
SHELL=/bin/bash
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
17 * * * * root /usr/local/sbin/rustproxy-opnsense-hourly >> /var/log/rustproxy-opnsense-builder.log 2>&1
|
||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "Run as root" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BUILDER_USER="${1:-builder}"
|
||||||
|
BUILDER_GROUP="$BUILDER_USER"
|
||||||
|
|
||||||
|
ASSUME_ALWAYS_YES=yes pkg bootstrap -f
|
||||||
|
pkg update
|
||||||
|
pkg install -y git rust python3 pkgconf cmake gmake perl5 rsync
|
||||||
|
|
||||||
|
if ! pw groupshow "$BUILDER_GROUP" >/dev/null 2>&1; then
|
||||||
|
pw groupadd "$BUILDER_GROUP"
|
||||||
|
fi
|
||||||
|
if ! pw usershow "$BUILDER_USER" >/dev/null 2>&1; then
|
||||||
|
pw useradd "$BUILDER_USER" -g "$BUILDER_GROUP" -m -s /bin/sh -c "RustProxy package builder"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -o "$BUILDER_USER" -g "$BUILDER_GROUP" -m 0755 /usr/local/rustproxy-build
|
||||||
|
install -d -o "$BUILDER_USER" -g "$BUILDER_GROUP" -m 0700 /usr/local/rustproxy-build/keys
|
||||||
|
|
||||||
|
echo "FreeBSD builder dependencies installed."
|
||||||
|
echo "Builder account: $BUILDER_USER"
|
||||||
|
echo "Add its SSH public key to /home/$BUILDER_USER/.ssh/authorized_keys."
|
||||||
|
echo "Then log in as $BUILDER_USER and create the repository signing key."
|
||||||
|
rust_version="$(rustc --version | awk '{print $2}')"
|
||||||
|
if [ "$(pkg version -t "$rust_version" 1.88)" = "<" ]; then
|
||||||
|
echo "RustProxy requires Rust >= 1.88, found $rust_version" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Rust version OK: $rust_version"
|
||||||
Executable
+108
@@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="${1:-$(pwd)}"
|
||||||
|
APP_DIR="$ROOT/app"
|
||||||
|
PLUGIN_SOURCE="$ROOT/opnsense-plugin/www/rustproxy"
|
||||||
|
DIST_DIR="$ROOT/dist"
|
||||||
|
CACHE_DIR="${RUSTPROXY_BUILD_CACHE:-$HOME/.cache/rustproxy-opnsense}"
|
||||||
|
PLUGINS_DIR="$CACHE_DIR/opnsense-plugins"
|
||||||
|
OPNSENSE_PLUGINS_REF="${OPNSENSE_PLUGINS_REF:-stable/26.7}"
|
||||||
|
OPNSENSE_ABI="${OPNSENSE_ABI:-26.7}"
|
||||||
|
SOURCE_REVISION="${SOURCE_REVISION:-0}"
|
||||||
|
SOURCE_COMMIT="${RUSTPROXY_SOURCE_COMMIT:-unknown}"
|
||||||
|
SOURCE_URL="${RUSTPROXY_SOURCE_URL:-https://git.linuxiarz.pl/gru/RustProxy}"
|
||||||
|
SOURCE_REF="${RUSTPROXY_SOURCE_REF:-HEAD}"
|
||||||
|
RUN_TESTS="${RUN_TESTS:-1}"
|
||||||
|
|
||||||
|
if [ "$(uname -s)" != "FreeBSD" ]; then
|
||||||
|
echo "This release builder must run on FreeBSD." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
case "$(uname -m)" in
|
||||||
|
amd64|x86_64) ;;
|
||||||
|
*) echo "Only amd64/x86_64 is supported by this pipeline." >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for tool in cargo git make pkg rsync; do
|
||||||
|
command -v "$tool" >/dev/null 2>&1 || { echo "Missing tool: $tool" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
rust_version="$(rustc --version | awk '{print $2}')"
|
||||||
|
echo "Using rustc $rust_version on $(freebsd-version -ku | tr '\n' ' ')"
|
||||||
|
|
||||||
|
app_version="$(awk -F '"' '/^version = "/ {print $2; exit}' "$APP_DIR/Cargo.toml")"
|
||||||
|
if [ -z "$app_version" ]; then
|
||||||
|
echo "Cannot read app version from Cargo.toml" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$CACHE_DIR"
|
||||||
|
if [ ! -d "$PLUGINS_DIR/.git" ]; then
|
||||||
|
git clone https://github.com/opnsense/plugins.git "$PLUGINS_DIR"
|
||||||
|
fi
|
||||||
|
git -C "$PLUGINS_DIR" fetch --prune origin "$OPNSENSE_PLUGINS_REF"
|
||||||
|
git -C "$PLUGINS_DIR" checkout -f -B rustproxy-build FETCH_HEAD
|
||||||
|
git -C "$PLUGINS_DIR" clean -ffd
|
||||||
|
|
||||||
|
cd "$APP_DIR"
|
||||||
|
if [ "$RUN_TESTS" = "1" ]; then
|
||||||
|
cargo test --locked --release
|
||||||
|
fi
|
||||||
|
cargo build --locked --release
|
||||||
|
|
||||||
|
plugin_dir="$PLUGINS_DIR/www/rustproxy"
|
||||||
|
rm -rf "$plugin_dir"
|
||||||
|
cp -R "$PLUGIN_SOURCE" "$plugin_dir"
|
||||||
|
mkdir -p "$plugin_dir/src/sbin"
|
||||||
|
install -m 0555 "$APP_DIR/target/release/rust-proxy" "$plugin_dir/src/sbin/rust-proxy"
|
||||||
|
|
||||||
|
cd "$plugin_dir"
|
||||||
|
make PLUGIN_VERSION="$app_version" PLUGIN_REVISION="$SOURCE_REVISION" PLUGIN_ABI="$OPNSENSE_ABI" package
|
||||||
|
|
||||||
|
package_file="$(find "$plugin_dir/work/pkg" -maxdepth 1 -type f -name 'os-rustproxy-*.pkg' | sort | tail -n 1)"
|
||||||
|
if [ -z "$package_file" ] || [ ! -f "$package_file" ]; then
|
||||||
|
echo "Package was not produced." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_dir="$DIST_DIR/repository/$OPNSENSE_ABI/amd64"
|
||||||
|
rm -rf "$DIST_DIR"
|
||||||
|
mkdir -p "$repo_dir"
|
||||||
|
cp "$package_file" "$repo_dir/"
|
||||||
|
|
||||||
|
if [ -n "${PKG_REPO_SIGN_KEY:-}" ]; then
|
||||||
|
if [ ! -r "$PKG_REPO_SIGN_KEY" ]; then
|
||||||
|
echo "Repository signing key is not readable: $PKG_REPO_SIGN_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
pkg repo "$repo_dir" "$PKG_REPO_SIGN_KEY"
|
||||||
|
else
|
||||||
|
echo "WARNING: creating unsigned development repository" >&2
|
||||||
|
pkg repo "$repo_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${PKG_REPO_PUBLIC_KEY:-}" ]; then
|
||||||
|
if [ ! -r "$PKG_REPO_PUBLIC_KEY" ]; then
|
||||||
|
echo "Repository public key is not readable: $PKG_REPO_PUBLIC_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cp "$PKG_REPO_PUBLIC_KEY" "$DIST_DIR/rustproxy-repo.pub"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$DIST_DIR/BUILD-INFO.txt" <<INFO
|
||||||
|
app_version=$app_version
|
||||||
|
plugin_revision=$SOURCE_REVISION
|
||||||
|
source_url=$SOURCE_URL
|
||||||
|
source_ref=$SOURCE_REF
|
||||||
|
source_commit=$SOURCE_COMMIT
|
||||||
|
opnsense_plugins_ref=$OPNSENSE_PLUGINS_REF
|
||||||
|
opnsense_abi=$OPNSENSE_ABI
|
||||||
|
freebsd_kernel=$(freebsd-version -k)
|
||||||
|
freebsd_userland=$(freebsd-version -u)
|
||||||
|
rustc=$rust_version
|
||||||
|
package=$(basename "$package_file")
|
||||||
|
INFO
|
||||||
|
|
||||||
|
sha256 "$repo_dir/$(basename "$package_file")" > "$DIST_DIR/SHA256"
|
||||||
|
echo "Release artifacts created in $DIST_DIR"
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
KEY_DIR="${1:-/usr/local/rustproxy-build/keys}"
|
||||||
|
KEY="$KEY_DIR/rustproxy-repo.key"
|
||||||
|
PUB="$KEY_DIR/rustproxy-repo.pub"
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
mkdir -p "$KEY_DIR"
|
||||||
|
if [ -e "$KEY" ] || [ -e "$PUB" ]; then
|
||||||
|
echo "Key already exists in $KEY_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
openssl genrsa -out "$KEY" 2048
|
||||||
|
chmod 0400 "$KEY"
|
||||||
|
openssl rsa -in "$KEY" -out "$PUB" -pubout
|
||||||
|
chmod 0444 "$PUB"
|
||||||
|
|
||||||
|
echo "Private key: $KEY"
|
||||||
|
echo "Public key: $PUB"
|
||||||
Executable
+120
@@ -0,0 +1,120 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
CONFIG_FILE="${RUSTPROXY_BUILDER_CONFIG:-/etc/rustproxy-opnsense-builder.env}"
|
||||||
|
if [[ -r "$CONFIG_FILE" ]]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
: "${BUILD_MODE:=native-freebsd}"
|
||||||
|
: "${STATE_DIR:=/var/lib/rustproxy-opnsense-builder}"
|
||||||
|
: "${OPNSENSE_PLUGINS_REF:=stable/26.7}"
|
||||||
|
: "${OPNSENSE_ABI:=26.7}"
|
||||||
|
: "${RUSTPROXY_SOURCE_DIR:?RUSTPROXY_SOURCE_DIR must point to a checked-out RustProxy repository}"
|
||||||
|
: "${RUSTPROXY_SOURCE_URL:=https://git.linuxiarz.pl/gru/RustProxy}"
|
||||||
|
: "${RUSTPROXY_SOURCE_REF:=HEAD}"
|
||||||
|
: "${RUSTPROXY_SOURCE_COMMIT:=$(git -C "$RUSTPROXY_SOURCE_DIR" rev-parse HEAD)}"
|
||||||
|
: "${RUSTPROXY_SOURCE_REVISION:=$(git -C "$RUSTPROXY_SOURCE_DIR" rev-list --count "$RUSTPROXY_SOURCE_COMMIT")}"
|
||||||
|
|
||||||
|
if [[ ! -f "$RUSTPROXY_SOURCE_DIR/Cargo.toml" ]]; then
|
||||||
|
echo "RustProxy source directory is invalid: $RUSTPROXY_SOURCE_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
revision="$RUSTPROXY_SOURCE_REVISION"
|
||||||
|
|
||||||
|
safe_value()
|
||||||
|
{
|
||||||
|
[[ "$1" =~ ^[A-Za-z0-9_./:@+-]*$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
publish_dist()
|
||||||
|
{
|
||||||
|
if [[ -z "${PUBLISH_TARGET:-}" ]]; then
|
||||||
|
echo "PUBLISH_TARGET is empty; artifacts remain in $ROOT/dist"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
local ssh_cmd=(ssh)
|
||||||
|
if [[ -n "${PUBLISH_SSH_KEY:-}" ]]; then
|
||||||
|
ssh_cmd+=( -i "$PUBLISH_SSH_KEY" )
|
||||||
|
fi
|
||||||
|
rsync -az --delete-delay -e "${ssh_cmd[*]}" "$ROOT/dist/" "$PUBLISH_TARGET"
|
||||||
|
}
|
||||||
|
|
||||||
|
auto_deploy_tests()
|
||||||
|
{
|
||||||
|
[[ -n "${AUTO_DEPLOY_HOSTS:-}" ]] || return 0
|
||||||
|
for host in $AUTO_DEPLOY_HOSTS; do
|
||||||
|
echo "Upgrading RustProxy on test firewall: $host"
|
||||||
|
ssh_args=( -o BatchMode=yes )
|
||||||
|
if [[ -n "${AUTO_DEPLOY_SSH_KEY:-}" ]]; then
|
||||||
|
ssh_args+=( -i "$AUTO_DEPLOY_SSH_KEY" )
|
||||||
|
fi
|
||||||
|
ssh "${ssh_args[@]}" "$host" \
|
||||||
|
'pkg update -f -r RustProxy && pkg install -y -r RustProxy os-rustproxy'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$BUILD_MODE" in
|
||||||
|
native-freebsd)
|
||||||
|
: "${FREEBSD_HOST:?FREEBSD_HOST is required}"
|
||||||
|
: "${FREEBSD_USER:?FREEBSD_USER is required}"
|
||||||
|
: "${FREEBSD_REMOTE_DIR:?FREEBSD_REMOTE_DIR is required}"
|
||||||
|
for value in "$FREEBSD_HOST" "$FREEBSD_USER" "$FREEBSD_REMOTE_DIR" \
|
||||||
|
"$OPNSENSE_PLUGINS_REF" "$OPNSENSE_ABI" \
|
||||||
|
"${PKG_REPO_SIGN_KEY:-}" "${PKG_REPO_PUBLIC_KEY:-}" \
|
||||||
|
"$RUSTPROXY_SOURCE_URL" "$RUSTPROXY_SOURCE_REF" \
|
||||||
|
"$RUSTPROXY_SOURCE_COMMIT" "$revision"; do
|
||||||
|
if ! safe_value "$value"; then
|
||||||
|
echo "Unsafe character in builder configuration value: $value" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
ssh_args=( -o BatchMode=yes )
|
||||||
|
if [[ -n "${FREEBSD_SSH_KEY:-}" ]]; then
|
||||||
|
ssh_args+=( -i "$FREEBSD_SSH_KEY" )
|
||||||
|
fi
|
||||||
|
remote="${FREEBSD_USER}@${FREEBSD_HOST}"
|
||||||
|
ssh "${ssh_args[@]}" "$remote" "mkdir -p '$FREEBSD_REMOTE_DIR' '$FREEBSD_REMOTE_DIR/app'"
|
||||||
|
|
||||||
|
# Send packaging/plugin sources separately from the application source.
|
||||||
|
rsync -az --delete \
|
||||||
|
--exclude .git/ --exclude app/ --exclude dist/ --exclude .cache/ \
|
||||||
|
-e "ssh ${ssh_args[*]}" \
|
||||||
|
"$ROOT/" "$remote:$FREEBSD_REMOTE_DIR/"
|
||||||
|
|
||||||
|
rsync -az --delete \
|
||||||
|
--exclude .git/ --exclude target/ \
|
||||||
|
-e "ssh ${ssh_args[*]}" \
|
||||||
|
"$RUSTPROXY_SOURCE_DIR/" "$remote:$FREEBSD_REMOTE_DIR/app/"
|
||||||
|
|
||||||
|
remote_command="OPNSENSE_PLUGINS_REF=$OPNSENSE_PLUGINS_REF OPNSENSE_ABI=$OPNSENSE_ABI RUSTPROXY_SOURCE_URL=$RUSTPROXY_SOURCE_URL RUSTPROXY_SOURCE_REF=$RUSTPROXY_SOURCE_REF RUSTPROXY_SOURCE_COMMIT=$RUSTPROXY_SOURCE_COMMIT SOURCE_REVISION=$revision"
|
||||||
|
if [[ -n "${PKG_REPO_SIGN_KEY:-}" ]]; then
|
||||||
|
remote_command+=" PKG_REPO_SIGN_KEY=$PKG_REPO_SIGN_KEY"
|
||||||
|
fi
|
||||||
|
if [[ -n "${PKG_REPO_PUBLIC_KEY:-}" ]]; then
|
||||||
|
remote_command+=" PKG_REPO_PUBLIC_KEY=$PKG_REPO_PUBLIC_KEY"
|
||||||
|
fi
|
||||||
|
remote_command+=" sh '$FREEBSD_REMOTE_DIR/builder/freebsd/build-release.sh' '$FREEBSD_REMOTE_DIR'"
|
||||||
|
ssh "${ssh_args[@]}" "$remote" "$remote_command"
|
||||||
|
|
||||||
|
rm -rf "$ROOT/dist"
|
||||||
|
mkdir -p "$ROOT/dist"
|
||||||
|
rsync -az -e "ssh ${ssh_args[*]}" "$remote:$FREEBSD_REMOTE_DIR/dist/" "$ROOT/dist/"
|
||||||
|
;;
|
||||||
|
cross-binary)
|
||||||
|
RUSTPROXY_SOURCE_DIR="$RUSTPROXY_SOURCE_DIR" "$ROOT/builder/debian/build-freebsd-cross.sh"
|
||||||
|
echo "Cross mode builds a binary only and is not accepted as a release package pipeline."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown BUILD_MODE: $BUILD_MODE" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
publish_dist
|
||||||
|
auto_deploy_tests
|
||||||
Executable
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "Run as root on OPNsense" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REPO_URL="${1:-}"
|
||||||
|
PUBLIC_KEY_FILE="${2:-}"
|
||||||
|
|
||||||
|
if [ -z "$REPO_URL" ] || [ -z "$PUBLIC_KEY_FILE" ]; then
|
||||||
|
echo "usage: $0 https://packages.example.net/rustproxy/26.7/amd64 /path/to/rustproxy-repo.pub" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
if [ ! -r "$PUBLIC_KEY_FILE" ]; then
|
||||||
|
echo "Public key not readable: $PUBLIC_KEY_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -m 0755 /usr/local/etc/pkg/repos /usr/local/etc/pkg/keys
|
||||||
|
install -m 0444 "$PUBLIC_KEY_FILE" /usr/local/etc/pkg/keys/rustproxy-repo.pub
|
||||||
|
|
||||||
|
cat > /usr/local/etc/pkg/repos/RustProxy.conf <<EOF_CONF
|
||||||
|
RustProxy: {
|
||||||
|
url: "$REPO_URL",
|
||||||
|
enabled: yes,
|
||||||
|
signature_type: "pubkey",
|
||||||
|
pubkey: "/usr/local/etc/pkg/keys/rustproxy-repo.pub"
|
||||||
|
}
|
||||||
|
EOF_CONF
|
||||||
|
|
||||||
|
pkg update -f -r RustProxy
|
||||||
|
pkg install -y -r RustProxy os-rustproxy
|
||||||
|
|
||||||
|
echo "RustProxy plugin installed. Open Services -> RustProxy in OPNsense."
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
rm -f /usr/local/etc/pkg/repos/RustProxy.conf
|
||||||
|
rm -f /usr/local/etc/pkg/keys/rustproxy-repo.pub
|
||||||
|
pkg update -f
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
pkg update -f -r RustProxy
|
||||||
|
pkg install -y -r RustProxy os-rustproxy
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Architecture
|
||||||
|
|
||||||
|
## Release path
|
||||||
|
|
||||||
|
1. Debian cron runs once per hour.
|
||||||
|
2. It refreshes the packaging repository containing this plugin/build logic.
|
||||||
|
3. Independently, it fetches `APP_REPO_REF` from `https://git.linuxiarz.pl/gru/RustProxy` into `APP_WORKDIR`.
|
||||||
|
4. It compares both current commits with the last successful build state.
|
||||||
|
5. If either commit changed, Debian rsyncs the packaging tree and the RustProxy checkout separately to a FreeBSD 15.1 amd64 builder.
|
||||||
|
6. FreeBSD reads the application version from the downloaded `Cargo.toml`, runs Cargo tests and a release build.
|
||||||
|
7. The binary is injected into `opnsense-plugin/www/rustproxy/src/sbin/rust-proxy` inside a clean checkout of the official OPNsense plugins tree.
|
||||||
|
8. `make package` creates `os-rustproxy-<version>_<revision>.pkg`.
|
||||||
|
9. `pkg repo` creates a signed package repository.
|
||||||
|
10. Debian downloads `dist/` and optionally publishes it over rsync/SSH.
|
||||||
|
11. OPNsense consumes only the custom RustProxy package repository.
|
||||||
|
|
||||||
|
The packaging repository deliberately contains no `app/` directory. This prevents stale application code from accidentally being packaged.
|
||||||
|
|
||||||
|
## Upstream selection
|
||||||
|
|
||||||
|
Default configuration:
|
||||||
|
|
||||||
|
```text
|
||||||
|
APP_REPO_URL=https://git.linuxiarz.pl/gru/RustProxy
|
||||||
|
APP_REPO_REF=HEAD
|
||||||
|
```
|
||||||
|
|
||||||
|
`HEAD` follows the repository's default branch. To freeze releases, set `APP_REPO_REF` to a branch, tag or other fetchable ref. The exact commit used for each package is written to `dist/BUILD-INFO.txt`.
|
||||||
|
|
||||||
|
## Why native FreeBSD for releases
|
||||||
|
|
||||||
|
Rust can cross-compile to `x86_64-unknown-freebsd`, but a release also needs the target ABI and FreeBSD/OPNsense packaging behavior. A native FreeBSD builder makes both the Rust link step and `pkg` metadata/catalog generation match the target platform. The Docker/cross path is intended for fast developer validation only.
|
||||||
|
|
||||||
|
## OPNsense plugin behavior
|
||||||
|
|
||||||
|
The first UI version exposes only `general.enabled`.
|
||||||
|
|
||||||
|
- Enabled: the service controller renders configuration and starts RustProxy through configd.
|
||||||
|
- Disabled: the service controller stops RustProxy.
|
||||||
|
- Boot: an OPNsense syshook regenerates configuration and starts the service only when enabled.
|
||||||
|
|
||||||
|
RustProxy runs as the unprivileged `rustproxy` user. Its data is stored in `/var/db/rustproxy` and logs in `/var/log/rustproxy/rustproxy.log`.
|
||||||
|
|
||||||
|
## Ports 80 and 443
|
||||||
|
|
||||||
|
The MVP does not run RustProxy as root. Keep initial listeners above port 1023. If public 80/443 is required later, prefer an explicit PF redirect from 80/443 to high RustProxy listener ports instead of running the whole proxy as root.
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# First run
|
||||||
|
|
||||||
|
## 1. Push this packaging repository
|
||||||
|
|
||||||
|
Create a repository for the generated OPNsense plugin/build files and push this tree there. RustProxy itself must not be copied into this repository; it will be fetched dynamically from:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://git.linuxiarz.pl/gru/RustProxy
|
||||||
|
```
|
||||||
|
|
||||||
|
After pushing, set that new repository address as `PACKAGING_REPO_URL` in the Debian configuration.
|
||||||
|
|
||||||
|
## 2. Prepare the FreeBSD release builder
|
||||||
|
|
||||||
|
Use FreeBSD 15.1 amd64.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo sh builder/freebsd/bootstrap.sh builder
|
||||||
|
sudo -u builder sh builder/freebsd/create-repo-key.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The bootstrap creates a non-root `builder` account and gives it `/usr/local/rustproxy-build`.
|
||||||
|
|
||||||
|
## 3. Prepare Debian
|
||||||
|
|
||||||
|
From a checkout of this packaging repository:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo bash builder/debian/install.sh
|
||||||
|
sudo editor /etc/rustproxy-opnsense-builder.env
|
||||||
|
```
|
||||||
|
|
||||||
|
At minimum configure:
|
||||||
|
|
||||||
|
```text
|
||||||
|
PACKAGING_REPO_URL=<URL of this new packaging repository>
|
||||||
|
PACKAGING_REPO_REF=main
|
||||||
|
|
||||||
|
APP_REPO_URL=https://git.linuxiarz.pl/gru/RustProxy
|
||||||
|
APP_REPO_REF=HEAD
|
||||||
|
|
||||||
|
FREEBSD_HOST=<FreeBSD builder>
|
||||||
|
FREEBSD_USER=builder
|
||||||
|
FREEBSD_REMOTE_DIR=/usr/local/rustproxy-build/project
|
||||||
|
```
|
||||||
|
|
||||||
|
`APP_REPO_REF=HEAD` means "build the current default branch". If you want controlled releases, change it to a specific branch or tag.
|
||||||
|
|
||||||
|
Run the first cycle manually:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo /usr/local/sbin/rustproxy-opnsense-hourly
|
||||||
|
```
|
||||||
|
|
||||||
|
Cron runs at minute 17 of every hour. Each run fetches the RustProxy upstream. A new build starts when either the upstream RustProxy commit or this packaging repository commit changed. A failed build does not update `last-successful-build`, so it is retried on the next run.
|
||||||
|
|
||||||
|
## 4. Build state
|
||||||
|
|
||||||
|
Debian stores checkouts separately:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/rustproxy-opnsense/packaging/ # this repository
|
||||||
|
/srv/rustproxy-opnsense/source/RustProxy # dynamically fetched app
|
||||||
|
/var/lib/rustproxy-opnsense-builder/ # lock + last successful commit pair
|
||||||
|
```
|
||||||
|
|
||||||
|
The FreeBSD build machine receives the two trees separately. Its temporary `$FREEBSD_REMOTE_DIR/app/` always comes from the upstream checkout, never from the packaging repository.
|
||||||
|
|
||||||
|
## 5. Publish `dist/`
|
||||||
|
|
||||||
|
Set `PUBLISH_TARGET`. The published layout is similar to:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/rustproxy/
|
||||||
|
BUILD-INFO.txt
|
||||||
|
SHA256
|
||||||
|
rustproxy-repo.pub
|
||||||
|
repository/
|
||||||
|
26.7/
|
||||||
|
amd64/
|
||||||
|
os-rustproxy-<Cargo-version>_<revision>.pkg
|
||||||
|
meta.conf
|
||||||
|
data.pkg
|
||||||
|
packagesite.pkg
|
||||||
|
```
|
||||||
|
|
||||||
|
`BUILD-INFO.txt` contains the RustProxy source URL, ref and exact commit used to create the package.
|
||||||
|
|
||||||
|
## 6. Install on OPNsense
|
||||||
|
|
||||||
|
Copy `rustproxy-repo.pub` to the firewall and run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sh deploy/opnsense/install-repo.sh \
|
||||||
|
https://packages.example.net/rustproxy/repository/26.7/amd64 \
|
||||||
|
/tmp/rustproxy-repo.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open `Services -> RustProxy`, enable it and click Apply.
|
||||||
|
|
||||||
|
## 7. Update
|
||||||
|
|
||||||
|
Publishing a new package does not automatically upgrade production firewalls. Run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sh deploy/opnsense/update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`AUTO_DEPLOY_HOSTS` exists only for explicitly listed test firewalls and is empty by default.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
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 daemon" -d /var/db/rustproxy -s /usr/sbin/nologin
|
||||||
|
fi
|
||||||
|
|
||||||
|
/usr/bin/install -d -o rustproxy -g rustproxy -m 0750 /var/db/rustproxy
|
||||||
|
/usr/bin/install -d -o rustproxy -g rustproxy -m 0750 /var/log/rustproxy
|
||||||
|
/usr/bin/install -d -o root -g wheel -m 0755 /usr/local/etc/rustproxy
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
/usr/local/sbin/configctl rustproxy stop >/dev/null 2>&1 || true
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
PLUGIN_NAME= rustproxy
|
||||||
|
PLUGIN_VERSION?= 0.20.0
|
||||||
|
PLUGIN_REVISION?= 0
|
||||||
|
PLUGIN_COMMENT= RustProxy reverse proxy service
|
||||||
|
PLUGIN_MAINTAINER?= local@localhost
|
||||||
|
PLUGIN_WWW?= https://example.invalid/rustproxy
|
||||||
|
PLUGIN_LICENSE= UNKNOWN
|
||||||
|
|
||||||
|
.include "../../Mk/plugins.mk"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
RustProxy packaged as an OPNsense plugin.
|
||||||
|
|
||||||
|
The initial OPNsense UI intentionally exposes only one setting: Enabled.
|
||||||
|
Runtime proxy configuration remains managed by RustProxy itself.
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# PROVIDE: rustproxy
|
||||||
|
# REQUIRE: LOGIN NETWORKING
|
||||||
|
# KEYWORD: shutdown
|
||||||
|
|
||||||
|
. /etc/rc.subr
|
||||||
|
|
||||||
|
name="rustproxy"
|
||||||
|
rcvar="${name}_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_log_file:="${rustproxy_log_dir}/rustproxy.log"}
|
||||||
|
: ${rustproxy_command:="/usr/local/sbin/rust-proxy"}
|
||||||
|
: ${rustproxy_restart_delay:="5"}
|
||||||
|
|
||||||
|
pidfile="/var/run/rustproxy-daemon.pid"
|
||||||
|
child_pidfile="/var/run/rustproxy.pid"
|
||||||
|
command="/usr/sbin/daemon"
|
||||||
|
command_args="-r -R ${rustproxy_restart_delay} -P ${pidfile} -p ${child_pidfile} -u ${rustproxy_user} -o ${rustproxy_log_file} ${rustproxy_command} --data-dir ${rustproxy_data_dir} --update-check-interval-secs 0 serve"
|
||||||
|
required_files="${rustproxy_command}"
|
||||||
|
start_precmd="rustproxy_prestart"
|
||||||
|
stop_postcmd="rustproxy_poststop"
|
||||||
|
|
||||||
|
rustproxy_prestart()
|
||||||
|
{
|
||||||
|
/usr/bin/install -d -o "${rustproxy_user}" -g "${rustproxy_group}" -m 0750 "${rustproxy_data_dir}"
|
||||||
|
/usr/bin/install -d -o "${rustproxy_user}" -g "${rustproxy_group}" -m 0750 "${rustproxy_log_dir}"
|
||||||
|
/usr/bin/touch "${rustproxy_log_file}"
|
||||||
|
/usr/sbin/chown "${rustproxy_user}:${rustproxy_group}" "${rustproxy_log_file}"
|
||||||
|
/bin/chmod 0640 "${rustproxy_log_file}"
|
||||||
|
}
|
||||||
|
|
||||||
|
rustproxy_poststop()
|
||||||
|
{
|
||||||
|
/bin/rm -f "${child_pidfile}"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_rc_command "$1"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
/usr/local/sbin/configctl template reload OPNsense/RustProxy >/dev/null 2>&1 || true
|
||||||
|
/usr/local/sbin/configctl rustproxy boot >/dev/null 2>&1 || true
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OPNsense\RustProxy\Api;
|
||||||
|
|
||||||
|
use OPNsense\Base\ApiMutableServiceControllerBase;
|
||||||
|
|
||||||
|
class ServiceController extends ApiMutableServiceControllerBase
|
||||||
|
{
|
||||||
|
protected static $internalServiceClass = '\\OPNsense\\RustProxy\\RustProxy';
|
||||||
|
protected static $internalServiceTemplate = 'OPNsense/RustProxy';
|
||||||
|
protected static $internalServiceEnabled = 'general.enabled';
|
||||||
|
protected static $internalServiceName = 'rustproxy';
|
||||||
|
|
||||||
|
protected function reconfigureForceRestart()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OPNsense\RustProxy\Api;
|
||||||
|
|
||||||
|
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||||
|
|
||||||
|
class SettingsController extends ApiMutableModelControllerBase
|
||||||
|
{
|
||||||
|
protected static $internalModelClass = 'OPNsense\RustProxy\RustProxy';
|
||||||
|
protected static $internalModelName = 'rustproxy';
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OPNsense\RustProxy;
|
||||||
|
|
||||||
|
class IndexController extends \OPNsense\Base\IndexController
|
||||||
|
{
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->view->generalForm = $this->getForm('general');
|
||||||
|
$this->view->pick('OPNsense/RustProxy/index');
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<form>
|
||||||
|
<field>
|
||||||
|
<id>rustproxy.general.enabled</id>
|
||||||
|
<label>Enabled</label>
|
||||||
|
<type>checkbox</type>
|
||||||
|
<help>Start RustProxy and keep it enabled after OPNsense restarts.</help>
|
||||||
|
</field>
|
||||||
|
</form>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<acl>
|
||||||
|
<page-services-rustproxy>
|
||||||
|
<name>Services: RustProxy</name>
|
||||||
|
<description>Allow access to RustProxy settings and service controls</description>
|
||||||
|
<patterns>
|
||||||
|
<pattern>ui/rustproxy/*</pattern>
|
||||||
|
<pattern>api/rustproxy/*</pattern>
|
||||||
|
</patterns>
|
||||||
|
</page-services-rustproxy>
|
||||||
|
</acl>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<menu>
|
||||||
|
<Services>
|
||||||
|
<RustProxy cssClass="fa fa-exchange fa-fw">
|
||||||
|
<General VisibleName="General" order="10" url="/ui/rustproxy/"/>
|
||||||
|
</RustProxy>
|
||||||
|
</Services>
|
||||||
|
</menu>
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OPNsense\RustProxy;
|
||||||
|
|
||||||
|
use OPNsense\Base\BaseModel;
|
||||||
|
|
||||||
|
class RustProxy extends BaseModel
|
||||||
|
{
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
<model>
|
||||||
|
<mount>//OPNsense/rustproxy</mount>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<description>RustProxy service settings</description>
|
||||||
|
<items>
|
||||||
|
<general>
|
||||||
|
<enabled type="BooleanField">
|
||||||
|
<default>0</default>
|
||||||
|
<Required>Y</Required>
|
||||||
|
</enabled>
|
||||||
|
</general>
|
||||||
|
</items>
|
||||||
|
</model>
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
mapDataToFormUI({'frm_GeneralSettings': '/api/rustproxy/settings/get'}).done(function() {
|
||||||
|
updateServiceControlUI('rustproxy');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#reconfigureAct').SimpleActionButton({
|
||||||
|
onPreAction: function() {
|
||||||
|
const deferred = new $.Deferred();
|
||||||
|
saveFormToEndpoint(
|
||||||
|
'/api/rustproxy/settings/set',
|
||||||
|
'frm_GeneralSettings',
|
||||||
|
function() { deferred.resolve(); },
|
||||||
|
true,
|
||||||
|
function() { deferred.reject(); }
|
||||||
|
);
|
||||||
|
return deferred;
|
||||||
|
},
|
||||||
|
onAction: function() {
|
||||||
|
updateServiceControlUI('rustproxy');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="page-content-main">
|
||||||
|
<div class="content-box">
|
||||||
|
{{ partial("layout_partials/base_form", ['fields': generalForm, 'id': 'frm_GeneralSettings']) }}
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<div class="content-box">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<br/>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
id="reconfigureAct"
|
||||||
|
data-endpoint="/api/rustproxy/service/reconfigure"
|
||||||
|
data-label="{{ lang._('Apply') }}"
|
||||||
|
data-error-title="{{ lang._('Error reconfiguring RustProxy') }}"
|
||||||
|
type="button"></button>
|
||||||
|
<br/><br/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
CONFIG_FILE="/usr/local/etc/rustproxy/opnsense.conf"
|
||||||
|
RC_SCRIPT="/usr/local/etc/rc.d/rustproxy"
|
||||||
|
enabled="0"
|
||||||
|
|
||||||
|
if [ -r "$CONFIG_FILE" ]; then
|
||||||
|
. "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
start_service()
|
||||||
|
{
|
||||||
|
if [ "$enabled" != "1" ]; then
|
||||||
|
echo "RustProxy is disabled in OPNsense configuration"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
"$RC_SCRIPT" onestart
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_service()
|
||||||
|
{
|
||||||
|
"$RC_SCRIPT" onestop >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
start|boot)
|
||||||
|
start_service
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_service
|
||||||
|
;;
|
||||||
|
restart|reload)
|
||||||
|
stop_service
|
||||||
|
start_service
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
"$RC_SCRIPT" status
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "usage: $0 {start|stop|restart|reload|status|boot}" >&2
|
||||||
|
exit 64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
[start]
|
||||||
|
command:/usr/local/opnsense/scripts/rustproxy/service.sh start
|
||||||
|
parameters:
|
||||||
|
type:script
|
||||||
|
message:starting RustProxy
|
||||||
|
|
||||||
|
[stop]
|
||||||
|
command:/usr/local/opnsense/scripts/rustproxy/service.sh stop
|
||||||
|
parameters:
|
||||||
|
type:script
|
||||||
|
message:stopping RustProxy
|
||||||
|
|
||||||
|
[restart]
|
||||||
|
command:/usr/local/opnsense/scripts/rustproxy/service.sh restart
|
||||||
|
parameters:
|
||||||
|
type:script
|
||||||
|
message:restarting RustProxy
|
||||||
|
|
||||||
|
[reload]
|
||||||
|
command:/usr/local/opnsense/scripts/rustproxy/service.sh restart
|
||||||
|
parameters:
|
||||||
|
type:script
|
||||||
|
message:reloading RustProxy
|
||||||
|
|
||||||
|
[status]
|
||||||
|
command:/usr/local/opnsense/scripts/rustproxy/service.sh status
|
||||||
|
parameters:
|
||||||
|
type:script_output
|
||||||
|
message:RustProxy status
|
||||||
|
|
||||||
|
[boot]
|
||||||
|
command:/usr/local/opnsense/scripts/rustproxy/service.sh boot
|
||||||
|
parameters:
|
||||||
|
type:script
|
||||||
|
message:starting RustProxy at boot
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
rustproxy.conf:/usr/local/etc/rustproxy/opnsense.conf
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
enabled="{% if not helpers.empty('OPNsense.rustproxy.general.enabled') %}1{% else %}0{% endif %}"
|
||||||
Executable
+43
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
while IFS= read -r file; do
|
||||||
|
first_line="$(head -n 1 "$file")"
|
||||||
|
if [[ "$first_line" == *bash* ]]; then
|
||||||
|
bash -n "$file"
|
||||||
|
else
|
||||||
|
sh -n "$file"
|
||||||
|
fi
|
||||||
|
done < <(find "$ROOT" -type f \( -name '*.sh' -o -path '*/src/etc/rc.d/rustproxy' -o -path '*/src/etc/rc.syshook.d/*.start' \))
|
||||||
|
|
||||||
|
python3 - "$ROOT" <<'PY'
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
root = pathlib.Path(sys.argv[1])
|
||||||
|
for path in root.glob('opnsense-plugin/**/*.xml'):
|
||||||
|
ET.parse(path)
|
||||||
|
print('xml ok:', path.relative_to(root))
|
||||||
|
PY
|
||||||
|
|
||||||
|
if command -v php >/dev/null 2>&1; then
|
||||||
|
while IFS= read -r file; do php -l "$file" >/dev/null; done < <(find "$ROOT/opnsense-plugin" -type f -name '*.php')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${RUSTPROXY_SOURCE_DIR:-}" ]] && [[ -f "$RUSTPROXY_SOURCE_DIR/Cargo.toml" ]] && command -v cargo >/dev/null 2>&1; then
|
||||||
|
cargo metadata --locked --no-deps --format-version 1 --manifest-path "$RUSTPROXY_SOURCE_DIR/Cargo.toml" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d "$ROOT/app" ]]; then
|
||||||
|
echo "RustProxy source must not be vendored in this packaging repository: $ROOT/app" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -e "$ROOT/opnsense-plugin/www/rustproxy/src/sbin/rust-proxy" ]]; then
|
||||||
|
echo "Generated binary must not be committed in plugin source." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Repository checks passed."
|
||||||
Reference in new issue
Block a user