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.