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
266 changes: 230 additions & 36 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,56 +1,250 @@
name: Build, Test, and Benchmark mexce
name: Build, Test, Install, and Diagnose mexce

# Trigger the workflow on push or pull request events for the main/master branch
on:
push:
branches: [ main, master ]
branches: [main, master]
pull_request:
branches: [ main, master ]
branches: [main, master]

permissions:
contents: read

jobs:
build-and-benchmark:
name: Build and Benchmark on ${{ matrix.os }}
release-matrix:
name: ${{ matrix.os }} / ${{ matrix.compiler }} / ${{ matrix.configuration }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]

runs-on: ${{ matrix.os }}
include:
- os: windows-2022
compiler: msvc
cc: cl
cxx: cl
configuration: ordinary
- os: windows-2022
compiler: msvc
cc: cl
cxx: cl
configuration: protected
- os: ubuntu-latest
compiler: gcc
cc: gcc
cxx: g++
configuration: ordinary
- os: ubuntu-latest
compiler: gcc
cc: gcc
cxx: g++
configuration: protected
- os: ubuntu-latest
compiler: clang
cc: clang
cxx: clang++
configuration: ordinary
- os: ubuntu-latest
compiler: clang
cc: clang
cxx: clang++
configuration: protected

steps:
# 1. Checks out your repository
- name: Checkout repository
- name: Checkout
uses: actions/checkout@v4

# 2. Configure the project using CMake
- name: Configure CMake
run: cmake -B build -S .
- name: Install Conan
if: matrix.configuration == 'protected'
run: pip install conan==2.20.1

- name: Install Linux Clang dependencies
if: runner.os == 'Linux' && matrix.compiler == 'clang'
run: |
sudo apt-get update
sudo apt-get install -y clang libomp-dev

- name: Resolve libsodium 1.0.22 on Windows
if: runner.os == 'Windows' && matrix.configuration == 'protected'
shell: pwsh
run: |
$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
$installationPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
& "$installationPath\Common7\Tools\Launch-VsDevShell.ps1" -Arch amd64 -HostArch amd64 -SkipAutomaticLocation
conan profile detect --force
conan install --requires=libsodium/1.0.22 --output-folder=deps `
--generator=CMakeDeps --generator=CMakeToolchain `
--settings=build_type=Release --build=missing

# 3. Build the project and all targets
- name: Build with CMake
run: cmake --build build --config Release
- name: Resolve libsodium 1.0.22 on Linux
if: runner.os == 'Linux' && matrix.configuration == 'protected'
run: |
conan profile detect --force
conan install --requires=libsodium/1.0.22 --output-folder=deps \
--generator=CMakeDeps --generator=CMakeToolchain \
--settings=build_type=Release --build=missing
shell: bash
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}

# 4. Run the quick validation tests
- name: Run Quick Tests with CTest
- name: Configure ordinary Windows release
if: runner.os == 'Windows' && matrix.configuration == 'ordinary'
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release

- name: Configure ordinary Linux release
if: runner.os == 'Linux' && matrix.configuration == 'ordinary'
run: >-
cmake -S . -B build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_C_COMPILER=${{ matrix.cc }}
-DCMAKE_CXX_COMPILER=${{ matrix.cxx }}

- name: Configure protected Windows release and issuer
if: runner.os == 'Windows' && matrix.configuration == 'protected'
run: >-
cmake -S . -B build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/deps/conan_toolchain.cmake
-DMEXCE_ENABLE_PROTECTED_EXPRESSIONS=ON
-DMEXCE_BUILD_ISSUER_TOOLS=ON

- name: Configure protected Linux release and issuer
if: runner.os == 'Linux' && matrix.configuration == 'protected'
run: >-
cmake -S . -B build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_C_COMPILER=${{ matrix.cc }}
-DCMAKE_CXX_COMPILER=${{ matrix.cxx }}
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/deps/conan_toolchain.cmake
-DMEXCE_ENABLE_PROTECTED_EXPRESSIONS=ON
-DMEXCE_BUILD_ISSUER_TOOLS=ON

- name: Build
run: cmake --build build --config Release --parallel

