Zum Inhalt springen

Managing secrets for CI/CD

I am currently building a CI/CD pipeline for a Flutter project. As you don’t want to share all your secret keys from Google, Apple and others to be shared with the world or other developers they are usually put in a variable. If it is a file it is usually base64 encoded and stored in GitHub or Codemagic.

For me this is inconvenient for two reasons:

  1. It is a little bit of a different approach for each service and does not work for my own machines. When I want to build the iOS version on a virtual Mac I need to collect half a dozen files and manually copy them.
  2. Updating all the individual pieces is quite tedious and error prone as you might have overlooked one of the files that you should have updated.

My solution to this is a super simple shell script that runs in all environments. By just calling

secrets.sh pack

it creates a secrets.zip and a secrets.b64 base64 encoded version of that zip file in the current directory. I then store the base64 content in an environment variable that gets dumped into secrets.zip and run

secrets.sh unpack

… and all the files land in the correct location.

This way creating a CI/CD is still painful but at least one task got a little easier.

#!/bin/bash

# --- Script: tools/secrets.sh ---
# Packs or unpacks secret files into a zip archive.

# --- Configuration ---
SECRETS_ZIP="secrets.zip"

# Define an array of secret files with their relative paths
SECRET_FILES=(
    "google-services.json:android/app/google-services.json"
    "GoogleService-Info.plist:ios/Runner/GoogleService-Info.plist"
    "firebase.json:firebase.json"
    "google-services-playstore.json:fastlane/google-services-playstore.json"
    "release-key.jks:android/app/release-key.jks"
    "key.properties:android/key.properties"
    # Add all your files here ...
)

# --- Functions ---

# Function to pack secret files into a zip archive
pack_secrets() {
    local files_to_pack=()
    for file_info in "${SECRET_FILES[@]}"; do
        local file=$(echo "$file_info" | cut -d ':' -f 1)
        local path=$(echo "$file_info" | cut -d ':' -f 2)
        if [ -f "$path" ]; then
            files_to_pack+=("$path")
        else
            echo "Warning: $path not found, skipping..."
        fi
    done

    if [ ${#files_to_pack[@]} -eq 0 ]; then
        echo "No secret files found to pack."
        exit 1
    fi

    zip -j "$SECRETS_ZIP" "${files_to_pack[@]}"
    echo "Secrets packed into $SECRETS_ZIP"

    base64 -w 0 secrets.zip > secrets.b64
    echo "Secrets base64 encoded into secrets.b64"

}

# Function to unpack secret files from a zip archive
unpack_secrets() {
    if [ ! -f "$SECRETS_ZIP" ]; then
        echo "Error: $SECRETS_ZIP not found"
        exit 1
    fi

    unzip -o "$SECRETS_ZIP"

    for file_info in "${SECRET_FILES[@]}"; do
        local file=$(echo "$file_info" | cut -d ':' -f 1)
        local path=$(echo "$file_info" | cut -d ':' -f 2)
        local dir=$(dirname "$path")

        # Create directory if it doesn't exist
        mkdir -p "$dir"

        # Move the file to its correct location
        if [ -f "$file" ]; then
            mv "$file" "$path"
            echo "Moved $file to $path"
        else
            echo "Warning: $file not found in zip, skipping..."
        fi
    done

    echo "Secrets unpacked from $SECRETS_ZIP"
}

# --- Main Script ---

if [ "$1" == "pack" ]; then
  pack_secrets
elif [ "$1" == "unpack" ]; then
  unpack_secrets
else
  echo "Usage: $0 [pack|unpack]"
  exit 1
fi
Published inSoftware

Sei der Erste der einen Kommentar abgibt

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert