Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
e8d3dc0
skip goreleaser publish step
Benjosh95 Oct 1, 2025
c4c86d4
fix typo
Benjosh95 Oct 1, 2025
8f27d27
skip tag validation
Benjosh95 Oct 1, 2025
84df183
temporarily outcomment most builds
Benjosh95 Oct 1, 2025
6bd3486
add rpm release job and script
Benjosh95 Oct 1, 2025
0317c11
change nfpms signing to embedded
Benjosh95 Oct 1, 2025
cbf953a
fix indentation
Benjosh95 Oct 1, 2025
4c7e6e5
add passphrase
Benjosh95 Oct 1, 2025
a332fd4
fix passphrase env
Benjosh95 Oct 1, 2025
fb156e5
remove ubuntu rpm package
Benjosh95 Oct 1, 2025
1225186
add particular endpoint flag
Benjosh95 Oct 1, 2025
de5d7fc
fix deletion packages bug
Benjosh95 Oct 1, 2025
66956eb
add gpg --batch to to signing of repo metadata
Benjosh95 Oct 2, 2025
7f198b6
download existing bucket rpm content and redo signing of metadata
Benjosh95 Oct 2, 2025
5992b0d
fix duplicating metadata
Benjosh95 Oct 2, 2025
3cae183
insert apt again with test env for testing
Benjosh95 Oct 6, 2025
a77d896
WORKAROUND for apt mirror issue
Benjosh95 Oct 6, 2025
755ec0b
WORKAROUND: fix aptly config for test env
Benjosh95 Oct 6, 2025
39e7d4d
add DNF/YUM/Zypper installation Guide
Benjosh95 Oct 6, 2025
e1e1958
remove the apt testing stuff and isolation work again after successfu…
Benjosh95 Oct 6, 2025
afb2cb5
improve installation docs
Benjosh95 Oct 6, 2025
4e5548a
remove duplicate message leftover
Benjosh95 Oct 6, 2025
9bdaa6d
publish rpm script improvement - regarding - sync
Benjosh95 Oct 6, 2025
d982c2d
add release comments
Benjosh95 Oct 6, 2025
5af38d8
remove some comments goreleaser
Benjosh95 Oct 6, 2025
067d3dd
fix installing typo
Benjosh95 Oct 13, 2025
3b82b58
remove installation auto-confirmation
Benjosh95 Oct 13, 2025
1f9e88e
fix unused variable
Benjosh95 Oct 13, 2025
8061c88
fix quotes codesplitting
Benjosh95 Oct 13, 2025
0b7f098
fix unused keyring
Benjosh95 Oct 13, 2025
71bf833
fix printf
Benjosh95 Oct 13, 2025
7f50890
fix filelist using find
Benjosh95 Oct 13, 2025
c616761
remove comment, fix gpg cleanup
Benjosh95 Oct 13, 2025
051cacb
fix gpg key storage
Benjosh95 Oct 13, 2025
bb4effa
add key redundancy comment
Benjosh95 Oct 13, 2025
5081b7d
updating links to point to production
Benjosh95 Oct 13, 2025
c6a7434
fix installation docs
Benjosh95 Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ jobs:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}

# nfpm-rpm signing needs gpg provided as filepath
# https://goreleaser.com/customization/nfpm/
- name: Create GPG key file
run: |
KEY_PATH="$RUNNER_TEMP/gpg-private-key.asc"
printf '%s' "${{ secrets.GPG_PRIVATE_KEY }}" > "$KEY_PATH"
chmod 600 "$KEY_PATH"
echo "GPG_KEY_PATH=$KEY_PATH" >> "$GITHUB_ENV"

- name: Set up keychain
run: |
echo -n $SIGNING_CERTIFICATE_BASE64 | base64 -d -o ./ApplicationID.p12
Expand Down Expand Up @@ -71,15 +80,22 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.CLI_RELEASE }}
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
GPG_KEY_PATH: ${{ env.GPG_KEY_PATH }}
# nfpm-rpm signing needs this env to be set.
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

# artifacts need to be passed to the "publish-apt" job somehow
- name: Clean up GPG key file
if: always()
run: |
rm -f "$GPG_KEY_PATH"

- name: Upload artifacts to workflow
uses: actions/upload-artifact@v4
with:
name: goreleaser-dist-temp
path: dist
retention-days: 1

publish-apt:
name: Publish APT
runs-on: macOS-latest
Expand Down Expand Up @@ -115,3 +131,42 @@ jobs:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_PRIVATE_KEY_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
run: ./scripts/publish-apt-packages.sh

