ghidra-noprompt #44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| 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 |