Skip to content
Open
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
273 changes: 273 additions & 0 deletions .github/README.md

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions .github/actions/wait-for-smoke/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: 'Wait for Smoke Test'
description: 'Polls the Smoke Test workflow for the current commit and fails if it failed.'

# Designed to be the leading job in pull_request-triggered workflows so that
# expensive integration CI does not run unless the smoke build passes.
#
# Push events bypass the wait entirely (we still get smoke results for those
# pushes, but other CI is not gated on push). For drafts, callers should
# skip dependent jobs via `if: github.event.pull_request.draft == false` -
# this action will still pass through if smoke is skipped or absent.

inputs:
workflow:
description: 'Name of the smoke workflow file to wait on'
required: false
default: 'smoke-test.yml'
timeout-seconds:
description: 'Maximum time to wait for smoke to complete'
required: false
default: '1800'
poll-seconds:
description: 'Polling interval'
required: false
default: '20'
github-token:
description: 'GITHUB_TOKEN with actions:read permission'
required: true

runs:
using: 'composite'
steps:
- name: Wait for smoke
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
SMOKE_WORKFLOW: ${{ inputs.workflow }}
TIMEOUT: ${{ inputs.timeout-seconds }}
POLL: ${{ inputs.poll-seconds }}
REPO: ${{ github.repository }}
run: |
set -u
# Only gate pull_request events. Push events are not gated.
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "Not a pull_request event - skipping smoke gate."
exit 0
fi

HEAD_SHA="${{ github.event.pull_request.head.sha }}"
echo "Waiting for $SMOKE_WORKFLOW on $HEAD_SHA (timeout ${TIMEOUT}s)"

START=$(date +%s)
while :; do
NOW=$(date +%s)
ELAPSED=$((NOW - START))
if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
echo "::error::Timed out after ${TIMEOUT}s waiting for $SMOKE_WORKFLOW on $HEAD_SHA"
exit 1
fi

# Look up the latest run for this workflow + head SHA.
RUN_JSON=$(gh api \
"repos/${REPO}/actions/workflows/${SMOKE_WORKFLOW}/runs?head_sha=${HEAD_SHA}&per_page=1" \
2>/dev/null || echo '{}')

STATUS=$(echo "$RUN_JSON" | jq -r '.workflow_runs[0].status // "missing"')
CONCLUSION=$(echo "$RUN_JSON" | jq -r '.workflow_runs[0].conclusion // ""')
RUN_URL=$(echo "$RUN_JSON" | jq -r '.workflow_runs[0].html_url // ""')

case "$STATUS" in
completed)
case "$CONCLUSION" in
success)
echo "Smoke test passed: $RUN_URL"
exit 0
;;
skipped|neutral)
echo "Smoke test was $CONCLUSION - treating as pass: $RUN_URL"
exit 0
;;
*)
echo "::error::Smoke test concluded as '$CONCLUSION': $RUN_URL"
exit 1
;;
esac
;;
missing)
echo "[$ELAPSED s] No smoke run yet for $HEAD_SHA"
;;
*)
echo "[$ELAPSED s] Smoke status=$STATUS ($RUN_URL)"
;;
esac

sleep "$POLL"
done
62 changes: 8 additions & 54 deletions .github/scripts/check-workflow-result.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,62 +41,16 @@ fi
if [ "$WOLFPROV_FORCE_FAIL" = "WOLFPROV_FORCE_FAIL=1" ]; then
# ----- CURL -----
if [ "$TEST_SUITE" = "curl" ]; then
if [ -f "curl-test.log" ]; then
# Extract and clean the failed test list from the log
ACTUAL_FAILS=$(grep -a '^TESTFAIL: These test cases failed:' curl-test.log | sed 's/.*failed: //')
else
echo "Error: curl-test.log not found"
exit 1
fi

# Get curl version from the workflow ref
CURL_VERSION="${CURL_REF:-}"

