name: Release Build and Upload on: push: tags: - "v*.*.*" jobs: build-and-release: runs-on: ubuntu-latest permissions: contents: write packages: write steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 1 - name: Set up QEMU uses: docker/setup-qemu-action@v3 with: platforms: linux/amd64,linux/arm64 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract version from tag id: get_version run: | echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT echo "HASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Build frontend files working-directory: frontend run: | sudo docker run --rm \ -v "$(pwd)":/app \ -w /app \ node:alpine \ sh -c "npm ci && npm run build-production" - name: Move frontend build to backend run: | rm -rf backend/frontend/build mkdir -p backend/frontend/build cp -r frontend/build/* backend/frontend/build/ - name: Build binaries for multiple architectures run: | mkdir -p build/amd64 build/arm64 # build amd64 binary sudo docker run --rm \ -v "$(pwd)":/app \ -w /app/backend \ -e CGO_ENABLED=1 \ -e GOOS=linux \ -e GOARCH=amd64 \ golang:1.25.1 \ go build -trimpath \ -ldflags='-X github.com/phishingclub/phishingclub/version.hash=ph${{ steps.get_version.outputs.HASH }} -X github.com/phishingclub/phishingclub/version.version=${{ steps.get_version.outputs.VERSION }}' \ -tags production -o ../build/amd64/phishingclub main.go # build arm64 binary sudo docker run --rm \ -v "$(pwd)":/app \ -w /app/backend \ -e CGO_ENABLED=1 \ -e GOOS=linux \ -e GOARCH=arm64 \ -e CC=aarch64-linux-gnu-gcc \ golang:1.25.1 \ bash -c "apt-get update && apt-get install -y gcc-aarch64-linux-gnu && go build -trimpath -ldflags='-X github.com/phishingclub/phishingclub/version.hash=ph${{ steps.get_version.outputs.HASH }} -X github.com/phishingclub/phishingclub/version.version=${{ steps.get_version.outputs.VERSION }}' -tags production -o ../build/arm64/phishingclub main.go" - name: Fix build directory permissions run: | sudo chown -R $USER:$USER build/ chmod 755 build/ ls -la build/ - name: Sign binaries with Ed25519 run: | # create directory for keys mkdir -p /tmp/keys chmod 700 /tmp/keys # save both private keys from github secrets echo "${{ secrets.SIGNKEY_1 }}" > /tmp/keys/private1.pem echo "${{ secrets.SIGNKEY_2 }}" > /tmp/keys/private2.pem chmod 600 /tmp/keys/private1.pem chmod 600 /tmp/keys/private2.pem # sign amd64 binary with primary key (key 1) openssl pkeyutl -sign -inkey /tmp/keys/private1.pem \ -rawin -in build/amd64/phishingclub \ -out build/amd64/phishingclub.sig # sign arm64 binary with primary key (key 1) openssl pkeyutl -sign -inkey /tmp/keys/private1.pem \ -rawin -in build/arm64/phishingclub \ -out build/arm64/phishingclub.sig # clean up keys rm -rf /tmp/keys - name: Create compressed packages with signatures run: | mkdir -p packages # package amd64 binary with signature tar -czf packages/phishingclub_${{ steps.get_version.outputs.VERSION }}_linux_amd64.tar.gz \ -C build/amd64 \ phishingclub \ phishingclub.sig # package arm64 binary with signature tar -czf packages/phishingclub_${{ steps.get_version.outputs.VERSION }}_linux_arm64.tar.gz \ -C build/arm64 \ phishingclub \ phishingclub.sig # create legacy-named package (amd64) for backward compatibility with pre-arm versions tar -czf packages/phishingclub_${{ steps.get_version.outputs.VERSION }}.tar.gz \ -C build/amd64 \ phishingclub \ phishingclub.sig - name: Build and push multi-arch Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.release push: true platforms: linux/amd64,linux/arm64 tags: | ghcr.io/${{ github.repository }}:latest ghcr.io/${{ github.repository }}:${{ steps.get_version.outputs.VERSION }} labels: | org.opencontainers.image.title=PhishingClub ${{ steps.get_version.outputs.VERSION }} org.opencontainers.image.description=PhishingClub production release image (linux/amd64, linux/arm64). Built from tag ${{ steps.get_version.outputs.TAG }}. org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} org.opencontainers.image.version=${{ steps.get_version.outputs.VERSION }} org.opencontainers.image.created=${{ github.event.head_commit.timestamp }} org.opencontainers.image.revision=${{ github.sha }} - name: Extract release notes from RELEASE.md id: get_release_notes run: | # extract the section for the current version from RELEASE.md VERSION="${{ steps.get_version.outputs.VERSION }}" # find the line containing the current version START_LINE=$(grep -n "## \[$VERSION\]" RELEASE.md | cut -d: -f1) if [ -z "$START_LINE" ]; then echo "Could not find version $VERSION in RELEASE.md" echo "NOTES=PhishingClub release ${{ steps.get_version.outputs.TAG }}" >> $GITHUB_OUTPUT exit 0 fi # find the next version section (next line starting with ##) NEXT_LINE=$(tail -n +$((START_LINE + 1)) RELEASE.md | grep -n "^## " | head -1 | cut -d: -f1) if [ -z "$NEXT_LINE" ]; then # no next section, take from start line to end of file RELEASE_NOTES=$(tail -n +$START_LINE RELEASE.md) else # calculate end line END_LINE=$((START_LINE + NEXT_LINE - 1)) RELEASE_NOTES=$(sed -n "${START_LINE},${END_LINE}p" RELEASE.md) fi # save to github output (escape newlines) echo "NOTES<> $GITHUB_OUTPUT echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Create GitHub Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release create ${{ steps.get_version.outputs.TAG }} \ ./packages/phishingclub_${{ steps.get_version.outputs.VERSION }}_linux_amd64.tar.gz \ ./packages/phishingclub_${{ steps.get_version.outputs.VERSION }}_linux_arm64.tar.gz \ ./packages/phishingclub_${{ steps.get_version.outputs.VERSION }}.tar.gz \ --title "PhishingClub ${{ steps.get_version.outputs.TAG }}" \ --notes "${{ steps.get_release_notes.outputs.NOTES }}" - name: Notify about release run: | curl -d "phishingclub version ${{ steps.get_version.outputs.VERSION }} has been released on GitHub" https://ntfy.sh/phishing_club_released