diff --git a/.github/workflows/exclude.txt b/.github/workflows/exclude.txt new file mode 100644 index 0000000..c9cbc98 --- /dev/null +++ b/.github/workflows/exclude.txt @@ -0,0 +1,4 @@ +**/.github/** +**/.git/** +**/.vscode/** +**/.gitattributes \ No newline at end of file diff --git a/.github/workflows/sign.sh b/.github/workflows/sign.sh new file mode 100644 index 0000000..8bc81f6 --- /dev/null +++ b/.github/workflows/sign.sh @@ -0,0 +1,113 @@ +#!/bin/bash + +# This creates and signs a .tar.gz file with a valid private key on your keyring. +# +# Params: sign.sh /location/of/module +# +# If key_base64 is supplied, it will be decoded and used as the GPG key. + +if [ ! "$1" ] || [ ! "$2" ] || [ ! "$3" ]; then + echo "$0: /location/of/module " + exit 1 +fi + +parse_xml_value() { + local file="$1" + local element="$2" + xmlstarlet sel -t -v "/module/$element" "$file" +} + +getHashes() { + local dir="$1" + local exclude_patterns="$2" + + if [ ! -d "$dir" ]; then + echo "getHashes was given $dir which is not a directory!" + exit 1 + fi + + # Use find + grep -v to filter based on exclude patterns + while IFS= read -r -d '' file; do + if [[ ! $file =~ $exclude_patterns ]]; then + local hash + hash=$(sha256sum "$file" | awk '{print $1}') + printf "%s = %s\n" "${file#$dir/}" "$hash" + fi + done < <(find "$dir" -type f -print0) +} + +loc="$1" +key_base64="$2" +keyindex=2 +exclude_file="$3" +version=$(parse_xml_value "$loc/module.xml" "version") +rawname=$(parse_xml_value "$loc/module.xml" "rawname") +tarball_name="$rawname-$version.tar.gz" + +# Validate if version and rawname are extracted +if [ -z "$version" ] || [ -z "$rawname" ]; then + echo "Error: Could not extract version or rawname from module.xml" + exit 1 +fi + +# Load exclude patterns if provided +exclude_patterns="" +if [ -f "$exclude_file" ]; then + exclude_patterns=$(cat "$exclude_file" | xargs -0 | awk '{print "|" $0}') +fi + +if [ "${loc: -1}" == "/" ]; then + # Strip off any trailing slash + loc="${loc:0:-1}" +fi + +if [ ! -d "$loc" ]; then + echo "$loc is not a directory" + exit 1 +fi + +if [ ! -e "$loc/module.xml" ]; then + echo "module.xml does not exist in $loc" + exit 1 +fi + +# Decode the base64 encoded key +key=$(echo "$key_base64" | base64 -d) + +# Import the decoded key into GPG +echo "Importing GPG key..." +echo "$key" | gpg --import - + +sig="$loc/module.sig" + +echo "Signing with provided key" +echo -ne "\tGenerating file list..." +rm -f "$sig" +files=$(getHashes "$loc" "$exclude_patterns") +echo "" +echo -ne "\tSigning $sig.." +{ + echo ";################################################" + echo "# FreePBX Module Signature File #" + echo ";################################################" + echo "# Do not alter the contents of this file! If #" + echo "# this file is tampered with, the module will #" + echo "# fail validation and be marked as invalid! #" + echo ";################################################" + echo "" + echo "[config]" + echo "version=2" + echo "hash=sha256" + echo "signedwith=$key" + echo "signedby=sign.php" + echo "repo=manual" + echo "type=public" + echo "[hashes]" + echo "$files" + echo ";# End" +} > >(gpg --default-key "268C8DD0" --clearsign >"$sig") +echo "" +echo -ne "\tCreating tarball $tarball_name..." +tar -czf "$tarball_name" -X "$exclude_file" "$loc" +echo "" +echo "Done" diff --git a/.github/workflows/signrelease.yml b/.github/workflows/signrelease.yml index d69772c..1bc2cf8 100644 --- a/.github/workflows/signrelease.yml +++ b/.github/workflows/signrelease.yml @@ -22,19 +22,19 @@ jobs: - name: Extract version and rawname from module.xml id: extract_info run: | - version=$(awk -F'[><]' '//{print $3}' module.xml) - rawname=$(awk -F'[><]' '//{print $3}' module.xml) - echo "::set-output name=version::$version" - echo "::set-output name=rawname::$rawname" + version=$(awk -F'[><]' '//{print $3}' module.xml) + rawname=$(awk -F'[><]' '//{print $3}' module.xml) + echo "::set-output name=version::$version" + echo "::set-output name=rawname::$rawname" + # Assuming your module build/packaging places the file and signing script in the working directory - name: Sign module - run: | - gpg --batch --yes --armor --detach-sign /location/of/module/${{ steps.extract_info.outputs.rawname }}-${{ steps.extract_info.outputs.version }}.tar.gz # Using outputs for variables + run: ./sign.sh ${{ steps.extract_info.outputs.rawname }} "${{ secrets.GPG_SIGNING_KEY }}" exclude.txt - name: Push signed module to releases uses: softprops/action-gh-release@v1 with: - files: /location/of/module/${{ steps.extract_info.outputs.rawname }}-${{ steps.extract_info.outputs.version }}.tar.gz.asc - tag_name: v${{ steps.extract_info.outputs.version }} - title: Release ${{ steps.extract_info.outputs.version }} - token: ${{ secrets.GITHUB_TOKEN }} + files: ${{ steps.extract_info.outputs.rawname }}-${{ steps.extract_info.outputs.version }}.tar.gz + tag_name: v${{ steps.extract_info.outputs.version }} + title: Release ${{ steps.extract_info.outputs.version }} + token: ${{ secrets.GITHUB_TOKEN }}