name: build-and-publish on: push: branches: [master] workflow_dispatch: jobs: build: runs-on: ubuntu-22.04 steps: - name: Checkout source uses: actions/checkout@v4 - name: Install build dependencies run: | set -euo pipefail sudo apt-get update -y sudo apt-get install -y --no-install-recommends \ git curl wget ca-certificates dpkg-dev fakeroot \ build-essential gnupg dpkg-sig - name: Compile nginx and modules run: | set -euo pipefail sudo touch /.dockerenv sudo bash build/run.sh new sudo bash build/run.sh build sudo bash build/run.sh postfix - name: Assemble .deb package id: pkg run: | set -euo pipefail PKG_NAME="twiy" VERSION="$(nginx -v 2>&1 | awk -F'/' '{print $2}')" ARCH="amd64" PKG_DIR="/opt/${PKG_NAME}_${VERSION}_${ARCH}" DEB_DIR="${PKG_DIR}/DEBIAN" 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" 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 for lib in $(ldd /usr/sbin/nginx | grep '=> /' | awk '{print $3}'); do sudo cp "$lib" "${PKG_DIR}/usr/lib/" || true done sudo mkdir -p "${DEB_DIR}" sudo tee "${DEB_DIR}/control" >/dev/null < Description: Nginx L7 DDoS Protection (The-World-Is-Yours), built by RAWeb CI. EOF sudo tee "${DEB_DIR}/postinst" >/dev/null <<'EOF' #!/bin/bash useradd -r -d /usr/local/nginx -s /bin/false nginx || true systemctl daemon-reload || true EOF sudo chmod 755 "${DEB_DIR}/postinst" sudo dpkg-deb --build "${PKG_DIR}" DEB_FILE="${PKG_DIR}.deb" sudo chown "$(id -u):$(id -g)" "${DEB_FILE}" { echo "deb_file=${DEB_FILE}" echo "version=${VERSION}" echo "pkg_name=${PKG_NAME}" } >> "$GITHUB_OUTPUT" ls -la "${DEB_FILE}" sha256sum "${DEB_FILE}" - name: Sign and publish to Nexus env: GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} NEXUS_USER: ${{ secrets.NEXUS_USER }} NEXUS_PASS: ${{ secrets.NEXUS_PASS }} NEXUS_URL: ${{ secrets.NEXUS_URL }} NEXUS_REPO: ${{ secrets.NEXUS_REPO }} DEB_FILE: ${{ steps.pkg.outputs.deb_file }} PKG_NAME: ${{ steps.pkg.outputs.pkg_name }} run: | set -euo pipefail umask 077 # Tmpfs (RAM-only) scratch for every byte of secret material. # Falls back to /tmp if /dev/shm is absent. SECDIR="$(mktemp -d -p /dev/shm raweb-XXXXXXXX 2>/dev/null \ || mktemp -d -t raweb-XXXXXXXX)" chmod 700 "$SECDIR" export GNUPGHOME="$SECDIR/gnupg" cleanup() { (gpg --batch --yes --quiet \ --delete-secret-and-public-key "$GPG_KEY_ID" 2>/dev/null) || true (gpgconf --kill all 2>/dev/null) || true find "$SECDIR" -type f -exec shred -uz {} + 2>/dev/null || true rm -rf "$SECDIR" } trap cleanup EXIT # Materialise secrets to in-memory files. After this, drop them from env # so any subprocess (or accidental `env`) cannot read them. printf '%s' "$GPG_PRIVATE_KEY" > "$SECDIR/key.asc" printf '%s' "$GPG_PASSPHRASE" > "$SECDIR/pp" printf 'machine apt.julio.al login %s password %s\n' \ "$NEXUS_USER" "$NEXUS_PASS" > "$SECDIR/netrc" unset GPG_PRIVATE_KEY GPG_PASSPHRASE NEXUS_PASS NEXUS_USER # Ephemeral keyring on tmpfs. mkdir -p "$GNUPGHOME"; chmod 700 "$GNUPGHOME" printf 'allow-loopback-pinentry\n' > "$GNUPGHOME/gpg-agent.conf" printf 'pinentry-mode loopback\n' > "$GNUPGHOME/gpg.conf" gpg --batch --import "$SECDIR/key.asc" # Sign the .deb. Passphrase passed via FILE — never argv, never env. dpkg-sig -k "$GPG_KEY_ID" \ -g "--batch --pinentry-mode loopback --passphrase-file $SECDIR/pp" \ --sign builder "$DEB_FILE" dpkg-sig --verify "$DEB_FILE" # Replace any prior component of the same name (best-effort). OLD_ID="$(curl -fsS --netrc-file "$SECDIR/netrc" \ "$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO" \ | PKG_NAME="$PKG_NAME" python3 -c ' import sys, json, os for c in json.load(sys.stdin).get("items", []): if c.get("name") == os.environ["PKG_NAME"]: print(c["id"]); break ' || true)" if [ -n "$OLD_ID" ]; then curl -fsS -X DELETE --netrc-file "$SECDIR/netrc" \ "$NEXUS_URL/service/rest/v1/components/$OLD_ID" -o /dev/null fi # Upload — auth via netrc (not -u, not query string). 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 ;; esac