enprot 0.5.8

Engyon Protected Text (EPT) — confidentiality processor and capability ledger
name: deploy

# Prevent overlapping deploy runs for the same tag. Don't cancel
# in-progress runs — a partially-built release is worse than waiting.
concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: false

on:
  push:
    tags:
      # release-plz creates v-prefixed tags (v0.5.0).
      # Also accept legacy bare-numeric tags (0.4.0) for back-compat.
      - 'v[0-9]*.[0-9]*.[0-9]*'
      - '[0-9]*.[0-9]*.[0-9]*'
  # Allow manual trigger to rebuild binaries for existing tags
  # (e.g., v0.5.0 was tagged before the deploy pattern was fixed).
  workflow_dispatch:
    inputs:
      tag:
        description: 'Tag to deploy (e.g., v0.5.0)'
        required: true
        type: string

env:
  CROSS_VERSION: 0.2.5
  BOTAN_VERSION: 3.7.0
  PROJECT_NAME: enprot
  EXE_NAME: enprot
  # Resolved tag for both trigger types:
  #   tag push → github.ref_name = "v0.5.0"
  #   workflow_dispatch → inputs.tag = "v0.5.0"
  # Jobs strip the v prefix locally to get the bare version (0.5.0).
  DEPLOY_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}

jobs:
  checks:
    name: Checks
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v7
        with:
          ref: ${{ env.DEPLOY_TAG }}
      - name: Check version
        run: |
          set -euxo pipefail
          TAG="${DEPLOY_TAG#v}"
          if [ "$(grep '^version' Cargo.toml | cut -d '"' -f2)" != "$TAG" ]; then
            echo "Version tag ($TAG) does not match manifest"
            exit 1
          fi

  generate-extras:
    name: man page + completions
    needs: [checks]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          ref: ${{ env.DEPLOY_TAG }}
      - name: Install rust toolchain
        uses: dtolnay/rust-toolchain@stable
      - name: Install dependencies
        env:
          BOTAN_VERSION: ${{ env.BOTAN_VERSION }}
          PREFIX: /usr
        run: ./ci/install.sh
      - name: Build enprot
        env:
          PKG_CONFIG_PATH: /usr/lib/pkgconfig
        run: cargo build --features cli --release
      - name: Generate man page
        run: cargo run --features cli --example gen-manpage > enprot.1
      - name: Generate shell completions
        run: |
          mkdir -p completions
          target/release/enprot completions bash > completions/enprot.bash
          target/release/enprot completions fish > completions/enprot.fish
          target/release/enprot completions zsh  > completions/_enprot
      - name: Upload extras
        uses: actions/upload-artifact@v7
        with:
          name: extras
          path: |
            enprot.1
            completions/

  release-archive:
    needs: [checks, generate-extras]
    name: archive
    timeout-minutes: 20
    strategy:
      # Don't cancel native builds (macOS, Windows MSVC) when Docker
      # cross-compile targets fail (blocked on upstream librnp).
      fail-fast: false
      matrix:
        target:
          - x86_64-unknown-linux-musl
          - aarch64-unknown-linux-musl
          - x86_64-apple-darwin
          - aarch64-apple-darwin
          - x86_64-pc-windows-gnu
          - x86_64-pc-windows-msvc
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-musl
            env:
              TARGET: x86_64-unknown-linux-musl
              PREFIX: /usr/local/x86_64-linux-musl
              TARGET_CC: x86_64-linux-musl-gcc
              TARGET_CXX: x86_64-linux-musl-g++
              TARGET_AR: x86_64-linux-musl-gcc-ar
          - os: ubuntu-latest
            target: aarch64-unknown-linux-musl
            env:
              TARGET: aarch64-unknown-linux-musl
              PREFIX: /usr/local/aarch64-linux-musl
              TARGET_CC: aarch64-linux-musl-gcc
              TARGET_CXX: aarch64-linux-musl-g++
              TARGET_AR: aarch64-linux-musl-gcc-ar
          # macos-13 is the last x86_64 runner. macos-latest (14+) is
          # Apple Silicon — building x86_64 there is a cross-compile
          # that needs x86_64 C libs (botan, json-c, librnp).
          - os: macos-13
            target: x86_64-apple-darwin
            env:
              TARGET: x86_64-apple-darwin
              PREFIX: /usr/local
          - os: macos-latest
            target: aarch64-apple-darwin
            env:
              TARGET: aarch64-apple-darwin
              PREFIX: /usr/local
          - os: ubuntu-latest
            target: x86_64-pc-windows-gnu
            env:
              TARGET: x86_64-pc-windows-gnu
              TARGET_CC: x86_64-w64-mingw32-gcc-posix
              TARGET_CXX: x86_64-w64-mingw32-g++-posix
              TARGET_AR: x86_64-w64-mingw32-gcc-ar-posix
              EXE_NAME: enprot.exe
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            env:
              TARGET: x86_64-pc-windows-msvc
              EXE_NAME: enprot.exe
              GIT_REDIRECT_STDERR: '2>&1'

    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v7
        with:
          ref: ${{ env.DEPLOY_TAG }}

      - name: Set environment (unix)
        if: "!startsWith(matrix.os, 'windows')"
        env: ${{ matrix.env }}
        run: |
          set -euxo pipefail
          TAG="${DEPLOY_TAG#v}"
          echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
          echo "PREFIX=${PREFIX-$GITHUB_WORKSPACE/installs}" >> $GITHUB_ENV
          echo "EXE_PATH=target/$TARGET/release/$EXE_NAME" >> $GITHUB_ENV
      - name: Set environment (windows)
        if: startsWith(matrix.os, 'windows')
        env: ${{ matrix.env }}
        run: |
          Set-StrictMode -Version 3.0
          $Tag = $Env:DEPLOY_TAG.TrimStart('v')
          "RELEASE_TAG=$Tag" | Out-File -Append -Encoding UTF8 -LiteralPath $Env:GITHUB_ENV
          # Join-Path produces a proper Windows path; convert to
          # forward-slash form so it works in cargo/CMake/etc.
          $Prefix = (Join-Path $PWD 'installs').Replace('\', '/')
          "PREFIX=$Prefix" | Out-File -Append -Encoding UTF8 -LiteralPath $Env:GITHUB_ENV
          "EXE_PATH=target/$Env:TARGET/release/$Env:EXE_NAME" | Out-File -Append -Encoding UTF8 -LiteralPath $Env:GITHUB_ENV

      - name: Install rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          target: ${{ matrix.env.TARGET }}

      - name: Install python (windows)
        if: startsWith(matrix.os, 'windows')
        uses: actions/setup-python@v7
        with:
          python-version: '3.x'

      - name: Build (unix)
        if: "!startsWith(matrix.os, 'windows')"
        env: ${{ matrix.env }}
        run: |
          set -euxo pipefail
          . ci/build-static.sh
      - name: Build (windows)
        if: startsWith(matrix.os, 'windows')
        env: ${{ matrix.env }}
        shell: pwsh
        run: |
          Set-StrictMode -Version 3.0
          . .\ci\build-static.ps1

      - name: Download extras
        uses: actions/download-artifact@v8
        with:
          name: extras
          path: extras

      - name: Archive (unix)
        if: "!startsWith(matrix.os, 'windows')"
        env: ${{ matrix.env }}
        run: |
          set -euxo pipefail
          . ci/archive.sh
      - name: Archive (windows)
        if: startsWith(matrix.os, 'windows')
        env: ${{ matrix.env }}
        shell: pwsh
        run: |
          Set-StrictMode -Version 3.0
          . .\ci\archive.ps1

      - name: Upload artifacts
        uses: actions/upload-artifact@v7
        with:
          name: archives
          path: archives

  github-release:
    name: github release
    needs: [release-archive]
    # Run even if some archive targets failed (e.g., Docker cross-compile
    # targets blocked on upstream librnp). Publish whatever archives
    # succeeded so users get macOS + Windows MSVC binaries.
    if: always() && !cancelled()
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v8
        with:
          name: archives
      - name: Create release
        env:
          GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euxo pipefail
          RELEASE_TAG="${DEPLOY_TAG#v}"
          git clone https://github.com/riboseinc/create-github-release
          cd create-github-release
          sudo apt-get -y install ruby
          export GEM_HOME="$(ruby -e 'print Gem.user_dir')"
          export PATH="$PATH:$GEM_HOME/bin"
          gem install --no-document bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)"
          bundle install
          bundle exec ./create-github-release.rb \
            ${{ github.repository }} \
            "$RELEASE_TAG" \
            ../archives/*

  publish-snap:
    name: snap
    needs: [github-release]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          ref: ${{ env.DEPLOY_TAG }}
      # snapcore/action-build@v1 invokes snapcraft as part of its
      # action — it needs the version replaced BEFORE this step.
      # Step is named "build" so ${{ steps.build.outputs.snap }} works.
      - name: Set snap version
        run: |
          RELEASE_TAG="${DEPLOY_TAG#v}"
          sed -i "s/RELEASE_TAG/${RELEASE_TAG}/g" snap/snapcraft.yaml
      - name: Install snapcraft
        id: build
        uses: snapcore/action-build@v1
        with:
          snapcraft_token: ${{ secrets.SNAPCRAFT_RELEASE_LOGIN }}
      - name: Install review-tools
        run: sudo snap install review-tools
      - name: Publish
        uses: snapcore/action-publish@v1
        with:
          store_token: ${{ secrets.SNAPCRAFT_RELEASE_LOGIN }}
          snap: ${{ steps.build.outputs.snap }}
          release: stable