diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c362419..f4e734a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 46c663d..5d672a4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,29 +7,116 @@ on: env: IMAGE_NAME: monadfoundation/soteria + CARGO_TERM_COLOR: always jobs: - artifacts: - runs-on: ubuntu-latest + binaries: + name: Build ${{ matrix.platform.name }} + runs-on: ${{ matrix.platform.runner }} + strategy: + fail-fast: false + matrix: + platform: + - name: linux x86_64 + runner: ubuntu-latest + target: x86_64-unknown-linux-gnu + artifact: soteria-linux-x86_64 + + - name: linux arm64 + runner: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + artifact: soteria-linux-arm64 + + # macOS Intel + - name: macos x86_64 + runner: macos-15-intel + target: x86_64-apple-darwin + artifact: soteria-darwin-x86_64 + + # macOS Apple Silicon + - name: macos arm64 + runner: macos-26 + target: aarch64-apple-darwin + artifact: soteria-darwin-arm64 + + # Windows x86_64 + - name: windows x86_64 + runner: windows-latest + target: x86_64-pc-windows-msvc + artifact: soteria-windows-x86_64 + + # Windows ARM64 + - name: windows arm64 + runner: windows-11-arm + target: aarch64-pc-windows-msvc + artifact: soteria-windows-arm64 + steps: - - uses: actions/checkout@v5 + - name: Checkout + uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable with: toolchain: stable + targets: ${{ matrix.platform.target }} components: rustfmt - - uses: Swatinem/rust-cache@v2 + - name: Cache dependencies + uses: Swatinem/rust-cache@v2 with: + key: ${{ matrix.platform.target }} cache-on-failure: true - - run: cargo build --release --locked --all-features -v - - - name: Upload release version artifact - uses: actions/upload-artifact@v4 + - name: Build release binary + run: cargo build --release --locked --all-features --target ${{ matrix.platform.target }} -v + + - name: Prepare artifact (Unix) + if: runner.os != 'Windows' + run: | + mkdir -p artifacts + cp target/${{ matrix.platform.target }}/release/soteria artifacts/ + cd artifacts + tar -czvf ${{ matrix.platform.artifact }}.tar.gz soteria + rm soteria + + - name: Prepare artifact (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path artifacts + Copy-Item "target/${{ matrix.platform.target }}/release/soteria.exe" -Destination "artifacts/" + Compress-Archive -Path "artifacts/soteria.exe" -DestinationPath "artifacts/${{ matrix.platform.artifact }}.zip" + Remove-Item "artifacts/soteria.exe" + + - name: Upload artifact + uses: actions/upload-artifact@v5 + with: + name: ${{ matrix.platform.artifact }} + path: artifacts/* + if-no-files-found: error + + publish: + name: Publish GitHub Release assets + runs-on: ubuntu-latest + needs: [binaries] + permissions: + contents: write + steps: + - name: Download build artifacts + uses: actions/download-artifact@v5 + with: + path: dist + merge-multiple: true + + - name: Update release and upload assets + uses: softprops/action-gh-release@v2 with: - name: soteria - path: ./target/release/soteria + generate_release_notes: true + fail_on_unmatched_files: true + files: | + dist/*.tar.gz + dist/*.zip docker: runs-on: ubuntu-latest @@ -53,6 +140,10 @@ jobs: uses: docker/build-push-action@v6 with: push: true + platforms: linux/amd64,linux/arm64 sbom: true provenance: mode=max tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Cargo.lock b/Cargo.lock index d4cbe2c..7d35535 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,7 @@ dependencies = [ [[package]] name = "soteria" -version = "0.1.0" +version = "0.1.6" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 5f94f9f..2ceca3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "soteria" authors = ["QEDK "] license = "Apache-2.0" -version = "0.1.0" +version = "0.1.6" edition = "2024" [dependencies] diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..1b834f5 --- /dev/null +++ b/action.yml @@ -0,0 +1,201 @@ +name: 'run soteria CLI' +description: 'uses the soteria CLI to validate safe transaction hashes in JSON log files' +author: 'Monad Foundation' + +branding: + icon: 'shield' + color: 'purple' + +inputs: + directory: + description: 'Path to the directory containing JSON files to validate' + required: true + version: + description: 'Version of Soteria to use (e.g., "v0.1.5" or "latest")' + required: false + default: 'latest' + github-token: + description: 'GitHub token for API requests (to avoid rate limiting)' + required: false + default: ${{ github.token }} + fail-on-error: + description: 'Whether to fail the workflow if validation errors are found' + required: false + default: 'true' + +outputs: + validation-result: + description: 'The result of the validation (success or failure)' + value: ${{ steps.run-soteria.outputs.result }} + soteria-version: + description: 'The version of Soteria that was used' + value: ${{ steps.download.outputs.tag_name }} + +runs: + using: 'composite' + steps: + - name: Determine platform + id: platform + shell: bash + run: | + OS="${{ runner.os }}" + ARCH="${{ runner.arch }}" + + case "$OS" in + Linux) + case "$ARCH" in + X64) + echo "target=x86_64-unknown-linux-gnu" >> $GITHUB_OUTPUT + echo "asset_pattern=soteria-*linux*x86_64*" >> $GITHUB_OUTPUT + echo "fallback_pattern=soteria*linux*" >> $GITHUB_OUTPUT + ;; + ARM64) + echo "target=aarch64-unknown-linux-gnu" >> $GITHUB_OUTPUT + echo "asset_pattern=soteria-*linux*aarch64*" >> $GITHUB_OUTPUT + echo "fallback_pattern=soteria*linux*arm*" >> $GITHUB_OUTPUT + ;; + *) + echo "::error::Unsupported architecture: $ARCH" + exit 1 + ;; + esac + ;; + macOS) + case "$ARCH" in + X64) + echo "target=x86_64-apple-darwin" >> $GITHUB_OUTPUT + echo "asset_pattern=soteria-*darwin*x86_64*" >> $GITHUB_OUTPUT + echo "fallback_pattern=soteria*darwin*" >> $GITHUB_OUTPUT + ;; + ARM64) + echo "target=aarch64-apple-darwin" >> $GITHUB_OUTPUT + echo "asset_pattern=soteria-*darwin*aarch64*" >> $GITHUB_OUTPUT + echo "fallback_pattern=soteria*darwin*arm*" >> $GITHUB_OUTPUT + ;; + *) + echo "::error::Unsupported architecture: $ARCH" + exit 1 + ;; + esac + ;; + Windows) + echo "target=x86_64-pc-windows-msvc" >> $GITHUB_OUTPUT + echo "asset_pattern=soteria-*windows*x86_64*" >> $GITHUB_OUTPUT + echo "fallback_pattern=soteria*windows*" >> $GITHUB_OUTPUT + ;; + *) + echo "::error::Unsupported operating system: $OS" + exit 1 + ;; + esac + + echo "os=$OS" >> $GITHUB_OUTPUT + echo "arch=$ARCH" >> $GITHUB_OUTPUT + + - name: Download Soteria binary + id: download + uses: robinraju/release-downloader@v1 + with: + repository: 'monad-developers/soteria' + latest: ${{ inputs.version == 'latest' }} + tag: ${{ inputs.version != 'latest' && inputs.version || '' }} + fileName: '*' + out-file-path: '${{ runner.temp }}/soteria-download' + extract: true + token: ${{ inputs.github-token }} + + - name: Find and setup Soteria binary + id: setup + shell: bash + run: | + DOWNLOAD_DIR="${{ runner.temp }}/soteria-download" + INSTALL_DIR="${{ runner.temp }}/soteria-bin" + mkdir -p "$INSTALL_DIR" + + echo "Looking for Soteria binary in: $DOWNLOAD_DIR" + ls -la "$DOWNLOAD_DIR" || true + + # Look for the binary - try various patterns + BINARY="" + + # First, try to find a binary matching the platform + for pattern in "soteria" "soteria-${{ steps.platform.outputs.target }}" "soteria_${{ steps.platform.outputs.target }}"; do + if [ -f "$DOWNLOAD_DIR/$pattern" ]; then + BINARY="$DOWNLOAD_DIR/$pattern" + break + fi + if [ -f "$DOWNLOAD_DIR/${pattern}.exe" ]; then + BINARY="$DOWNLOAD_DIR/${pattern}.exe" + break + fi + done + + # If not found, search recursively for any soteria binary + if [ -z "$BINARY" ]; then + BINARY=$(find "$DOWNLOAD_DIR" -type f \( -name "soteria" -o -name "soteria.exe" -o -name "soteria-*" \) 2>/dev/null | head -n 1) + fi + + if [ -z "$BINARY" ] || [ ! -f "$BINARY" ]; then + echo "::warning::No pre-built binary found. Building from source..." + + # Install Rust if needed + if ! command -v cargo &> /dev/null; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + source "$HOME/.cargo/env" + fi + + # Install soteria from source + cargo install --git https://github.com/monad-developers/soteria.git --root "$INSTALL_DIR" + BINARY="$INSTALL_DIR/bin/soteria" + else + cp "$BINARY" "$INSTALL_DIR/soteria" + BINARY="$INSTALL_DIR/soteria" + fi + + # Make executable (on Unix systems) + if [ "${{ runner.os }}" != "Windows" ]; then + chmod +x "$BINARY" + fi + + echo "binary_path=$BINARY" >> $GITHUB_OUTPUT + echo "Binary location: $BINARY" + + # Verify binary + "$BINARY" --help || "$BINARY" -h || echo "Binary verification skipped" + + - name: Run Soteria validation + id: run-soteria + shell: bash + run: | + BINARY="${{ steps.setup.outputs.binary_path }}" + DIRECTORY="${{ inputs.directory }}" + + echo "Running Soteria on directory: $DIRECTORY" + echo "Using binary: $BINARY" + + # Validate directory exists + if [ ! -d "$DIRECTORY" ]; then + echo "::error::Directory does not exist: $DIRECTORY" + exit 1 + fi + + # Run soteria + set +e + OUTPUT=$("$BINARY" "$DIRECTORY" 2>&1) + EXIT_CODE=$? + set -e + + echo "$OUTPUT" + + if [ $EXIT_CODE -eq 0 ]; then + echo "result=success" >> $GITHUB_OUTPUT + echo "::notice::Soteria validation completed successfully" + else + echo "result=failure" >> $GITHUB_OUTPUT + if [ "${{ inputs.fail-on-error }}" == "true" ]; then + echo "::error::Soteria validation failed" + exit $EXIT_CODE + else + echo "::warning::Soteria validation found issues (exit code: $EXIT_CODE)" + fi + fi