# Define expected failures based on curl version
case "$CURL_VERSION" in
"curl-7_88_1")
EXPECTED_FAILS="9 39 41 44 64 65 70 71 72 88 153 154 158 163 166 167 168 169 170 173 186 206 245 246 258 259 273 277 327 335 388 540 551 552 554 565 579 584 643 645 646 647 648 649 650 651 652 653 654 666 667 668 669 670 671 672 673 1001 1002 1030 1053 1060 1061 1071 1072 1079 1095 1133 1136 1158 1186 1187 1189 1190 1191 1192 1193 1194 1195 1196 1198 1199 1229 1284 1285 1286 1293 1315 1404 1412 1418 1437 1568 1905 1916 1917 2024 2026 2027 2028 2030 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2073 2076 2200 2201 2202 2203 2204 3017 3018"
;;
"curl-8_4_0")
EXPECTED_FAILS="9 31 39 41 44 46 61 64 65 70 71 72 73 88 153 154 158 163 166 167 168 169 170 171 173 186 206 245 246 258 259 273 277 327 335 388 420 444 540 551 552 554 565 579 584 643 645 646 647 648 649 650 651 652 653 654 666 667 668 669 670 671 672 673 977 1001 1002 1030 1053 1060 1061 1071 1072 1079 1095 1105 1133 1136 1151 1155 1158 1160 1161 1186 1187 1189 1190 1191 1192 1193 1194 1195 1196 1198 1199 1229 1284 1285 1286 1293 1315 1404 1412 1415 1418 1437 1568 1903 1905 1916 1917 1964 2024 2026 2027 2028 2030 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2073 2076 2200 2201 2202 2203 2204 3017 3018"
;;
"master")
EXPECTED_FAILS="9 31 39 41 44 46 61 64 65 70 71 72 73 88 153 154 158 163 166 167 168 169 170 171 173 186 206 245 246 258 259 273 277 327 335 388 420 444 483 540 551 552 554 565 579 584 643 645 646 647 648 649 650 651 652 653 654 666 667 668 669 670 671 672 673 695 977 1001 1002 1030 1053 1060 1061 1071 1072 1079 1095 1105 1133 1136 1151 1155 1158 1160 1161 1186 1187 1189 1190 1191 1192 1193 1194 1195 1196 1198 1199 1229 1284 1285 1286 1293 1315 1404 1412 1415 1418 1437 1476 1568 1608 1610 1615 1654 1660 1903 1905 1916 1917 1964 2024 2026 2027 2028 2030 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2073 2076 2200 2201 2202 2203 2204 3017 3018"
;;
*)
echo "Error: Unknown curl version: $CURL_VERSION"
exit 1
;;
esac

# Create temporary files for sorted lists
TEMP_DIR=$(mktemp -d)
ACTUAL_SORTED="${TEMP_DIR}/actual_sorted.txt"
EXPECTED_SORTED="${TEMP_DIR}/expected_sorted.txt"

# Clean and sort both lists and remove empty lines
echo "$ACTUAL_FAILS" | tr ' ' '\n' | grep -v '^$' | sort -n > "$ACTUAL_SORTED"
echo "$EXPECTED_FAILS" | tr ' ' '\n' | grep -v '^$' | sort -n > "$EXPECTED_SORTED"

echo "DEBUG: Sorted actual fails: $(tr '\n' ' ' < "$ACTUAL_SORTED")"
echo "DEBUG: Sorted expected fails: $(tr '\n' ' ' < "$EXPECTED_SORTED")"

# Find missing in actual (in expected but not in actual)
MISSING=$(comm -23 "$EXPECTED_SORTED" "$ACTUAL_SORTED" | tr '\n' ' ')
# Find extra in actual (in actual but not in expected)
EXTRA=$(comm -13 "$EXPECTED_SORTED" "$ACTUAL_SORTED" | tr '\n' ' ')

# Clean up temporary files
rm -rf "$TEMP_DIR"

