From 44efd905c562d08a63b8be56867e77d8102f16f9 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 25 Apr 2026 21:18:04 +0000 Subject: [PATCH] ci: drop dpkg-sig per-deb signing (broken on modern .debs); rely on Nexus repo signing for apt trust chain --- .gitea/workflows/build-publish.yml | 59 +++++++++--------------------- 1 file changed, 18 insertions(+), 41 deletions(-) diff --git a/.gitea/workflows/build-publish.yml b/.gitea/workflows/build-publish.yml index 24af465..6cc890a 100644 --- a/.gitea/workflows/build-publish.yml +++ b/.gitea/workflows/build-publish.yml @@ -85,58 +85,31 @@ jobs: ls -la "${DEB_FILE}" sha256sum "${DEB_FILE}" - - name: Sign and publish to Nexus + - name: 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 }} + 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. + # All secret material lives in tmpfs (RAM); shredded on exit either way. SECDIR="$(mktemp -d -p /dev/shm raweb-XXXXXXXX 2>/dev/null \ || mktemp -d -t raweb-XXXXXXXX)" chmod 700 "$SECDIR" - export GNUPGHOME="$SECDIR/gnupg" + trap 'find "$SECDIR" -type f -exec shred -uz {} + 2>/dev/null || true; rm -rf "$SECDIR"' EXIT - 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" + # Auth via netrc file — never via -u user:pass on the command line, + # which would be visible to anything that can read /proc. 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 + unset NEXUS_USER NEXUS_PASS - # 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). + # Replace prior component of the same name, if any (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 ' @@ -150,7 +123,6 @@ jobs: "$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" \ @@ -159,3 +131,8 @@ jobs: 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 + + # Note: per-.deb signing intentionally not performed here. apt's trust + # chain is Release.gpg → Packages SHA256 → .deb SHA256, and Nexus signs + # the Release file on every upload using the key bound at repo creation. + # The private key never leaves the Nexus host.