Skip to content
Open
161 changes: 91 additions & 70 deletions .github/workflows/build-rpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,18 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Import GPG key
run: |
echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --import --batch --yes
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

- name: Show signing subkey expiration
shell: bash
run: |
gpg --list-secret-keys --with-colons \
| awk -F: '
$1=="ssb" && $12 ~ /s/ {
keyid = $5
expires = $7
if (expires == "" || expires == "0") {
edate = "never"
} else {
cmd = "date -u -d @" expires " +\"%Y-%m-%d %H:%M:%S UTC\""
cmd | getline edate
close(cmd)
}
printf "signing subkey %s expires: %s\n", keyid, edate
}
'
- name: Check signing subkey expiration
uses: OpenCHAMI/gpg-signing-manager/actions/check-subkey-expiration@main
with:
subkey-armored-b64: ${{ secrets.GPG_SUBKEY_B64 }}
warn-days: '30'

- name: Setup RPM signing
id: repo_key
uses: OpenCHAMI/gpg-signing-manager/actions/setup-rpm-signing@main
with:
subkey-armored-b64: ${{ secrets.GPG_SUBKEY_B64 }}
public-key-output: public_gpg_key.asc

- name: Get version
id: get_version
Expand All @@ -69,7 +57,7 @@ jobs:
else
VERSION=0.0.0
fi
echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "Version is ${VERSION}"

- name: Setup RPM build environment
Expand All @@ -80,109 +68,142 @@ jobs:

