Skip to content

crux-mir

crux-mir #3432

name: crux-mir
on:
push:
tags: ["crux-v?[0-9]+.[0-9]+(.[0-9]+)?"]
branches: [master, "release-**"]
pull_request:
schedule:
- cron: "0 10 * * *" # 10am UTC -> 2/3am PST
workflow_dispatch:
defaults:
run:
shell: bash
env:
# The CABAL_CACHE_VERSION and CARGO_CACHE_VERSION environment variables can
# be updated to force the use of a new cabal or cargo cache if the respective
# cache contents become corrupted/invalid. This can sometimes happen when
# (for example) the OS version is changed but older .so files are cached,
# which can have various effects (e.g. cabal complains it can't find a valid
# version of the "happy" tool).
#
# This also periodically happens on MacOS builds due to a tar bug (symptom:
# "No suitable image found ... unknown file type, first eight bytes: 0x00
# 0x00 0x00 0x00 0x00 0x00 0x00 0x00")
CABAL_CACHE_VERSION: 1
CARGO_CACHE_VERSION: 1
# If you update this, make sure to also update RUST_TOOLCHAIN in
# .github/Dockerfile-crux-mir
RUST_TOOLCHAIN: "nightly-2025-02-16"
jobs:
config:
runs-on: ubuntu-24.04
outputs:
name: ${{ steps.config.outputs.name }}
crux-mir-version: ${{ steps.config.outputs.crux-mir-version }}
event-tag: ${{ steps.config.outputs.tag }}
event-schedule: ${{ steps.config.outputs.schedule }}
publish: ${{ steps.config.outputs.publish }}
release: ${{ steps.config.outputs.release }}
retention-days: ${{ steps.config.outputs.retention-days }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: config
id: config
env:
EVENT_TAG: ${{ startsWith(github.event.ref, 'refs/tags/') }}
EVENT_SCHEDULE: ${{ github.event_name == 'schedule' }}
EVENT_DISPATCH: ${{ github.event_name == 'workflow_dispatch' }}
RELEASE: ${{ startsWith(github.event.ref, 'refs/heads/release-crux-') }}
run: |
set -x
.github/ci.sh output name crux-mir-$(.github/ci.sh crux_mir_ver)
.github/ci.sh output crux-mir-version $(.github/ci.sh crux_mir_ver)
.github/ci.sh output tag $EVENT_TAG
.github/ci.sh output schedule $EVENT_SCHEDULE
.github/ci.sh output publish $({ $EVENT_TAG || $EVENT_SCHEDULE; } && echo true || echo false)
.github/ci.sh output release $([[ "refs/heads/release-crux-$(.github/ci.sh crux_mir_ver)" == "${{ github.event.ref }}" ]] && echo true || echo false)
.github/ci.sh output retention-days $($RELEASE && echo 90 || echo 5)
build:
runs-on: ${{ matrix.os }}
needs: [config]
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04]
cabal: ["3.14.2.0"]
ghc: ["9.6.7", "9.8.4", "9.10.1"]
include:
- os: ubuntu-22.04
cabal: 3.14.2.0
ghc: 9.10.1
- os: macos-14
cabal: 3.14.2.0
ghc: 9.10.1
# We want Windows soon, but it doesn't need to be now
name: crux-mir - GHC v${{ matrix.ghc }} - ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: haskell-actions/setup@v2
id: setup-haskell
with:
ghc-version: ${{ matrix.ghc }}
cabal-version: ${{ matrix.cabal }}
- name: Post-GHC installation fixups on Windows
if: runner.os == 'Windows'
run: |
# A workaround for https://github.com/Mistuke/CabalChoco/issues/5
cabal user-config update -a "extra-include-dirs: \"\""
cabal user-config update -a "extra-lib-dirs: \"\""
- name: Install latest Rust nightly
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
components: rustc-dev, rust-src
- uses: actions/cache/restore@v4
name: Restore cabal store cache
id: cache
env:
key: ${{ env.CABAL_CACHE_VERSION }}-crux-mir-${{ matrix.os }}-cabal${{ steps.setup-haskell.outputs.cabal-version }}-ghc${{ steps.setup-haskell.outputs.ghc-version }}
with:
path: |
${{ steps.setup-haskell.outputs.cabal-store }}
dist-newstyle
key: ${{ env.key }}-${{ hashFiles(format('cabal.GHC-{0}.config', matrix.ghc)) }}-${{ github.ref }}
restore-keys: |
${{ env.key }}-${{ hashFiles(format('cabal.GHC-{0}.config', matrix.ghc)) }}-
${{ env.key }}-
- uses: Swatinem/rust-cache@v2
name: cargo cache
with:
cache-on-failure: "true"
prefix-key: "${{ env.CARGO_CACHE_VERSION }}-${{ matrix.os }}"
shared-key: "cargo-cache"
workspaces: "dependencies/mir-json"
- run: .github/ci.sh install_system_deps
env:
SOLVER_PKG_VERSION: "snapshot-20250606"
BUILD_TARGET_OS: ${{ matrix.os }}
BUILD_TARGET_ARCH: ${{ runner.arch }}
- name: Install mir-json
working-directory: dependencies/mir-json
run: |
cargo install --locked --force
mir-json-translate-libs
echo "CRUX_RUST_LIBRARY_PATH=$(pwd)/rlibs" >> $GITHUB_ENV
- run: .github/ci.sh configure
- name: Generate source distributions
run: cabal sdist crucible-syntax crucible-concurrency crucible-mir crux-mir
- run: >
cabal build
crucible
crucible-cli
crucible-concurrency
crucible-debug
crucible-mir
crucible-mir-cli
crucible-mir-debug
crucible-mir-syntax
crucible-syntax
crux-mir
- name: Haddock
# See Note [--disable-documentation] in `crucible-go-build.yml`.
run: cabal haddock --disable-documentation crucible-syntax crucible-concurrency crux-mir
- run: .github/ci.sh test crucible-mir-syntax
- run: .github/ci.sh test crucible-mir-cli
- run: .github/ci.sh test crux-mir
- uses: actions/cache/save@v4
name: Save cabal store cache
if: always()
with:
path: |
${{ steps.setup-haskell.outputs.cabal-store }}
dist-newstyle
key: ${{ steps.cache.outputs.cache-primary-key }}
# We support older Cabal versions so that users can build the project even
# if they lack access to the latest Cabal package, e.g., when using the
# version provided by their OS package manager on older systems.
#
# Rather than running the whole CI workflow with multiple Cabal versions
# (e.g., in the `matrix`), we run the equivalent of `cabal clean`, but
# using the version of the Cabal library that is bundled with GHC. This is
# sufficient to check that the bundled version of Cabal can parse the Cabal
# configuration files (`.cabal`, `cabal.project{,freeze}`). This guarantees
# that our package can be built with the versions of Cabal that are likely to
# be available alongside the supported versions of GHC.
#
# We run this after `actions/cache/save` since it deletes most of
# `dist-newstyle`.
- name: Check Cabal/GHC compatibility
run: |
cd crux-mir
echo 'import Distribution.Simple; main = defaultMain' > Setup.hs
runhaskell Setup.hs clean
- name: Create binary artifact
run: |
NAME="crux-mir-${{ needs.config.outputs.crux-mir-version }}-${{ matrix.os }}-${{ runner.arch }}"
echo "NAME=$NAME" >> $GITHUB_ENV
.github/ci.sh bundle_crux_mir_files
if: github.event.pull_request.head.repo.fork == false && github.repository_owner == 'GaloisInc'
env:
OS_TAG: ${{ matrix.os }}
ARCH_TAG: ${{ runner.arch }}
VERSION: ${{ needs.config.outputs.crux-mir-version }}
- name: Sign binary artifact
# The SIGNING_PASSPHRASE and SIGNING_KEY secrets are only available on
# jobs run from the main repo, and as a result, they won't work when
# run from a fork. Signing binaries isn't essential to the rest of the
# workflow, so it is safe to skip this step on forks. Note that it
# isn't sufficient to test the pull request info because this job is
# also scheduled. See notes in README.md.
if: github.event.pull_request.head.repo.fork == false && github.repository_owner == 'GaloisInc'
env:
SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
run: |
.github/ci.sh sign "${NAME}.tar.gz"
- uses: actions/upload-artifact@v4
if: github.event.pull_request.head.repo.fork == false && github.repository_owner == 'GaloisInc'
with:
path: crux-mir-*.tar.gz*
name: crux-mir-${{ matrix.os }}-${{ runner.arch }}-${{ matrix.ghc }}
build-push-image:
runs-on: ubuntu-24.04
needs: [config]
if: (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || needs.config.outputs.release == 'true') && github.repository_owner == 'GaloisInc'
strategy:
fail-fast: false
matrix:
include:
- file: .github/Dockerfile-crux-mir
image: ghcr.io/galoisinc/crux-mir
cache: ghcr.io/galoisinc/cache-crux-mir
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Generate crux.buildinfo.json
shell: bash
run: .github/ci.sh generate_buildinfo "${{ github.sha }}" "${{ github.ref_name }}"
- name: Clear up some disk space
run: |
# The crux-mir Docker image is rather large (~1GB compressed), and
# the mere act of building the image requires just over 14 GB of disk
# space, which the maximum provided by a GitHub Action CI runner. To
# clear up some extra space, we delete ~10GB worth of pre-installed
# GitHub Actions tools, none of which we make use of.
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY" # Python installations
- uses: rlespinasse/[email protected]
- id: common-tag
run: |
echo "::set-output name=common-tag::$GITHUB_REF_SLUG"
echo "COMMON_TAG=$GITHUB_REF_SLUG" >> $GITHUB_ENV
- uses: docker/setup-buildx-action@v1
- uses: crazy-max/ghaction-docker-meta@v1
name: Labels
id: labels
with:
images: ${{ matrix.image }}
- uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v2
with:
context: .
tags: ${{ matrix.image }}:${{ steps.common-tag.outputs.common-tag }}
labels: ${{ steps.labels.outputs.labels }}
load: true
push: false
file: ${{ matrix.file }}
build-args: ${{ matrix.build-args }}
cache-from: |
type=registry,ref=${{ matrix.cache }}:${{ steps.prefix.outputs.prefix }}master
type=registry,ref=${{ matrix.cache }}:${{ steps.common-tag.outputs.common-tag }}
- name: Cache image build
uses: docker/build-push-action@v2
continue-on-error: true # Tolerate cache upload failures - this should be handled better
with:
context: .
file: ${{ matrix.file }}
build-args: ${{ matrix.build-args }}
cache-to: type=registry,ref=${{ matrix.cache }}:${{ steps.common-tag.outputs.common-tag }},mode=max
- if: needs.config.outputs.event-schedule == 'true'
name: ${{ matrix.image }}:nightly
run: |
docker tag ${{ matrix.image }}:$COMMON_TAG ${{ matrix.image }}:nightly
docker push ${{ matrix.image }}:nightly
- if: needs.config.outputs.release == 'true'
name: ${{ matrix.image }}:${{ needs.config.outputs.crux-mir-version }}
run: |
docker tag ${{ matrix.image }}:$COMMON_TAG ${{ matrix.image }}:${{ needs.config.outputs.crux-mir-version }}
docker push ${{ matrix.image }}:${{ needs.config.outputs.crux-mir-version }}
docker tag ${{ matrix.image }}:$COMMON_TAG ${{ matrix.image }}:latest
docker push ${{ matrix.image }}:latest