publish-rpm:
name: Publish RPM
runs-on: ubuntu-latest
needs: [goreleaser]
env:
# Needed to publish new packages to our S3-hosted RPM repo
AWS_ACCESS_KEY_ID: ${{ secrets.OBJECT_STORAGE_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.OBJECT_STORAGE_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu01
AWS_ENDPOINT_URL: https://object.storage.eu01.onstackit.cloud
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Download artifacts from workflow
uses: actions/download-artifact@v5
with:
name: goreleaser-dist-temp
path: dist

- name: Install RPM tools
run: |
sudo apt-get update
sudo apt-get install -y createrepo-c

- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
id: import_gpg
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}

- name: Publish RPM packages
if: contains(github.ref_name, '-') == false
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_PRIVATE_KEY_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
run: ./scripts/publish-rpm-packages.sh
15 changes: 4 additions & 11 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,10 @@ nfpms:
- deb
- rpm

signs:
- artifacts: package
args:
[
"-u",
"{{ .Env.GPG_FINGERPRINT }}",
"--output",
"${signature}",
"--detach-sign",
"${artifact}",
]
rpm:
# The package is signed if a key_file is set
signature:
key_file: "{{ .Env.GPG_KEY_PATH }}"

homebrew_casks:
- name: stackit
Expand Down
50 changes: 44 additions & 6 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,54 @@ asset_filters=["stackit-cli_", "_linux_amd64.tar.gz"]
eget stackitcloud/stackit-cli
```

#### RPM package via dnf, yum and zypper
#### RHEL/Fedora/Rocky/Alma/openSUSE/... (`DNF/YUM/Zypper`)

The STACKIT CLI is available as [RPM Package](https://github.com/stackitcloud/stackit-cli/releases) and can be installed via dnf, yum and zypper package manager.
The STACKIT CLI can be installed through the [`DNF/YUM`](https://docs.fedoraproject.org/en-US/fedora/f40/system-administrators-guide/package-management/DNF/) / [`Zypper`](https://de.opensuse.org/Zypper) package managers.

Just download the rpm package from the [release page](https://github.com/stackitcloud/stackit-cli/releases) and run the install command like the following:
> Requires rpm version 4.15 or newer to support Ed25519 signatures.

> `$basearch` is supported by modern distributions. On older systems that don't expand `$basearch`, replace it in the `baseurl` with your architecture explicitly (for example, `.../rpm/cli/x86_64` or `.../rpm/cli/aarch64`).

##### Installation via DNF/YUM

1. Add the repository:

```shell
sudo tee /etc/yum.repos.d/stackit.repo > /dev/null << 'EOF'
[stackit]
name=STACKIT CLI
baseurl=https://packages.stackit.cloud/rpm/cli/$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.stackit.cloud/keys/key.gpg
EOF
```

2. Install the CLI:

```shell
sudo dnf install stackit
```

##### Installation via Zypper

1. Add the repository:

```shell
sudo tee /etc/zypp/repos.d/stackit.repo > /dev/null << 'EOF'
[stackit]
name=STACKIT CLI
baseurl=https://packages.stackit.cloud/rpm/cli/$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.stackit.cloud/keys/key.gpg
EOF
```

2. Install the CLI:

```shell
dnf install stackitcli.rpm
yum install stackitcli.rpm
zypper install stackitcli.rpm
sudo zypper install stackit
```

#### Any distribution
Expand Down
2 changes: 1 addition & 1 deletion scripts/publish-apt-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ aptly snapshot pull -no-remove -architectures="amd64,i386,arm64" current-snapsho

# Publish the new snapshot to the remote repo
printf "\n>>> Publishing updated snapshot \n"
aptly publish snapshot -keyring="${CUSTOM_KEYRING_FILE}" -gpg-key="${GPG_PRIVATE_KEY_FINGERPRINT}" -passphrase "${GPG_PASSPHRASE}" -config "${APTLY_CONFIG_FILE_PATH}" updated-snapshot "s3:${APT_BUCKET_NAME}:${APT_REPO_PATH}"
aptly publish snapshot -keyring="${CUSTOM_KEYRING_FILE}" -gpg-key="${GPG_PRIVATE_KEY_FINGERPRINT}" -passphrase "${GPG_PASSPHRASE}" -config "${APTLY_CONFIG_FILE_PATH}" updated-snapshot "s3:${APT_BUCKET_NAME}:${APT_REPO_PATH}"
112 changes: 112 additions & 0 deletions scripts/publish-rpm-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env bash

# This script is used to publish new RPM packages to the CLI RPM repository
# Usage: ./publish-rpm-packages.sh
set -eo pipefail

PACKAGES_BUCKET_URL="https://packages.stackit.cloud"
PUBLIC_KEY_FILE_PATH="keys/key.gpg"
RPM_REPO_PATH="rpm/cli"
RPM_BUCKET_NAME="distribution"
GORELEASER_PACKAGES_FOLDER="dist/"

# We need to disable the key database daemon (keyboxd)
# This can be done by removing "use-keyboxd" from ~/.gnupg/common.conf (see https://github.com/gpg/gnupg/blob/master/README)
echo -n >~/.gnupg/common.conf

# Create RPM repository directory structure
printf ">>> Creating RPM repository structure \n"
mkdir -p rpm-repo/x86_64
mkdir -p rpm-repo/i386
mkdir -p rpm-repo/aarch64

# Copy RPM packages to appropriate architecture directories
printf "\n>>> Copying RPM packages to architecture directories \n"

# Copy x86_64 packages (amd64)
for rpm_file in "${GORELEASER_PACKAGES_FOLDER}"*_amd64.rpm; do
if [ -f "$rpm_file" ]; then
cp "$rpm_file" rpm-repo/x86_64/
printf "Copied %s to x86_64/\n" "$(basename "$rpm_file")"
fi
done

# Copy i386 packages
for rpm_file in "${GORELEASER_PACKAGES_FOLDER}"*_386.rpm; do
if [ -f "$rpm_file" ]; then
cp "$rpm_file" rpm-repo/i386/
printf "Copied %s to i386/\n" "$(basename "$rpm_file")"
fi
done

# Copy aarch64 packages (arm64)
for rpm_file in "${GORELEASER_PACKAGES_FOLDER}"*_arm64.rpm; do
if [ -f "$rpm_file" ]; then
cp "$rpm_file" rpm-repo/aarch64/
printf "Copied %s to aarch64/\n" "$(basename "$rpm_file")"
fi
done

# Download existing repository content (RPMs and metadata) if it exists
printf "\n>>> Downloading existing repository content \n"
aws s3 sync s3://${RPM_BUCKET_NAME}/${RPM_REPO_PATH}/ rpm-repo/ --endpoint-url "${AWS_ENDPOINT_URL}" --exclude "*.asc" || echo "No existing repository found, creating new one"

# Create repository metadata for each architecture
printf "\n>>> Creating repository metadata \n"
for arch in x86_64 i386 aarch64; do
if [ -d "rpm-repo/${arch}" ] && [ -n "$(find "rpm-repo/${arch}" -mindepth 1 -maxdepth 1 -print -quit)" ]; then
printf "Creating metadata for %s...\n" "$arch"

# List what we're working with
file_list=$(find "rpm-repo/${arch}" -maxdepth 1 -type f -exec basename {} \; | tr '\n' ' ')
printf "Files in %s: %s\n" "$arch" "${file_list% }"

# Create repository metadata
createrepo_c --update rpm-repo/${arch}

# Sign the repository metadata
printf "Signing repository metadata for %s...\n" "$arch"
# Remove existing signature file if it exists
rm -f rpm-repo/${arch}/repodata/repomd.xml.asc
gpg --batch --pinentry-mode loopback --detach-sign --armor \
--local-user "${GPG_PRIVATE_KEY_FINGERPRINT}" \
--passphrase "${GPG_PASSPHRASE}" \
rpm-repo/${arch}/repodata/repomd.xml

# Verify the signature was created
if [ -f "rpm-repo/${arch}/repodata/repomd.xml.asc" ]; then
printf "Repository metadata signed successfully for %s\n" "$arch"
else
printf "WARNING: Repository metadata signature not created for %s\n" "$arch"
fi
else
printf "No packages found for %s, skipping...\n" "$arch"
fi
done

# Upload the updated repository to S3 in two phases (repodata pointers last)
# clients reading the repo won't see a state where repomd.xml points to files not uploaded yet.
printf "\n>>> Uploading repository to S3 (phase 1: all except repomd*) \n"
aws s3 sync rpm-repo/ s3://${RPM_BUCKET_NAME}/${RPM_REPO_PATH}/ \
--endpoint-url "${AWS_ENDPOINT_URL}" \
--delete \
--exclude "*/repodata/repomd.xml" \
--exclude "*/repodata/repomd.xml.asc"

printf "\n>>> Uploading repository to S3 (phase 2: repomd* only) \n"
aws s3 sync rpm-repo/ s3://${RPM_BUCKET_NAME}/${RPM_REPO_PATH}/ \
--endpoint-url "${AWS_ENDPOINT_URL}" \
--exclude "*" \
--include "*/repodata/repomd.xml" \
--include "*/repodata/repomd.xml.asc"

# Upload the public key
# Also uploaded in APT publish; intentionally redundant
# Safe to overwrite and ensures updates if APT fails or key changes.
printf "\n>>> Uploading public key \n"
gpg --armor --export "${GPG_PRIVATE_KEY_FINGERPRINT}" > public-key.asc
aws s3 cp public-key.asc s3://${RPM_BUCKET_NAME}/${PUBLIC_KEY_FILE_PATH} --endpoint-url "${AWS_ENDPOINT_URL}"

printf "\n>>> RPM repository published successfully! \n"
printf "Repository URL: %s/%s/ \n" "$PACKAGES_BUCKET_URL" "$RPM_REPO_PATH"
printf "Public key URL: %s/%s \n" "$PACKAGES_BUCKET_URL" "$PUBLIC_KEY_FILE_PATH"
Loading