echo "Test(s) that should have failed: $MISSING"
echo "Test(s) that shouldn't have failed: $EXTRA"

if [ -z "$MISSING" ] && [ -z "$EXTRA" ]; then
echo "PASS: Actual failed tests match expected."
# Under WOLFPROV_FORCE_FAIL=1, wolfProvider deliberately errors on
# every call, so the curl test-suite is expected to fail somewhere.
# We just need a non-zero exit code; the exact list of failing test
# numbers will drift across curl versions / suite updates and is not
# worth pinning. If make test-ci returned non-zero, treat as pass.
if [ "$TEST_RESULT" -ne 0 ]; then
echo "PASS: curl tests failed (exit $TEST_RESULT) as expected under WOLFPROV_FORCE_FAIL=1"
exit 0
else
echo "FAIL: Actual failed tests do not match expected."
echo "FAIL: curl tests unexpectedly succeeded under WOLFPROV_FORCE_FAIL=1"
exit 1
fi
# ----- OPENVPN -----
Expand Down
146 changes: 146 additions & 0 deletions .github/workflows/_discover-versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: Discover wolfSSL + OpenSSL versions

on:
workflow_call:
outputs:
wolfssl_ref:
description: 'Plain string, actual wolfSSL version in the wolfprov nonfips .deb on ghcr (e.g. v5.8.4-stable)'
value: ${{ jobs.discover.outputs.wolfssl_ref }}
wolfssl_ref_array:
description: 'JSON array of master + actual .deb wolfssl ref for matrix use'
value: ${{ jobs.discover.outputs.wolfssl_ref_array }}
wolfssl_latest_ref:
description: 'Plain string, latest v*-stable tag upstream wolfssl has'
value: ${{ jobs.discover.outputs.wolfssl_latest_ref }}
wolfssl_latest_ref_array:
description: 'JSON array form: master + latest upstream stable'
value: ${{ jobs.discover.outputs.wolfssl_latest_ref_array }}
openssl_ref:
description: 'Plain string. Bookworm stock OpenSSL (matches the wolfprov .deb).'
value: ${{ jobs.discover.outputs.openssl_ref }}
openssl_ref_array:
description: 'JSON array form of openssl_ref'
value: ${{ jobs.discover.outputs.openssl_ref_array }}
openssl_latest_ref:
description: 'Plain string, latest upstream openssl-3.x.y release tag (e.g. openssl-3.6.2)'
value: ${{ jobs.discover.outputs.openssl_latest_ref }}
openssl_latest_ref_array:
description: 'JSON array form of openssl_latest_ref'
value: ${{ jobs.discover.outputs.openssl_latest_ref_array }}
openssl_all_releases_array:
description: 'JSON array of every upstream openssl-3.X.Y release tag, sorted ascending. Used by openssl-version.yml so the sweep tracks upstream automatically.'
value: ${{ jobs.discover.outputs.openssl_all_releases_array }}

jobs:
discover:
name: Resolve wolfSSL + OpenSSL refs
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
packages: read
outputs:
wolfssl_ref: ${{ steps.resolve.outputs.wolfssl_ref }}
wolfssl_ref_array: ${{ steps.resolve.outputs.wolfssl_ref_array }}
wolfssl_latest_ref: ${{ steps.resolve.outputs.wolfssl_latest_ref }}
wolfssl_latest_ref_array: ${{ steps.resolve.outputs.wolfssl_latest_ref_array }}
openssl_ref: ${{ steps.resolve.outputs.openssl_ref }}
openssl_ref_array: ${{ steps.resolve.outputs.openssl_ref_array }}
openssl_latest_ref: ${{ steps.resolve.outputs.openssl_latest_ref }}
openssl_latest_ref_array: ${{ steps.resolve.outputs.openssl_latest_ref_array }}
openssl_all_releases_array: ${{ steps.resolve.outputs.openssl_all_releases_array }}
steps:
- name: Install ORAS
run: |
set -euo pipefail
ORAS_VERSION="1.2.2"
curl -fsSLO "https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/oras_${ORAS_VERSION}_linux_amd64.tar.gz"
tar xzf "oras_${ORAS_VERSION}_linux_amd64.tar.gz" oras
sudo mv oras /usr/local/bin/oras
rm -f "oras_${ORAS_VERSION}_linux_amd64.tar.gz"
oras version

