name: Build All Platforms on: push: branches: [master, cpp20-modernization] tags: ['v*'] pull_request: branches: [master] workflow_dispatch: jobs: test-linux-unit: runs-on: ubuntu-22.04 continue-on-error: true steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential cmake ninja-build \ libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \ librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev - name: Configure run: | cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_QT=OFF \ -DBUILD_DAEMON=ON \ -DBUILD_TESTS=ON \ -DUSE_UPNP=OFF - name: Build run: cmake --build build -j$(nproc) - name: Run unit tests run: cd build && ctest --output-on-failure || true test-linux-sanitizers: # ASan + UBSan build of the daemon + unit tests. Allowed to fail until # findings are triaged — see .github/workflows/lint.yml comment block. # Once the test suite is clean under sanitizers, drop continue-on-error. runs-on: ubuntu-22.04 continue-on-error: true env: # ASan: leak detection off by default (BDB and OpenSSL produce noise on shutdown). # Re-enable once we've quieted the legitimate suspects. ASAN_OPTIONS: "detect_leaks=0:halt_on_error=1:abort_on_error=1:print_stacktrace=1:strict_string_checks=1:detect_stack_use_after_return=1" # UBSan: print full stack traces on first error and exit non-zero. UBSAN_OPTIONS: "halt_on_error=1:abort_on_error=1:print_stacktrace=1" # Suppress UB categories that are pervasive in the Hash9 C cascade # and BDB until they're fixed file-by-file. SAN_FLAGS: "-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=undefined -fno-sanitize=alignment,signed-integer-overflow,vptr" steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential cmake ninja-build \ libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \ librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev - name: Configure with sanitizers run: | cmake -B build-san -G Ninja \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_C_FLAGS="$SAN_FLAGS" \ -DCMAKE_CXX_FLAGS="$SAN_FLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$SAN_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="$SAN_FLAGS" \ -DBUILD_QT=OFF \ -DBUILD_DAEMON=ON \ -DBUILD_TESTS=ON \ -DUSE_UPNP=OFF - name: Build run: cmake --build build-san -j$(nproc) - name: Run unit tests under sanitizers run: cd build-san && ctest --output-on-failure build-windows-qt: runs-on: windows-latest defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 with: submodules: recursive - uses: msys2/setup-msys2@v2 with: msystem: MINGW64 update: true install: >- mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-qt5-base mingw-w64-x86_64-qt5-tools mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-db mingw-w64-x86_64-libevent mingw-w64-x86_64-miniupnpc mingw-w64-x86_64-zlib mingw-w64-x86_64-rocksdb - name: Set VERSION run: | if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV else MAJOR=$(grep 'CLIENT_VERSION_MAJOR' src/clientversion.h | awk '{print $3}') MINOR=$(grep 'CLIENT_VERSION_MINOR' src/clientversion.h | awk '{print $3}') REV=$(grep 'CLIENT_VERSION_REVISION' src/clientversion.h | awk '{print $3}') echo "VERSION=${MAJOR}.${MINOR}.${REV}" >> $GITHUB_ENV fi - name: Configure run: | cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_QT=ON \ -DBUILD_DAEMON=OFF \ -DBUILD_TESTS=OFF \ -DUSE_UPNP=ON \ -DUSE_QRCODE=OFF - name: Build run: cmake --build build -j$(nproc) - name: Package run: | mkdir -p dist cp build/bin/triangles-qt.exe dist/ windeployqt dist/triangles-qt.exe || true # Copy ALL runtime DLLs the binary needs # MinGW runtime for dll in libgcc_s_seh-1.dll libstdc++-6.dll libwinpthread-1.dll; do cp /mingw64/bin/$dll dist/ 2>/dev/null || true done # Boost for dll in /mingw64/bin/libboost_system*.dll /mingw64/bin/libboost_filesystem*.dll \ /mingw64/bin/libboost_thread*.dll /mingw64/bin/libboost_program_options*.dll \ /mingw64/bin/libboost_chrono*.dll; do cp $dll dist/ 2>/dev/null || true done # OpenSSL for dll in /mingw64/bin/libssl*.dll /mingw64/bin/libcrypto*.dll; do cp $dll dist/ 2>/dev/null || true done # BerkeleyDB, libevent, miniupnpc, zlib for dll in /mingw64/bin/libdb*.dll /mingw64/bin/libevent*.dll \ /mingw64/bin/libminiupnpc*.dll /mingw64/bin/zlib1.dll; do cp $dll dist/ 2>/dev/null || true done # Catch anything we missed: scan ldd output for /mingw64 deps ldd dist/triangles-qt.exe | grep '/mingw64' | awk '{print $3}' | while read dll; do cp "$dll" dist/ 2>/dev/null || true done # Write qt.conf so the exe finds plugins relative to itself printf '[Paths]\nPlugins = .\n' > dist/qt.conf # Ensure Qt platform plugins are present (windeployqt sometimes misses them in MSYS2) if [ ! -f dist/platforms/qwindows.dll ]; then echo "WARNING: windeployqt did not copy platform plugins, copying manually..." mkdir -p dist/platforms cp /mingw64/share/qt5/plugins/platforms/qwindows.dll dist/platforms/ 2>/dev/null || \ cp /mingw64/lib/qt5/plugins/platforms/qwindows.dll dist/platforms/ 2>/dev/null || \ find /mingw64 -name 'qwindows.dll' -exec cp {} dist/platforms/ \; 2>/dev/null fi # Also copy styles and imageformats for good measure for plugdir in styles imageformats; do if [ ! -d "dist/$plugdir" ]; then srcdir=$(find /mingw64 -type d -name "$plugdir" -path "*/plugins/*" 2>/dev/null | head -1) if [ -n "$srcdir" ]; then cp -r "$srcdir" dist/ fi fi done strip --strip-all dist/triangles-qt.exe echo "=== dist/ contents ===" find dist/ -type f | head -50 - name: Download Tor shell: powershell run: | $TOR_VERSION = "15.0.9" $TOR_URL = "https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_VERSION}/tor-expert-bundle-windows-x86_64-${TOR_VERSION}.tar.gz" Invoke-WebRequest -Uri $TOR_URL -OutFile tor-bundle.tar.gz New-Item -ItemType Directory -Path tor-extract -Force tar -xzf tor-bundle.tar.gz -C tor-extract New-Item -ItemType Directory -Path tor-files -Force Copy-Item -Recurse tor-extract/tor/* tor-files/ if (Test-Path tor-extract/tor/pluggable_transports) { Copy-Item -Recurse tor-extract/tor/pluggable_transports tor-files/pluggable_transports -Force } if (Test-Path tor-extract/data) { Copy-Item -Recurse tor-extract/data tor-files/data } Write-Host "Bundled Tor runtime files:" Get-ChildItem -Recurse tor-files | Select-Object FullName - name: Install NSIS via MSYS2 run: pacman -S --noconfirm mingw-w64-x86_64-nsis - name: Install NSIS inetc plugin run: | pacman -S --noconfirm unzip NSIS_DIR="/mingw64/share/nsis" cd /tmp curl -L -o Inetc.zip "https://nsis.sourceforge.io/mediawiki/images/c/c9/Inetc.zip" unzip -o Inetc.zip -d inetc_extract # MSYS2 mingw64 NSIS is 64-bit, needs amd64-unicode plugin in Plugins/unicode/ mkdir -p "$NSIS_DIR/Plugins/unicode" cp inetc_extract/Plugins/amd64-unicode/INetC.dll "$NSIS_DIR/Plugins/unicode/" echo "Installed 64-bit INetC.dll to $NSIS_DIR/Plugins/unicode/" - name: Build NSIS installer run: makensis //DVERSION=$VERSION contrib/nsis/setup.nsi - name: Upload installer uses: actions/upload-artifact@v4 with: name: windows-qt-setup path: contrib/nsis/Cryptographic-Triangles-*-setup.exe build-windows-daemon: runs-on: windows-latest defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 with: submodules: recursive - uses: msys2/setup-msys2@v2 with: msystem: MINGW64 update: true install: >- mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-db mingw-w64-x86_64-libevent mingw-w64-x86_64-miniupnpc mingw-w64-x86_64-zlib mingw-w64-x86_64-rocksdb - name: Configure run: | cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_QT=OFF \ -DBUILD_DAEMON=ON \ -DBUILD_TESTS=OFF \ -DUSE_UPNP=ON - name: Build run: | cmake --build build -j$(nproc) strip --strip-all build/bin/trianglesd.exe - name: Package daemon with DLLs run: | mkdir -p daemon-dist/tor cp build/bin/trianglesd.exe daemon-dist/ # Copy all linked DLLs from MSYS2 ldd build/bin/trianglesd.exe | grep '/mingw64' | awk '{print $3}' | while read dll; do cp "$dll" daemon-dist/ 2>/dev/null || true done - name: Bundle Tor for daemon shell: powershell run: | $TOR_VERSION = "15.0.9" Invoke-WebRequest -Uri "https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_VERSION}/tor-expert-bundle-windows-x86_64-${TOR_VERSION}.tar.gz" -OutFile tor-bundle.tar.gz New-Item -ItemType Directory -Path tor-extract -Force tar -xzf tor-bundle.tar.gz -C tor-extract Copy-Item -Recurse tor-extract/tor/* daemon-dist/tor/ if (Test-Path tor-extract/data) { Copy-Item -Recurse tor-extract/data daemon-dist/tor/data } - name: Upload artifact uses: actions/upload-artifact@v4 with: name: windows-daemon path: daemon-dist/ build-linux-qt: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set VERSION run: | if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV else MAJOR=$(grep 'CLIENT_VERSION_MAJOR' src/clientversion.h | awk '{print $3}') MINOR=$(grep 'CLIENT_VERSION_MINOR' src/clientversion.h | awk '{print $3}') REV=$(grep 'CLIENT_VERSION_REVISION' src/clientversion.h | awk '{print $3}') echo "VERSION=${MAJOR}.${MINOR}.${REV}" >> $GITHUB_ENV fi - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential cmake ninja-build \ qtbase5-dev qttools5-dev-tools \ libboost-all-dev libssl-dev libdb++-dev \ libleveldb-dev librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev - name: Configure run: | cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_QT=ON \ -DBUILD_DAEMON=OFF \ -DBUILD_TESTS=OFF \ -DUSE_UPNP=ON - name: Build run: cmake --build build -j$(nproc) - name: Strip binary run: strip --strip-all build/bin/triangles-qt - name: Build .deb package (fully self-contained) run: | TOR_VERSION="15.0.9" curl -sL "https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_VERSION}/tor-expert-bundle-linux-x86_64-${TOR_VERSION}.tar.gz" -o tor-bundle.tar.gz mkdir -p tor-extract && tar -xzf tor-bundle.tar.gz -C tor-extract PKG="cryptographic-triangles_${VERSION}_amd64" mkdir -p ${PKG}/DEBIAN mkdir -p ${PKG}/usr/lib/cryptographic-triangles/lib mkdir -p ${PKG}/usr/lib/cryptographic-triangles/tor mkdir -p ${PKG}/usr/bin mkdir -p ${PKG}/usr/share/applications mkdir -p ${PKG}/usr/share/pixmaps cp build/bin/triangles-qt ${PKG}/usr/lib/cryptographic-triangles/ cp tor-extract/tor/tor ${PKG}/usr/lib/cryptographic-triangles/tor/ chmod +x ${PKG}/usr/lib/cryptographic-triangles/tor/tor [ -d tor-extract/data ] && cp -r tor-extract/data ${PKG}/usr/lib/cryptographic-triangles/tor/data # Bundle ALL shared library dependencies (except glibc/kernel) ldd build/bin/triangles-qt | grep '=> /' | awk '{print $3}' | while read lib; do case "$lib" in /lib/x86_64-linux-gnu/libc.so*|/lib/x86_64-linux-gnu/libm.so*|/lib/x86_64-linux-gnu/libpthread.so*|/lib/x86_64-linux-gnu/libdl.so*|/lib/x86_64-linux-gnu/librt.so*|/lib/x86_64-linux-gnu/ld-linux*|/lib64/ld-linux*) ;; # Skip glibc core — always present *) cp -L "$lib" ${PKG}/usr/lib/cryptographic-triangles/lib/ 2>/dev/null || true ;; esac done echo "=== Bundled libs ===" ls ${PKG}/usr/lib/cryptographic-triangles/lib/ | wc -l ls ${PKG}/usr/lib/cryptographic-triangles/lib/ # Launcher with LD_LIBRARY_PATH cat > ${PKG}/usr/bin/cryptographic-triangles << 'LAUNCHER' #!/bin/bash INSTALL_DIR=/usr/lib/cryptographic-triangles export LD_LIBRARY_PATH="${INSTALL_DIR}/lib:${LD_LIBRARY_PATH}" exec "${INSTALL_DIR}/triangles-qt" "$@" LAUNCHER sed -i 's/^ //' ${PKG}/usr/bin/cryptographic-triangles chmod +x ${PKG}/usr/bin/cryptographic-triangles cat > ${PKG}/usr/share/applications/cryptographic-triangles.desktop << 'DESKTOP' [Desktop Entry] Name=Cryptographic Triangles Comment=Triangles Cryptocurrency Wallet Exec=cryptographic-triangles Terminal=false Type=Application Icon=cryptographic-triangles Categories=Finance;Network; DESKTOP sed -i 's/^ //' ${PKG}/usr/share/applications/cryptographic-triangles.desktop cp src/qt/res/icons/triangles.ico ${PKG}/usr/share/pixmaps/cryptographic-triangles.ico 2>/dev/null || true cat > ${PKG}/DEBIAN/control << CTRL Package: cryptographic-triangles Version: ${VERSION} Architecture: amd64 Maintainer: Cryptographic Triangles Description: Cryptographic Triangles wallet with integrated Tor Fully self-contained wallet with all libraries and Tor bundled. No external dependencies required — runs on any x86_64 Linux. Section: finance Priority: optional CTRL sed -i 's/^ //' ${PKG}/DEBIAN/control dpkg-deb --build ${PKG} - name: Upload .deb uses: actions/upload-artifact@v4 with: name: linux-qt-deb path: cryptographic-triangles_*_amd64.deb build-linux-daemon: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set VERSION run: | if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV else MAJOR=$(grep 'CLIENT_VERSION_MAJOR' src/clientversion.h | awk '{print $3}') MINOR=$(grep 'CLIENT_VERSION_MINOR' src/clientversion.h | awk '{print $3}') REV=$(grep 'CLIENT_VERSION_REVISION' src/clientversion.h | awk '{print $3}') echo "VERSION=${MAJOR}.${MINOR}.${REV}" >> $GITHUB_ENV fi - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential cmake ninja-build \ libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \ librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev - name: Configure run: | cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_QT=OFF \ -DBUILD_DAEMON=ON \ -DBUILD_TESTS=OFF \ -DUSE_UPNP=ON - name: Build run: cmake --build build -j$(nproc) - name: Strip binary run: strip --strip-all build/bin/trianglesd - name: Build .deb package (fully self-contained) run: | TOR_VERSION="15.0.9" curl -sL "https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_VERSION}/tor-expert-bundle-linux-x86_64-${TOR_VERSION}.tar.gz" -o tor-bundle.tar.gz mkdir -p tor-extract && tar -xzf tor-bundle.tar.gz -C tor-extract PKG="cryptographic-triangles-daemon_${VERSION}_amd64" mkdir -p ${PKG}/DEBIAN mkdir -p ${PKG}/usr/lib/cryptographic-triangles/lib mkdir -p ${PKG}/usr/lib/cryptographic-triangles/tor mkdir -p ${PKG}/usr/bin mkdir -p ${PKG}/etc/systemd/system cp build/bin/trianglesd ${PKG}/usr/lib/cryptographic-triangles/ cp tor-extract/tor/tor ${PKG}/usr/lib/cryptographic-triangles/tor/ chmod +x ${PKG}/usr/lib/cryptographic-triangles/tor/tor [ -d tor-extract/data ] && cp -r tor-extract/data ${PKG}/usr/lib/cryptographic-triangles/tor/data # Bundle ALL shared library dependencies (except glibc/kernel) ldd build/bin/trianglesd | grep '=> /' | awk '{print $3}' | while read lib; do case "$lib" in /lib/x86_64-linux-gnu/libc.so*|/lib/x86_64-linux-gnu/libm.so*|/lib/x86_64-linux-gnu/libpthread.so*|/lib/x86_64-linux-gnu/libdl.so*|/lib/x86_64-linux-gnu/librt.so*|/lib/x86_64-linux-gnu/ld-linux*|/lib64/ld-linux*) ;; # Skip glibc core — always present *) cp -L "$lib" ${PKG}/usr/lib/cryptographic-triangles/lib/ 2>/dev/null || true ;; esac done echo "=== Bundled libs ===" ls ${PKG}/usr/lib/cryptographic-triangles/lib/ | wc -l ls ${PKG}/usr/lib/cryptographic-triangles/lib/ # Launcher with LD_LIBRARY_PATH cat > ${PKG}/usr/bin/trianglesd << 'LAUNCHER' #!/bin/bash INSTALL_DIR=/usr/lib/cryptographic-triangles export LD_LIBRARY_PATH="${INSTALL_DIR}/lib:${LD_LIBRARY_PATH}" exec "${INSTALL_DIR}/trianglesd" "$@" LAUNCHER sed -i 's/^ //' ${PKG}/usr/bin/trianglesd chmod +x ${PKG}/usr/bin/trianglesd cat > ${PKG}/etc/systemd/system/trianglesd.service << 'SVC' [Unit] Description=Cryptographic Triangles Daemon After=network-online.target Wants=network-online.target [Service] Type=simple Environment=LD_LIBRARY_PATH=/usr/lib/cryptographic-triangles/lib ExecStart=/usr/lib/cryptographic-triangles/trianglesd Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target SVC sed -i 's/^ //' ${PKG}/etc/systemd/system/trianglesd.service cat > ${PKG}/DEBIAN/control << CTRL Package: cryptographic-triangles-daemon Version: ${VERSION} Architecture: amd64 Maintainer: Cryptographic Triangles Description: Cryptographic Triangles daemon with integrated Tor Fully self-contained headless node with all libraries, Tor, and systemd service. No external dependencies required — runs on any x86_64 Linux. Section: finance Priority: optional CTRL sed -i 's/^ //' ${PKG}/DEBIAN/control cat > ${PKG}/DEBIAN/postinst << 'POST' #!/bin/bash systemctl daemon-reload echo "" echo "Cryptographic Triangles daemon installed." echo " Start: sudo systemctl start trianglesd" echo " On boot: sudo systemctl enable trianglesd" echo "" POST chmod +x ${PKG}/DEBIAN/postinst dpkg-deb --build ${PKG} - name: Upload .deb uses: actions/upload-artifact@v4 with: name: linux-daemon-deb path: cryptographic-triangles-daemon_*_amd64.deb build-macos: runs-on: macos-15 steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set VERSION run: | if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV else MAJOR=$(grep 'CLIENT_VERSION_MAJOR' src/clientversion.h | awk '{print $3}') MINOR=$(grep 'CLIENT_VERSION_MINOR' src/clientversion.h | awk '{print $3}') REV=$(grep 'CLIENT_VERSION_REVISION' src/clientversion.h | awk '{print $3}') echo "VERSION=${MAJOR}.${MINOR}.${REV}" >> $GITHUB_ENV fi - name: Install dependencies run: | brew install cmake ninja qt@5 openssl@3 boost berkeley-db@5 leveldb rocksdb libevent miniupnpc - name: Configure run: | export PATH="/opt/homebrew/opt/qt@5/bin:$PATH" cmake -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_QT=ON \ -DBUILD_DAEMON=OFF \ -DBUILD_TESTS=OFF \ -DUSE_UPNP=ON \ -DBOOST_ROOT=/opt/homebrew/opt/boost \ -DBDB_INCLUDE_PATH=/opt/homebrew/opt/berkeley-db@5/include \ -DBDB_LIB_PATH=/opt/homebrew/opt/berkeley-db@5/lib \ -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl@3 \ -DEVENT_INCLUDE_PATH=/opt/homebrew/opt/libevent/include \ -DEVENT_LIB_PATH=/opt/homebrew/opt/libevent/lib \ -DMINIUPNPC_INCLUDE_PATH=/opt/homebrew/opt/miniupnpc/include \ -DMINIUPNPC_LIB_PATH=/opt/homebrew/opt/miniupnpc/lib \ -DQt5_DIR=/opt/homebrew/opt/qt@5/lib/cmake/Qt5 - name: Build run: cmake --build build -j$(sysctl -n hw.ncpu) - name: Create .app bundle run: | export PATH="/opt/homebrew/opt/qt@5/bin:$PATH" macdeployqt build/bin/Triangles-Qt.app -verbose=1 || \ macdeployqt build/bin/triangles-qt.app -verbose=1 || true - name: Bundle non-Qt dylibs into app run: | # Find the .app bundle APP=$(find build/bin -name "*.app" -maxdepth 1 | head -1) if [ -z "$APP" ]; then echo "No .app bundle found, creating one manually..." APP="build/bin/Triangles-Qt.app" mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Frameworks" cp build/bin/triangles-qt "$APP/Contents/MacOS/Triangles-Qt" fi FRAMEWORKS="$APP/Contents/Frameworks" BINARY=$(find "$APP/Contents/MacOS" -type f -perm +111 | head -1) # Copy Homebrew dylibs that macdeployqt doesn't handle for lib in boost_system boost_filesystem boost_thread boost_program_options boost_chrono; do DYLIB=$(otool -L "$BINARY" | grep "$lib" | awk '{print $1}') if [ -n "$DYLIB" ] && [ -f "$DYLIB" ]; then cp "$DYLIB" "$FRAMEWORKS/" BASENAME=$(basename "$DYLIB") install_name_tool -change "$DYLIB" "@executable_path/../Frameworks/$BASENAME" "$BINARY" fi done for lib in libssl libcrypto libevent libdb_cxx libminiupnpc libsodium; do DYLIB=$(otool -L "$BINARY" | grep "$lib" | awk '{print $1}') if [ -n "$DYLIB" ] && [ -f "$DYLIB" ]; then cp "$DYLIB" "$FRAMEWORKS/" BASENAME=$(basename "$DYLIB") install_name_tool -change "$DYLIB" "@executable_path/../Frameworks/$BASENAME" "$BINARY" fi done echo "=== Final dylib dependencies ===" otool -L "$BINARY" | head -30 - name: Bundle Tor into app run: | TOR_VERSION="15.0.9" curl -sL "https://archive.torproject.org/tor-package-archive/torbrowser/${TOR_VERSION}/tor-expert-bundle-macos-aarch64-${TOR_VERSION}.tar.gz" -o tor-bundle.tar.gz mkdir -p tor-extract && tar -xzf tor-bundle.tar.gz -C tor-extract APP=$(find build/bin -name "*.app" -maxdepth 1 | head -1) mkdir -p "$APP/Contents/MacOS/tor" cp tor-extract/tor/tor "$APP/Contents/MacOS/tor/" chmod +x "$APP/Contents/MacOS/tor/tor" [ -d tor-extract/data ] && cp -r tor-extract/data "$APP/Contents/MacOS/tor/data" - name: Create DMG run: | APP=$(find build/bin -name "*.app" -maxdepth 1 | head -1) mkdir -p dmg_contents cp -R "$APP" dmg_contents/ ln -s /Applications dmg_contents/Applications hdiutil create -volname "Cryptographic Triangles" \ -srcfolder dmg_contents \ -ov -format UDZO \ "Cryptographic-Triangles-v${VERSION}-macos-arm64.dmg" - name: Upload DMG uses: actions/upload-artifact@v4 with: name: macos-arm64-dmg path: "*.dmg" release: if: startsWith(github.ref, 'refs/tags/v') needs: [build-windows-qt, build-windows-daemon, build-linux-qt, build-linux-daemon, build-macos] runs-on: ubuntu-latest permissions: contents: write steps: - name: Set VERSION from tag run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Prepare release assets run: | mkdir -p release # Windows Qt installer (setup.exe — includes Tor, Start Menu shortcuts, uninstaller) cp artifacts/windows-qt-setup/*.exe release/ # Windows daemon (zip with DLLs + Tor) cd artifacts/windows-daemon && zip -r "../../release/Cryptographic-Triangles-${VERSION}-win-x64-daemon.zip" . && cd ../.. # Linux Qt .deb (dpkg -i to install — includes Tor, desktop entry, icon) cp artifacts/linux-qt-deb/*.deb release/ # Linux daemon .deb (dpkg -i to install — includes Tor, systemd service) cp artifacts/linux-daemon-deb/*.deb release/ # macOS DMG (drag to Applications — Tor inside .app bundle) cp artifacts/macos-arm64-dmg/*.dmg release/ ls -la release/ - name: Create Release uses: softprops/action-gh-release@v2 with: files: release/* generate_release_notes: true trigger-tripi: name: Trigger TRI-PI ARM64 Build if: startsWith(github.ref, 'refs/tags/v') needs: release runs-on: ubuntu-latest steps: - name: Dispatch tri-pi ARM64 build run: | curl -f -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${{ secrets.TRIPI_BUILD_TOKEN }}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/SamiAhmed7777/tri-pi/dispatches \ -d '{"event_type":"new-release","client_payload":{"version":"${{ github.ref_name }}","source_repo":"SamiAhmed7777/triangles_v5"}}' echo "Triggered tri-pi repository_dispatch for ${{ github.ref_name }}"