cleanup
This commit is contained in:
1 parent
feb9d91a3d
commit
1f0daa0679
25 files changed
+174
-1035
No files matched your search
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
SRC=${1:?usage: check-rustproxy-source.sh /path/to/RustProxy}
|
||||
|
||||
for f in Cargo.toml grafana/rustproxy-overview.json src/main/bootstrap.rs; do
|
||||
[[ -f "$SRC/$f" ]] || { echo "missing: $f" >&2; exit 1; }
|
||||
done
|
||||
grep -q '^name = "rust-proxy"' "$SRC/Cargo.toml"
|
||||
grep -q 'RUST_PROXY_CONFIG' "$SRC/src/main/bootstrap.rs"
|
||||
grep -q 'Reload,' "$SRC/src/main/bootstrap.rs"
|
||||
|
||||
# Old RustProxy releases shipped full Debian metadata. The 0.34.x source
|
||||
# archive no longer does; the builder's own nFPM fallback is authoritative.
|
||||
if [[ -f "$SRC/debian/rustproxy.service" ]]; then
|
||||
grep -q 'ExecStart=' "$SRC/debian/rustproxy.service"
|
||||
else
|
||||
[[ -f "$SRC/deploy/rustproxy.service" ]] || { echo 'no reference systemd unit found' >&2; exit 1; }
|
||||
grep -q '^ExecReload=' "$SRC/deploy/rustproxy.service"
|
||||
fi
|
||||
|
||||
echo 'RustProxy source supports --config and soft reload: OK'
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Offline verification of the agent-specific nFPM packaging pipeline.
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
SRC=${1:-}
|
||||
if [[ ! -d "${SRC:-}/docker-agent" ]]; then
|
||||
SRC="$WORK/source"
|
||||
mkdir -p "$SRC/docker-agent"
|
||||
cat > "$SRC/docker-agent/rustproxy-docker-agent.service" <<'UNIT'
|
||||
[Service]
|
||||
User=rustproxy-docker-agent
|
||||
Group=docker
|
||||
EnvironmentFile=/etc/rustproxy/docker-agent.env
|
||||
ExecStart=/usr/local/bin/rustproxy-docker-agent
|
||||
StateDirectory=rustproxy-docker-agent
|
||||
UNIT
|
||||
cat > "$SRC/docker-agent/docker-agent.env.example" <<'ENV'
|
||||
RUSTPROXY_DOCKER_AGENT_TOKEN=replace-with-at-least-24-random-characters
|
||||
ENV
|
||||
echo '# Docker Agent' > "$SRC/docker-agent/README.md"
|
||||
fi
|
||||
if [[ -f "$SRC/docker-agent/go.mod" && $(command -v go || true) ]]; then
|
||||
(cd "$SRC/docker-agent" && GOWORK=off CGO_ENABLED=0 go test ./... && \
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -o "$WORK/agent" .)
|
||||
else
|
||||
cat > "$WORK/agent" <<'MOCK'
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
MOCK
|
||||
chmod 0755 "$WORK/agent"
|
||||
fi
|
||||
export BUILDER_ROOT="$ROOT" VERSION=0.34.2 PACKAGE_RELEASE=4
|
||||
export MAINTAINER='Package QA <qa@example.invalid>' HOMEPAGE=https://example.invalid
|
||||
export GPG_PRIVATE_KEY_FILE="$WORK/test-key.asc"
|
||||
"$ROOT/scripts/prepare-agent-package.sh" "$SRC" "$WORK/package" "$WORK/agent"
|
||||
PKG="$WORK/package"
|
||||
test -x "$PKG/payload/usr/bin/rustproxy-docker-agent"
|
||||
grep -Fqx 'ExecStart=/usr/bin/rustproxy-docker-agent' "$PKG/payload/usr/lib/systemd/system/rustproxy-docker-agent.service"
|
||||
grep -Fq 'config|noreplace' "$PKG/nfpm-deb.yaml"
|
||||
grep -Fq 'config|noreplace' "$PKG/nfpm-rpm.yaml"
|
||||
grep -q 'type: origin' "$PKG/nfpm-deb.yaml"
|
||||
grep -q 'signature:' "$PKG/nfpm-rpm.yaml"
|
||||
! grep -q '\.pkg' "$PKG/nfpm-deb.yaml"
|
||||
for script in "$PKG"/scripts/*; do sh -n "$script"; done
|
||||
for script in "$PKG"/scripts/*postinstall.sh; do
|
||||
grep -Fq '/usr/bin/rustproxy-docker-agent init' "$script"
|
||||
grep -Fq 'systemctl enable rustproxy-docker-agent.service' "$script"
|
||||
done
|
||||
if python3 -c 'import yaml' >/dev/null 2>&1; then
|
||||
python3 - "$PKG" <<'PY_YAML'
|
||||
import yaml, pathlib, sys
|
||||
pkg=pathlib.Path(sys.argv[1])
|
||||
for kind in ('deb','rpm'):
|
||||
x=yaml.safe_load((pkg/f'nfpm-{kind}.yaml').read_text())
|
||||
assert x['name']=='rustproxy-docker-agent'
|
||||
assert x['version']=='0.34.2'
|
||||
assert x['arch']=='amd64'
|
||||
assert len(x['contents'])==4
|
||||
assert x['scripts']['postinstall']
|
||||
assert any(c['dst']=='/etc/rustproxy/docker-agent.env' and c['type']=='config|noreplace' for c in x['contents'])
|
||||
PY_YAML
|
||||
fi
|
||||
echo 'Docker Agent package manifests, service layout and lifecycle scripts: OK'
|
||||
@@ -1,96 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
SLEEP_PID=""
|
||||
cleanup() {
|
||||
[[ -z "$SLEEP_PID" ]] || kill "$SLEEP_PID" 2>/dev/null || true
|
||||
rm -rf "$WORK"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
for tool in file zstd tar python3; do
|
||||
command -v "$tool" >/dev/null 2>&1 || { echo "SKIP FreeBSD native packaging: missing $tool"; exit 0; }
|
||||
done
|
||||
mkdir -p "$WORK/source" "$WORK/repo/FreeBSD:15:amd64" "$WORK/run"
|
||||
printf '[package]\nname = "rust-proxy"\nversion = "0.34.1"\n' > "$WORK/source/Cargo.toml"
|
||||
python3 - "$WORK/bin" <<'PY'
|
||||
from pathlib import Path
|
||||
import struct,sys
|
||||
p=Path(sys.argv[1]); p.write_bytes(b'\x7fELF\x02\x01\x01\x09'+bytes(8)+struct.pack('<HHIQQQIHHHHHH',2,62,1,0,0,0,0,64,56,0,64,0,0));p.chmod(0o755)
|
||||
PY
|
||||
export BUILDER_ROOT="$ROOT" FREEBSD_ABI=FreeBSD:15:amd64 FREEBSD_ARCH=freebsd:15:x86:64
|
||||
"$ROOT/scripts/package-freebsd.sh" "$WORK/source" "$WORK/bin" "$WORK/rustproxy-0.34.1_2.pkg" 0.34.1_2
|
||||
zstd -dc "$WORK/rustproxy-0.34.1_2.pkg" | tar -xOf - +MANIFEST > "$WORK/manifest.json"
|
||||
python3 - "$WORK/manifest.json" <<'PY'
|
||||
import json,sys
|
||||
m=json.load(open(sys.argv[1])); names=set(m['files'])
|
||||
assert m['name']=='rustproxy'
|
||||
assert m['origin']=='www/rustproxy'
|
||||
assert m['version']=='0.34.1_2'
|
||||
assert m['abi']=='FreeBSD:15:amd64'
|
||||
assert '/usr/local/sbin/rust-proxy' in names
|
||||
assert '/usr/local/etc/rc.d/rustproxy' in names
|
||||
assert '/usr/local/etc/newsyslog.conf.d/rustproxy.conf' in names
|
||||
assert len(names)==3
|
||||
assert not any('/opnsense/' in n or 'syshook' in n for n in names)
|
||||
assert 'post-install' in m['scripts'] and 'pre-deinstall' in m['scripts']
|
||||
PY
|
||||
|
||||
# Test the actual rc.d reload command without a running FreeBSD machine.
|
||||
cat > "$WORK/rc.subr" <<'SH'
|
||||
load_rc_config() { :; }
|
||||
checkyesno() { eval 'v=${'"$1"'-NO}'; [ "$v" = YES ]; }
|
||||
run_rc_command() { case "$1" in reload) "$reload_cmd" ;; *) return 1 ;; esac; }
|
||||
SH
|
||||
cat > "$WORK/su" <<'SH'
|
||||
#!/bin/sh
|
||||
printf '%s\n' "$*" > "$TEST_ARGS"
|
||||
SH
|
||||
chmod +x "$WORK/su"
|
||||
python3 - "$ROOT/packaging/freebsd/rustproxy.rc" "$WORK/rc" "$WORK" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
src=Path(sys.argv[1]).read_text();w=Path(sys.argv[3]);
|
||||
src=src.replace('. /etc/rc.subr', f'. "{w}/rc.subr"')
|
||||
src=src.replace('/usr/bin/su -m', f'"{w}/su" -m')
|
||||
Path(sys.argv[2]).write_text(src)
|
||||
PY
|
||||
sleep 120 & SLEEP_PID=$!
|
||||
printf '%s\n' "$SLEEP_PID" > "$WORK/run/rustproxy.pid"
|
||||
export TEST_ARGS="$WORK/cli-args" rustproxy_run_dir="$WORK/run"
|
||||
export rustproxy_config=/usr/local/etc/rustproxy/config.json rustproxy_enable=YES
|
||||
sh "$WORK/rc" reload
|
||||
rg_args=$(cat "$TEST_ARGS")
|
||||
[[ "$rg_args" == *'--data-dir /var/db/rustproxy'* ]]
|
||||
[[ "$rg_args" == *'--config /usr/local/etc/rustproxy/config.json'* ]]
|
||||
[[ "$rg_args" == *'--admin-listen 127.0.0.1:9090 reload'* ]]
|
||||
export rustproxy_config='/usr/local/etc/rustproxy/config.json;touch /tmp/bad'
|
||||
if sh "$WORK/rc" reload >/dev/null 2>&1; then
|
||||
echo 'unsafe config path was accepted' >&2; exit 1
|
||||
fi
|
||||
unset rustproxy_config
|
||||
|
||||
# Catalog generation: mock FreeBSD bsdtar on Linux using zstd + tar.
|
||||
mkdir -p "$WORK/mockbin"
|
||||
cat > "$WORK/mockbin/bsdtar" <<'SH'
|
||||
#!/bin/sh
|
||||
case "$1" in
|
||||
-xOf) zstd -dc "$2" | tar -xOf - "$3" ;;
|
||||
*) exit 2 ;;
|
||||
esac
|
||||
SH
|
||||
chmod +x "$WORK/mockbin/bsdtar"
|
||||
cp "$WORK/rustproxy-0.34.1_2.pkg" "$WORK/repo/FreeBSD:15:amd64/"
|
||||
cp "$WORK/rustproxy-0.34.1_2.pkg" "$WORK/repo/rustproxy-latest.pkg"
|
||||
PATH="$WORK/mockbin:$PATH" python3 "$ROOT/scripts/generate-opnsense-repo.py" "$WORK/repo" --retention 10
|
||||
python3 - "$WORK/repo/packagesite.pkg" <<'PY'
|
||||
import json,tarfile,sys
|
||||
with tarfile.open(sys.argv[1]) as archive:
|
||||
content=archive.extractfile('packagesite.yaml').read().decode().splitlines()
|
||||
assert len(content)==1,content
|
||||
pkg=json.loads(content[0]);assert pkg['name']=='rustproxy'
|
||||
assert pkg['path']=='FreeBSD:15:amd64/rustproxy-0.34.1_2.pkg',pkg['path']
|
||||
PY
|
||||
|
||||
echo 'FreeBSD native package, rc.d reload and repository catalog: OK'
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$WORK/source"
|
||||
printf '#!/bin/sh\nexit 0\n' > "$WORK/rust-proxy"
|
||||
chmod 0755 "$WORK/rust-proxy"
|
||||
|
||||
export BUILDER_ROOT="$ROOT" PACKAGE_NAME=rustproxy BINARY_NAME=rust-proxy
|
||||
export VERSION=1.0.0 PACKAGE_RELEASE=1 DESCRIPTION=RustProxy LICENSE=UNKNOWN
|
||||
export MAINTAINER=test@example.invalid HOMEPAGE=https://example.invalid
|
||||
export GPG_PRIVATE_KEY_FILE=/nonexistent/test.gpg
|
||||
|
||||
check_unit() {
|
||||
local unit=$1
|
||||
# A read-only home does not conceal /home, unlike ProtectHome=true/tmpfs.
|
||||
[[ $(grep -c '^ProtectHome=read-only$' "$unit") -eq 1 ]]
|
||||
! grep -Eq '^ProtectHome=(true|yes|tmpfs|false|no)$' "$unit"
|
||||
grep -Fxq 'ProtectSystem=strict' "$unit"
|
||||
grep -Fxq 'User=rustproxy' "$unit"
|
||||
grep -Fxq 'Group=rustproxy' "$unit"
|
||||
grep -Fxq 'NoNewPrivileges=true' "$unit"
|
||||
grep -Fxq 'CapabilityBoundingSet=CAP_NET_BIND_SERVICE' "$unit"
|
||||
grep -Fq 'ReadWritePaths=-/etc/rustproxy' "$unit"
|
||||
grep -Fxq 'ExecReload=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 reload' "$unit"
|
||||
}
|
||||
|
||||
# Current RustProxy archive has no debian unit; both nFPM targets use fallback.
|
||||
"$ROOT/scripts/prepare-package.sh" "$WORK/source" "$WORK/fallback" "$WORK/rust-proxy"
|
||||
check_unit "$WORK/fallback/payload/usr/lib/systemd/system/rustproxy.service"
|
||||
for platform in deb rpm; do
|
||||
grep -Fq '/usr/lib/systemd/system/rustproxy.service' "$WORK/fallback/nfpm-$platform.yaml"
|
||||
grep -Fq '/usr/share/doc/rustproxy/FILESYSTEM_ACCESS.md' "$WORK/fallback/nfpm-$platform.yaml"
|
||||
done
|
||||
cmp "$ROOT/packaging/rustproxy-filesystem-access.md" \
|
||||
"$WORK/fallback/payload/usr/share/doc/rustproxy/FILESYSTEM_ACCESS.md"
|
||||
|
||||
# Some source releases ship their own unit. Normalize its outdated home policy
|
||||
# rather than letting it override the new package default.
|
||||
mkdir -p "$WORK/source/debian"
|
||||
cat > "$WORK/source/debian/rustproxy.service" <<'UNIT'
|
||||
[Unit]
|
||||
Description=RustProxy unit supplied with a source release
|
||||
|
||||
[Service]
|
||||
User=rustproxy
|
||||
Group=rustproxy
|
||||
ExecStart=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy serve
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/lib/rustproxy /var/log/rustproxy
|
||||
ProtectHome=true
|
||||
NoNewPrivileges=true
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
UNIT
|
||||
python3 "$ROOT/scripts/normalize-systemd-unit.py" "$WORK/source/debian/rustproxy.service" rust-proxy
|
||||
check_unit "$WORK/source/debian/rustproxy.service"
|
||||
|
||||
# A custom unit without ProtectHome must also get the new safe policy.
|
||||
sed -i '/^ProtectHome=/d' "$WORK/source/debian/rustproxy.service"
|
||||
python3 "$ROOT/scripts/normalize-systemd-unit.py" "$WORK/source/debian/rustproxy.service" rust-proxy
|
||||
check_unit "$WORK/source/debian/rustproxy.service"
|
||||
|
||||
echo 'Linux DEB/RPM external path access policy: OK'
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
|
||||
# The bundled Linux rules must match the expected user-provided settings.
|
||||
diff -u "$ROOT/packaging/rustproxy.logrotate" - <<'CONFIG'
|
||||
/var/log/rustproxy/*.jsonl /var/log/rustproxy/*.log /var/log/rustproxy/vhosts/*.jsonl {
|
||||
daily
|
||||
maxsize 512M
|
||||
rotate 14
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
copytruncate
|
||||
su rustproxy rustproxy
|
||||
}
|
||||
CONFIG
|
||||
|
||||
# All three log groups must also be tracked by native FreeBSD newsyslog.
|
||||
OPNSENSE_CONF="$ROOT/opnsense/plugin/src/etc/newsyslog.conf.d/rustproxy.conf"
|
||||
for pattern in '/var/log/rustproxy/*.jsonl' '/var/log/rustproxy/*.log' '/var/log/rustproxy/vhosts/*.jsonl'; do
|
||||
grep -Fq "$pattern " "$OPNSENSE_CONF"
|
||||
done
|
||||
[[ $(grep -c '^/var/log/rustproxy/' "$OPNSENSE_CONF") == 3 ]]
|
||||
grep -Fq '14 100M $D0 GBEZPN' "$OPNSENSE_CONF"
|
||||
grep -Fq '14 100M $D0 GBEZP /var/run/rustproxy/daemon.pid SIGHUP' "$OPNSENSE_CONF"
|
||||
grep -Fq ' -H -P ${pidfile}' "$ROOT/opnsense/plugin/src/etc/rc.d/rustproxy"
|
||||
grep -Fq 'COPY packaging/ /opt/rust-package-builder/packaging/' "$ROOT/Dockerfile"
|
||||
grep -Fq 'packaging_revision=$PACKAGING_REVISION' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'packaging_revision=$OPNSENSE_PACKAGING_REVISION' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
|
||||
# Test staging and native PKG manifest without compiling Rust or signing RPM/DEB.
|
||||
for tool in file zstd tar sha256sum python3; do
|
||||
command -v "$tool" >/dev/null 2>&1 || { echo "SKIP packaging integration: missing $tool"; exit 0; }
|
||||
done
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$WORK/source" "$WORK/linux"
|
||||
|
||||
if command -v logrotate >/dev/null 2>&1; then
|
||||
# Test parser compatibility even if the local test machine has no rustproxy user.
|
||||
sed 's/su rustproxy rustproxy/su root root/' "$ROOT/packaging/rustproxy.logrotate" > "$WORK/logrotate-test.conf"
|
||||
logrotate -d -s "$WORK/logrotate.state" "$WORK/logrotate-test.conf" > "$WORK/logrotate-output" 2>&1
|
||||
grep -Fq 'reading config file' "$WORK/logrotate-output"
|
||||
fi
|
||||
printf '[package]\nname = "rust-proxy"\nversion = "1.0.0"\n' > "$WORK/source/Cargo.toml"
|
||||
python3 - "$WORK/bin" <<'PY'
|
||||
from pathlib import Path
|
||||
import struct, sys
|
||||
p = Path(sys.argv[1])
|
||||
# ELF header with FreeBSD OSABI is enough to check the OPNsense packaging path.
|
||||
e_ident = b'\x7fELF\x02\x01\x01\x09' + bytes(8)
|
||||
header = struct.pack('<HHIQQQIHHHHHH', 2, 62, 1, 0, 0, 0, 0, 64, 56, 0, 64, 0, 0)
|
||||
p.write_bytes(e_ident + header)
|
||||
p.chmod(0o755)
|
||||
PY
|
||||
|
||||
export BUILDER_ROOT="$ROOT" PACKAGE_NAME=rustproxy BINARY_NAME=rust-proxy
|
||||
export VERSION=1.0.0 PACKAGE_RELEASE=2 DESCRIPTION=RustProxy LICENSE=UNKNOWN
|
||||
export MAINTAINER=test@example.invalid HOMEPAGE=https://example.invalid
|
||||
export GPG_PRIVATE_KEY_FILE=/nonexistent/test.gpg
|
||||
"$ROOT/scripts/prepare-package.sh" "$WORK/source" "$WORK/linux" "$WORK/bin"
|
||||
cmp "$ROOT/packaging/rustproxy.logrotate" "$WORK/linux/payload/etc/logrotate.d/rustproxy"
|
||||
UNIT="$WORK/linux/payload/usr/lib/systemd/system/rustproxy.service"
|
||||
grep -Fq 'ExecReload=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 reload' "$UNIT"
|
||||
grep -Fq 'ReadWritePaths=-/etc/rustproxy' "$UNIT"
|
||||
grep -Fxq 'ProtectHome=read-only' "$UNIT"
|
||||
grep -Fxq 'ProtectSystem=strict' "$UNIT"
|
||||
for metadata in nfpm-deb.yaml nfpm-rpm.yaml; do
|
||||
grep -Fq '/etc/logrotate.d/rustproxy' "$WORK/linux/$metadata"
|
||||
grep -Fq 'config|noreplace' "$WORK/linux/$metadata"
|
||||
grep -Fq ' - logrotate' "$WORK/linux/$metadata"
|
||||
done
|
||||
|
||||
"$ROOT/scripts/package-opnsense.sh" "$WORK/source" "$WORK/bin" "$WORK/os-rustproxy.pkg" '1.0.0_20'
|
||||
zstd -dc "$WORK/os-rustproxy.pkg" | tar -xOf - +MANIFEST > "$WORK/manifest.json"
|
||||
python3 - "$WORK/manifest.json" <<'PY'
|
||||
import json, sys
|
||||
with open(sys.argv[1]) as f:
|
||||
manifest=json.load(f)
|
||||
path='/usr/local/etc/newsyslog.conf.d/rustproxy.conf'
|
||||
assert path in manifest['files'], f'{path} missing from PKG manifest'
|
||||
assert path in manifest['files'] and len(manifest['files'][path]) == 64
|
||||
assert '/usr/local/etc/rc.d/rustproxy' in manifest['files']
|
||||
assert '/usr/local/etc/rc.syshook.d/start/50-rustproxy.start' in manifest['files']
|
||||
assert '/usr/local/etc/rc.syshook.d/10-rustproxy.start' not in manifest['files']
|
||||
PY
|
||||
zstd -dc "$WORK/os-rustproxy.pkg" | tar -xOf - /usr/local/etc/newsyslog.conf.d/rustproxy.conf > "$WORK/packaged-newsyslog.conf"
|
||||
cmp "$OPNSENSE_CONF" "$WORK/packaged-newsyslog.conf"
|
||||
echo 'log rotation package integration: OK'
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
SRC="$ROOT/opnsense/plugin/src"
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
RC="$SRC/etc/rc.d/rustproxy"
|
||||
HOOK="$SRC/etc/rc.syshook.d/start/50-rustproxy.start"
|
||||
SERVICE="$SRC/opnsense/scripts/rustproxy/service.sh"
|
||||
MODEL="$SRC/opnsense/mvc/app/models/OPNsense/RustProxy/RustProxy.xml"
|
||||
FORM="$SRC/opnsense/mvc/app/controllers/OPNsense/RustProxy/forms/general.xml"
|
||||
TEMPLATE="$SRC/opnsense/service/templates/OPNsense/RustProxy/rustproxy.conf"
|
||||
|
||||
[[ -f "$HOOK" && -x "$HOOK" ]] || { echo 'Boot syshook must exist and be executable' >&2; exit 1; }
|
||||
[[ ! -e "$SRC/etc/rc.syshook.d/10-rustproxy.start" ]] || { echo 'Old hook path still exists' >&2; exit 1; }
|
||||
for script in "$RC" "$HOOK" "$SERVICE"; do
|
||||
sh -n "$script"
|
||||
done
|
||||
php -l "$SRC/opnsense/mvc/app/models/OPNsense/RustProxy/Migrations/M1_5_0.php" >/dev/null
|
||||
|
||||
# Ensure GUI, model and Jinja template agree about the new setting.
|
||||
python3 - "$MODEL" "$FORM" "$TEMPLATE" <<'PY'
|
||||
import pathlib, sys, xml.etree.ElementTree as ET
|
||||
model = ET.parse(sys.argv[1]).getroot()
|
||||
form = ET.parse(sys.argv[2]).getroot()
|
||||
template = pathlib.Path(sys.argv[3]).read_text()
|
||||
assert model.find('version').text == '1.5.0'
|
||||
field = model.find('./items/general/updateCheckIntervalSecs')
|
||||
assert field is not None and field.attrib['type'] == 'IntegerField'
|
||||
assert field.findtext('Default') == '3600'
|
||||
assert field.findtext('MinimumValue') == '60'
|
||||
assert field.findtext('MaximumValue') == '604800'
|
||||
assert 'rustproxy.general.updateCheckIntervalSecs' in [e.text for e in form.iter('id')]
|
||||
assert 'rustproxy_update_check_interval_secs=' in template
|
||||
assert 'OPNsense.rustproxy.general.updateCheckIntervalSecs' in template
|
||||
PY
|
||||
|
||||
# Isolate the rc.d argument composition without running FreeBSD-only commands.
|
||||
cat > "$WORK/rc.subr" <<'EOF'
|
||||
load_rc_config() { :; }
|
||||
run_rc_command() {
|
||||
if [ "$1" = reload ]; then "$reload_cmd"; else printf '%s\n' "$command_args"; fi
|
||||
}
|
||||
EOF
|
||||
python3 - "$RC" "$WORK/rc-test" "$WORK" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
src = Path(sys.argv[1]).read_text()
|
||||
work = Path(sys.argv[3])
|
||||
src = src.replace('. /etc/rc.subr', '. "'+str(work/'rc.subr')+'"')
|
||||
src = src.replace('config_file="/usr/local/etc/rustproxy/opnsense.conf"', 'config_file="'+str(work/'opnsense.conf')+'"')
|
||||
Path(sys.argv[2]).write_text(src)
|
||||
PY
|
||||
|
||||
assert_interval() {
|
||||
local val=$1
|
||||
printf 'enabled="1"\nrustproxy_update_check_interval_secs="%s"\n' "$val" > "$WORK/opnsense.conf"
|
||||
local args
|
||||
args=$(sh "$WORK/rc-test" start)
|
||||
[[ "$args" == *"--update-check-interval-secs $val serve"* ]] || {
|
||||
echo "Wrong update interval arguments: $args" >&2; exit 1;
|
||||
}
|
||||
}
|
||||
assert_interval 3600
|
||||
assert_interval 7200
|
||||
assert_interval 60
|
||||
assert_interval 604800
|
||||
printf 'enabled="1"\n' > "$WORK/opnsense.conf"
|
||||
args=$(sh "$WORK/rc-test" start)
|
||||
[[ "$args" == *'--update-check-interval-secs 3600 serve'* ]] || exit 1
|
||||
# Exercise the rc.d soft reload itself with a live mock child and CLI.
|
||||
mkdir -p "$WORK/bin"
|
||||
cat > "$WORK/bin/mock-cli" <<'EOF'
|
||||
#!/bin/sh
|
||||
printf '%s\n' "$*" > "$TEST_CLI_ARGS"
|
||||
EOF
|
||||
chmod +x "$WORK/bin/mock-cli"
|
||||
printf 'enabled="1"\nrustproxy_config_path="/usr/local/etc/rustproxy/config.json"\n' > "$WORK/opnsense.conf"
|
||||
echo "$$" > "$WORK/rustproxy.pid"
|
||||
export TEST_CLI_ARGS="$WORK/cli-args"
|
||||
rustproxy_run_dir="$WORK" rustproxy_command="$WORK/bin/mock-cli" sh "$WORK/rc-test" reload
|
||||
args=$(cat "$TEST_CLI_ARGS")
|
||||
[[ "$args" == *'--data-dir /var/db/rustproxy'* ]]
|
||||
[[ "$args" == *'--config /usr/local/etc/rustproxy/config.json'* ]]
|
||||
[[ "$args" == *'--admin-listen 127.0.0.1:9090 reload'* ]]
|
||||
printf 'enabled="1"\nrustproxy_config_path="/usr/local/etc/rustproxy/config.json;touch /tmp/bad"\n' > "$WORK/opnsense.conf"
|
||||
if rustproxy_run_dir="$WORK" rustproxy_command="$WORK/bin/mock-cli" sh "$WORK/rc-test" reload >/dev/null 2>&1; then
|
||||
echo 'Unsafe OPNsense config path was accepted' >&2; exit 1
|
||||
fi
|
||||
|
||||
for invalid in 0 59 604801 nope '1;touch /tmp/pwn'; do
|
||||
printf 'enabled="1"\nrustproxy_update_check_interval_secs="%s"\n' "$invalid" > "$WORK/opnsense.conf"
|
||||
if sh "$WORK/rc-test" start >/dev/null 2>&1; then
|
||||
echo "Interval '$invalid' should have failed" >&2; exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Mock configd + rc.d so we can exercise the actual hook and service wrapper.
|
||||
mkdir -p "$WORK/bin"
|
||||
cat > "$WORK/bin/configctl" <<'EOF'
|
||||
#!/bin/sh
|
||||
printf 'template %s\n' "$*" >> "$TEST_LOG"
|
||||
if [ "${FAIL_RENDER:-0}" = 1 ]; then
|
||||
exit 2
|
||||
fi
|
||||
printf 'enabled="%s"\n' "${ENABLED:-1}" > "$TEST_CONFIG"
|
||||
EOF
|
||||
cat > "$WORK/bin/rustproxy-rc" <<'EOF'
|
||||
#!/bin/sh
|
||||
case "$1" in
|
||||
status) [ -f "$TEST_PID" ] ;;
|
||||
onestart) printf 'start\n' >> "$TEST_LOG"; touch "$TEST_PID" ;;
|
||||
onestop) printf 'stop\n' >> "$TEST_LOG"; rm -f "$TEST_PID" ;;
|
||||
reload) printf 'reload\n' >> "$TEST_LOG" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$WORK/bin/configctl" "$WORK/bin/rustproxy-rc"
|
||||
python3 - "$HOOK" "$SERVICE" "$WORK" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
hook = Path(sys.argv[1]).read_text()
|
||||
service = Path(sys.argv[2]).read_text()
|
||||
w = Path(sys.argv[3])
|
||||
hook = hook.replace('/usr/local/sbin/configctl', str(w/'bin/configctl'))
|
||||
hook = hook.replace('/usr/local/opnsense/scripts/rustproxy/service.sh', str(w/'service-test'))
|
||||
service = service.replace('/usr/local/etc/rustproxy/opnsense.conf', str(w/'opnsense.conf'))
|
||||
service = service.replace('/usr/local/etc/rc.d/rustproxy', str(w/'bin/rustproxy-rc'))
|
||||
(w/'hook-test').write_text(hook)
|
||||
(w/'service-test').write_text(service)
|
||||
PY
|
||||
chmod +x "$WORK/hook-test" "$WORK/service-test"
|
||||
export TEST_LOG="$WORK/actions.log" TEST_CONFIG="$WORK/opnsense.conf" TEST_PID="$WORK/pidfile"
|
||||
: > "$TEST_LOG"
|
||||
ENABLED=1 "$WORK/hook-test"
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Boot did not start service' >&2; exit 1; }
|
||||
ENABLED=1 "$WORK/hook-test"
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Duplicate supervisor start' >&2; exit 1; }
|
||||
ENABLED=1 "$WORK/service-test" reload
|
||||
[[ $(grep -cx reload "$TEST_LOG") == 1 ]] || { echo 'Soft reload not passed through' >&2; exit 1; }
|
||||
[[ $(grep -cx stop "$TEST_LOG" || true) == 0 ]] || { echo 'Soft reload restarted service' >&2; exit 1; }
|
||||
rm -f "$TEST_PID"
|
||||
ENABLED=0 "$WORK/hook-test"
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Disabled service started' >&2; exit 1; }
|
||||
if FAIL_RENDER=1 ENABLED=1 "$WORK/hook-test" >/dev/null 2>&1; then
|
||||
echo 'Broken configuration reload was not reported' >&2; exit 1
|
||||
fi
|
||||
[[ $(grep -cx start "$TEST_LOG") == 1 ]] || { echo 'Started despite failed template rendering' >&2; exit 1; }
|
||||
|
||||
echo 'OPNsense boot / update interval / soft reload checks: OK'
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
|
||||
for f in "$ROOT"/start.sh "$ROOT"/scripts/*.sh "$ROOT"/tests/*.sh; do
|
||||
bash -n "$f"
|
||||
done
|
||||
python3 -m py_compile "$ROOT/scripts/generate-opnsense-repo.py"
|
||||
|
||||
# Main image/build dependencies.
|
||||
grep -q 'FROM rockylinux:9' "$ROOT/Dockerfile"
|
||||
grep -q 'FREEBSD_RELEASE=15.1-RELEASE' "$ROOT/Dockerfile"
|
||||
grep -q 'x86_64-unknown-freebsd' "$ROOT/Dockerfile"
|
||||
grep -q '/opt/freebsd-sysroot' "$ROOT/Dockerfile"
|
||||
|
||||
# Coordinator uses one checkout but independent branches.
|
||||
grep -q 'build-linux-release.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'build-opnsense-release.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'build-freebsd-release.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'package-freebsd.sh' "$ROOT/scripts/build-freebsd-release.sh"
|
||||
grep -q 'FREEBSD_NATIVE_PACKAGING_REVISION=1' "$ROOT/scripts/lib.sh"
|
||||
grep -Fq 'FREEBSD_NATIVE_ENABLED: "${FREEBSD_NATIVE_ENABLED:-0}"' "$ROOT/docker-compose.yml"
|
||||
grep -Fq 'location /freebsd/' "$ROOT/http/nginx.conf"
|
||||
grep -Fq 'FREEBSD_NATIVE_ENABLED=0' "$ROOT/.env.example"
|
||||
grep -Fq 'ExecReload=/usr/bin/' "$ROOT/scripts/normalize-systemd-unit.py"
|
||||
grep -q 'OPNsense branch will still run' "$ROOT/scripts/build-release.sh"
|
||||
|
||||
# Linux tests gate Linux packaging only.
|
||||
grep -Fq 'cargo "+$LINUX_RUST_TOOLCHAIN" test --release' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'CGO_ENABLED=0 go test ./...' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'prepare-agent-package.sh' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'AGENT_DEB_FILE=' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'AGENT_RPM_FILE=' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'rustproxy-docker-agent' "$ROOT/scripts/generate-index.sh"
|
||||
grep -Fq 'COPY --from=go-toolchain' "$ROOT/Dockerfile"
|
||||
grep -q 'PACKAGING_REVISION=5' "$ROOT/scripts/lib.sh"
|
||||
grep -Fq 'ensure-rust-toolchain.sh' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -Fq 'ensure-rust-toolchain.sh' "$ROOT/scripts/build-opnsense.sh"
|
||||
grep -Fq 'nfpm package' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -q 'aptly .*publish' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -q 'createrepo_c' "$ROOT/scripts/build-linux-release.sh"
|
||||
[[ -x "$ROOT/tests/linux-path-access.sh" ]]
|
||||
! grep -q 'cargo test' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
! grep -q 'cargo test' "$ROOT/scripts/build-opnsense.sh"
|
||||
|
||||
# FreeBSD/OPNsense branch.
|
||||
grep -q 'build-opnsense.sh' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
grep -q 'package-opnsense.sh' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
grep -q 'generate-opnsense-repo.py' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
grep -q 'last_opnsense_commit' "$ROOT/scripts/build-opnsense-release.sh"
|
||||
test -f "$ROOT/opnsense/plugin/src/etc/rc.d/rustproxy"
|
||||
test -x "$ROOT/opnsense/plugin/src/etc/rc.syshook.d/start/50-rustproxy.start"
|
||||
[[ ! -e "$ROOT/opnsense/plugin/src/etc/rc.syshook.d/10-rustproxy.start" ]]
|
||||
grep -q 'OPNSENSE_PACKAGING_REVISION=4' "$ROOT/scripts/lib.sh"
|
||||
test -f "$ROOT/opnsense/patches/0.20.0/0001-opnsense-build.patch"
|
||||
|
||||
# Per-branch state/retry logic.
|
||||
grep -q 'last_linux_commit' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'last_opnsense_commit' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'BUILD_LINUX' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'BUILD_OPNSENSE' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'RUN_LINUX_TESTS=${RUN_LINUX_TESTS:-1}' "$ROOT/scripts/entrypoint.sh"
|
||||
grep -Fq 'RUN_LINUX_TESTS: "${RUN_LINUX_TESTS:-1}"' "$ROOT/docker-compose.yml"
|
||||
|
||||
# Two public endpoints from one nginx container.
|
||||
grep -Fq '${REPOSITORY_URL:?REPOSITORY_URL is required}' "$ROOT/docker-compose.yml"
|
||||
grep -Fq '${OPNSENSE_REPOSITORY_URL:?OPNSENSE_REPOSITORY_URL is required}' "$ROOT/docker-compose.yml"
|
||||
grep -Fq '0.0.0.0:${HTTP_PORT:-18765}:8080' "$ROOT/docker-compose.yml"
|
||||
grep -Fq '0.0.0.0:${OPNSENSE_HTTP_PORT:-18766}:8081' "$ROOT/docker-compose.yml"
|
||||
grep -q 'listen 8080' "$ROOT/http/nginx.conf"
|
||||
grep -q 'listen 8081' "$ROOT/http/nginx.conf"
|
||||
grep -q 'root /srv/repository/opnsense' "$ROOT/http/nginx.conf"
|
||||
|
||||
grep -q 'DEFAULT_HTTP_PORT=18765' "$ROOT/start.sh"
|
||||
grep -q 'DEFAULT_OPNSENSE_HTTP_PORT=18766' "$ROOT/start.sh"
|
||||
grep -q 'OPNSENSE_REPOSITORY_URL=https://opn-rustproxy.linuxiarz.pl' "$ROOT/.env.example"
|
||||
grep -q 'RUN_LINUX_TESTS=1' "$ROOT/.env.example"
|
||||
|
||||
echo 'static checks: OK'
|
||||
@@ -1,157 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run: python3 -m unittest discover -s tests -p 'test_dashboard.py' -v"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
from datetime import datetime, timezone
|
||||
from http.server import ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
spec = importlib.util.spec_from_file_location("dashboard_app", ROOT / "dashboard" / "app.py")
|
||||
app = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(app)
|
||||
|
||||
|
||||
class RepoFixture:
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.repo = Path(self.temp.name) / "repository"
|
||||
self.r1 = self.repo / "releases" / "r1"
|
||||
self.r1.mkdir(parents=True)
|
||||
(self.repo / "current").symlink_to("releases/r1")
|
||||
|
||||
def make_file(self, name, *, contents="package-bytes", timestamp=1735853760):
|
||||
path = self.r1 / name
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
path.write_text(contents,encoding="utf-8")
|
||||
os.utime(path,(timestamp,timestamp))
|
||||
return path
|
||||
|
||||
def make_catalog(self):
|
||||
self.make_file("apt/pool/r/rustproxy/rustproxy_0.34.6-2_amd64.deb")
|
||||
self.make_file("apt/pool/r/rustproxy/rustproxy-docker-agent_0.34.6-2_amd64.deb")
|
||||
self.make_file("rpm/x86_64/rustproxy-0.34.6-2.x86_64.rpm")
|
||||
self.make_file("rpm/x86_64/rustproxy-docker-agent-0.34.6-2.x86_64.rpm")
|
||||
self.make_file("opnsense/26.7/amd64/os-rustproxy-0.34.6_123.pkg")
|
||||
self.make_file("opnsense/packagesite.pkg",contents="index")
|
||||
self.make_file("opnsense/os-rustproxy-latest.pkg",contents="duplicate")
|
||||
self.make_file("freebsd/FreeBSD:15:amd64/rustproxy-0.34.6_123.pkg")
|
||||
self.make_file("freebsd/rustproxy-latest.pkg",contents="duplicate")
|
||||
self.make_file("LINUX-BUILD-INFO.txt",contents="app_version=0.34.6\npackage_release=2\nsource_commit=abc123\nbuilt_at=2026-10-22T08:41:00Z\n")
|
||||
self.make_file("opnsense/BUILD-INFO.txt",contents="app_version=0.34.6\npackage_version=0.34.6_123\nsource_commit=abc123\nbuilt_at=2026-10-22T08:43:00Z\n")
|
||||
self.make_file("freebsd/BUILD-INFO.txt",contents="app_version=0.34.6\npackage_version=0.34.6_123\nsource_commit=abc123\nbuilt_at=2026-10-22T08:45:00Z\n")
|
||||
|
||||
class CatalogTests(RepoFixture, unittest.TestCase):
|
||||
def test_scans_real_file_layout_without_index_duplicates(self):
|
||||
self.make_catalog()
|
||||
catalog = app.generate_catalog(self.repo)
|
||||
self.assertEqual(6, catalog["summary"]["packages_count"])
|
||||
self.assertEqual(3, catalog["summary"]["channels_published"])
|
||||
self.assertEqual(4, catalog["summary"]["channel_counts"]["linux"])
|
||||
self.assertEqual(1, catalog["summary"]["channel_counts"]["opnsense"])
|
||||
self.assertEqual(1, catalog["summary"]["channel_counts"]["freebsd"])
|
||||
self.assertEqual("0.34.6-2",catalog["builds"]["linux"]["package_version"])
|
||||
self.assertEqual("2026-10-22T08:45:00Z",catalog["summary"]["latest_build_at"])
|
||||
linux = [p for p in catalog["packages"] if p["format"] == "RPM"]
|
||||
self.assertEqual({"rustproxy","rustproxy-docker-agent"}, {p["name"] for p in linux})
|
||||
self.assertEqual("2026-10-22T08:41:00Z", linux[0]["built_at"])
|
||||
self.assertEqual("build",linux[0]["date_source"])
|
||||
opnsense = next(p for p in catalog["packages"] if p["channel"] == "opnsense")
|
||||
self.assertTrue(opnsense["download_url"].endswith("/26.7/amd64/os-rustproxy-0.34.6_123.pkg"))
|
||||
freebsd = next(p for p in catalog["packages"] if p["channel"] == "freebsd")
|
||||
self.assertIn("/freebsd/FreeBSD%3A15%3Aamd64/",freebsd["download_url"])
|
||||
self.assertEqual("2026-10-22T08:45:00Z",freebsd["built_at"])
|
||||
|
||||
def test_mtime_backwards_compatibility(self):
|
||||
self.make_file("LINUX-BUILD-INFO.txt",contents="app_version=0.21.0\npackage_release=5\n")
|
||||
self.make_file("rpm/x86_64/rustproxy-0.21.0-5.x86_64.rpm")
|
||||
catalog = app.generate_catalog(self.repo)
|
||||
self.assertEqual("file", catalog["builds"]["linux"]["date_source"])
|
||||
self.assertEqual("file", catalog["packages"][0]["date_source"])
|
||||
self.assertEqual("0.21.0-5",catalog["packages"][0]["version"])
|
||||
self.assertTrue(catalog["packages"][0]["built_at"].endswith("Z"))
|
||||
|
||||
def test_symlink_rotation_gives_current_packages(self):
|
||||
self.make_file("rpm/x86_64/rustproxy-0.1.0-1.x86_64.rpm")
|
||||
v2 = self.repo / "releases" / "r2"
|
||||
v2.mkdir()
|
||||
(v2 / "rpm/x86_64").mkdir(parents=True)
|
||||
(v2 / "rpm/x86_64/rustproxy-0.2.0-1.x86_64.rpm").write_bytes(b"new package")
|
||||
before = app.generate_catalog(self.repo)
|
||||
self.assertEqual("0.1.0-1",before["packages"][0]["version"])
|
||||
(self.repo / "current.new").symlink_to("releases/r2")
|
||||
os.replace(self.repo / "current.new",self.repo / "current")
|
||||
after = app.generate_catalog(self.repo)
|
||||
self.assertEqual("0.2.0-1",after["packages"][0]["version"])
|
||||
|
||||
def test_empty_repo_and_untrusted_symlink(self):
|
||||
first = app.generate_catalog(self.repo)
|
||||
self.assertFalse(first["ready"])
|
||||
self.assertEqual([],first["packages"])
|
||||
(self.repo / "current").unlink()
|
||||
(self.repo / "current").symlink_to(self.temp.name) # outside repo root
|
||||
second = app.generate_catalog(self.repo)
|
||||
self.assertFalse(second["ready"])
|
||||
self.assertEqual([],second["packages"])
|
||||
|
||||
def test_regexes_and_metadata_parser(self):
|
||||
self.assertEqual(("rustproxy-docker-agent","0.34.6-2","x86_64"),app.parse_filename("rustproxy-docker-agent-0.34.6-2.x86_64.rpm","rpm"))
|
||||
self.assertEqual(("os-rustproxy","0.34.6_123","amd64"),app.parse_filename("os-rustproxy-0.34.6_123.pkg","pkg"))
|
||||
self.assertIsNone(app.parse_filename("packagesite.pkg","pkg"))
|
||||
self.assertIsNone(app.parse_filename("rustproxy-latest.pkg","pkg"))
|
||||
self.assertIsNone(app.parse_filename("repomd.xml","rpm"))
|
||||
self.assertEqual({},app.parse_metadata(self.repo/"missing-info.txt"))
|
||||
|
||||
|
||||
class HttpTests(RepoFixture, unittest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.make_catalog()
|
||||
original_cache = app.CACHE
|
||||
app.CACHE = app.CatalogCache(self.repo,ttl=1)
|
||||
self.addCleanup(lambda: setattr(app,"CACHE",original_cache))
|
||||
self.server = ThreadingHTTPServer(("127.0.0.1",0),app.DashboardHandler)
|
||||
self.thread = threading.Thread(target=self.server.serve_forever,daemon=True)
|
||||
self.thread.start()
|
||||
self.addCleanup(self.server.server_close)
|
||||
self.addCleanup(self.server.shutdown)
|
||||
self.base = f"http://127.0.0.1:{self.server.server_port}"
|
||||
|
||||
def test_http_catalog_page_assets_head(self):
|
||||
with urlopen(self.base + "/api/v1/packages") as response:
|
||||
self.assertIn("no-store",response.headers["Cache-Control"])
|
||||
catalog = json.load(response)
|
||||
self.assertEqual(6,len(catalog["packages"]))
|
||||
request = Request(self.base + "/",headers={"X-Repo-Site":"opnsense"})
|
||||
with urlopen(request) as response:
|
||||
html = response.read().decode()
|
||||
self.assertIn('data-site="opnsense"',html)
|
||||
self.assertIn("Package Registry",html)
|
||||
self.assertIn("Content-Security-Policy",response.headers)
|
||||
with urlopen(self.base + "/freebsd/") as response:
|
||||
self.assertIn('data-site="freebsd"',response.read().decode())
|
||||
with urlopen(self.base + "/ui/style.css") as response:
|
||||
self.assertIn("text/css",response.headers["Content-Type"])
|
||||
self.assertIn("--accent:#f69b74",response.read().decode())
|
||||
request = Request(self.base + "/ui/app.js", method="HEAD")
|
||||
with urlopen(request) as response:
|
||||
self.assertEqual(200,response.status)
|
||||
self.assertEqual(b"",response.read())
|
||||
with self.assertRaises(HTTPError) as raised:
|
||||
urlopen(self.base + "/../something")
|
||||
self.assertEqual(404,raised.exception.code)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,136 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Offline simulation of rustup installation/selection; no Rust or network required.
|
||||
set -Eeuo pipefail
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
mkdir -p "$WORK/bin" "$WORK/source" "$WORK/state"
|
||||
cat > "$WORK/bin/rustup" <<'MOCK'
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
state=${MOCK_RUSTUP_STATE:?}
|
||||
case "$1" in
|
||||
run)
|
||||
channel=$2
|
||||
[[ -r "$state/$channel.version" ]] || exit 1
|
||||
printf 'rustc %s (mock)\n' "$(cat "$state/$channel.version")"
|
||||
;;
|
||||
toolchain)
|
||||
[[ "$2" == install ]] || exit 7
|
||||
channel=$3
|
||||
[[ ${MOCK_INSTALL_FAIL:-0} != 1 ]] || exit 9
|
||||
case "$channel" in
|
||||
stable) version=${MOCK_NEW_STABLE:-1.100.0} ;;
|
||||
*) case "$channel" in *.*.*) version=$channel ;; *) version=${channel}.0 ;; esac ;;
|
||||
esac
|
||||
echo "$version" > "$state/$channel.version"
|
||||
printf 'install %s\n' "$channel" >> "$state/calls"
|
||||
;;
|
||||
target)
|
||||
action=$2
|
||||
if [[ "$action" == list ]]; then
|
||||
[[ "$3" == --toolchain && "$5" == --installed ]] || exit 7
|
||||
[[ -f "$state/$4.target" ]] && cat "$state/$4.target"
|
||||
elif [[ "$action" == add ]]; then
|
||||
[[ "$4" == --toolchain ]] || exit 7
|
||||
echo "$3" > "$state/$5.target"
|
||||
printf 'target %s %s\n' "$5" "$3" >> "$state/calls"
|
||||
else exit 7
|
||||
fi
|
||||
;;
|
||||
*) printf 'Unexpected rustup arguments: %s\n' "$*" >&2; exit 7 ;;
|
||||
esac
|
||||
MOCK
|
||||
chmod +x "$WORK/bin/rustup"
|
||||
export PATH="$WORK/bin:$PATH" MOCK_RUSTUP_STATE="$WORK/state" TOML_PYTHON=python3
|
||||
TOOL="$ROOT/scripts/ensure-rust-toolchain.sh"
|
||||
reset_state() { rm -f "$WORK/state/"*; }
|
||||
manifest() { printf '[package]\nname = "rust-proxy"\nversion = "0.31.2"\nrust-version = "%s"\n' "$1" > "$WORK/source/Cargo.toml"; rm -f "$WORK/source/rust-toolchain" "$WORK/source/rust-toolchain.toml"; }
|
||||
|
||||
# No update or download when installed stable already satisfies the manifest.
|
||||
reset_state
|
||||
manifest 1.99
|
||||
printf '1.100.0\n' > "$WORK/state/stable.version"
|
||||
result=$($TOOL "$WORK/source" linux)
|
||||
[[ "$result" == stable ]]
|
||||
[[ ! -e "$WORK/state/calls" ]]
|
||||
|
||||
# Upgrade stable only when too old, then reuse it on subsequent checks.
|
||||
reset_state
|
||||
printf '1.98.1\n' > "$WORK/state/stable.version"
|
||||
result=$($TOOL "$WORK/source" linux)
|
||||
[[ "$result" == stable ]]
|
||||
grep -Fqx 'install stable' "$WORK/state/calls"
|
||||
[[ $($TOOL "$WORK/source" linux) == stable ]]
|
||||
[[ $(wc -l < "$WORK/state/calls") == 1 ]]
|
||||
|
||||
# FreeBSD default 1.88 is auto raised to the project's 1.99 MSRV with its own target.
|
||||
reset_state
|
||||
result=$(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd)
|
||||
[[ "$result" == 1.99 ]]
|
||||
grep -Fqx 'install 1.99' "$WORK/state/calls"
|
||||
grep -Fqx 'target 1.99 x86_64-unknown-freebsd' "$WORK/state/calls"
|
||||
[[ $(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) == 1.99 ]]
|
||||
[[ $(wc -l < "$WORK/state/calls") == 2 ]]
|
||||
|
||||
# A deliberate rust-toolchain.toml pin is respected; do not silently override it.
|
||||
reset_state
|
||||
cat > "$WORK/source/rust-toolchain.toml" <<'PIN'
|
||||
[toolchain]
|
||||
channel = "1.98.0"
|
||||
PIN
|
||||
if "$TOOL" "$WORK/source" linux >/dev/null 2>&1; then
|
||||
printf 'An incompatible explicit pin should have failed\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -e "$WORK/state/calls" ]] || { echo 'Should not install an incompatible pin' >&2; exit 1; }
|
||||
rm "$WORK/source/rust-toolchain.toml"
|
||||
|
||||
# Pin that meets the project requirement is installed without changing stable.
|
||||
reset_state
|
||||
cat > "$WORK/source/rust-toolchain.toml" <<'PIN'
|
||||
[toolchain]
|
||||
channel = "1.99.0"
|
||||
PIN
|
||||
[[ $($TOOL "$WORK/source" linux) == 1.99.0 ]]
|
||||
grep -Fqx 'install 1.99.0' "$WORK/state/calls"
|
||||
rm "$WORK/source/rust-toolchain.toml"
|
||||
|
||||
# RustProxy-like rust-toolchain.toml (stable) also upgrades stale stable for FreeBSD.
|
||||
reset_state
|
||||
manifest 1.99
|
||||
cat > "$WORK/source/rust-toolchain.toml" <<'PIN'
|
||||
[toolchain]
|
||||
channel = "stable"
|
||||
profile = "minimal"
|
||||
components = ["rustfmt", "clippy"]
|
||||
PIN
|
||||
printf '1.98.1\n' > "$WORK/state/stable.version"
|
||||
[[ $(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) == stable ]]
|
||||
grep -Fqx 'install stable' "$WORK/state/calls"
|
||||
grep -Fqx 'target stable x86_64-unknown-freebsd' "$WORK/state/calls"
|
||||
rm "$WORK/source/rust-toolchain.toml"
|
||||
|
||||
# Workspace-inherited rust-version is resolved through TOML, not grep.
|
||||
reset_state
|
||||
cat > "$WORK/source/Cargo.toml" <<'MANIFEST'
|
||||
[workspace.package]
|
||||
rust-version = "1.99"
|
||||
[package]
|
||||
name = "rust-proxy"
|
||||
version = "0.31.2"
|
||||
rust-version = { workspace = true }
|
||||
MANIFEST
|
||||
printf '1.100.0\n' > "$WORK/state/stable.version"
|
||||
[[ $($TOOL "$WORK/source" linux) == stable ]]
|
||||
|
||||
# An unavailable upgrade must be a hard failure.
|
||||
reset_state
|
||||
manifest 1.99
|
||||
printf '1.98.1\n' > "$WORK/state/stable.version"
|
||||
if MOCK_INSTALL_FAIL=1 "$TOOL" "$WORK/source" linux >/dev/null 2>&1; then
|
||||
printf 'A failed rustup update should abort the build\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 'Rust toolchain selection: 8 offline scenarios OK'
|
||||
Reference in new issue
Block a user