ubuntu 26.04
This commit is contained in:
+144
-204
@@ -1,16 +1,19 @@
|
||||
# =============================================================================
|
||||
# build-and-publish
|
||||
# build-and-publish (multi-distro matrix)
|
||||
#
|
||||
# Compiles a custom nginx (with ModSecurity, naxsi, lua, brotli, geoip2, etc.),
|
||||
# packages the result as a Debian .deb named `twiy`, and uploads it to a
|
||||
# Sonatype Nexus apt-hosted repository so users can install via `apt`.
|
||||
# Builds twiy as a Debian .deb for each target distro in parallel:
|
||||
# - trixie (Debian 13) -> uploaded to NEXUS_REPO_TRIXIE
|
||||
# - raccoon (Ubuntu 26.04 LTS) -> uploaded to NEXUS_REPO_RACCOON
|
||||
#
|
||||
# Triggers:
|
||||
# * Every push to master.
|
||||
# * Manual run from the Actions UI (workflow_dispatch).
|
||||
# Each matrix job spins up a Docker container of the target distro on the
|
||||
# Gitea runner host, builds nginx + modules INSIDE the container so apt deps
|
||||
# and ldd resolution match what end users have, then uploads the resulting
|
||||
# .deb to that distro's Nexus apt-hosted repository.
|
||||
#
|
||||
# Required repository secrets (see the "Publish to Nexus" step for details):
|
||||
# NEXUS_USER, NEXUS_PASS, NEXUS_URL, NEXUS_REPO
|
||||
# Required repository secrets:
|
||||
# NEXUS_USER, NEXUS_PASS, NEXUS_URL (shared)
|
||||
# NEXUS_REPO_TRIXIE (Debian 13 target)
|
||||
# NEXUS_REPO_RACCOON (Ubuntu 26.04 target)
|
||||
# =============================================================================
|
||||
name: build-and-publish
|
||||
|
||||
@@ -21,160 +24,140 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Pinned to ubuntu-22.04 because the build script targets the toolchain
|
||||
# versions that ship with that release. Bumping this needs validation
|
||||
# against the modules pinned in /version.
|
||||
# Runner is just a docker host; build OS is determined by matrix.image.
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
# If trixie fails, still finish raccoon (and vice versa) — surface both.
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [trixie, raccoon]
|
||||
include:
|
||||
- target: trixie
|
||||
image: debian:13
|
||||
nexus_repo_secret: NEXUS_REPO_TRIXIE
|
||||
- target: raccoon
|
||||
image: ubuntu:26.04
|
||||
nexus_repo_secret: NEXUS_REPO_RACCOON
|
||||
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Minimal toolchain to: build nginx (build-essential), package the
|
||||
# output (dpkg-dev, fakeroot), and fetch sources (git, curl, wget).
|
||||
# gnupg is kept in case a future step needs to verify upstream sigs.
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
git curl wget ca-certificates dpkg-dev fakeroot \
|
||||
build-essential gnupg
|
||||
|
||||
- name: Compile nginx and modules
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Touch /.dockerenv so build/run.sh's container-detection branch is
|
||||
# taken: it skips `systemctl start nginx` (the runner has no systemd).
|
||||
# The .deb's own postinst handles service start on the user's host.
|
||||
sudo touch /.dockerenv
|
||||
sudo bash build/run.sh new # download sources for nginx + modules
|
||||
sudo bash build/run.sh build # configure, compile, install
|
||||
sudo bash build/run.sh postfix # drop default configs into /nginx
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# Assemble the .deb by hand (we don't use debhelper because the build
|
||||
# script already places everything at its final paths under the runner's
|
||||
# root; we just need to mirror those paths into PKG_DIR and add control
|
||||
# metadata).
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
- name: Assemble .deb package
|
||||
- name: Build nginx and assemble .deb inside ${{ matrix.image }}
|
||||
id: pkg
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
IMAGE: ${{ matrix.image }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PKG_NAME="twiy"
|
||||
NGINX_VER="$(nginx -v 2>&1 | awk -F'/' '{print $2}')"
|
||||
# Append the CI run number as the Debian revision so each rebuild
|
||||
# produces a strictly-greater version (e.g. 1.26.0-3 > 1.26.0-2 >
|
||||
# 1.26.0). Without this, `apt upgrade twiy` would be a no-op when
|
||||
# upstream nginx hasn't moved, so packaging fixes wouldn't reach
|
||||
# users who already have the package installed.
|
||||
VERSION="${NGINX_VER}-${GITHUB_RUN_NUMBER:-1}"
|
||||
ARCH="amd64"
|
||||
PKG_DIR="/opt/${PKG_NAME}_${VERSION}_${ARCH}"
|
||||
DEB_DIR="${PKG_DIR}/DEBIAN"
|
||||
mkdir -p dist
|
||||
# The whole compile + .deb assembly happens inside the target distro
|
||||
# container. Output is dropped into ./dist/ (mounted from the runner)
|
||||
# so the publish step on the host can grab it.
|
||||
sudo docker run --rm \
|
||||
-v "$PWD:/repo" \
|
||||
-w /repo \
|
||||
-e TARGET="$TARGET" \
|
||||
"$IMAGE" \
|
||||
bash -euxc '
|
||||
# build script handles its own apt-get install (per-distro list)
|
||||
touch /.dockerenv
|
||||
bash build/${TARGET}.sh new
|
||||
bash build/${TARGET}.sh build
|
||||
bash build/${TARGET}.sh postfix
|
||||
|
||||
# The `*_temp` dirs under /usr/local/nginx are nginx's compiled-in
|
||||
# defaults for client_body / proxy / fastcgi / uwsgi / scgi temp
|
||||
# storage (no --http-*-temp-path was passed to ./configure). They
|
||||
# must exist before `nginx -t` runs, so we ship them empty in the
|
||||
# .deb and the postinst chowns them to the nginx user.
|
||||
sudo mkdir -p "${PKG_DIR}/usr/sbin" "${PKG_DIR}/nginx" \
|
||||
"${PKG_DIR}/etc/systemd/system" "${PKG_DIR}/var/log/nginx" \
|
||||
"${PKG_DIR}/usr/lib" "${PKG_DIR}/usr/local/lib" \
|
||||
"${PKG_DIR}/hostdata/default/public_html" \
|
||||
"${PKG_DIR}/usr/nginx_lua" \
|
||||
"${PKG_DIR}/usr/local/nginx/client_body_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/proxy_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/fastcgi_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/uwsgi_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/scgi_temp"
|
||||
PKG_NAME="twiy"
|
||||
NGINX_VER="$(nginx -v 2>&1 | awk -F/ "{print \$2}")"
|
||||
# Append CI run number AND target so each rebuild is a strictly-
|
||||
# greater Debian revision. Without this, `apt upgrade twiy` would
|
||||
# be a no-op when upstream nginx hasnt moved, so packaging fixes
|
||||
# wouldnt reach users who already have the package installed.
|
||||
# The ~target suffix keeps trixie/raccoon versions distinct in
|
||||
# case any introspection ever compares them.
|
||||
VERSION="${NGINX_VER}-${GITHUB_RUN_NUMBER:-1}~${TARGET}"
|
||||
ARCH="amd64"
|
||||
PKG_DIR="/opt/${PKG_NAME}_${VERSION}_${ARCH}"
|
||||
DEB_DIR="${PKG_DIR}/DEBIAN"
|
||||
|
||||
# Pull every artifact the build produced into the package tree.
|
||||
# `|| true` on the recursive copies tolerates a missing source dir
|
||||
# (e.g. when rebuilding without re-running postfix locally).
|
||||
sudo cp /usr/sbin/nginx "${PKG_DIR}/usr/sbin/"
|
||||
sudo cp -R /nginx/* "${PKG_DIR}/nginx/" || true
|
||||
sudo cp /etc/systemd/system/nginx.service "${PKG_DIR}/etc/systemd/system/"
|
||||
sudo cp -R /hostdata/default "${PKG_DIR}/hostdata/" || true
|
||||
sudo cp -R /usr/nginx_lua "${PKG_DIR}/usr/" || true
|
||||
# The *_temp dirs under /usr/local/nginx are nginxs compiled-in
|
||||
# defaults for client_body / proxy / fastcgi / uwsgi / scgi temp
|
||||
# storage (no --http-*-temp-path was passed to ./configure). They
|
||||
# must exist before `nginx -t` runs, so we ship them empty in the
|
||||
# .deb and the postinst chowns them to the nginx user.
|
||||
mkdir -p "${PKG_DIR}/usr/sbin" "${PKG_DIR}/nginx" \
|
||||
"${PKG_DIR}/etc/systemd/system" "${PKG_DIR}/var/log/nginx" \
|
||||
"${PKG_DIR}/usr/lib" "${PKG_DIR}/usr/local/lib" \
|
||||
"${PKG_DIR}/hostdata/default/public_html" \
|
||||
"${PKG_DIR}/usr/nginx_lua" \
|
||||
"${PKG_DIR}/usr/local/nginx/client_body_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/proxy_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/fastcgi_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/uwsgi_temp" \
|
||||
"${PKG_DIR}/usr/local/nginx/scgi_temp"
|
||||
|
||||
# Bundle every shared library nginx links against. This makes the
|
||||
# package self-contained: users don't need our exact build-host
|
||||
# versions of libssl, libluajit, libmodsecurity, etc. The grep
|
||||
# filters out the vDSO and the dynamic linker (which never appear
|
||||
# as `=> /...`).
|
||||
for lib in $(ldd /usr/sbin/nginx | grep '=> /' | awk '{print $3}'); do
|
||||
sudo cp "$lib" "${PKG_DIR}/usr/lib/" || true
|
||||
done
|
||||
cp /usr/sbin/nginx "${PKG_DIR}/usr/sbin/"
|
||||
cp -R /nginx/* "${PKG_DIR}/nginx/" || true
|
||||
cp /etc/systemd/system/nginx.service "${PKG_DIR}/etc/systemd/system/"
|
||||
cp -R /hostdata/default "${PKG_DIR}/hostdata/" || true
|
||||
cp -R /usr/nginx_lua "${PKG_DIR}/usr/" || true
|
||||
|
||||
# ---- DEBIAN/control --------------------------------------------------
|
||||
# Minimum metadata dpkg requires. The .deb bundles every shared library
|
||||
# nginx links against (see the ldd loop above), so the only Depends we
|
||||
# declare is libjemalloc2 — the systemd unit LD_PRELOADs it for the
|
||||
# nginx workers; without it, the unit would fail to start.
|
||||
sudo mkdir -p "${DEB_DIR}"
|
||||
sudo tee "${DEB_DIR}/control" >/dev/null <<EOF
|
||||
Package: ${PKG_NAME}
|
||||
Version: ${VERSION}
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: ${ARCH}
|
||||
Depends: libjemalloc2
|
||||
Maintainer: Julio <me@julio.al>
|
||||
Description: Nginx L7 DDoS Protection (The-World-Is-Yours), built by RAWeb CI.
|
||||
EOF
|
||||
# Bundle every shared library nginx links against. ldd resolves
|
||||
# against THIS containers libraries (not the runner host) so the
|
||||
# .deb gets the correct per-distro libs.
|
||||
for lib in $(ldd /usr/sbin/nginx | grep "=> /" | awk "{print \$3}"); do
|
||||
cp "$lib" "${PKG_DIR}/usr/lib/" || true
|
||||
done
|
||||
|
||||
# ---- DEBIAN/postinst -------------------------------------------------
|
||||
# Runs after dpkg unpacks the files. Designed to be safe to re-run:
|
||||
# `apt install --reinstall twiy` and `apt upgrade twiy` both invoke
|
||||
# this script and must not fail.
|
||||
#
|
||||
# Every step that may legitimately fail on a re-run (user already
|
||||
# exists, service already enabled, host has no systemd, etc.) ends
|
||||
# in `|| true`, and we `exit 0` explicitly so a flaky systemctl
|
||||
# never aborts a dpkg transaction.
|
||||
sudo tee "${DEB_DIR}/postinst" >/dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Idempotent: safe on first install, upgrade, and reinstall.
|
||||
# ---- DEBIAN/control --------------------------------------------
|
||||
mkdir -p "${DEB_DIR}"
|
||||
cat > "${DEB_DIR}/control" <<EOF
|
||||
Package: ${PKG_NAME}
|
||||
Version: ${VERSION}
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: ${ARCH}
|
||||
Depends: libjemalloc2
|
||||
Maintainer: Julio <me@julio.al>
|
||||
Description: Nginx L7 DDoS Protection (The-World-Is-Yours), built by RAWeb CI for ${TARGET}.
|
||||
EOF
|
||||
|
||||
# System user nginx workers run as. -r = system account (no aging,
|
||||
# UID below SYS_UID_MAX), no shell, home set to nginx's prefix.
|
||||
useradd -r -d /usr/local/nginx -s /bin/false nginx 2>/dev/null || true
|
||||
# ---- DEBIAN/postinst -------------------------------------------
|
||||
cat > "${DEB_DIR}/postinst" <<"EOFPOSTINST"
|
||||
#!/bin/bash
|
||||
# Idempotent: safe on first install, upgrade, and reinstall.
|
||||
useradd -r -d /usr/local/nginx -s /bin/false nginx 2>/dev/null || true
|
||||
install -d -o nginx -g nginx -m 0755 \
|
||||
/usr/local/nginx \
|
||||
/usr/local/nginx/client_body_temp \
|
||||
/usr/local/nginx/proxy_temp \
|
||||
/usr/local/nginx/fastcgi_temp \
|
||||
/usr/local/nginx/uwsgi_temp \
|
||||
/usr/local/nginx/scgi_temp \
|
||||
/var/log/nginx
|
||||
chown -R nginx:nginx /var/log/nginx /nginx /usr/local/nginx 2>/dev/null || true
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
systemctl enable nginx.service 2>/dev/null || true
|
||||
systemctl restart nginx.service 2>/dev/null || true
|
||||
exit 0
|
||||
EOFPOSTINST
|
||||
chmod 755 "${DEB_DIR}/postinst"
|
||||
|
||||
# nginx was compiled without --http-*-temp-path, so it defaults to
|
||||
# <prefix>/<name> (/usr/local/nginx/client_body_temp etc.). The dirs
|
||||
# already ship in the .deb, but `install -d` is the cleanest way to
|
||||
# set owner/group/mode in one shot and is a no-op when the dir
|
||||
# already exists with the right attributes.
|
||||
install -d -o nginx -g nginx -m 0755 \
|
||||
/usr/local/nginx \
|
||||
/usr/local/nginx/client_body_temp \
|
||||
/usr/local/nginx/proxy_temp \
|
||||
/usr/local/nginx/fastcgi_temp \
|
||||
/usr/local/nginx/uwsgi_temp \
|
||||
/usr/local/nginx/scgi_temp \
|
||||
/var/log/nginx
|
||||
dpkg-deb --build "${PKG_DIR}"
|
||||
cp "${PKG_DIR}.deb" /repo/dist/
|
||||
|
||||
# Recursive chown picks up any user-supplied configs already under
|
||||
# /nginx (vhosts, certs) so reloads don't trip on permissions.
|
||||
chown -R nginx:nginx /var/log/nginx /nginx /usr/local/nginx 2>/dev/null || true
|
||||
# Hand ownership back to the runner UID so the host job can read.
|
||||
chown $(stat -c "%u:%g" /repo) /repo/dist/$(basename "${PKG_DIR}.deb")
|
||||
|
||||
# Refresh systemd's view of unit files we just dropped, then bring
|
||||
# the service up. `restart` (rather than `start`) handles the case
|
||||
# where a previous broken install left the unit failed.
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
systemctl enable nginx.service 2>/dev/null || true
|
||||
systemctl restart nginx.service 2>/dev/null || true
|
||||
exit 0
|
||||
EOF
|
||||
sudo chmod 755 "${DEB_DIR}/postinst"
|
||||
|
||||
# Build the .deb and hand ownership back to the runner user so the
|
||||
# next step can read it without sudo.
|
||||
sudo dpkg-deb --build "${PKG_DIR}"
|
||||
DEB_FILE="${PKG_DIR}.deb"
|
||||
sudo chown "$(id -u):$(id -g)" "${DEB_FILE}"
|
||||
# Stash version for the publish step.
|
||||
echo "${PKG_NAME}_${VERSION}_${ARCH}.deb" > /repo/dist/${TARGET}.name
|
||||
echo "${VERSION}" > /repo/dist/${TARGET}.version
|
||||
echo "${PKG_NAME}" > /repo/dist/${TARGET}.pkg
|
||||
'
|
||||
|
||||
# Surface the artifact paths for the next step.
|
||||
DEB_FILE="$PWD/dist/$(cat dist/${TARGET}.name)"
|
||||
PKG_NAME="$(cat dist/${TARGET}.pkg)"
|
||||
VERSION="$(cat dist/${TARGET}.version)"
|
||||
{
|
||||
echo "deb_file=${DEB_FILE}"
|
||||
echo "version=${VERSION}"
|
||||
@@ -185,73 +168,44 @@ jobs:
|
||||
sha256sum "${DEB_FILE}"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# Publish the built .deb to a Sonatype Nexus apt-hosted repository.
|
||||
#
|
||||
# Threat model for this step (the workflow file is public):
|
||||
# * Credentials come exclusively from repository secrets, never source.
|
||||
# * Credentials must never appear in argv (visible via /proc/<pid>/cmdline
|
||||
# to any local user) or in the runner's persistent filesystem.
|
||||
# * If the job is cancelled or killed, secrets must still be wiped.
|
||||
#
|
||||
# To run this in your own fork, set four repository secrets:
|
||||
# NEXUS_USER — Nexus account with write access to the apt repo
|
||||
# NEXUS_PASS — its password (or token)
|
||||
# NEXUS_URL — base URL, e.g. https://apt.example.com
|
||||
# NEXUS_REPO — the apt-hosted repository name in Nexus
|
||||
# Publish to Nexus (runs on the runner host, not in the build container).
|
||||
# Same security posture as the previous workflow:
|
||||
# * tmpfs scratch dir for credentials
|
||||
# * trap covers EXIT INT TERM HUP
|
||||
# * netrc auth (no -u user:pass on cmdline → no /proc leak)
|
||||
# * NEXUS_HOST derived from NEXUS_URL so forks don't have to edit YAML
|
||||
# The matrix-driven secret indirection picks the right per-distro repo.
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
- name: Publish to Nexus
|
||||
- name: Publish to Nexus (${{ matrix.target }})
|
||||
env:
|
||||
NEXUS_USER: ${{ secrets.NEXUS_USER }}
|
||||
NEXUS_PASS: ${{ secrets.NEXUS_PASS }}
|
||||
NEXUS_URL: ${{ secrets.NEXUS_URL }}
|
||||
NEXUS_REPO: ${{ secrets.NEXUS_REPO }}
|
||||
NEXUS_REPO: ${{ secrets[matrix.nexus_repo_secret] }}
|
||||
DEB_FILE: ${{ steps.pkg.outputs.deb_file }}
|
||||
PKG_NAME: ${{ steps.pkg.outputs.pkg_name }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
umask 077 # any file we create is rw for us only
|
||||
umask 077
|
||||
|
||||
# ---- Secret-handling scratch dir ------------------------------------
|
||||
# /dev/shm is tmpfs (RAM-backed). Even if the runner's disk is later
|
||||
# imaged or recovered, secrets written here never touch persistent
|
||||
# storage. Fall back to /tmp on minimal images that lack /dev/shm.
|
||||
SECDIR="$(mktemp -d -p /dev/shm twiy-XXXXXXXX 2>/dev/null \
|
||||
|| mktemp -d -t twiy-XXXXXXXX)"
|
||||
chmod 700 "$SECDIR"
|
||||
|
||||
# Trap covers normal exit, errors (set -e), and the common cancellation
|
||||
# signals Gitea / GitHub send when a job is cancelled or times out.
|
||||
# `shred -uz` overwrites then unlinks; on tmpfs the overwrite is mostly
|
||||
# symbolic, but it's free defence-in-depth in case /dev/shm wasn't
|
||||
# available and we fell back to a disk-backed /tmp.
|
||||
cleanup() {
|
||||
find "$SECDIR" -type f -exec shred -uz {} + 2>/dev/null || true
|
||||
rm -rf "$SECDIR"
|
||||
}
|
||||
trap cleanup EXIT INT TERM HUP
|
||||
|
||||
# ---- Build the netrc -------------------------------------------------
|
||||
# Why netrc and not `curl -u user:pass`:
|
||||
# - `-u` puts the password in argv; any local user can read it from
|
||||
# /proc/<pid>/cmdline while the curl is in flight.
|
||||
# - netrc is a 0600 file curl reads itself; the password never
|
||||
# appears on a command line.
|
||||
# Why `printf` (a bash builtin): builtins don't fork an external
|
||||
# process, so the password is never an argv to any executable.
|
||||
# The host string in netrc must match the URL host exactly, so we
|
||||
# derive it from $NEXUS_URL rather than hardcoding it — this lets
|
||||
# forks reuse the workflow without editing it.
|
||||
NEXUS_HOST="$(printf '%s' "$NEXUS_URL" | awk -F/ '{print $3}')"
|
||||
printf 'machine %s login %s password %s\n' \
|
||||
"$NEXUS_HOST" "$NEXUS_USER" "$NEXUS_PASS" > "$SECDIR/netrc"
|
||||
# Drop the in-memory copies now that the file is the source of truth.
|
||||
unset NEXUS_USER NEXUS_PASS
|
||||
|
||||
# ---- Replace any prior version of this package -----------------------
|
||||
# Nexus's apt-hosted format keeps every uploaded .deb forever unless we
|
||||
# explicitly delete the old component. Without this, the repo grows
|
||||
# unboundedly and `apt` may pick a stale version. Best-effort: a
|
||||
# missing prior component is not an error.
|
||||
# Replace the prior version of this same package in this same repo,
|
||||
# if any. Best-effort: missing prior is not an error. (apt-hosted
|
||||
# repos in Nexus retain every upload otherwise.)
|
||||
OLD_ID="$(curl -fsS --netrc-file "$SECDIR/netrc" \
|
||||
"$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO" \
|
||||
| PKG_NAME="$PKG_NAME" python3 -c '
|
||||
@@ -265,25 +219,11 @@ jobs:
|
||||
"$NEXUS_URL/service/rest/v1/components/$OLD_ID" -o /dev/null
|
||||
fi
|
||||
|
||||
# ---- Upload the new .deb --------------------------------------------
|
||||
# Body goes to a file inside SECDIR so the trap shreds it too — Nexus
|
||||
# error responses sometimes echo request metadata we'd rather not
|
||||
# leave on disk.
|
||||
HTTP="$(curl -sS --netrc-file "$SECDIR/netrc" \
|
||||
-o "$SECDIR/upload.body" -w '%{http_code}' \
|
||||
-X POST -F "apt.asset=@$DEB_FILE" \
|
||||
"$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO")"
|
||||
case "$HTTP" in
|
||||
201|204) echo "Uploaded $(basename "$DEB_FILE") to $NEXUS_URL/repository/$NEXUS_REPO/" ;;
|
||||
*) echo "Upload failed (HTTP $HTTP)"; head -c 400 "$SECDIR/upload.body"; exit 1 ;;
|
||||
201|204) echo "[$TARGET] uploaded $(basename "$DEB_FILE") to $NEXUS_URL/repository/$NEXUS_REPO/" ;;
|
||||
*) echo "[$TARGET] upload failed (HTTP $HTTP)"; head -c 400 "$SECDIR/upload.body"; exit 1 ;;
|
||||
esac
|
||||
|
||||
# ---- Why we don't sign each .deb ourselves ---------------------------
|
||||
# apt's trust chain on the client is:
|
||||
# Release.gpg → Packages (verified by SHA256 in Release)
|
||||
# → the .deb (verified by SHA256 in Packages)
|
||||
# Signing the Release file is enough; per-.deb signatures are not
|
||||
# consulted by apt during install. Nexus signs Release on every
|
||||
# upload using a key bound at repo-creation time, and that private
|
||||
# key never leaves the Nexus host — so we deliberately keep all
|
||||
# signing material off the CI runner.
|
||||
|
||||
Reference in New Issue
Block a user