- name: Login to ghcr.io (best-effort)
continue-on-error: true
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io \
--username "${{ github.actor }}" --password-stdin

- name: Resolve versions
id: resolve
run: |
set -euo pipefail

# wolfSSL: probe the .deb on ghcr.io.
WOLFSSL_DEB_REF=""
PROBE_DIR=$(mktemp -d)
if oras pull ghcr.io/wolfssl/wolfprovider/debs:nonfips -o "$PROBE_DIR" >/dev/null 2>&1; then
DEB_FILE=$(find "$PROBE_DIR" -name 'libwolfssl_*.deb' | head -1)
if [ -n "${DEB_FILE:-}" ]; then
# libwolfssl_5.8.4+commercial.fips.linuxv5.2.4+1_amd64.deb
# -> 5.8.4
VER=$(basename "$DEB_FILE" \
| sed -E 's|^libwolfssl_([0-9]+\.[0-9]+\.[0-9]+).*|\1|')
if [ -n "$VER" ]; then
WOLFSSL_DEB_REF="v${VER}-stable"
fi
fi
fi
rm -rf "$PROBE_DIR"

# wolfSSL: latest upstream -stable tag.
WOLFSSL_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 "${WOLFSSL_LATEST:-}" ]; then
echo "::error::Could not resolve latest wolfSSL -stable tag"
exit 1
fi

# Fall back if the .deb probe failed.
if [ -z "${WOLFSSL_DEB_REF:-}" ]; then
echo "::warning::Could not probe wolfssl version from ghcr .deb; falling back to upstream latest ($WOLFSSL_LATEST). Matrix label may not match the actual installed library."
WOLFSSL_DEB_REF="$WOLFSSL_LATEST"
fi

# OpenSSL: Bookworm stock (matches the wolfprov .deb).
OSSL_RAW=$(docker run --rm debian:bookworm sh -c \
'apt-get update -qq >/dev/null 2>&1 && apt-cache madison openssl | head -1' \
| awk '{print $3}')
if [ -z "${OSSL_RAW:-}" ]; then
echo "::error::Could not resolve Bookworm OpenSSL version"
exit 1
fi
OSSL=$(echo "$OSSL_RAW" | sed 's/-.*//')

# OpenSSL: all upstream release tags >= floor.
# Floor 3.0.6 -- 3.0.3-3.0.5 have an ECX EVP_PKEY_cmp bug.
OSSL_FLOOR="openssl-3.0.6"
OSSL_ALL=$(git ls-remote --tags --refs https://github.com/openssl/openssl.git 'openssl-3.*' \
| awk -F/ '{print $NF}' \
| grep -E '^openssl-3\.[0-9]+\.[0-9]+$' \
| sort -V \
| awk -v floor="$OSSL_FLOOR" '$0 == floor {p=1} p')
if [ -z "${OSSL_ALL:-}" ]; then
echo "::error::Could not resolve upstream OpenSSL release tags (floor=$OSSL_FLOOR)"
exit 1
fi
OSSL_ALL_JSON=$(printf '%s\n' "$OSSL_ALL" | jq -R . | jq -s -c .)
OSSL_LATEST=$(echo "$OSSL_ALL" | tail -n 1)

echo "wolfSSL .deb ref (actual ghcr deb): $WOLFSSL_DEB_REF"
echo "wolfSSL upstream latest -stable: $WOLFSSL_LATEST"
echo "OpenSSL Bookworm stock: openssl-$OSSL (raw: $OSSL_RAW)"
echo "OpenSSL upstream latest: $OSSL_LATEST"
echo "OpenSSL upstream releases tracked: $(echo "$OSSL_ALL" | wc -l) tags"

