Good news! The Skpr CLI is now available from a secure deb repository.
This means you can install the Skpr CLI with a simple set of commands:
wget -q https://packages.skpr.io/apt/packages.skpr.io.pub -O- | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/packages.skpr.io.pub > /dev/null
echo "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/packages.skpr.io.pub] https://packages.skpr.io/apt stable main" | sudo tee -a /etc/apt/sources.list.d/skpr.list > /dev/null
sudo apt update && sudo apt install skpr
From then on, the Skpr CLI will be updated automatically when you run apt upgrade.
How it works
In this post we will share how to create a self-hosted deb repository using Github Actions, a GPG keypair and Amazon S3.
Generate a GPG keypair
First, we need to generate a GPG keypair. This will be used to sign the packages in the repository.
Instead of repeating all the same steps, I recommend reading through the GitHub docs on Generating a new GPG key
You will need to export the private and public keys to use with GitHub actions.
Use the following commands to find your key ID:
gpg --list-secret-keys --keyid-format=long
Then assuming you set KEY_ID=1234567890ABCDEF to your key ID:
gpg --armor --export ${KEY_ID} > public.key
gpg --armor --export-secret-keys ${KEY_ID} > private.key
Note: You should keep the private key safe, and not commit it to your repository.
In your GitHub repository, go to Settings > Secrets and variables > Actions add GPG_PRIVATE_KEY and GPG_PUBLIC_KEY
with the contents of the private and public keys respectively.
Use the generate-apt-repo.sh script
The following bash script can be used to generate the apt repository.
You will need dpkg-dev installed to use this script.
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
main() {
ARCHS=(amd64 arm64)
SUITE_DIR="dists/${SUITE:-stable}"
COMPONENT_DIR="${SUITE_DIR}/${COMPONENTS-main}"
echo "Cleaning up dist dir"
rm -rf ./dist
echo "Generating Packages files"
for ARCH in "${ARCHS[@]}"; do
PACKAGE_DIR=${COMPONENT_DIR}/binary-${ARCH}
mkdir -p ${PACKAGE_DIR}
dpkg-scanpackages --multiversion --arch ${ARCH} pool/ > ${PACKAGE_DIR}/Packages
gzip -fk ${PACKAGE_DIR}/Packages
bzip2 -fk ${PACKAGE_DIR}/Packages
done
pushd "${SUITE_DIR}" >/dev/null
echo "Making Release file"
{
echo "Origin: ${ORIGIN:-skpr}"
echo "Label: ${REPO_OWNER:-skpr}"
echo "Suite: ${SUITE:-stable}"
echo "Codename: ${SUITE:-stable}"
echo "Version: 1.0"
echo "Architectures: amd64 arm64"
echo "Components: ${COMPONENTS:-main}"
echo "Description: ${DESCRIPTION:-A repository for packages released by ${REPO_OWNER:-skpr}}"
echo "Date: $(date -Ru)"
generate_hashes MD5Sum md5sum
generate_hashes SHA1 sha1sum
generate_hashes SHA256 sha256sum
generate_hashes SHA512 sha512sum
} > Release
echo "Signing Release files"
gpg --batch --yes --armor --sign --detach-sign --output Release.gpg Release
gpg --batch --yes --armor --sign --detach-sign --clearsign --output InRelease Release
popd >/dev/null
echo "Apt repo generated"
}
generate_hashes() {
HASH_TYPE="$1"
HASH_COMMAND="$2"
echo "${HASH_TYPE}:"
find ${COMPONENTS-main} -type f | while read -r file
do
echo " $(${HASH_COMMAND} "$file" | cut -d" " -f1) $(wc -c "$file")"
done
}
main
Create a Github Action
You can use the following as an example.
name: ๐ฆ Build Apt Repo
# Maunal trigger builds
on:
workflow_dispatch:
env:
BUCKET_NAME: my-bucket
AWS_REGION: us-east-1
jobs:
publish_debs:
runs-on: ubuntu-latest
steps:
- name: โฌ๏ธ Git clone the repository
uses: actions/checkout@v4
- name: ๐ Make apt repo dirs
run: mkdir -p apt-repo/pool/main/skpr
# Download all deb files from the latest release.
- name: ๐ฆ Download latest release
uses: robinraju/release-downloader@v1.8
with:
repository: skpr/cli
latest: true
fileName: "*.deb"
out-file-path: apt-repo/pool/main/skpr
- name: โ๏ธ Configure aws credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: ๐ Import GPG Private Key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
- name: ๐ List keys
run: gpg -K
- name: ๐ฆ Generate Apt Repo
run: |
cd apt-repo
../scripts/generate-apt-repo.sh
cd -
- name: ๐ Export Public Key
run: |
cd apt-repo
echo "${{ secrets.GPG_PUBLIC_KEY }}" > packages.skpr.io.pub
cd -
- name: โ๏ธ Sync to S3
run: |
cd apt-repo
aws s3 sync --delete . s3://${{ env.BUCKET_NAME }}/apt/
cd -
- name: ๐งน Invalidate Cloudfront
run: |
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_ID }} --paths /apt/*
Acknowledgements
Much of the heavy lifting was taken from Benoit Perroud and this blog post.