opn
This commit is contained in:
1 parent
e2398a4379
commit
92aa0b676d
9 files changed
+425
-310
No files matched your search
+1
-1
@@ -30,7 +30,7 @@ ARG APTLY_ZIP_SHA256=535ed24eb706bc25a316b59d709a7e74e10165f2ffab8552097ba7e4816
|
||||
RUN dnf -y install --allowerasing \
|
||||
bash binutils ca-certificates clang cmake coreutils createrepo_c curl file findutils \
|
||||
gcc gcc-c++ git gnupg2 gzip libarchive lld llvm make openssl pkgconf-pkg-config \
|
||||
python3 python3.11 rpm rsync shadow-utils sqlite-devel tar unzip xz bzip2 zstd bsdtar \
|
||||
python3 python3.11 rpm rsync shadow-utils sqlite-devel tar unzip xz bzip2 zstd \
|
||||
&& dnf clean all \
|
||||
&& rm -rf /var/cache/dnf
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Jeden kontener buildera buduje z jednego commita RustProxy:
|
||||
- FreeBSD x86_64: cross-build bez VM FreeBSD,
|
||||
- OPNsense: `os-rustproxy-<version>_<revision>.pkg` + statyczne repo `pkg`.
|
||||
|
||||
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, ale wszystkie artefakty są publikowane jednym atomowym przełączeniem `repository/current`.
|
||||
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.
|
||||
|
||||
## Szybki start
|
||||
|
||||
@@ -44,26 +44,22 @@ opn-rustproxy.linuxiarz.pl -> http://builder:18766
|
||||
## Pipeline
|
||||
|
||||
```text
|
||||
Git RustProxy
|
||||
|
|
||||
+-> cargo test
|
||||
+-> Linux cargo build
|
||||
| +-> DEB
|
||||
| +-> RPM
|
||||
|
|
||||
+-> izolowana kopia źródła
|
||||
+-> poprawki FreeBSD/OPNsense
|
||||
+-> x86_64-unknown-freebsd
|
||||
+-> os-rustproxy.pkg
|
||||
|
|
||||
+-> APT metadata
|
||||
+-> RPM metadata
|
||||
+-> OPNsense pkg metadata
|
||||
+-> walidacja
|
||||
+-> atomic switch repository/current
|
||||
Git RustProxy
|
||||
|
|
||||
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
|
||||
```
|
||||
|
||||
Jeżeli którykolwiek etap się nie powiedzie, publiczne repozytoria nie są przełączane.
|
||||
`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łąź.
|
||||
|
||||
## OPNsense repo
|
||||
|
||||
@@ -124,6 +120,8 @@ FREEBSD_RUST_TOOLCHAIN=1.88.0
|
||||
APPLY_FREEBSD_PATCHES=1
|
||||
```
|
||||
|
||||
`RUN_LINUX_TESTS=1` jest domyślne. Testy są bramką tylko dla DEB/RPM i nie wpływają na gałąź OPNsense. Ustaw `0`, jeśli chcesz całkowicie pominąć testy Linux.
|
||||
|
||||
`OPNSENSE_RETENTION=10` zachowuje ostatnie 10 wersji pakietu dla danej serii/architektury OPNsense. `0` wyłącza usuwanie starych wersji.
|
||||
|
||||
## FreeBSD cross-build
|
||||
@@ -169,7 +167,7 @@ data/
|
||||
└── work/
|
||||
```
|
||||
|
||||
Jeden release zawiera jednocześnie `apt/`, `rpm/` i `opnsense/`. Dzięki temu oba publiczne adresy przechodzą na nową wersję jednocześnie.
|
||||
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.
|
||||
|
||||
## HTTP i logi
|
||||
|
||||
@@ -196,12 +194,11 @@ curl -f http://127.0.0.1:18766/healthz
|
||||
|
||||
## Migracja ze starszego buildera Linux-only
|
||||
|
||||
`last_commit` nie jest już jedynym warunkiem pominięcia kompilacji. Builder sprawdza też, czy aktualnie opublikowany release zawiera kompletne APT, RPM i OPNsense repo oraz czy `opnsense/BUILD-INFO.txt` wskazuje na ten sam commit.
|
||||
|
||||
Jeżeli `data/state/last_commit` pochodzi ze starszej wersji narzędzia i DEB/RPM są już opublikowane, ale OPNsense repo jeszcze nie istnieje, pierwszy cykl zaloguje:
|
||||
Builder używa osobnych stanów:
|
||||
|
||||
```text
|
||||
commit unchanged, but unified release is incomplete; rebuilding missing artifacts for <sha>
|
||||
data/state/last_linux_commit
|
||||
data/state/last_opnsense_commit
|
||||
```
|
||||
|
||||
i wykona build dla tego samego commita. Przy `PACKAGE_RELEASE=auto` taki build naprawczy zachowuje dotychczasowy numer wydania DEB/RPM zamiast sztucznie go zwiększać.
|
||||
Jeżeli istnieje starsze `last_commit` oraz poprawne APT/RPM dla tego SHA, zostanie ono potraktowane jako stan gałęzi Linux. Brak repo OPNsense uruchomi wyłącznie gałąź OPNsense. Po udanym OPNsense kolejny cykl nie będzie ponownie kompilował FreeBSD, nawet jeśli testy Linux nadal nie przechodzą.
|
||||
Executable
+175
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
|
||||
: "${SHA:?SHA required}"
|
||||
: "${SRC:?SRC required}"
|
||||
: "${PKG:?PKG required}"
|
||||
: "${OUT:?OUT required}"
|
||||
: "${VERSION:?VERSION required}"
|
||||
: "${BINARY_NAME:?BINARY_NAME required}"
|
||||
: "${PACKAGE_NAME:?PACKAGE_NAME required}"
|
||||
|
||||
REPOSITORY="$DATA_DIR/repository"
|
||||
APTLY_CONF="$DATA_DIR/state/aptly.conf"
|
||||
BRANCH_RELEASE_ID="$(date -u '+%Y%m%dT%H%M%SZ')-${SHORT_SHA}-linux"
|
||||
RELEASE_DIR="$REPOSITORY/releases/$BRANCH_RELEASE_ID"
|
||||
PUBLISHED=0
|
||||
|
||||
cleanup_linux_release() {
|
||||
if [[ "$PUBLISHED" != "1" && -d "$RELEASE_DIR" ]]; then
|
||||
rm -rf "$RELEASE_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup_linux_release EXIT
|
||||
|
||||
REQUESTED_PACKAGE_RELEASE=$PACKAGE_RELEASE
|
||||
if [[ "$REQUESTED_PACKAGE_RELEASE" == "auto" ]]; then
|
||||
LAST_LINUX_COMMIT=""
|
||||
LAST_VERSION=""
|
||||
LAST_PACKAGE_RELEASE=0
|
||||
[[ -r "$DATA_DIR/state/last_linux_commit" ]] && LAST_LINUX_COMMIT=$(cat "$DATA_DIR/state/last_linux_commit")
|
||||
[[ -r "$DATA_DIR/state/last_version" ]] && LAST_VERSION=$(cat "$DATA_DIR/state/last_version")
|
||||
[[ -r "$DATA_DIR/state/last_package_release" ]] && LAST_PACKAGE_RELEASE=$(cat "$DATA_DIR/state/last_package_release")
|
||||
|
||||
if [[ "$LAST_LINUX_COMMIT" == "$SHA" \
|
||||
&& "$LAST_VERSION" == "$VERSION" \
|
||||
&& "$LAST_PACKAGE_RELEASE" =~ ^[1-9][0-9]*$ ]]; then
|
||||
PACKAGE_RELEASE=$LAST_PACKAGE_RELEASE
|
||||
log "Linux repair build: reusing package release $PACKAGE_RELEASE"
|
||||
elif [[ "$LAST_VERSION" == "$VERSION" && "$LAST_PACKAGE_RELEASE" =~ ^[0-9]+$ ]]; then
|
||||
PACKAGE_RELEASE=$((LAST_PACKAGE_RELEASE + 1))
|
||||
else
|
||||
PACKAGE_RELEASE=1
|
||||
fi
|
||||
else
|
||||
PACKAGE_RELEASE=$REQUESTED_PACKAGE_RELEASE
|
||||
fi
|
||||
export PACKAGE_RELEASE
|
||||
|
||||
cd "$SRC"
|
||||
log "Linux branch: version $VERSION release $PACKAGE_RELEASE"
|
||||
|
||||
if [[ "${RUN_LINUX_TESTS:-1}" == "1" ]]; then
|
||||
log "Linux cargo tests started"
|
||||
if [[ -f Cargo.lock ]]; then
|
||||
cargo test --release --locked
|
||||
else
|
||||
cargo test --release
|
||||
fi
|
||||
log "Linux cargo tests completed"
|
||||
fi
|
||||
|
||||
log "Linux cargo build started"
|
||||
if [[ -f Cargo.lock ]]; then
|
||||
cargo build --release --locked
|
||||
else
|
||||
cargo build --release
|
||||
fi
|
||||
log "Linux cargo build completed"
|
||||
|
||||
BINARY_PATH="$CARGO_TARGET_DIR/release/$BINARY_NAME"
|
||||
[[ -x "$BINARY_PATH" ]] || fatal "built binary not found: $BINARY_PATH"
|
||||
|
||||
MAX_GLIBC_FOUND=$(objdump -T "$BINARY_PATH" 2>/dev/null | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sed 's/^GLIBC_//' | sort -V | tail -n1 || true)
|
||||
if [[ -n "$MAX_GLIBC_FOUND" ]]; then
|
||||
if [[ "$(printf '%s\n%s\n' "$MAX_GLIBC_VERSION" "$MAX_GLIBC_FOUND" | sort -V | tail -n1)" != "$MAX_GLIBC_VERSION" ]]; then
|
||||
fatal "binary requires GLIBC_$MAX_GLIBC_FOUND, target maximum is GLIBC_$MAX_GLIBC_VERSION"
|
||||
fi
|
||||
log "glibc compatibility check: <= $MAX_GLIBC_FOUND"
|
||||
fi
|
||||
|
||||
/opt/rust-package-builder/scripts/prepare-package.sh "$SRC" "$PKG" "$BINARY_PATH"
|
||||
|
||||
DEB_FILE="$OUT/${PACKAGE_NAME}_${VERSION}-${PACKAGE_RELEASE}_amd64.deb"
|
||||
RPM_FILE="$OUT/${PACKAGE_NAME}-${VERSION}-${PACKAGE_RELEASE}.x86_64.rpm"
|
||||
|
||||
log "creating deb package"
|
||||
nfpm package --config "$PKG/nfpm-deb.yaml" --packager deb --target "$DEB_FILE"
|
||||
log "creating rpm package"
|
||||
nfpm package --config "$PKG/nfpm-rpm.yaml" --packager rpm --target "$RPM_FILE"
|
||||
|
||||
ar t "$DEB_FILE" | grep '^_gpgorigin$' >/dev/null || fatal "DEB package does not contain nFPM GPG origin signature"
|
||||
rpm -qpi "$RPM_FILE" | awk -F: '/^Signature/ && $0 !~ /\(none\)/ {ok=1} END{exit !ok}' || fatal "RPM package is not signed"
|
||||
log "Linux package signatures verified"
|
||||
|
||||
cp -f "$DEB_FILE" "$DATA_DIR/packages/deb/"
|
||||
cp -f "$RPM_FILE" "$DATA_DIR/packages/rpm/x86_64/"
|
||||
|
||||
log "updating aptly internal repository"
|
||||
aptly -config="$APTLY_CONF" repo add -force-replace package-builder "$DEB_FILE" >/dev/null
|
||||
SNAPSHOT="linux-${VERSION}-${SHORT_SHA}-$(date +%s)"
|
||||
aptly -config="$APTLY_CONF" snapshot create "$SNAPSHOT" from repo package-builder >/dev/null
|
||||
|
||||
APTLY_SIGN_ARGS=(-batch -gpg-key="$GPG_KEY_ID")
|
||||
if [[ -r "$GPG_PASSPHRASE_FILE" ]]; then
|
||||
APTLY_SIGN_ARGS+=(-passphrase-file="$GPG_PASSPHRASE_FILE")
|
||||
fi
|
||||
|
||||
if aptly -config="$APTLY_CONF" publish list -raw | awk -v d="$REPO_DISTRIBUTION" '$2 == d {found=1} END{exit !found}'; then
|
||||
aptly -config="$APTLY_CONF" publish switch -force-overwrite "${APTLY_SIGN_ARGS[@]}" "$REPO_DISTRIBUTION" . "$SNAPSHOT" >/dev/null
|
||||
else
|
||||
aptly -config="$APTLY_CONF" publish snapshot -force-overwrite "${APTLY_SIGN_ARGS[@]}" \
|
||||
-distribution="$REPO_DISTRIBUTION" -component="$REPO_COMPONENT" -architectures=amd64 "$SNAPSHOT" >/dev/null
|
||||
fi
|
||||
|
||||
APT_PUBLIC="$DATA_DIR/aptly/public"
|
||||
[[ -f "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/InRelease" ]] || fatal "aptly did not create InRelease"
|
||||
[[ -f "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release.gpg" ]] || fatal "aptly did not create Release.gpg"
|
||||
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"
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "$REPOSITORY/current" ]]; then
|
||||
CURRENT_LINK=$(readlink "$REPOSITORY/current")
|
||||
CURRENT_TARGET="$REPOSITORY/$CURRENT_LINK"
|
||||
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"/
|
||||
fi
|
||||
|
||||
rsync -a --delete "$APT_PUBLIC"/ "$RELEASE_DIR/apt"/
|
||||
rsync -a --delete "$DATA_DIR/packages/rpm"/ "$RELEASE_DIR/rpm"/
|
||||
rm -rf "$RELEASE_DIR/rpm/x86_64/repodata"
|
||||
createrepo_c --update "$RELEASE_DIR/rpm/x86_64" >/dev/null
|
||||
|
||||
GPG_SIGN_ARGS=(--batch --yes --pinentry-mode loopback)
|
||||
if [[ -r "$GPG_PASSPHRASE_FILE" ]]; then
|
||||
GPG_SIGN_ARGS+=(--passphrase-file "$GPG_PASSPHRASE_FILE")
|
||||
fi
|
||||
gpg "${GPG_SIGN_ARGS[@]}" --armor --detach-sign --local-user "$GPG_KEY_ID" \
|
||||
--output "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml.asc" "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml"
|
||||
gpg --batch --verify "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml.asc" "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml" >/dev/null 2>&1 \
|
||||
|| fatal "RPM metadata signature verification failed"
|
||||
|
||||
gpg --batch --armor --export "$GPG_KEY_ID" > "$RELEASE_DIR/repo-key.gpg"
|
||||
[[ -s "$RELEASE_DIR/repo-key.gpg" ]] || fatal "public GPG key export failed"
|
||||
/opt/rust-package-builder/scripts/generate-index.sh "$RELEASE_DIR/index.html" "$PACKAGE_NAME"
|
||||
cat > "$RELEASE_DIR/LINUX-BUILD-INFO.txt" <<INFO
|
||||
app_version=$VERSION
|
||||
package_release=$PACKAGE_RELEASE
|
||||
source_url=$SOURCE_REPO
|
||||
source_ref=$SOURCE_BRANCH
|
||||
source_commit=$SHA
|
||||
build_reason=$BUILD_REASON
|
||||
INFO
|
||||
|
||||
[[ -s "$RELEASE_DIR/index.html" ]]
|
||||
[[ -f "$RELEASE_DIR/apt/dists/$REPO_DISTRIBUTION/InRelease" ]]
|
||||
[[ -f "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml" ]]
|
||||
|
||||
log "publishing Linux 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_linux_commit"
|
||||
printf '%s\n' "$VERSION" | atomic_write "$DATA_DIR/state/last_version"
|
||||
printf '%s\n' "$PACKAGE_RELEASE" | atomic_write "$DATA_DIR/state/last_package_release"
|
||||
printf '%s\n' "$BRANCH_RELEASE_ID" | atomic_write "$DATA_DIR/state/last_linux_release"
|
||||
printf '%s\n' "$BRANCH_RELEASE_ID" | atomic_write "$DATA_DIR/state/last_release"
|
||||
log "Linux publication completed: version=$VERSION release=$PACKAGE_RELEASE commit=$SHA"
|
||||
Executable
+112
@@ -0,0 +1,112 @@
|
||||
#!/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}"
|
||||
: "${BINARY_NAME:?BINARY_NAME required}"
|
||||
: "${SOURCE_REVISION:?SOURCE_REVISION required}"
|
||||
|
||||
REPOSITORY="$DATA_DIR/repository"
|
||||
BRANCH_RELEASE_ID="$(date -u '+%Y%m%dT%H%M%SZ')-${SHORT_SHA}-opnsense"
|
||||
RELEASE_DIR="$REPOSITORY/releases/$BRANCH_RELEASE_ID"
|
||||
PUBLISHED=0
|
||||
|
||||
cleanup_opnsense_release() {
|
||||
if [[ "$PUBLISHED" != "1" && -d "$RELEASE_DIR" ]]; then
|
||||
rm -rf "$RELEASE_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup_opnsense_release EXIT
|
||||
|
||||
FREEBSD_BINARY="$OUT/rust-proxy-freebsd"
|
||||
/opt/rust-package-builder/scripts/build-opnsense.sh "$SRC" "$FREEBSD_BINARY" "$BINARY_NAME" "$WORK"
|
||||
|
||||
if [[ "$SOURCE_REVISION" == "0" ]]; then
|
||||
OPNSENSE_PACKAGE_VERSION="$VERSION"
|
||||
else
|
||||
OPNSENSE_PACKAGE_VERSION="${VERSION}_${SOURCE_REVISION}"
|
||||
fi
|
||||
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"
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "$REPOSITORY/current" ]]; then
|
||||
CURRENT_LINK=$(readlink "$REPOSITORY/current")
|
||||
CURRENT_TARGET="$REPOSITORY/$CURRENT_LINK"
|
||||
fi
|
||||
|
||||
log "staging OPNsense repository snapshot"
|
||||
if [[ -n "$CURRENT_TARGET" ]]; then
|
||||
for component in apt rpm opnsense; do
|
||||
if [[ -d "$CURRENT_TARGET/$component" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/$component"/ "$CURRENT_TARGET/$component"/ "$RELEASE_DIR/$component"/
|
||||
fi
|
||||
done
|
||||
for file in repo-key.gpg index.html LINUX-BUILD-INFO.txt; do
|
||||
if [[ -f "$CURRENT_TARGET/$file" ]]; then
|
||||
cp -a "$CURRENT_TARGET/$file" "$RELEASE_DIR/$file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
OPNSENSE_PACKAGE_DIR="$RELEASE_DIR/opnsense/$OPNSENSE_ABI/amd64"
|
||||
mkdir -p "$OPNSENSE_PACKAGE_DIR"
|
||||
rm -f \
|
||||
"$OPNSENSE_PACKAGE_DIR/$(basename "$OPNSENSE_PACKAGE_FILE")" \
|
||||
"$RELEASE_DIR/opnsense/RustProxy.conf" \
|
||||
"$RELEASE_DIR/opnsense/os-rustproxy-latest.pkg" \
|
||||
"$RELEASE_DIR/opnsense/SHA256" \
|
||||
"$RELEASE_DIR/opnsense/BUILD-INFO.txt" \
|
||||
"$RELEASE_DIR/opnsense/index.html"
|
||||
cp -f "$OPNSENSE_PACKAGE_FILE" "$OPNSENSE_PACKAGE_DIR/"
|
||||
/opt/rust-package-builder/scripts/generate-opnsense-repo.py "$RELEASE_DIR/opnsense" --retention "$OPNSENSE_RETENTION"
|
||||
cat > "$RELEASE_DIR/opnsense/RustProxy.conf" <<REPOCONF
|
||||
RustProxy: {
|
||||
url: "${OPNSENSE_REPOSITORY_URL%/}",
|
||||
enabled: yes,
|
||||
mirror_type: "none",
|
||||
signature_type: "none"
|
||||
}
|
||||
REPOCONF
|
||||
cp -f "$OPNSENSE_PACKAGE_FILE" "$RELEASE_DIR/opnsense/os-rustproxy-latest.pkg"
|
||||
(cd "$RELEASE_DIR/opnsense" && sha256sum "$OPNSENSE_ABI/amd64/$(basename "$OPNSENSE_PACKAGE_FILE")") > "$RELEASE_DIR/opnsense/SHA256"
|
||||
cat > "$RELEASE_DIR/opnsense/BUILD-INFO.txt" <<INFO
|
||||
app_version=$VERSION
|
||||
package_version=$OPNSENSE_PACKAGE_VERSION
|
||||
source_url=$SOURCE_REPO
|
||||
source_ref=$SOURCE_BRANCH
|
||||
source_commit=$SHA
|
||||
build_reason=$BUILD_REASON
|
||||
source_revision=$SOURCE_REVISION
|
||||
opnsense_series=$OPNSENSE_ABI
|
||||
freebsd_release=$FREEBSD_RELEASE
|
||||
freebsd_abi=$FREEBSD_ABI
|
||||
freebsd_arch=$FREEBSD_ARCH
|
||||
package=$OPNSENSE_ABI/amd64/$(basename "$OPNSENSE_PACKAGE_FILE")
|
||||
INFO
|
||||
/opt/rust-package-builder/scripts/generate-opnsense-index.sh "$RELEASE_DIR/opnsense/index.html"
|
||||
|
||||
[[ -s "$RELEASE_DIR/opnsense/index.html" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/meta.conf" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/packagesite.pkg" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/data.pkg" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/os-rustproxy-latest.pkg" ]]
|
||||
bsdtar -tf "$RELEASE_DIR/opnsense/packagesite.pkg" | grep -Fx 'packagesite.yaml' >/dev/null || fatal "invalid OPNsense packagesite.pkg"
|
||||
bsdtar -xOf "$OPNSENSE_PACKAGE_DIR/$(basename "$OPNSENSE_PACKAGE_FILE")" +COMPACT_MANIFEST >/dev/null || fatal "invalid OPNsense package manifest"
|
||||
|
||||
log "publishing OPNsense 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_opnsense_commit"
|
||||
printf '%s\n' "$OPNSENSE_PACKAGE_VERSION" | atomic_write "$DATA_DIR/state/last_opnsense_package_version"
|
||||
printf '%s\n' "$BRANCH_RELEASE_ID" | atomic_write "$DATA_DIR/state/last_opnsense_release"
|
||||
printf '%s\n' "$BRANCH_RELEASE_ID" | atomic_write "$DATA_DIR/state/last_release"
|
||||
log "OPNsense publication completed: package=$OPNSENSE_PACKAGE_VERSION commit=$SHA"
|
||||
+33
-231
@@ -4,21 +4,21 @@ source /opt/rust-package-builder/scripts/lib.sh
|
||||
|
||||
SHA=${1:?commit SHA required}
|
||||
BUILD_REASON=${2:-new-commit}
|
||||
BUILD_LINUX=${3:-1}
|
||||
BUILD_OPNSENSE=${4:-1}
|
||||
|
||||
[[ "$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; }
|
||||
|
||||
SHORT_SHA=${SHA:0:12}
|
||||
BUILD_ID="$(date -u '+%Y%m%dT%H%M%SZ')-${SHORT_SHA}"
|
||||
WORK="$DATA_DIR/work/$BUILD_ID"
|
||||
SRC="$WORK/source"
|
||||
PKG="$WORK/package"
|
||||
OUT="$WORK/out"
|
||||
REPOSITORY="$DATA_DIR/repository"
|
||||
APTLY_CONF="$DATA_DIR/state/aptly.conf"
|
||||
RELEASE_DIR=""
|
||||
PUBLISHED=0
|
||||
|
||||
cleanup() {
|
||||
if [[ "$PUBLISHED" != "1" && -n "$RELEASE_DIR" && -d "$RELEASE_DIR" ]]; then
|
||||
rm -rf "$RELEASE_DIR"
|
||||
fi
|
||||
if [[ "${KEEP_WORKSPACE:-0}" != "1" ]]; then
|
||||
rm -rf "$WORK"
|
||||
else
|
||||
@@ -99,239 +99,41 @@ DESCRIPTION=${DESCRIPTION:-$PACKAGE_NAME}
|
||||
LICENSE=${LICENSE:-Proprietary}
|
||||
HOMEPAGE=${PACKAGE_HOMEPAGE:-${CARGO_HOMEPAGE:-${CARGO_REPOSITORY:-${CONTROL_HOMEPAGE:-$SOURCE_REPO}}}}
|
||||
|
||||
REQUESTED_PACKAGE_RELEASE=$PACKAGE_RELEASE
|
||||
if [[ "$REQUESTED_PACKAGE_RELEASE" == "auto" ]]; then
|
||||
LAST_COMMIT=""
|
||||
LAST_VERSION=""
|
||||
LAST_PACKAGE_RELEASE=0
|
||||
[[ -r "$DATA_DIR/state/last_commit" ]] && LAST_COMMIT=$(cat "$DATA_DIR/state/last_commit")
|
||||
[[ -r "$DATA_DIR/state/last_version" ]] && LAST_VERSION=$(cat "$DATA_DIR/state/last_version")
|
||||
[[ -r "$DATA_DIR/state/last_package_release" ]] && LAST_PACKAGE_RELEASE=$(cat "$DATA_DIR/state/last_package_release")
|
||||
export SHA SHORT_SHA BUILD_ID BUILD_REASON SOURCE_REVISION WORK SRC PKG OUT
|
||||
export PACKAGE_NAME VERSION BINARY_NAME DESCRIPTION LICENSE HOMEPAGE MAINTAINER
|
||||
|
||||
# Repairing an incomplete unified release for the exact same source commit
|
||||
# must not create an artificial new DEB/RPM release number. This is the
|
||||
# migration path from the older Linux-only builder: Linux packages already
|
||||
# exist, while the new OPNsense artifacts still need to be produced.
|
||||
if [[ "$BUILD_REASON" == "repair-missing-artifacts" \
|
||||
&& "$LAST_COMMIT" == "$SHA" \
|
||||
&& "$LAST_VERSION" == "$VERSION" \
|
||||
&& "$LAST_PACKAGE_RELEASE" =~ ^[1-9][0-9]*$ ]]; then
|
||||
PACKAGE_RELEASE=$LAST_PACKAGE_RELEASE
|
||||
log "repair build: reusing Linux package release $PACKAGE_RELEASE for unchanged commit"
|
||||
elif [[ "$LAST_VERSION" == "$VERSION" && "$LAST_PACKAGE_RELEASE" =~ ^[0-9]+$ ]]; then
|
||||
PACKAGE_RELEASE=$((LAST_PACKAGE_RELEASE + 1))
|
||||
log "build plan: commit=$SHA linux=$BUILD_LINUX opnsense=$BUILD_OPNSENSE version=$VERSION"
|
||||
|
||||
LINUX_OK=1
|
||||
OPNSENSE_OK=1
|
||||
|
||||
if [[ "$BUILD_LINUX" == "1" ]]; then
|
||||
if /opt/rust-package-builder/scripts/build-linux-release.sh; then
|
||||
log "Linux branch completed for $SHA"
|
||||
else
|
||||
PACKAGE_RELEASE=1
|
||||
LINUX_OK=0
|
||||
log "ERROR: Linux branch failed for $SHA; OPNsense branch will still run"
|
||||
fi
|
||||
else
|
||||
PACKAGE_RELEASE=$REQUESTED_PACKAGE_RELEASE
|
||||
fi
|
||||
|
||||
export PACKAGE_NAME VERSION BINARY_NAME DESCRIPTION LICENSE HOMEPAGE MAINTAINER PACKAGE_RELEASE
|
||||
log "building version $VERSION ($PACKAGE_NAME / $BINARY_NAME)"
|
||||
|
||||
if [[ "${RUN_LINUX_TESTS:-1}" == "1" ]]; then
|
||||
log "cargo tests started"
|
||||
if [[ -f Cargo.lock ]]; then
|
||||
cargo test --release --locked
|
||||
if [[ "$BUILD_OPNSENSE" == "1" ]]; then
|
||||
if /opt/rust-package-builder/scripts/build-opnsense-release.sh; then
|
||||
log "OPNsense branch completed for $SHA"
|
||||
else
|
||||
cargo test --release
|
||||
OPNSENSE_OK=0
|
||||
log "ERROR: OPNsense branch failed for $SHA"
|
||||
fi
|
||||
log "cargo tests completed"
|
||||
fi
|
||||
|
||||
log "Linux cargo build started"
|
||||
if [[ -f Cargo.lock ]]; then
|
||||
cargo build --release --locked
|
||||
else
|
||||
cargo build --release
|
||||
fi
|
||||
log "Linux cargo build completed"
|
||||
|
||||
BINARY_PATH="$CARGO_TARGET_DIR/release/$BINARY_NAME"
|
||||
[[ -x "$BINARY_PATH" ]] || fatal "built binary not found: $BINARY_PATH"
|
||||
|
||||
MAX_GLIBC_FOUND=$(objdump -T "$BINARY_PATH" 2>/dev/null | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sed 's/^GLIBC_//' | sort -V | tail -n1 || true)
|
||||
if [[ -n "$MAX_GLIBC_FOUND" ]]; then
|
||||
if [[ "$(printf '%s\n%s\n' "$MAX_GLIBC_VERSION" "$MAX_GLIBC_FOUND" | sort -V | tail -n1)" != "$MAX_GLIBC_VERSION" ]]; then
|
||||
fatal "binary requires GLIBC_$MAX_GLIBC_FOUND, target maximum is GLIBC_$MAX_GLIBC_VERSION"
|
||||
fi
|
||||
log "glibc compatibility check: <= $MAX_GLIBC_FOUND"
|
||||
LINUX_STATE=""
|
||||
OPNSENSE_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
|
||||
printf '%s\n' "$SHA" | atomic_write "$DATA_DIR/state/last_commit"
|
||||
log "all branches complete for $SHA"
|
||||
fi
|
||||
|
||||
/opt/rust-package-builder/scripts/prepare-package.sh "$SRC" "$PKG" "$BINARY_PATH"
|
||||
|
||||
DEB_FILE="$OUT/${PACKAGE_NAME}_${VERSION}-${PACKAGE_RELEASE}_amd64.deb"
|
||||
RPM_FILE="$OUT/${PACKAGE_NAME}-${VERSION}-${PACKAGE_RELEASE}.x86_64.rpm"
|
||||
|
||||
log "creating deb package"
|
||||
nfpm package --config "$PKG/nfpm-deb.yaml" --packager deb --target "$DEB_FILE"
|
||||
log "creating rpm package"
|
||||
nfpm package --config "$PKG/nfpm-rpm.yaml" --packager rpm --target "$RPM_FILE"
|
||||
|
||||
ar t "$DEB_FILE" | grep '^_gpgorigin$' >/dev/null || fatal "DEB package does not contain nFPM GPG origin signature"
|
||||
rpm -qpi "$RPM_FILE" | awk -F: '/^Signature/ && $0 !~ /\(none\)/ {ok=1} END{exit !ok}' || fatal "RPM package is not signed"
|
||||
log "Linux package signatures verified"
|
||||
|
||||
# OPNsense is built from an isolated source copy. FreeBSD-specific patches never
|
||||
# touch the Linux source checkout used above.
|
||||
FREEBSD_BINARY="$OUT/rust-proxy-freebsd"
|
||||
/opt/rust-package-builder/scripts/build-opnsense.sh "$SRC" "$FREEBSD_BINARY" "$BINARY_NAME" "$WORK"
|
||||
|
||||
if [[ "$SOURCE_REVISION" == "0" ]]; then
|
||||
OPNSENSE_PACKAGE_VERSION="$VERSION"
|
||||
else
|
||||
OPNSENSE_PACKAGE_VERSION="${VERSION}_${SOURCE_REVISION}"
|
||||
if [[ "$LINUX_OK" != "1" || "$OPNSENSE_OK" != "1" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
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"
|
||||
|
||||
# Only after all package formats have been built successfully do we update the
|
||||
# persistent Linux package stores and the internal APT repository.
|
||||
cp -f "$DEB_FILE" "$DATA_DIR/packages/deb/"
|
||||
cp -f "$RPM_FILE" "$DATA_DIR/packages/rpm/x86_64/"
|
||||
|
||||
log "updating aptly internal repository"
|
||||
aptly -config="$APTLY_CONF" repo add -force-replace package-builder "$DEB_FILE" >/dev/null
|
||||
SNAPSHOT="release-${VERSION}-${SHORT_SHA}-$(date +%s)"
|
||||
aptly -config="$APTLY_CONF" snapshot create "$SNAPSHOT" from repo package-builder >/dev/null
|
||||
|
||||
APTLY_SIGN_ARGS=(-batch -gpg-key="$GPG_KEY_ID")
|
||||
if [[ -r "$GPG_PASSPHRASE_FILE" ]]; then
|
||||
APTLY_SIGN_ARGS+=(-passphrase-file="$GPG_PASSPHRASE_FILE")
|
||||
fi
|
||||
|
||||
if aptly -config="$APTLY_CONF" publish list -raw | awk -v d="$REPO_DISTRIBUTION" '$2 == d {found=1} END{exit !found}'; then
|
||||
aptly -config="$APTLY_CONF" publish switch \
|
||||
-force-overwrite \
|
||||
"${APTLY_SIGN_ARGS[@]}" \
|
||||
"$REPO_DISTRIBUTION" . "$SNAPSHOT" >/dev/null
|
||||
else
|
||||
aptly -config="$APTLY_CONF" publish snapshot \
|
||||
-force-overwrite \
|
||||
"${APTLY_SIGN_ARGS[@]}" \
|
||||
-distribution="$REPO_DISTRIBUTION" \
|
||||
-component="$REPO_COMPONENT" \
|
||||
-architectures=amd64 \
|
||||
"$SNAPSHOT" >/dev/null
|
||||
fi
|
||||
|
||||
APT_PUBLIC="$DATA_DIR/aptly/public"
|
||||
[[ -f "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/InRelease" ]] || fatal "aptly did not create InRelease"
|
||||
[[ -f "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release.gpg" ]] || fatal "aptly did not create Release.gpg"
|
||||
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"
|
||||
|
||||
RELEASE_DIR="$REPOSITORY/releases/$BUILD_ID"
|
||||
mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense"
|
||||
|
||||
CURRENT_TARGET=""
|
||||
if [[ -L "$REPOSITORY/current" ]]; then
|
||||
CURRENT_LINK=$(readlink "$REPOSITORY/current")
|
||||
CURRENT_TARGET="$REPOSITORY/$CURRENT_LINK"
|
||||
fi
|
||||
|
||||
log "staging apt repository"
|
||||
if [[ -n "$CURRENT_TARGET" && -d "$CURRENT_TARGET/apt" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/apt"/ "$APT_PUBLIC"/ "$RELEASE_DIR/apt"/
|
||||
else
|
||||
rsync -a --delete "$APT_PUBLIC"/ "$RELEASE_DIR/apt"/
|
||||
fi
|
||||
|
||||
log "updating rpm repository"
|
||||
if [[ -n "$CURRENT_TARGET" && -d "$CURRENT_TARGET/rpm" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/rpm"/ "$DATA_DIR/packages/rpm"/ "$RELEASE_DIR/rpm"/
|
||||
else
|
||||
rsync -a --delete "$DATA_DIR/packages/rpm"/ "$RELEASE_DIR/rpm"/
|
||||
fi
|
||||
rm -rf "$RELEASE_DIR/rpm/x86_64/repodata"
|
||||
createrepo_c --update "$RELEASE_DIR/rpm/x86_64" >/dev/null
|
||||
|
||||
GPG_SIGN_ARGS=(--batch --yes --pinentry-mode loopback)
|
||||
if [[ -r "$GPG_PASSPHRASE_FILE" ]]; then
|
||||
GPG_SIGN_ARGS+=(--passphrase-file "$GPG_PASSPHRASE_FILE")
|
||||
fi
|
||||
gpg "${GPG_SIGN_ARGS[@]}" --armor --detach-sign \
|
||||
--local-user "$GPG_KEY_ID" \
|
||||
--output "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml.asc" \
|
||||
"$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml"
|
||||
gpg --batch --verify \
|
||||
"$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml.asc" \
|
||||
"$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml" >/dev/null 2>&1 || fatal "RPM metadata signature verification failed"
|
||||
|
||||
log "staging OPNsense pkg repository"
|
||||
if [[ -n "$CURRENT_TARGET" && -d "$CURRENT_TARGET/opnsense" ]]; then
|
||||
rsync -a --delete --link-dest="$CURRENT_TARGET/opnsense"/ "$CURRENT_TARGET/opnsense"/ "$RELEASE_DIR/opnsense"/
|
||||
fi
|
||||
OPNSENSE_PACKAGE_DIR="$RELEASE_DIR/opnsense/$OPNSENSE_ABI/amd64"
|
||||
mkdir -p "$OPNSENSE_PACKAGE_DIR"
|
||||
# The previous OPNsense snapshot is hard-linked into this one. Unlink every
|
||||
# file we are about to replace so the currently published snapshot stays immutable.
|
||||
rm -f \
|
||||
"$OPNSENSE_PACKAGE_DIR/$(basename "$OPNSENSE_PACKAGE_FILE")" \
|
||||
"$RELEASE_DIR/opnsense/RustProxy.conf" \
|
||||
"$RELEASE_DIR/opnsense/os-rustproxy-latest.pkg" \
|
||||
"$RELEASE_DIR/opnsense/SHA256" \
|
||||
"$RELEASE_DIR/opnsense/BUILD-INFO.txt" \
|
||||
"$RELEASE_DIR/opnsense/index.html"
|
||||
cp -f "$OPNSENSE_PACKAGE_FILE" "$OPNSENSE_PACKAGE_DIR/"
|
||||
/opt/rust-package-builder/scripts/generate-opnsense-repo.py \
|
||||
"$RELEASE_DIR/opnsense" --retention "$OPNSENSE_RETENTION"
|
||||
cat > "$RELEASE_DIR/opnsense/RustProxy.conf" <<REPOCONF
|
||||
RustProxy: {
|
||||
url: "${OPNSENSE_REPOSITORY_URL%/}",
|
||||
enabled: yes,
|
||||
mirror_type: "none",
|
||||
signature_type: "none"
|
||||
}
|
||||
REPOCONF
|
||||
cp -f "$OPNSENSE_PACKAGE_FILE" "$RELEASE_DIR/opnsense/os-rustproxy-latest.pkg"
|
||||
(cd "$RELEASE_DIR/opnsense" && sha256sum "$OPNSENSE_ABI/amd64/$(basename "$OPNSENSE_PACKAGE_FILE")") > "$RELEASE_DIR/opnsense/SHA256"
|
||||
cat > "$RELEASE_DIR/opnsense/BUILD-INFO.txt" <<INFO
|
||||
app_version=$VERSION
|
||||
package_version=$OPNSENSE_PACKAGE_VERSION
|
||||
source_url=$SOURCE_REPO
|
||||
source_ref=$SOURCE_BRANCH
|
||||
source_commit=$SHA
|
||||
build_reason=$BUILD_REASON
|
||||
source_revision=$SOURCE_REVISION
|
||||
opnsense_series=$OPNSENSE_ABI
|
||||
freebsd_release=$FREEBSD_RELEASE
|
||||
freebsd_abi=$FREEBSD_ABI
|
||||
freebsd_arch=$FREEBSD_ARCH
|
||||
package=$OPNSENSE_ABI/amd64/$(basename "$OPNSENSE_PACKAGE_FILE")
|
||||
INFO
|
||||
/opt/rust-package-builder/scripts/generate-opnsense-index.sh "$RELEASE_DIR/opnsense/index.html"
|
||||
|
||||
gpg --batch --armor --export "$GPG_KEY_ID" > "$RELEASE_DIR/repo-key.gpg"
|
||||
[[ -s "$RELEASE_DIR/repo-key.gpg" ]] || fatal "public GPG key export failed"
|
||||
|
||||
/opt/rust-package-builder/scripts/generate-index.sh "$RELEASE_DIR/index.html" "$PACKAGE_NAME"
|
||||
|
||||
# Validate both public repositories before one atomic switch exposes either one.
|
||||
[[ -s "$RELEASE_DIR/index.html" ]]
|
||||
[[ -f "$RELEASE_DIR/apt/dists/$REPO_DISTRIBUTION/InRelease" ]]
|
||||
[[ -f "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml" ]]
|
||||
[[ -s "$RELEASE_DIR/opnsense/index.html" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/meta.conf" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/packagesite.pkg" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/data.pkg" ]]
|
||||
[[ -f "$RELEASE_DIR/opnsense/os-rustproxy-latest.pkg" ]]
|
||||
bsdtar -tf "$RELEASE_DIR/opnsense/packagesite.pkg" | grep -Fx 'packagesite.yaml' >/dev/null || fatal "invalid OPNsense packagesite.pkg"
|
||||
bsdtar -xOf "$OPNSENSE_PACKAGE_DIR/$(basename "$OPNSENSE_PACKAGE_FILE")" +COMPACT_MANIFEST >/dev/null || fatal "invalid OPNsense package manifest"
|
||||
|
||||
log "publishing Linux and OPNsense repositories atomically"
|
||||
rm -f "$REPOSITORY/current.new"
|
||||
ln -s "releases/$BUILD_ID" "$REPOSITORY/current.new"
|
||||
mv -Tf "$REPOSITORY/current.new" "$REPOSITORY/current"
|
||||
PUBLISHED=1
|
||||
|
||||
printf '%s\n' "$SHA" | atomic_write "$DATA_DIR/state/last_commit"
|
||||
printf '%s\n' "$VERSION" | atomic_write "$DATA_DIR/state/last_version"
|
||||
printf '%s\n' "$PACKAGE_RELEASE" | atomic_write "$DATA_DIR/state/last_package_release"
|
||||
printf '%s\n' "$OPNSENSE_PACKAGE_VERSION" | atomic_write "$DATA_DIR/state/last_opnsense_package_version"
|
||||
printf '%s\n' "$BUILD_ID" | atomic_write "$DATA_DIR/state/last_release"
|
||||
|
||||
log "build completed: reason=$BUILD_REASON version=$VERSION linux_release=$PACKAGE_RELEASE opnsense=$OPNSENSE_PACKAGE_VERSION commit=$SHA release=$BUILD_ID"
|
||||
+51
-26
@@ -2,24 +2,37 @@
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
|
||||
STATE_FILE="$DATA_DIR/state/last_commit"
|
||||
REPOSITORY="$DATA_DIR/repository"
|
||||
CURRENT="$REPOSITORY/current"
|
||||
|
||||
published_release_complete_for_commit() {
|
||||
linux_release_complete_for_commit() {
|
||||
local sha=$1
|
||||
local current="$REPOSITORY/current"
|
||||
local opnsense="$current/opnsense"
|
||||
[[ -d "$CURRENT" ]] || return 1
|
||||
[[ -f "$CURRENT/apt/dists/$REPO_DISTRIBUTION/InRelease" ]] || return 1
|
||||
[[ -f "$CURRENT/rpm/x86_64/repodata/repomd.xml" ]] || return 1
|
||||
|
||||
if [[ -f "$CURRENT/LINUX-BUILD-INFO.txt" ]] && grep -Fqx "source_commit=$sha" "$CURRENT/LINUX-BUILD-INFO.txt"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local state_sha=""
|
||||
[[ -r "$DATA_DIR/state/last_linux_commit" ]] && state_sha=$(cat "$DATA_DIR/state/last_linux_commit")
|
||||
[[ "$state_sha" == "$sha" ]] && return 0
|
||||
|
||||
# Migration from the older unified/Linux-only builder. Its last_commit
|
||||
# represented the Linux publication before per-branch state existed.
|
||||
local legacy_sha=""
|
||||
[[ -r "$DATA_DIR/state/last_commit" ]] && legacy_sha=$(cat "$DATA_DIR/state/last_commit")
|
||||
[[ "$legacy_sha" == "$sha" ]] || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
opnsense_release_complete_for_commit() {
|
||||
local sha=$1
|
||||
local opnsense="$CURRENT/opnsense"
|
||||
local package_dir="$opnsense/$OPNSENSE_ABI/amd64"
|
||||
|
||||
[[ -d "$current" ]] || return 1
|
||||
|
||||
# Linux side of the atomic release.
|
||||
[[ -f "$current/apt/dists/$REPO_DISTRIBUTION/InRelease" ]] || return 1
|
||||
[[ -f "$current/rpm/x86_64/repodata/repomd.xml" ]] || return 1
|
||||
|
||||
# OPNsense side. BUILD-INFO ties the published pkg repository to the same
|
||||
# source commit so an old Linux-only release cannot be mistaken for a
|
||||
# complete unified release after migration.
|
||||
[[ -d "$CURRENT" ]] || return 1
|
||||
[[ -f "$opnsense/meta.conf" ]] || return 1
|
||||
[[ -f "$opnsense/packagesite.pkg" ]] || return 1
|
||||
[[ -f "$opnsense/data.pkg" ]] || return 1
|
||||
@@ -30,7 +43,6 @@ published_release_complete_for_commit() {
|
||||
grep -Fqx "opnsense_series=$OPNSENSE_ABI" "$opnsense/BUILD-INFO.txt" || return 1
|
||||
[[ -d "$package_dir" ]] || return 1
|
||||
find "$package_dir" -maxdepth 1 -type f -name 'os-rustproxy-*.pkg' -print -quit | grep -q . || return 1
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -38,19 +50,32 @@ 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"
|
||||
|
||||
LAST_SHA=""
|
||||
[[ -r "$STATE_FILE" ]] && LAST_SHA=$(cat "$STATE_FILE")
|
||||
BUILD_LINUX=1
|
||||
BUILD_OPNSENSE=1
|
||||
if linux_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
BUILD_LINUX=0
|
||||
# Persist migrated per-branch state when an older installation already has
|
||||
# a valid Linux repository for this exact commit.
|
||||
printf '%s\n' "$REMOTE_SHA" | atomic_write "$DATA_DIR/state/last_linux_commit"
|
||||
fi
|
||||
if opnsense_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
BUILD_OPNSENSE=0
|
||||
printf '%s\n' "$REMOTE_SHA" | atomic_write "$DATA_DIR/state/last_opnsense_commit"
|
||||
fi
|
||||
|
||||
if [[ "$REMOTE_SHA" == "$LAST_SHA" ]]; then
|
||||
if published_release_complete_for_commit "$REMOTE_SHA"; then
|
||||
log "no changes and unified release is complete: $REMOTE_SHA"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "commit unchanged, but unified release is incomplete; rebuilding missing artifacts for $REMOTE_SHA"
|
||||
/opt/rust-package-builder/scripts/build-release.sh "$REMOTE_SHA" repair-missing-artifacts
|
||||
if [[ "$BUILD_LINUX" == "0" && "$BUILD_OPNSENSE" == "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"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "new commit detected: $REMOTE_SHA"
|
||||
/opt/rust-package-builder/scripts/build-release.sh "$REMOTE_SHA" new-commit
|
||||
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"
|
||||
@@ -80,7 +80,7 @@ fi
|
||||
log "builder started: branch=$SOURCE_BRANCH interval=${POLL_INTERVAL}s opnsense=$OPNSENSE_ABI freebsd=$FREEBSD_RELEASE"
|
||||
while true; do
|
||||
if ! /opt/rust-package-builder/scripts/check-and-build.sh; then
|
||||
log "ERROR: build cycle failed; published repositories were not switched"
|
||||
log "ERROR: one or more build branches failed; any successful branch was published independently"
|
||||
fi
|
||||
sleep "$POLL_INTERVAL"
|
||||
done
|
||||
@@ -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; do
|
||||
for item in apt rpm opnsense 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
|
||||
@@ -45,3 +45,4 @@ ln -sfn current/rpm "$REPOSITORY/rpm"
|
||||
ln -sfn current/opnsense "$REPOSITORY/opnsense"
|
||||
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"
|
||||
+28
-25
@@ -7,34 +7,40 @@ for f in "$ROOT"/start.sh "$ROOT"/scripts/*.sh "$ROOT"/tests/*.sh; do
|
||||
done
|
||||
python3 -m py_compile "$ROOT/scripts/generate-opnsense-repo.py"
|
||||
|
||||
# Main Linux builder.
|
||||
# Main image/build dependencies.
|
||||
grep -q 'FROM rockylinux:9' "$ROOT/Dockerfile"
|
||||
grep -q 'nfpm package' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'aptly .*publish' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'createrepo_c' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'repo add -force-replace' "$ROOT/scripts/build-release.sh"
|
||||
grep -q '/run/package-builder/gnupg' "$ROOT/scripts/entrypoint.sh"
|
||||
grep -q 'rustproxy-overview.json' "$ROOT/scripts/prepare-package.sh"
|
||||
|
||||
# Integrated FreeBSD/OPNsense build.
|
||||
grep -q 'FREEBSD_RELEASE=15.1-RELEASE' "$ROOT/Dockerfile"
|
||||
grep -q 'x86_64-unknown-freebsd' "$ROOT/Dockerfile"
|
||||
grep -q '/opt/freebsd-sysroot' "$ROOT/Dockerfile"
|
||||
grep -q 'build-opnsense.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'package-opnsense.sh' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'generate-opnsense-repo.py' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'OPNSENSE_REPOSITORY_URL' "$ROOT/scripts/entrypoint.sh"
|
||||
grep -q 'OPNSENSE_RETENTION' "$ROOT/scripts/entrypoint.sh"
|
||||
|
||||
# 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 'OPNsense branch will still run' "$ROOT/scripts/build-release.sh"
|
||||
|
||||
# Linux tests gate Linux packaging only.
|
||||
grep -q 'cargo test --release' "$ROOT/scripts/build-linux-release.sh"
|
||||
grep -q '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"
|
||||
! 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 -f "$ROOT/opnsense/patches/0.20.0/0001-opnsense-build.patch"
|
||||
|
||||
# One atomic switch exposes Linux and OPNsense together.
|
||||
grep -q 'current.new' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'current/opnsense' "$ROOT/scripts/init-storage.sh"
|
||||
grep -q 'last_opnsense_package_version' "$ROOT/scripts/build-release.sh"
|
||||
grep -q 'published_release_complete_for_commit' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'repair-missing-artifacts' "$ROOT/scripts/check-and-build.sh"
|
||||
grep -q 'BUILD-INFO.txt' "$ROOT/scripts/check-and-build.sh"
|
||||
# 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"
|
||||
@@ -44,13 +50,10 @@ 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 'GET|HEAD' "$ROOT/http/nginx.conf"
|
||||
grep -q 'autoindex off' "$ROOT/http/nginx.conf"
|
||||
grep -q 'healthz' "$ROOT/http/nginx.conf"
|
||||
|
||||
# start.sh and example configuration expose both URLs/ports.
|
||||
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'
|
||||
Reference in new issue
Block a user