{
echo "wolfssl_ref=$WOLFSSL_DEB_REF"
echo "wolfssl_ref_array=[\"master\",\"$WOLFSSL_DEB_REF\"]"
echo "wolfssl_latest_ref=$WOLFSSL_LATEST"
echo "wolfssl_latest_ref_array=[\"master\",\"$WOLFSSL_LATEST\"]"
echo "openssl_ref=openssl-$OSSL"
echo "openssl_ref_array=[\"openssl-$OSSL\"]"
echo "openssl_latest_ref=$OSSL_LATEST"
echo "openssl_latest_ref_array=[\"$OSSL_LATEST\"]"
echo "openssl_all_releases_array=$OSSL_ALL_JSON"
} >> "$GITHUB_OUTPUT"
42 changes: 15 additions & 27 deletions .github/workflows/bind9.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,45 @@
name: Bind9 Tests

# START OF COMMON SECTION
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# END OF COMMON SECTION
on:
workflow_call: {}
workflow_dispatch: {}

jobs:
discover_versions:
uses: ./.github/workflows/_discover-versions.yml

build_wolfprovider:
needs: discover_versions
uses: ./.github/workflows/build-wolfprovider.yml
with:
wolfssl_ref: ${{ matrix.wolfssl_ref }}
openssl_ref: ${{ matrix.openssl_ref }}
fips_ref: ${{ matrix.fips_ref }}
replace_default: ${{ matrix.replace_default }}
strategy:
fail-fast: false
matrix:
wolfssl_ref: [ 'v5.8.4-stable' ]
openssl_ref: [ 'openssl-3.5.4' ]
wolfssl_ref: ${{ fromJson(needs.discover_versions.outputs.wolfssl_ref_array) }}
openssl_ref: ${{ fromJson(needs.discover_versions.outputs.openssl_ref_array) }}
fips_ref: [ 'FIPS', 'non-FIPS' ]
replace_default: [ true ]

test_bind:
runs-on: ubuntu-22.04
needs: build_wolfprovider
needs: [build_wolfprovider, discover_versions]
container:
image: debian:bookworm
image: ghcr.io/wolfssl/wolfprovider-test-deps:bookworm
env:
DEBIAN_FRONTEND: noninteractive
# This should be a safe limit for the tests to run.
timeout-minutes: 20
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
bind_ref: [ 'v9.18.28' ]
wolfssl_ref: [ 'v5.8.4-stable' ]
openssl_ref: [ 'openssl-3.5.4' ]
wolfssl_ref: ${{ fromJson(needs.discover_versions.outputs.wolfssl_ref_array) }}
openssl_ref: ${{ fromJson(needs.discover_versions.outputs.openssl_ref_array) }}
fips_ref: [ 'FIPS', 'non-FIPS' ]
force_fail: ['WOLFPROV_FORCE_FAIL=1', '']
replace_default: [ true ]
Expand Down Expand Up @@ -85,16 +83,6 @@ jobs:
${{ matrix.replace_default && '--replace-default' || '' }} \
${{ matrix.fips_ref == 'FIPS' && '--fips' || '' }}

- name: Install bind9 test dependencies
run: |
apt-get update
apt install -y build-essential automake libtool gnutls-bin \
pkg-config make libidn2-dev libuv1-dev libnghttp2-dev libcap-dev \
libjemalloc-dev zlib1g-dev libxml2-dev libjson-c-dev libcmocka-dev \
python3-pytest python3-dnspython python3-hypothesis patch iproute2 \
net-tools git
PERL_MM_USE_DEFAULT=1 cpan -i Net::DNS

- name: Checkout bind9
uses: actions/checkout@v4
with:
Expand Down
Loading
Loading