fix workflow 8 #5
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release | |
| permissions: | |
| contents: write | |
| on: | |
| push: | |
| tags: | |
| - "[0-9]+.[0-9]+.[0-9]+" | |
| workflow_dispatch: | |
| jobs: | |
| build-rpm-package: | |
| runs-on: ubuntu-latest | |
| name: Build and Sign RPM Package | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| - name: Extract and Validate Version | |
| id: version | |
| run: | | |
| # Extract version from pyproject.toml | |
| VERSION=$(grep -E '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/') | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| # Extract version from tag | |
| TAG_VERSION="$GITHUB_REF_NAME" | |
| echo "tag_version=$TAG_VERSION" >> $GITHUB_OUTPUT | |
| # Validate that tag matches pyproject.toml version | |
| if [ "$TAG_VERSION" != "$VERSION" ]; then | |
| echo "ERROR: Tag version ($TAG_VERSION) does not match pyproject.toml version ($VERSION)" | |
| exit 1 | |
| fi | |
| echo "✓ Version validated: $VERSION" | |
| - name: Import GPG Key | |
| run: | | |
| echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import | |
| # Set ultimate trust for the imported key | |
| KEY_FPR=$(gpg --list-keys --with-colons | grep '^fpr' | head -n1 | cut -d: -f10) | |
| echo "${KEY_FPR}:6:" | gpg --import-ownertrust | |
| # Configure GPG for non-interactive use in CI | |
| export GPG_TTY=$(tty) || export GPG_TTY=/dev/null | |
| mkdir -p ~/.gnupg | |
| chmod 700 ~/.gnupg | |
| # Configure GPG to use loopback pinentry (no GUI) | |
| cat > ~/.gnupg/gpg.conf << 'EOF' | |
| use-agent | |
| pinentry-mode loopback | |
| EOF | |
| cat > ~/.gnupg/gpg-agent.conf << 'EOF' | |
| allow-loopback-pinentry | |
| max-cache-ttl 3600 | |
| EOF | |
| # Restart GPG agent to apply new configuration | |
| gpgconf --kill gpg-agent || true | |
| gpg-agent --daemon || true | |
| echo "✓ GPG configured for CI environment" | |
| - name: Build RPM in Fedora Container | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| mkdir -p output | |
| echo "🔨 Building RPM package version $VERSION..." | |
| docker pull docker.io/library/fedora:latest | |
| docker run --rm \ | |
| -v "$PWD:/workspace:ro" \ | |
| -v "$PWD/output:/output:rw" \ | |
| -w /workspace \ | |
| docker.io/library/fedora:latest \ | |
| bash -c " | |
| set -e | |
| # Install build dependencies | |
| dnf -y install rpm-build rpmdevtools python3-devel python3-setuptools pyproject-rpm-macros | |
| # Setup rpmbuild directories | |
| rpmdev-setuptree | |
| # Copy spec file | |
| cp /workspace/build/tuxgrade.spec ~/rpmbuild/SPECS/ | |
| # Create source tarball | |
| mkdir -p ~/tuxgrade-${VERSION} | |
| cp -r /workspace/src ~/tuxgrade-${VERSION}/ | |
| cp /workspace/pyproject.toml ~/tuxgrade-${VERSION}/ | |
| cp /workspace/LICENSE ~/tuxgrade-${VERSION}/ | |
| cp /workspace/README.md ~/tuxgrade-${VERSION}/ | |
| tar czf ~/rpmbuild/SOURCES/tuxgrade-${VERSION}.tar.gz -C ~ tuxgrade-${VERSION} | |
| # Build RPM | |
| rpmbuild -ba ~/rpmbuild/SPECS/tuxgrade.spec | |
| # Copy built packages to output | |
| cp ~/rpmbuild/RPMS/noarch/*.rpm /output/ | |
| echo 'RPM package built successfully!' | |
| " | |
| echo "✓ RPM build complete" | |
| ls -lh output/ | |
| # Fix permissions (container creates files as root) | |
| sudo chown -R $(id -u):$(id -g) output/ | |
| - name: Install RPM Signing Tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y rpm | |
| - name: Sign RPM Package | |
| env: | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| echo "🔐 Signing RPM package..." | |
| # Get key fingerprint | |
| KEY_FPR=$(gpg --list-keys --with-colons | grep '^fpr' | head -n1 | cut -d: -f10) | |
| # Configure RPM signing with GPG batch mode | |
| cat > ~/.rpmmacros << EOF | |
| %_signature gpg | |
| %_gpg_name $KEY_FPR | |
| %__gpg /usr/bin/gpg | |
| %__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-armor --pinentry-mode loopback --passphrase-fd 3 --detach-sign --output %{__signature_filename} %{__plaintext_filename} | |
| EOF | |
| # Sign all RPM packages | |
| for rpm in output/*.rpm; do | |
| if [ -f "$rpm" ]; then | |
| echo "Signing: $(basename $rpm)" | |
| echo "$GPG_PASSPHRASE" | rpm --addsign "$rpm" 3<&0 | |
| fi | |
| done | |
| echo "✓ RPM packages signed" | |
| - name: Verify RPM Signatures | |
| run: | | |
| echo "🔍 Verifying RPM signatures..." | |
| # Import public key into RPM database for verification | |
| gpg --armor --export > /tmp/gpg-pubkey.asc | |
| sudo rpm --import /tmp/gpg-pubkey.asc | |
| # Verify signatures | |
| for rpm in output/*.rpm; do | |
| if [ -f "$rpm" ]; then | |
| echo "Checking: $(basename $rpm)" | |
| rpm --checksig "$rpm" | |
| fi | |
| done | |
| echo "✓ All signatures verified" | |
| - name: Upload RPM Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: signed-rpm | |
| path: output/*.rpm | |
| retention-days: 30 | |
| build-deb-package: | |
| runs-on: ubuntu-latest | |
| name: Build DEB Package | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| - name: Extract and Validate Version | |
| id: version | |
| run: | | |
| # Extract version from pyproject.toml | |
| VERSION=$(grep -E '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/') | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| # Extract version from tag | |
| TAG_VERSION="$GITHUB_REF_NAME" | |
| echo "tag_version=$TAG_VERSION" >> $GITHUB_OUTPUT | |
| # Validate that tag matches pyproject.toml version | |
| if [ "$TAG_VERSION" != "$VERSION" ]; then | |
| echo "ERROR: Tag version ($TAG_VERSION) does not match pyproject.toml version ($VERSION)" | |
| exit 1 | |
| fi | |
| echo "✓ Version validated: $VERSION" | |
| - name: Build DEB in Ubuntu Container | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| mkdir -p output | |
| echo "🔨 Building DEB package version $VERSION..." | |
| docker pull docker.io/library/ubuntu:24.04 | |
| docker run --rm \ | |
| -v "$PWD:/workspace:ro" \ | |
| -v "$PWD/output:/output:rw" \ | |
| docker.io/library/ubuntu:24.04 \ | |
| bash -c " | |
| set -e | |
| # Prevent interactive prompts | |
| export DEBIAN_FRONTEND=noninteractive | |
| # Install build dependencies | |
| apt-get update | |
| apt-get install -y \ | |
| debhelper \ | |
| dh-python \ | |
| python3-all \ | |
| python3-setuptools \ | |
| python3-pip \ | |
| python3-build \ | |
| python3-distro \ | |
| pybuild-plugin-pyproject \ | |
| dpkg-dev \ | |
| fakeroot | |
| # Create build directory | |
| mkdir -p /build | |
| # Copy project to build directory (need write access for build) | |
| cp -r /workspace/* /build/ | |
| # Change to build directory | |
| cd /build | |
| # Build the package | |
| dpkg-buildpackage -us -uc -b | |
| # Copy built packages to output (only .deb files) | |
| cp ../*.deb /output/ | |
| echo 'DEB package built successfully!' | |
| " | |
| echo "✓ DEB build complete" | |
| ls -lh output/ | |
| # Fix permissions (container creates files as root) | |
| sudo chown -R $(id -u):$(id -g) output/ | |
| - name: Upload DEB Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: deb | |
| path: output/*.deb | |
| retention-days: 30 | |
| create-release: | |
| needs: [build-rpm-package, build-deb-package] | |
| runs-on: ubuntu-latest | |
| name: Create GitHub Release | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v4 | |
| - name: Download RPM Artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: signed-rpm | |
| path: packages | |
| - name: Download DEB Artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: deb | |
| path: packages | |
| - name: Extract Version | |
| id: version | |
| run: | | |
| VERSION=$(grep -E '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/') | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Generate Release Notes | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| cat > release-notes.md << 'EOF' | |
| ## Tuxgrade ${{ steps.version.outputs.version }} | |
| **🔒 Security:** RPM packages are cryptographically signed. DEB packages are distributed via a GPG-signed APT repository for secure installation. | |
| ### Installation | |
| **Debian / Ubuntu / Linux Mint** | |
| 1. Import GPG key: | |
| ```bash | |
| sudo mkdir -p /usr/share/keyrings | |
| sudo curl -fsSL -o /usr/share/keyrings/tuxgrade-archive-keyring.gpg \ | |
| https://Lineax17.github.io/tuxgrade/deb/tuxgrade-archive-keyring.gpg | |
| ``` | |
| 2. Add repository: | |
| ```bash | |
| sudo curl -fsSL -o /etc/apt/sources.list.d/tuxgrade.list \ | |
| https://raw.githubusercontent.com/Lineax17/tuxgrade/master/extras/tuxgrade.list | |
| ``` | |
| 3. Install: | |
| ```bash | |
| sudo apt update | |
| sudo apt install tuxgrade | |
| ``` | |
| **Fedora / RHEL / Rocky / AlmaLinux** | |
| 1. Add repository: | |
| ```bash | |
| sudo curl -fsSL -o /etc/yum.repos.d/tuxgrade.repo \ | |
| https://raw.githubusercontent.com/Lineax17/tuxgrade/master/extras/tuxgrade.repo | |
| ``` | |
| 2. Install: | |
| ```bash | |
| sudo dnf install tuxgrade | |
| ``` | |
| ### Security Verification | |
| **GPG Fingerprint:** `F7CF 5667 CC26 2DDC 072F 2274 496C BE37 E61D EE21` | |
| **Verify package signatures:** | |
| ```bash | |
| # RPM package signature | |
| rpm --checksig tuxgrade-${{ steps.version.outputs.version }}-1.fc43.noarch.rpm | |
| ``` | |
| **Note:** DEB packages are distributed via a GPG-signed APT repository. Signature verification happens automatically when you install from the repository. For direct .deb installation, the repository signing ensures package authenticity. | |
| --- | |
| 📚 [Full Documentation](https://github.com/Lineax17/tuxgrade/blob/master/README.md) | 🔐 [Security & Verification](https://github.com/Lineax17/tuxgrade/blob/master/README.md#security--verification) | |
| EOF | |
| - name: List Packages | |
| run: | | |
| echo "📦 Packages to be released:" | |
| ls -lh packages/ | |
| - name: Create Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh release create "$GITHUB_REF_NAME" \ | |
| packages/*.rpm packages/*.deb \ | |
| --title "Tuxgrade v${{ steps.version.outputs.version }}" \ | |
| --notes-file release-notes.md \ | |
| --verify-tag | |
| echo "✅ Release $GITHUB_REF_NAME created successfully!" |