Skip to content

ci: ORAS-backed OpenSSL/wolfSSL dep cache for from-source builders #47

ci: ORAS-backed OpenSSL/wolfSSL dep cache for from-source builders

ci: ORAS-backed OpenSSL/wolfSSL dep cache for from-source builders #47

name: wolfSSL Versions (PQC)
# Backward-compatibility matrix for ML-KEM and ML-DSA. Mirrors wolfTPM's
# wolfssl-versions-pqc.yml pattern: a discover-versions job dynamically
# resolves the latest -stable wolfSSL tag and decides if it is past the PQC
# floor, then the build job runs three rows: pre-PQC floor, dynamically
# resolved latest -stable, and master.
#
# PQC is opt-in (--enable-pqc). PQC_FLOOR is v5.9.1-stable: the wc_MlDsaKey_*
# seed/message API wolfProvider's PQC code depends on lands post-v5.9.1-stable
# (wolfSSL PR #10436), so v5.9.2-stable+ is the first PQC-eligible release.
# PQC rows build with --enable-pqc against the latest OpenSSL (>= 3.6 required);
# older/no-flag rows build without it and verify PQC is absent (opt-in).
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
discover-versions:
name: Resolve wolfSSL version matrix
runs-on: ubuntu-22.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
latest-stable: ${{ steps.set-matrix.outputs.latest-stable }}
openssl-tag: ${{ steps.set-matrix.outputs.openssl-tag }}
steps:
- name: Resolve latest -stable wolfSSL tag and latest OpenSSL release
id: set-matrix
run: |
set -euo pipefail
LATEST=$(git ls-remote --tags --refs \
https://github.com/wolfSSL/wolfssl.git 'v*-stable' \
| awk -F/ '{print $NF}' | sort -V | tail -n 1)
if [ -z "${LATEST:-}" ]; then
echo "::error::Could not resolve latest wolfSSL -stable tag"
exit 1
fi
# PQC needs OpenSSL 3.6+, so always build against the latest release.
OSSL=$(git ls-remote --tags --refs \
https://github.com/openssl/openssl.git 'openssl-3.*' \
| awk -F/ '{print $NF}' | grep -E '^openssl-3\.[0-9.]+$' \
| sort -V | tail -n 1)
if [ -z "${OSSL:-}" ]; then
echo "::error::Could not resolve latest OpenSSL release tag"
exit 1
fi
echo "Latest stable wolfSSL: $LATEST"
echo "Latest OpenSSL: $OSSL"
echo "latest-stable=$LATEST" >> "$GITHUB_OUTPUT"
echo "openssl-tag=$OSSL" >> "$GITHUB_OUTPUT"
# Enable PQC when $LATEST is strictly newer than v5.9.1-stable
# (i.e. v5.9.2-stable, v5.10+, v6+, ...). Anything at or before
# the floor lacks the wc_MlDsaKey_* / wc_dilithium_sign_ctx_msg
# API and stays on the no-symbol path.
PQC_FLOOR="v5.9.1-stable"
if [ "$(printf '%s\n%s\n' "$PQC_FLOOR" "$LATEST" \
| sort -V | tail -n1)" != "$PQC_FLOOR" ]; then
LATEST_PQC_ELIGIBLE=true
else
LATEST_PQC_ELIGIBLE=false
fi
echo "latest-stable PQC eligible: $LATEST_PQC_ELIGIBLE"
# Each row carries the build flag (enable) and which PQC test families
# must result (expect: both | mlkem | mldsa | none). This exercises the
# combined, per-algorithm, and opt-in-absent paths.
MATRIX=$(jq -nc \
--arg latest "$LATEST" \
--argjson latest_pqc "$LATEST_PQC_ELIGIBLE" '{
include: [
{"name":"pre-PQC (v5.8.0-stable)",
"wolfssl-ref":"v5.8.0-stable","enable":"","expect":"none"},
{"name":("latest stable (" + $latest + ")"),"wolfssl-ref":$latest,
"enable":(if $latest_pqc then "--enable-pqc" else "" end),
"expect":(if $latest_pqc then "both" else "none" end)},
{"name":"master (--enable-pqc)",
"wolfssl-ref":"master","enable":"--enable-pqc","expect":"both"},
{"name":"master (no flag, opt-in check)",
"wolfssl-ref":"master","enable":"","expect":"none"},
{"name":"master (--enable-mlkem only)",
"wolfssl-ref":"master","enable":"--enable-mlkem","expect":"mlkem"},
{"name":"master (--enable-mldsa only)",
"wolfssl-ref":"master","enable":"--enable-mldsa","expect":"mldsa"}
]
}')
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
pqc-build-test:
name: ${{ matrix.name }}
needs: discover-versions
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
timeout-minutes: 30
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.discover-versions.outputs.matrix) }}
steps:
- name: Checkout wolfProvider
uses: actions/checkout@v4
with:
fetch-depth: 1
# Every row builds against the latest OpenSSL release. PQC needs OpenSSL
# 3.6+ (and the enable flag enforces that floor); the interop step then
# compares wolfProvider against that release's native ML-KEM/ML-DSA.
- name: Cache build dependencies
id: deps
uses: ./.github/actions/oras-build-deps
with:
variant: pqc
openssl_ref: ${{ needs.discover-versions.outputs.openssl-tag }}
wolfssl_ref: ${{ matrix.wolfssl-ref }}
extra_key: ${{ matrix.enable }}
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Build wolfProvider (${{ matrix.enable || 'no PQC flag' }})
run: |
OPENSSL_TAG=${{ needs.discover-versions.outputs.openssl-tag }} \
WOLFSSL_TAG=${{ matrix.wolfssl-ref }} \
./scripts/build-wolfprovider.sh ${{ matrix.enable }}
- name: Push build dependencies
uses: ./.github/actions/oras-build-deps-push
with:
registry: ${{ steps.deps.outputs.registry }}
openssl_install_tag: ${{ steps.deps.outputs.openssl_install_tag }}
wolfssl_install_tag: ${{ steps.deps.outputs.wolfssl_install_tag }}
openssl_hit: ${{ steps.deps.outputs.openssl_hit }}
wolfssl_hit: ${{ steps.deps.outputs.wolfssl_hit }}
# Opt-in is per-algorithm: assert exactly the expected PQC test families
# are present (both / mlkem / mldsa / none). This catches a leaked
# algorithm, a missing one, or PQC dragged in without a flag.
- name: Verify PQC test presence matches opt-in (${{ matrix.expect }})
run: |
tests=$(./test/unit.test --list) || exit 1
kem=0; dsa=0
printf '%s\n' "$tests" | grep -q 'test_mlkem_keygen' && kem=1
printf '%s\n' "$tests" | grep -q 'test_mldsa_sign_verify' && dsa=1
echo "expect=${{ matrix.expect }} mlkem=$kem mldsa=$dsa"
case "${{ matrix.expect }}" in
both) [ "$kem" = 1 ] && [ "$dsa" = 1 ] ;;
mlkem) [ "$kem" = 1 ] && [ "$dsa" = 0 ] ;;
mldsa) [ "$kem" = 0 ] && [ "$dsa" = 1 ] ;;
none) [ "$kem" = 0 ] && [ "$dsa" = 0 ] ;;
*) false ;;
esac || { echo "ERROR: PQC test families do not match expect=${{ matrix.expect }}"; exit 1; }
# Run the ML-KEM / ML-DSA / hybrid unit tests: keygen, sign/verify,
# encap/decap, PEM encoder/decoder round-trip, X.509 signing, and the
# hybrid-group KEM. Selected by index from --list so it tracks however
# many PQC tests are registered. LD_LIBRARY_PATH carries libwolfprov's
# deps; the provider module itself is found via the default .libs dir.
- name: Run PQC unit tests
if: matrix.expect != 'none'
run: |
export LD_LIBRARY_PATH="$(pwd)/wolfssl-install/lib:$(pwd)/openssl-install/lib:$(pwd)/openssl-install/lib64"
idxs=$(./test/unit.test --list | grep -iE 'mlkem|mldsa|mlx' \
| grep -oE '^[0-9]+')
if [ -z "$idxs" ]; then
echo "::error::No PQC unit tests found"
exit 1
fi
for i in $idxs; do
echo "== PQC unit test $i =="
./test/unit.test "$i" || exit 1
done
# Three-way interop: wolfProvider <-> OpenSSL default <-> wolfSSL direct.
# Only runs on PQC-enabled rows; the latest OpenSSL (3.6+, the PQC floor)
# has native ML-KEM/ML-DSA in the default provider, so this proves
# wolfProvider's bytes are FIPS 203/204 standards-compliant against two
# reference implementations.
# Linux x86_64 OpenSSL installs to lib64 by default; LD_LIBRARY_PATH
# must include both lib and lib64 or the dynamic linker falls through
# to the system libcrypto/libssl (Ubuntu 22.04 ships 3.0.2, which has
# no ML-KEM/ML-DSA in the default provider).
- name: Three-way PQC interop validation
if: matrix.expect == 'both'
run: |
LD_LIBRARY_PATH="$(pwd)/wolfssl-install/lib:$(pwd)/openssl-install/lib:$(pwd)/openssl-install/lib64" \
./test/pqc_interop.test
- name: Print errors on failure
if: ${{ failure() }}
run: |
if [ -f test-suite.log ]; then
cat test-suite.log
fi