- name: Test
run: ctest --test-dir build -C Release --output-on-failure

# 5. Run a short benchmark
- name: Run Short Benchmark
run: cmake --build build --config Release --target run_benchmarks

# 6. Display Benchmark Summary in Log
# FIX: Use the 'head' command to show only the first 58 lines of the
# results file, which contains the summary tables.
- name: Display Benchmark Summary

- name: Install
run: cmake --install build --config Release --prefix "${{ runner.temp }}/mexce-install"

- name: Check installed notice surface
env:
EXPECT_NOTICE: ${{ matrix.configuration == 'protected' && '1' || '0' }}
run: >-
python -c "import os, pathlib;
p=pathlib.Path(r'${{ runner.temp }}')/'mexce-install/share/licenses/mexce/THIRD_PARTY_NOTICES.md';
assert p.exists() == (os.environ['EXPECT_NOTICE'] == '1')"

- name: Configure installed Windows consumer
if: runner.os == 'Windows' && matrix.configuration == 'ordinary'
run: >-
cmake -S test/install_consumer -B consumer-build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_PREFIX_PATH=${{ runner.temp }}/mexce-install
-DMEXCE_FORBIDDEN_INCLUDE_ROOT=${{ github.workspace }}

- name: Configure installed Linux consumer
if: runner.os == 'Linux' && matrix.configuration == 'ordinary'
run: >-
cmake -S test/install_consumer -B consumer-build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_CXX_COMPILER=${{ matrix.cxx }}
-DCMAKE_PREFIX_PATH=${{ runner.temp }}/mexce-install
-DMEXCE_FORBIDDEN_INCLUDE_ROOT=${{ github.workspace }}

- name: Configure installed protected Windows consumer
if: runner.os == 'Windows' && matrix.configuration == 'protected'
run: >-
cmake -S test/install_consumer -B consumer-build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/deps/conan_toolchain.cmake
-DCMAKE_PREFIX_PATH=${{ runner.temp }}/mexce-install
-DMEXCE_FORBIDDEN_INCLUDE_ROOT=${{ github.workspace }}
-DMEXCE_CONSUMER_PROTECTED=ON

- name: Configure installed protected Linux consumer
if: runner.os == 'Linux' && matrix.configuration == 'protected'
run: >-
cmake -S test/install_consumer -B consumer-build
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_CXX_COMPILER=${{ matrix.cxx }}
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/deps/conan_toolchain.cmake
-DCMAKE_PREFIX_PATH=${{ runner.temp }}/mexce-install
-DMEXCE_FORBIDDEN_INCLUDE_ROOT=${{ github.workspace }}
-DMEXCE_CONSUMER_PROTECTED=ON

- name: Build installed consumer
run: cmake --build consumer-build --config Release --parallel

- name: Run installed consumers on Linux
if: runner.os == 'Linux'
run: |
./consumer-build/mexce_ordinary_consumer
if [ "${{ matrix.configuration }}" = protected ]; then
./consumer-build/mexce_protected_consumer
fi
shell: bash

- name: Run installed consumers on Windows
if: runner.os == 'Windows'
run: |
.\consumer-build\Release\mexce_ordinary_consumer.exe
if ('${{ matrix.configuration }}' -eq 'protected') {
.\consumer-build\Release\mexce_protected_consumer.exe
}

- name: Create documented issuer inputs
if: matrix.configuration == 'protected'
run: >-
python -c "from pathlib import Path;
Path('expression.txt').write_bytes(b'value+1\n');
Path('bindings.txt').write_bytes(b'value=0\n')"

- name: Run installed issuer and file consumer on Linux
if: runner.os == 'Linux' && matrix.configuration == 'protected'
run: |
"${{ runner.temp }}/mexce-install/bin/mexce_protect" expression.txt bindings.txt expression.mxp expression.key
./consumer-build/mexce_protected_file_consumer expression.mxp expression.key
shell: bash

