You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Ensure a smoother GPG key update process for September 2026 expiration #9572
In #9569, we detail the expiration of the GPG key used to sign our .deb and .rpm package repository contents. With the late notice, we were limited in the options available to us, choosing to extend the expiration date of the existing key. Unfortunately, all our users need to obtain this new key through some mechanism, and this is likely to be an inconvenient process for many.
In #6856 there was a suggested approach to avoiding this issue in the future by packaging the key inside the .deb, so that as users updated their version of the CLI, with enough advanced notice, they would hopefully already have the new key long before their expiration. Another approach discussed internally is to package the key separately and to make that a dependency of gh. Thus, as users ran apt update, with enough advanced notice, they would hopefully already have the new key long before their expiration.
The approaches above were primarily focused on our .deb repository. We should ensure that any solution is also relevant for our .rpm repository.
We should decide an approach to follow up on fairly quickly, such that this doesn't get lost through team changes or in the myriad other work.
If anyone in the community has experience with managing GPG keys for self-hosted repositories, we'd love to hear from you on this issue.
Expected Output
The expected output of this issue is:
A document in this repository outlining the options and recommending one
A comment closing out this issue pointing to that document
A new issue in this repository capturing the recommended work
If anyone in the community has experience with managing GPG keys for self-hosted repositories, we'd love to hear from you on this issue.
You're very welcome to get in touch with @scalefactory - this is something we can help you manage, albeit it's usually not gratis help if you're a commercial operation.
Just capturing a script I cobbled together between ChatGPT and this Earthly Blog Post (thanks @alexcb). It's a starting point to create an apt repository that serves a golang binary. Later I will enhance it to handle signing to act as a baseline for exploring this piece of work.
#!/bin/bash# Enable strict modeset -e
# Check if DEBUG is set to true or 1, enable debug print statements if soif [[ "$DEBUG"=="true"||"$DEBUG"=="1" ]];thenset -x
fi# Default artifacts directory
DEFAULT_ARTIFACTS_DIR="$(pwd)/deb-repo-test"# Function to prompt user to continue to the next step with explanationsprompt_continue() {
echoread -p "$1 Press Enter to continue..."
}
# Function to prompt for the artifacts directory and ensure it existsprompt_for_artifacts_dir() {
read -p "Please provide a directory location for storing all artifacts (leave empty for default: $DEFAULT_ARTIFACTS_DIR): "# Use default if the user provides no inputif [ -z"$ARTIFACTS_DIR" ];then
ARTIFACTS_DIR="$DEFAULT_ARTIFACTS_DIR"echo"No directory provided. Using default: $ARTIFACTS_DIR"fi
}
# Function to handle the setup processsetup() {
# Step 1: Install prerequisites (including Go)echo"Step 1: Installing prerequisites (Go, dpkg-dev, gpg, tree)"
sudo apt-get install -y golang-go dpkg-dev gpg tree
prompt_continue "Next, we will ask you to provide a directory location to store all artifacts."# Prompt for the artifacts directory
prompt_for_artifacts_dir
# Check if directory exists, if not, create itif [ !-d"$ARTIFACTS_DIR" ];thenecho"Directory does not exist. Creating $ARTIFACTS_DIR..."
mkdir -p "$ARTIFACTS_DIR"echo"Directory $ARTIFACTS_DIR created."elseecho"Directory $ARTIFACTS_DIR already exists."fi
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will create a simple Go program within the specified directory."# Step 2: Create Go Programecho"Step 2: Creating a simple Go program"
mkdir -p "$ARTIFACTS_DIR/hello-world-program"
cat <<EOF > "$ARTIFACTS_DIR/hello-world-program/main.go"package mainimport "fmt"func main() { fmt.Println("hello statically compiled world")}EOF# Step 3: Compile the Go program staticallyecho"Step 3: Compiling the Go program statically"cd"$ARTIFACTS_DIR/hello-world-program"
CGO_ENABLED=0 go build -o hello-world -ldflags="-extldflags=-static" main.go
echo"Go program compiled as a static binary."
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will create the directory structure for the deb package."# Step 4: Create directory structure for deb packageecho"Step 4: Creating directory structure for the deb package"
mkdir -p "$ARTIFACTS_DIR/hello-world_0.0.1-1_arm64"cd"$ARTIFACTS_DIR/hello-world_0.0.1-1_arm64"
mkdir -p usr/bin
cp "$ARTIFACTS_DIR/hello-world-program/hello-world" usr/bin/
echo"Binary copied to usr/bin/hello-world."
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will create the necessary control file for the deb package."# Step 5: Create DEBIAN control fileecho"Step 5: Creating DEBIAN control file"
mkdir -p DEBIAN
echo"Package: hello-worldVersion: 0.0.1Maintainer: example <[email protected]>Architecture: arm64Homepage: http://example.comDescription: A statically compiled Go program that prints hello"> DEBIAN/control
echo"Control file created at $ARTIFACTS_DIR/hello-world_0.0.1-1_arm64/DEBIAN/control."
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will build the .deb package from the files we have set up."# Step 6: Build the deb packageecho"Step 6: Building the .deb package"cd"$ARTIFACTS_DIR"
dpkg --build hello-world_0.0.1-1_arm64
echo"Deb package created: hello-world_0.0.1-1_arm64.deb"
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will inspect the .deb package to verify its contents."# Step 7: Inspect the deb packageecho"Step 7: Inspecting the .deb package"
dpkg-deb --info hello-world_0.0.1-1_arm64.deb
dpkg-deb --contents hello-world_0.0.1-1_arm64.deb
prompt_continue "Next, we will set up a directory structure for hosting this package in an apt repository."# Step 8: Create apt repository directory structureecho"Step 8: Creating apt repository directory structure"
mkdir -p "$ARTIFACTS_DIR/apt-repo/pool/main/"
cp "$ARTIFACTS_DIR/hello-world_0.0.1-1_arm64.deb""$ARTIFACTS_DIR/apt-repo/pool/main/"
mkdir -p "$ARTIFACTS_DIR/apt-repo/dists/stable/main/binary-arm64"
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will generate the 'Packages' file, which lists the available deb packages in the repository."# Step 9: Generate Packages fileecho"Step 9: Generating Packages file"cd"$ARTIFACTS_DIR/apt-repo"
dpkg-scanpackages --arch arm64 pool/ > dists/stable/main/binary-arm64/Packages
cat dists/stable/main/binary-arm64/Packages | gzip -9 > dists/stable/main/binary-arm64/Packages.gz
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will create a Release file, which is required by apt repositories."# Step 10: Create Release file with a bash script (with debugging logs to stderr)echo"Step 10: Generating Release file using bash script with detailed debugging"
cat <<EOF > "$ARTIFACTS_DIR/generate-release.sh"#!/bin/bashset -e# Enable debug output if DEBUG is set to true or 1DEBUG="\${DEBUG:-false}"# Debug function to print messages to stderr if DEBUG is enableddebug_log() { if [[ "\$DEBUG" == "true" || "\$DEBUG" == "1" ]]; then echo "[DEBUG] \$1" >&2 fi}# Function to handle hashing with more detailed debuggingdo_hash() { HASH_NAME=\$1 HASH_CMD=\$2 echo "\${HASH_NAME}:" # Find all files and remove the './' prefix for f in \$(find . -type f); do f=\$(echo "\$f" | cut -c3-) # Skip the Release file itself if [ "\$f" = "Release" ]; then debug_log "Skipping the Release file: \$f" continue fi # Check file permissions and existence before hashing if [ -r "\$f" ]; then debug_log "Processing file: \$f" debug_log "File permissions: \$(ls -l "\$f")" echo " \$(\${HASH_CMD} "\$f" | cut -d' ' -f1) \$(wc -c < "\$f") \$f" else debug_log "[ERROR] Permission denied or file not readable: \$f" echo "[ERROR] Permission denied or file not readable: \$f" >&2 exit 1 fi done}# Start loggingdebug_log "Generating Release file with detailed debugging..."# Output Release file metadatacat <<EOF2Origin: Example RepositoryLabel: ExampleSuite: stableCodename: stableVersion: 1.0Architectures: arm64Components: mainDescription: An example software repositoryDate: \$(date -Ru)EOF2# Perform MD5, SHA1, and SHA256 hashes with debuggingdo_hash "MD5Sum" "md5sum"do_hash "SHA1" "sha1sum"do_hash "SHA256" "sha256sum"debug_log "Release file generation complete."EOF
chmod +x "$ARTIFACTS_DIR/generate-release.sh"cd"$ARTIFACTS_DIR/apt-repo/dists/stable""$ARTIFACTS_DIR/generate-release.sh"> Release
echo"Release file generated."
tree "$ARTIFACTS_DIR"
prompt_continue "Next, we will host the repository using Python's HTTP server for testing."# Step 11: Serve the repository using a local HTTP serverecho"Step 11: Hosting repository with Python HTTP server"cd"$ARTIFACTS_DIR"
python3 -m http.server 8000 > /dev/null 2>&1&echo"HTTP server started at http://127.0.0.1:8000"
prompt_continue "Next, we will add the local repository to the system's sources list and update apt."# Step 12: Add the repository to the system's sourcesecho"Step 12: Adding repository to /etc/apt/sources.list.d"echo"deb [arch=arm64] http://127.0.0.1:8000/apt-repo stable main"| sudo tee /etc/apt/sources.list.d/example.list
prompt_continue "Next, we will update apt and install the 'hello-world' package from the repository."# Step 13: Update and install the packageecho"Step 13: Updating apt and installing the package"
sudo apt-get update --allow-insecure-repositories
sudo apt-get install hello-world
echo"Hello World package installed successfully."
}
# Function to handle the teardown processteardown() {
# Prompt for the artifacts directory during teardown
prompt_for_artifacts_dir
echo"Teardown: Cleaning up everything."# Kill the Python HTTP server if it's runningif pgrep -f "python3 -m http.server"> /dev/null;thenecho"Stopping the Python HTTP server..."
pkill -f "python3 -m http.server"echo"Server stopped."fi# Check if the hello-world package is installed, and remove it safelyif dpkg -l | grep -q "^ii hello-world";thenecho"Removing the hello-world package..."
sudo apt-get remove --purge -y hello-world
echo"Package hello-world removed."elseecho"Package hello-world is not installed, skipping removal."fi# Remove the repository from sources.list.dif [ -f /etc/apt/sources.list.d/example.list ];thenecho"Removing the repository from /etc/apt/sources.list.d..."
sudo rm /etc/apt/sources.list.d/example.list
echo"Repository removed."fi# Remove the artifacts directoryif [ -d"$ARTIFACTS_DIR" ];thenecho"No directory provided. Using default: $ARTIFACTS_DIR"echo"Removing the artifacts directory: $ARTIFACTS_DIR"
rm -rf "$ARTIFACTS_DIR"echo"Artifacts directory removed."fi# Clean apt cacheecho"Cleaning apt cache..."
sudo apt-get clean
echo"Cleanup complete."
}
# Check for the setup or teardown argumentif [ "$1"=="setup" ];then
setup
elif [ "$1"=="teardown" ];then
teardown
elseecho"Usage: $0 {setup|teardown}"exit 1
fi
Thank you for your issue! We have categorized it as an enhancement (feature or improvement) request, and it has been added to our backlog. In doing so, we are not committing to implementing this feature at this time, but, we will consider it for future releases based on community feedback and our own product roadmap.
Unless you see the
help wantedContributions welcome
label, we are not currently looking for external contributions for this feature.
If you come across this issue and would like to see it implemented, please add a thumbs up! This will help us prioritize the feature. Please only comment if you have additional information or viewpoints to contribute.
Activity
sftim commentedon Sep 7, 2024
You're very welcome to get in touch with @scalefactory - this is something we can help you manage, albeit it's usually not gratis help if you're a commercial operation.
williammartin commentedon Sep 16, 2024
Just capturing a script I cobbled together between ChatGPT and this Earthly Blog Post (thanks @alexcb). It's a starting point to create an apt repository that serves a golang binary. Later I will enhance it to handle signing to act as a baseline for exploring this piece of work.
https://gist.github.com/williammartin/8ed21a08254eb764129e8437a89b815a
Details
T4hob commentedon Sep 27, 2024
j3262049232 commentedon Nov 3, 2024
Add initial prototype for iterating
kharakhararonakronakkhara-ai commentedon Aug 9, 2025
cli#9572
github-actions commentedon Feb 17, 2026
Thank you for your issue! We have categorized it as an enhancement (feature or improvement) request, and it has been added to our backlog. In doing so, we are not committing to implementing this feature at this time, but, we will consider it for future releases based on community feedback and our own product roadmap.
Unless you see the help wantedContributions welcome
label, we are not currently looking for external contributions for this feature.
If you come across this issue and would like to see it implemented, please add a thumbs up! This will help us prioritize the feature. Please only comment if you have additional information or viewpoints to contribute.