Skip to content

ghidra-noprompt

ghidra-noprompt #44

---
name: ghidra-noprompt
# xerootg/ghidra republishes every upstream Ghidra stable release with the
# "would you like to analyze it now?" prompt patched out. This job notices a new
# release there, repackages it for Arch, and serves it as its own small pacman
# repository hosted in a GitHub Release.
#
# It deliberately does not go through build-pacman-repo / GitHub Pages: the
# package is ~500 MB and GitHub rejects any pushed file over 100 MB, which would
# break the Pages repo for every other package too.
on:
schedule:
- cron: "40 8 * * *"
workflow_dispatch:
inputs:
force:
description: "Rebuild and re-upload even if the PKGBUILD is already current"
type: boolean
default: false
permissions:
contents: write
concurrency:
group: "${{ github.workflow }}"
cancel-in-progress: false
env:
FORK: xerootg/ghidra
PKGDIR: release-pkgbuilds/ghidra-noprompt
REPO_NAME: ghidra
RELEASE_TAG: pacman-repo
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Fetch the newest fork release metadata
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="$(gh release view --repo "$FORK" --json tagName --jq .tagName)"
echo "Newest $FORK release: $tag"
# --dir rather than --output: gh rejects --output when the pattern
# could match more than one asset.
gh release download "$tag" --repo "$FORK" \
--pattern release-metadata.json --dir . --clobber
cat release-metadata.json
- name: Update PKGBUILD
id: bump
run: python3 .github/scripts/bump-ghidra-noprompt.py release-metadata.json "$PKGDIR"
- name: Decide whether to build
id: gate
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.bump.outputs.version }}
run: |
set -euo pipefail
# The published release is the state, not the committed PKGBUILD.
# main is protected by a ruleset, so this job cannot commit a version
# bump; deciding from the release keeps the job stateless and correct
# whether or not the PKGBUILD in git happens to be current.
build=false
if [ "${{ inputs.force }}" = "true" ]; then
build=true
echo "Forced rebuild requested."
else
assets="$(gh release view "$RELEASE_TAG" --json assets --jq '.assets[].name' 2>/dev/null || true)"
if ! grep -q "^ghidra-noprompt-${VERSION}-" <<<"$assets"; then
build=true
echo "No ghidra-noprompt-${VERSION}-* asset published yet."
else
echo "ghidra-noprompt ${VERSION} is already published."
fi
fi
echo "build=$build" >> "$GITHUB_OUTPUT"
- name: Build the package and its pacman database
if: steps.gate.outputs.build == 'true'
env:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
set -euo pipefail
docker run --rm \
-v "${{ github.workspace }}:/work" \
-e REPO_NAME="$REPO_NAME" \
-e GPG_SIGNING_KEY \
-e GPG_PASSPHRASE \
-w /work \
archlinux:base-devel \
bash .github/scripts/build-ghidra-noprompt.sh
- name: Publish to the pacman repo release
if: steps.gate.outputs.build == 'true'
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.bump.outputs.version }}
run: |
set -euo pipefail
ls -lh out/
# Notes live in .github/release-notes/ so the same text is used when the
# release is first created and whenever sign-backfill refreshes it.
# Inline heredocs could only ever run at creation time, which meant the
# published install instructions could never be corrected.
if ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release create "$RELEASE_TAG" \
--title "pacman repo" --notes-file .github/release-notes/ghidra.md
else
gh release edit "$RELEASE_TAG" --notes-file .github/release-notes/ghidra.md
fi
# Only files that exist: gh treats each argument as a pattern and fails
# the whole call on one that matches nothing, and the signing
# artifacts are absent until the signing secrets are configured.
# nullglob covers *.sig but not a literal path.
uploads=(
out/ghidra-noprompt-*.pkg.tar.zst
"out/${REPO_NAME}.db" "out/${REPO_NAME}.files"
"out/${REPO_NAME}.db.tar.gz" "out/${REPO_NAME}.files.tar.gz"
)
shopt -s nullglob
uploads+=( out/*.sig )
shopt -u nullglob
[ -f out/xerootg.asc ] && uploads+=( out/xerootg.asc )
# Signatures go up in the same call as what they sign, so there is no
# window where pacman fetches a package it cannot verify.
printf 'uploading: %s\n' "${uploads[@]}"
gh release upload "$RELEASE_TAG" "${uploads[@]}" --clobber
# Drop superseded package assets, but only after the new one is up.
# In the steady state both greps come up empty -- there is one package
# asset and it is the one just uploaded -- and an empty grep exits 1,
# which under pipefail would fail the step after a successful publish.
keep="$(basename out/ghidra-noprompt-*.pkg.tar.zst)"
gh release view "$RELEASE_TAG" --json assets --jq '.assets[].name' \
| { grep -E '^ghidra-noprompt-.*\.pkg\.tar\.zst(\.sig)?$' || true; } \
| { grep -vxF -e "$keep" -e "${keep}.sig" || true; } \
| while read -r old; do
echo "Removing superseded asset $old"
gh release delete-asset "$RELEASE_TAG" "$old" --yes
done
{
echo "### Published ghidra-noprompt ${VERSION}"
echo
echo '```'
echo "$keep"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Refresh the PKGBUILD in the repository
# Best effort, and deliberately not fatal. main is covered by a
# repository ruleset requiring a pull request, which github-actions[bot]
# cannot bypass. The package and its database are already published at
# this point, so a rejected push must not fail the run -- it only means
# the checked-in recipe still names the previous version.
if: steps.gate.outputs.build == 'true'
run: |
set -euo pipefail
rm -f release-metadata.json release-notes.md
rm -rf out .build
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add "$PKGDIR"
if git diff --cached --quiet; then
echo "PKGBUILD already matches the published release."
exit 0
fi
git commit -q -m "ghidra-noprompt: ${{ steps.bump.outputs.previous || 'rebuild' }} -> ${{ steps.bump.outputs.version }}"
if git push 2>&1; then
echo "Pushed the PKGBUILD refresh."
else
echo "::warning::Could not push the PKGBUILD refresh; main requires changes to go through a pull request. The published release is authoritative and is up to date."
{
echo
echo "> The PKGBUILD refresh could not be pushed: \`main\` requires a pull"
echo "> request. The release is published and correct regardless. To have this"
echo "> committed automatically, give the Actions bot a bypass on the ruleset."
} >> "$GITHUB_STEP_SUMMARY"
fi