- name: Create source tarball
run: |
mkdir -p ~/rpmbuild/SOURCES/openchami-${{ env.VERSION }}
cp -r ./* ~/rpmbuild/SOURCES/openchami-${{ env.VERSION }}/
tar -czf ~/rpmbuild/SOURCES/openchami-${{ env.VERSION }}.tar.gz \
-C ~/rpmbuild/SOURCES openchami-${{ env.VERSION }} \
--transform "s|openchami-${{ env.VERSION }}-${{ env.COMMIT_SHA }}|openchami-${{ env.VERSION }}|"
mkdir -p ~/rpmbuild/SOURCES/openchami-${{ steps.get_version.outputs.version }}
cp -r ./* ~/rpmbuild/SOURCES/openchami-${{ steps.get_version.outputs.version }}/
tar -czf ~/rpmbuild/SOURCES/openchami-${{ steps.get_version.outputs.version }}.tar.gz \
-C ~/rpmbuild/SOURCES openchami-${{ steps.get_version.outputs.version }}

- name: Sign source tarball
env:
GPG_SIGNING_KEYID: ${{ steps.repo_key.outputs.repo-signing-keyid }}
GPG_SIGNING_FINGERPRINT: ${{ steps.repo_key.outputs.repo-signing-fingerprint }}
run: |
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 --pinentry-mode loopback \
set -euo pipefail
unset GPG_TTY
echo "Signing source tarball with key: ${GPG_SIGNING_KEYID} (${GPG_SIGNING_FINGERPRINT})"
gpg --batch --list-secret-keys --keyid-format LONG "${GPG_SIGNING_FINGERPRINT}"
gpg --batch --yes \
--no-tty --pinentry-mode loopback \
--status-fd 2 \
--armor --detach-sign \
--local-user admin@openchami.org \
--output ~/rpmbuild/SOURCES/openchami-${{ env.VERSION }}.tar.gz.asc \
~/rpmbuild/SOURCES/openchami-${{ env.VERSION }}.tar.gz
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
--local-user "${GPG_SIGNING_KEYID}" \
--output ~/rpmbuild/SOURCES/openchami-${{ steps.get_version.outputs.version }}.tar.gz.asc \
~/rpmbuild/SOURCES/openchami-${{ steps.get_version.outputs.version }}.tar.gz

- name: Build RPM package
run: |
rpmbuild -ba ~/rpmbuild/SPECS/*.spec \
--define "version ${{ env.VERSION }}" \
--define "version ${{ steps.get_version.outputs.version }}" \
--define "rel 1"

- name: Sign RPM packages
run: |
for rpm in $(find ~/rpmbuild/RPMS/ -type f -name "*.rpm"); do
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 --pinentry-mode loopback \
--detach-sign --armor "$rpm"
rpm --define "_gpg_name admin@openchami.org" --addsign "$rpm"
done
shell: bash
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_SIGNING_KEYID: ${{ steps.repo_key.outputs.repo-signing-keyid }}
GPG_SIGNING_FINGERPRINT: ${{ steps.repo_key.outputs.repo-signing-fingerprint }}
run: |
set -euo pipefail
unset GPG_TTY
echo "Using RPM signing key: ${GPG_SIGNING_KEYID} (${GPG_SIGNING_FINGERPRINT})"
gpg --batch --list-secret-keys --keyid-format LONG "${GPG_SIGNING_FINGERPRINT}"
echo 'Configured ~/.rpmmacros:'
cat ~/.rpmmacros

found=0
while IFS= read -r -d '' rpm_file; do
found=1
echo "Signing RPM: $rpm_file"
rpmsign --key-id "${GPG_SIGNING_KEYID}" --addsign "$rpm_file"
done < <(find ~/rpmbuild/RPMS/ -type f -name "*.rpm" -print0)

if [ "$found" -eq 0 ]; then
echo 'No RPM packages were produced to sign' >&2
exit 1
fi

- name: Verify RPM signatures
shell: bash
run: |
found=0
while IFS= read -r -d '' rpm_file; do
found=1
output=$(rpm --checksig -v "$rpm_file" 2>&1)
printf '%s\n' "$output"

if printf '%s\n' "$output" | grep -q 'SIGNATURES NOT OK'; then
echo "RPM signature verification failed for $rpm_file" >&2
exit 1
fi

if ! printf '%s\n' "$output" | grep -Eiq 'Key ID|RSA/SHA|RSA/sha|EdDSA|pgp'; then
echo "RPM appears unsigned: $rpm_file" >&2
exit 1
fi
done < <(find ~/rpmbuild/RPMS/ -type f -name "*.rpm" -print0)

if [ "$found" -eq 0 ]; then
echo 'No RPM packages were produced to verify' >&2
exit 1
fi

- name: Find RPM file
if: env.VERSION != '0.0.0'
if: steps.get_version.outputs.version != '0.0.0'
id: find_rpm
run: |
rpm_file=$(ls ~/rpmbuild/RPMS/noarch/*.rpm)
echo "rpm_file=${rpm_file}" >> $GITHUB_ENV
echo "::set-output name=path::${rpm_file}"
echo "path=${rpm_file}" >> "$GITHUB_OUTPUT"

- name: Compute RPM Checksum
if: env.VERSION != '0.0.0'
if: steps.get_version.outputs.version != '0.0.0'
id: compute_checksum
run: |
rpm_file=$(ls ~/rpmbuild/RPMS/noarch/*.rpm)
checksum=$(sha256sum "$rpm_file" | awk '{print $1}')
echo "checksum=${checksum}" >> $GITHUB_ENV
echo "::set-output name=checksum::${checksum}"

- name: Export Public GPG Key
if: env.VERSION != '0.0.0'
run: |
gpg --armor --export admin@openchami.org > public_gpg_key.asc

- name: Get Public GPG Key Content
if: env.VERSION != '0.0.0'
id: get_pubkey
run: |
key=$(cat public_gpg_key.asc)
escaped_key=$(echo "$key" | sed ':a;N;$!ba;s/\n/\\n/g')
echo "::set-output name=pubkey::${escaped_key}"
echo "checksum=${checksum}" >> "$GITHUB_OUTPUT"

- name: Genereate release notes
if: env.VERSION != '0.0.0'
if: steps.get_version.outputs.version != '0.0.0'
id: gen_rel_notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
{
echo '# OpenCHAMI v${{ env.VERSION }}'
echo '# OpenCHAMI v${{ steps.get_version.outputs.version }}'
echo ''
echo '**RPM SHA256 Checksum:**'
echo '`${{ steps.compute_checksum.outputs.checksum }}`'
echo ''
gh api "repos/${GITHUB_REPOSITORY}/releases/generate-notes" -F tag_name='v${{ env.VERSION }}' --jq .body
gh api "repos/${GITHUB_REPOSITORY}/releases/generate-notes" -F tag_name='v${{ steps.get_version.outputs.version }}' --jq .body
} > CHANGELOG.md

- name: Create GitHub Release
if: env.VERSION != '0.0.0'
if: steps.get_version.outputs.version != '0.0.0'
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ env.VERSION }}
release_name: v${{ env.VERSION }}
tag_name: v${{ steps.get_version.outputs.version }}
release_name: v${{ steps.get_version.outputs.version }}
draft: false
prerelease: false
body_path: CHANGELOG.md

- name: Upload RPM to GitHub Release
if: env.VERSION != '0.0.0'
if: steps.get_version.outputs.version != '0.0.0'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ steps.find_rpm.outputs.path }}
asset_name: openchami-${{ env.VERSION }}.rpm
asset_name: openchami-${{ steps.get_version.outputs.version }}.rpm
asset_content_type: application/x-rpm

- name: Upload Public GPG Key to GitHub Release
if: env.VERSION != '0.0.0'
if: steps.get_version.outputs.version != '0.0.0'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ Clean built RPMs in repo directory:
make clean
```

## Automated RPM Signing

The GitHub release workflow signs built RPMs with the repository signing subkey
stored in the `GPG_SUBKEY_B64` repository secret. The workflow also exports the
matching ASCII-armored public key as a release asset so downstream consumers can
verify the published RPM signature.

## Current Release

OpenCHAMI is in development without an initial release. We expect a first supported release in Q1 2025. If you would like to follow the most current, stable configuration, each of the partners maintains a deployment recipe that will become a release candidate in our [Deployment Recipes](https://github.com/OpenCHAMI/deployment-recipes) Repository.
Expand Down
Loading