Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[registry]
global-credential-providers = ["cargo:token"]

[registries.terraphim]
index = "sparse+https://git.terraphim.cloud/api/packages/terraphim/cargo/"

187 changes: 187 additions & 0 deletions .github/workflows/release-binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
name: Release Client Binaries

on:
workflow_dispatch:
inputs:
version:
description: 'Release version without v prefix (e.g. 1.20.5)'
required: true
type: string
release_tag:
description: 'GitHub release tag (e.g. v1.20.5)'
required: true
type: string
target_repo:
description: 'GitHub repo to attach binaries to'
required: false
default: terraphim-ai
type: string

permissions:
contents: write

env:
CARGO_TERM_COLOR: always

jobs:
build-binaries:
name: Build client binaries for ${{ matrix.target }}
strategy:
fail-fast: false
matrix:
include:
- os: [self-hosted, bigbox]
target: x86_64-unknown-linux-gnu
use_cross: false
- os: [self-hosted, bigbox]
target: x86_64-unknown-linux-musl
use_cross: true
- os: [self-hosted, bigbox]
target: aarch64-unknown-linux-musl
use_cross: true
- os: [self-hosted, macOS]
target: x86_64-apple-darwin
use_cross: false
- os: [self-hosted, macOS]
target: aarch64-apple-darwin
use_cross: false
- os: windows-latest
target: x86_64-pc-windows-msvc
use_cross: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install zig
if: contains(matrix.target, 'apple-darwin') || contains(matrix.target, 'windows')
shell: bash
run: |
if command -v zig &>/dev/null; then exit 0; fi
if command -v brew &>/dev/null; then brew install zig; fi
if command -v choco &>/dev/null; then choco install zig -y; fi
- name: Install cross
if: matrix.use_cross
run: cargo install cross
- uses: Swatinem/rust-cache@v2
if: matrix.target != 'x86_64-unknown-linux-gnu'
with:
key: clients-${{ matrix.target }}
- name: Build client binaries
env:
CARGO_REGISTRIES_TERRAPHIM_TOKEN: ${{ secrets.CARGO_REGISTRIES_TERRAPHIM_TOKEN }}
run: |
BUILD="${{ matrix.use_cross && 'cross' || 'cargo' }}"
$BUILD build --release --target ${{ matrix.target }} -p terraphim_agent --bin terraphim-agent
$BUILD build --release --target ${{ matrix.target }} -p terraphim_cli --bin terraphim-cli
$BUILD build --release --target ${{ matrix.target }} -p terraphim_grep --bin terraphim-grep --features "code-search openrouter"
- name: Package artifacts (Unix)
if: matrix.os != 'windows-latest'
env:
VERSION: ${{ inputs.version }}
run: |
mkdir -p artifacts
tar -czf "artifacts/terraphim-agent-${VERSION}-${{ matrix.target }}.tar.gz" -C "target/${{ matrix.target }}/release" terraphim-agent
tar -czf "artifacts/terraphim-cli-${VERSION}-${{ matrix.target }}.tar.gz" -C "target/${{ matrix.target }}/release" terraphim-cli
tar -czf "artifacts/terraphim-grep-${VERSION}-${{ matrix.target }}.tar.gz" -C "target/${{ matrix.target }}/release" terraphim-grep
cp target/${{ matrix.target }}/release/terraphim-agent artifacts/terraphim-agent-${{ matrix.target }}
cp target/${{ matrix.target }}/release/terraphim-cli artifacts/terraphim-cli-${{ matrix.target }}
cp target/${{ matrix.target }}/release/terraphim-grep artifacts/terraphim-grep-${{ matrix.target }}
chmod +x artifacts/*
- name: Package artifacts (Windows)
if: matrix.os == 'windows-latest'
shell: bash
env:
VERSION: ${{ inputs.version }}
run: |
mkdir -p artifacts
cd "target/${{ matrix.target }}/release"
7z a -tzip "../../../artifacts/terraphim-agent-${VERSION}-${{ matrix.target }}.zip" terraphim-agent.exe
7z a -tzip "../../../artifacts/terraphim-cli-${VERSION}-${{ matrix.target }}.zip" terraphim-cli.exe
7z a -tzip "../../../artifacts/terraphim-grep-${VERSION}-${{ matrix.target }}.zip" terraphim-grep.exe
cd -
cp target/${{ matrix.target }}/release/terraphim-agent.exe artifacts/terraphim-agent-${{ matrix.target }}.exe
cp target/${{ matrix.target }}/release/terraphim-cli.exe artifacts/terraphim-cli-${{ matrix.target }}.exe
cp target/${{ matrix.target }}/release/terraphim-grep.exe artifacts/terraphim-grep-${{ matrix.target }}.exe
- uses: actions/upload-artifact@v4
with:
name: client-binaries-${{ matrix.target }}
path: artifacts/*

create-universal-macos:
name: Create macOS universal client binaries
needs: build-binaries
if: always() && needs.build-binaries.result != 'cancelled'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/download-artifact@v4
with:
name: client-binaries-x86_64-apple-darwin
path: x86_64
- uses: actions/download-artifact@v4
with:
name: client-binaries-aarch64-apple-darwin
path: aarch64
- run: |
mkdir -p universal
lipo -create x86_64/terraphim-agent-x86_64-apple-darwin aarch64/terraphim-agent-aarch64-apple-darwin -output universal/terraphim-agent-universal-apple-darwin
lipo -create x86_64/terraphim-grep-x86_64-apple-darwin aarch64/terraphim-grep-aarch64-apple-darwin -output universal/terraphim-grep-universal-apple-darwin
chmod +x universal/*
- uses: actions/upload-artifact@v4
with:
name: client-binaries-universal-apple-darwin
path: universal/*

sign-and-notarize-macos:
name: Sign and notarize macOS client binaries
needs: create-universal-macos
if: always() && needs.create-universal-macos.result == 'success'
runs-on: [self-hosted, macOS]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: client-binaries-universal-apple-darwin
path: universal
- uses: 1password/install-cli-action@v2
- name: Load signing credentials
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
run: |
echo "APPLE_ID=$(op read 'op://TerraphimPlatform/apple.developer.credentials/username' --no-newline)" >> $GITHUB_ENV
echo "APPLE_TEAM_ID=$(op read 'op://TerraphimPlatform/apple.developer.credentials/APPLE_TEAM_ID' --no-newline)" >> $GITHUB_ENV
echo "APPLE_APP_PASSWORD=$(op read 'op://TerraphimPlatform/apple.developer.credentials/APPLE_APP_SPECIFIC_PASSWORD' --no-newline)" >> $GITHUB_ENV
echo "CERT_BASE64=$(op read 'op://TerraphimPlatform/apple.developer.certificate/base64' --no-newline)" >> $GITHUB_ENV
echo "CERT_PASSWORD=$(op read 'op://TerraphimPlatform/apple.developer.certificate/password' --no-newline)" >> $GITHUB_ENV
- name: Sign and notarize agent and grep
env:
RUNNER_TEMP: ${{ runner.temp }}
run: |
chmod +x scripts/sign-macos-binary.sh
./scripts/sign-macos-binary.sh universal/terraphim-agent-universal-apple-darwin "$APPLE_ID" "$APPLE_TEAM_ID" "$APPLE_APP_PASSWORD" "$CERT_BASE64" "$CERT_PASSWORD"
./scripts/sign-macos-binary.sh universal/terraphim-grep-universal-apple-darwin "$APPLE_ID" "$APPLE_TEAM_ID" "$APPLE_APP_PASSWORD" "$CERT_BASE64" "$CERT_PASSWORD"
- uses: actions/upload-artifact@v4
with:
name: client-binaries-signed-universal-apple-darwin
path: universal/*

upload-to-target-release:
name: Attach client binaries to terraphim-ai release
needs: [build-binaries, sign-and-notarize-macos]
if: always() && needs.build-binaries.result == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: client-binaries*
path: release-assets
merge-multiple: true
- name: Upload to target GitHub release
env:
GH_TOKEN: ${{ secrets.TERRAPHIM_AI_RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
run: |
TAG="${{ inputs.release_tag }}"
REPO="terraphim/${{ inputs.target_repo }}"
find release-assets -type f | sort
gh release upload "$TAG" release-assets/* --repo "$REPO" --clobber
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ members = [
]

[workspace.package]
version = "1.20.4"
version = "1.20.5"
edition = "2024"
authors = ["Terraphim Team <team@terraphim.ai>"]
documentation = "https://terraphim.ai"
Expand All @@ -23,6 +23,9 @@ repository = "https://git.terraphim.cloud/terraphim/terraphim-clients"
license = "Apache-2.0"
readme = "README.md"

[patch.crates-io]
terraphim_service = { version = "1.20.5", registry = "terraphim" }

[workspace.dependencies]
tokio = { version = "1.0", features = ["full"] }
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion crates/terraphim_agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ terraphim_persistence = { version = "1.0.0" }
terraphim_config = { version = "1.0.0" }
terraphim_command_runtime = { path = "../terraphim_command_runtime", version = "0.1.0" }
terraphim_automata = { version = "1.19.2" }
terraphim_service = { version = "1.0.0", default-features = false }
terraphim_service = { version = "1.20.5", default-features = false, registry = "terraphim" }
terraphim_middleware = { version = "1.0.0" }
terraphim_rolegraph = { version = "1.0.0" }
terraphim_hooks = { path = "../terraphim_hooks", version = "1.0.0" }
Expand Down
2 changes: 1 addition & 1 deletion crates/terraphim_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ path = "src/main.rs"

[dependencies]
# Core terraphim crates
terraphim_service = { version = "1.0.0" }
terraphim_service = { version = "1.20.5", registry = "terraphim" }
terraphim_config = { version = "1.0.0" }
terraphim_command_runtime = { path = "../terraphim_command_runtime", version = "0.1.0" }
terraphim_types = { version = "1.0.0" }
Expand Down
2 changes: 1 addition & 1 deletion crates/terraphim_grep/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ log.workspace = true
terraphim_types = { version = "1.15.0" }
terraphim_rolegraph = { version = "1.15.0" }
terraphim_automata = { version = "1.19.2" }
terraphim_service = { version = "1.16.15", optional = true }
terraphim_service = { version = "1.20.5", optional = true, registry = "terraphim" }
terraphim_config = { version = "1.15.0" }

fff-search = { version = "0.8.4", optional = true }
Expand Down
99 changes: 99 additions & 0 deletions scripts/sign-macos-binary.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/bash
set -euo pipefail

# Sign and notarize a macOS binary
# Usage: ./sign-macos-binary.sh <binary_path> <apple_id> <team_id> <app_password> <cert_base64> <cert_password>

# Parameters passed from workflow (not hardcoded secrets)
BINARY_PATH="$1"
APPLE_ID="$2"
TEAM_ID="$3"
APP_PASS="$4"
CERT_BASE64="$5"
CERT_PASS="$6"

echo "==> Signing and notarizing: $(basename "$BINARY_PATH")"

# Create temporary keychain
KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db"
KEYCHAIN_PASS=$(openssl rand -base64 32)

echo "==> Creating temporary keychain"
security create-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"

# Import certificate
echo "==> Importing certificate"
CERT_PATH="$RUNNER_TEMP/certificate.p12"
# Remove newlines from base64 before decoding (macOS base64 is strict)
echo "$CERT_BASE64" | tr -d '\n' | base64 --decode > "$CERT_PATH"

security import "$CERT_PATH" \
-k "$KEYCHAIN_PATH" \
-P "$CERT_PASS" \
-T /usr/bin/codesign \
-T /usr/bin/security

# Set key partition list to allow codesign to access the key
security set-key-partition-list \
-S apple-tool:,apple: \
-s -k "$KEYCHAIN_PASS" \
"$KEYCHAIN_PATH"

# Add keychain to search list
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g)

# Find signing identity
SIGNING_IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F'"' '{print $2}')
echo "==> Found signing identity: $SIGNING_IDENTITY"

# Sign the binary
echo "==> Signing binary"
codesign \
--sign "$SIGNING_IDENTITY" \
--options runtime \
--timestamp \
--verbose \
"$BINARY_PATH"

# Verify signature
echo "==> Verifying signature"
codesign --verify --deep --strict --verbose=2 "$BINARY_PATH"

# Create ZIP for notarization
ZIP_PATH="${BINARY_PATH}.zip"
echo "==> Creating ZIP for notarization"
ditto -c -k --keepParent "$BINARY_PATH" "$ZIP_PATH"

# Submit for notarization
echo "==> Submitting for notarization"
xcrun notarytool submit "$ZIP_PATH" \
--apple-id "$APPLE_ID" \
--team-id "$TEAM_ID" \
--password "$APP_PASS" \
--wait

# Check notarization status
echo "==> Checking notarization status"
SUBMISSION_ID=$(xcrun notarytool history \
--apple-id "$APPLE_ID" \
--team-id "$TEAM_ID" \
--password "$APP_PASS" \
| grep -m1 "id:" | awk '{print $2}')

xcrun notarytool log "$SUBMISSION_ID" \
--apple-id "$APPLE_ID" \
--team-id "$TEAM_ID" \
--password "$APP_PASS"

# Verify with spctl
echo "==> Verifying Gatekeeper acceptance"
spctl --assess --type execute --verbose "$BINARY_PATH" || true

# Cleanup
echo "==> Cleaning up"
rm -f "$CERT_PATH" "$ZIP_PATH"
security delete-keychain "$KEYCHAIN_PATH" || true

echo "✅ Successfully signed and notarized: $(basename "$BINARY_PATH")"
Loading