- name: Run installed issuer and file consumer on Windows
if: runner.os == 'Windows' && matrix.configuration == 'protected'
run: |
echo "--- Benchmark Summary (first 58 lines) ---"
head -n 58 build/benchmark_results.txt
echo "------------------------------------------"
& "${{ runner.temp }}\mexce-install\bin\mexce_protect.exe" expression.txt bindings.txt expression.mxp expression.key
.\consumer-build\Release\mexce_protected_file_consumer.exe expression.mxp expression.key

- name: Run clear performance diagnostic
run: cmake --build build --config Release --target run_benchmarks

- name: Run protected performance diagnostic
if: matrix.configuration == 'protected'
run: ctest --test-dir build -C Release -R mexce_protected_benchmark --verbose > build/protected_benchmark_results.txt

- name: Run phase-isolated protected performance diagnostic on Linux
if: runner.os == 'Linux' && matrix.configuration == 'protected'
run: >-
python analysis/run_protected_benchmarks.py
build/protected_benchmark
build/protected_benchmark_results.json
--repeats 3
--resource-repeats 1

- name: Run phase-isolated protected performance diagnostic on Windows
if: runner.os == 'Windows' && matrix.configuration == 'protected'
run: >-
python analysis/run_protected_benchmarks.py
build/Release/protected_benchmark.exe
build/protected_benchmark_results.json
--repeats 3
--resource-repeats 1

# 7. Upload Full Benchmark Results as an Artifact
# This still saves the complete file for detailed analysis.
- name: Upload Benchmark Artifact
- name: Upload diagnostic results
if: always()
uses: actions/upload-artifact@v4
with:
name: benchmark-results-${{ matrix.os }}
path: build/benchmark_results.txt
name: diagnostics-${{ matrix.os }}-${{ matrix.compiler }}-${{ matrix.configuration }}
if-no-files-found: warn
path: |
build/benchmark_results.txt
build/protected_benchmark_results.txt
build/protected_benchmark_results.json
66 changes: 66 additions & 0 deletions .github/workflows/protected-fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Protected decoder extended fuzz

on:
schedule:
- cron: "17 3 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
fuzz:
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install compiler and dependency tooling
run: |
sudo apt-get update
sudo apt-get install -y clang libomp-dev
pip install conan==2.20.1

- name: Resolve libsodium 1.0.22
run: |
conan profile detect --force
conan install --requires=libsodium/1.0.22 --output-folder=deps \
--generator=CMakeDeps --generator=CMakeToolchain \
--settings=build_type=RelWithDebInfo --build=missing

- name: Configure sanitizer build
run: >-
cmake -S . -B build -G Ninja
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/deps/conan_toolchain.cmake
-DMEXCE_ENABLE_PROTECTED_EXPRESSIONS=ON

- name: Build fuzz target
run: cmake --build build --target protected_decoder_fuzz --parallel

- name: Seed authenticated format corpus
run: |
test -s test/fixtures/protected_format_1_0.bin
mkdir -p fuzz-corpus
cp test/fixtures/protected_format_1_0.bin fuzz-corpus/format-1.0.bin
cmp test/fixtures/protected_format_1_0.bin fuzz-corpus/format-1.0.bin

- name: Run extended decoder fuzzing
run: |
mkdir -p fuzz-artifacts
./build/protected_decoder_fuzz \
fuzz-corpus \
-max_total_time=900 \
-timeout=10 \
-artifact_prefix=fuzz-artifacts/

- name: Upload crashing inputs
if: failure()
uses: actions/upload-artifact@v4
with:
name: protected-fuzz-artifacts
if-no-files-found: ignore
path: fuzz-artifacts/
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- Opt-in authenticated protected-expression encoding and runtime loading on
x64 through libsodium 1.0.22.
- The `mexce::protected` installed target and protected Conan/vcpkg package
variants while keeping the ordinary target dependency-free.
- The opt-in `mexce_protect` issuer utility with owner-only raw-key output,
no-overwrite publication, partial-state detection, and Windows/Linux tests.
- Protected usage, threat-model, issuer, example, and third-party notice
documentation.

## [1.0.1] - 2025-10-10
### Added
- GitHub Actions workflows for build, benchmark, and coverage reporting, plus Codecov configuration and badges to track quality metrics.
Expand Down
Loading
Loading