diff --git a/.github/actions/build-wolfssl/action.yml b/.github/actions/build-wolfssl/action.yml new file mode 100644 index 000000000..2788764a7 --- /dev/null +++ b/.github/actions/build-wolfssl/action.yml @@ -0,0 +1,92 @@ +name: 'Build wolfSSL' +description: > + Clone, build, cache and install wolfSSL (autotools) into /usr/local. + The build is keyed on the live wolfssl master commit plus the requested + configure options, so it is rebuilt only when wolfssl master advances or + the options change. Caches created on master are readable by pull-request + jobs, so PRs typically get an instant cache hit. + +inputs: + config: + description: 'wolfSSL configure options' + required: false + default: '--enable-enckeys' + cflags: + description: 'Extra CFLAGS for the wolfSSL build' + required: false + default: '' + cc: + description: 'CC override, e.g. "gcc -fsanitize=address" (empty = default)' + required: false + default: '' + +runs: + using: 'composite' + steps: + - name: Resolve wolfSSL master revision and cache key + id: rev + shell: bash + run: | + set -e + sha=$(git ls-remote https://github.com/wolfssl/wolfssl refs/heads/master | cut -f1) + if [ -z "$sha" ]; then + echo "ERROR: failed to resolve wolfssl master SHA" >&2 + exit 1 + fi + echo "sha=$sha" >> "$GITHUB_OUTPUT" + # Key on the specific runner image (e.g. ubuntu22 vs ubuntu24) not + # just the OS, so a binary built against a newer glibc is not + # restored onto an older image. Falls back to runner.os if unset. + echo "image=${ImageOS:-${{ runner.os }}}" >> "$GITHUB_OUTPUT" + # Hash the build options so different configs do not share a cache. + # sha256sum is absent on some runners (e.g. macOS); fall back to shasum. + opts="${{ inputs.config }}|${{ inputs.cflags }}|${{ inputs.cc }}" + if command -v sha256sum >/dev/null 2>&1; then + optkey=$(printf '%s' "$opts" | sha256sum | cut -c1-12) + else + optkey=$(printf '%s' "$opts" | shasum -a 256 | cut -c1-12) + fi + echo "optkey=$optkey" >> "$GITHUB_OUTPUT" + + - name: Cache wolfSSL + id: cache + uses: actions/cache@v4 + with: + path: ~/wolfssl-install + key: wolfssl-${{ steps.rev.outputs.image }}-${{ steps.rev.outputs.sha }}-${{ steps.rev.outputs.optkey }} + + - name: Build wolfSSL + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + run: | + set -e + cd "$HOME" + rm -rf wolfssl-src + mkdir wolfssl-src + cd wolfssl-src + # Check out the exact commit the cache key was computed from, so the + # artifact saved under that key matches even if master advanced + # between resolving the SHA and cloning. + git init -q + git remote add origin https://github.com/wolfssl/wolfssl.git + git fetch -q --depth 1 origin "${{ steps.rev.outputs.sha }}" + git checkout -q FETCH_HEAD + ./autogen.sh + jobs=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2) + if [ -n "${{ inputs.cc }}" ]; then + ./configure --prefix="$HOME/wolfssl-install" ${{ inputs.config }} \ + CC="${{ inputs.cc }}" CFLAGS="${{ inputs.cflags }}" + else + ./configure --prefix="$HOME/wolfssl-install" ${{ inputs.config }} \ + CFLAGS="${{ inputs.cflags }}" + fi + make -j"$jobs" + make install + + - name: Install wolfSSL into /usr/local + shell: bash + run: | + set -e + sudo cp -a "$HOME/wolfssl-install/." /usr/local/ + # ldconfig is Linux-only; macOS resolves via the cached prefix path. + sudo ldconfig || true diff --git a/.github/workflows/broker-check.yml b/.github/workflows/broker-check.yml index 14e3cf672..53b8171a5 100644 --- a/.github/workflows/broker-check.yml +++ b/.github/workflows/broker-check.yml @@ -6,9 +6,39 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: + # Build wolfSSL once per distinct configuration and populate the shared + # cache. The matrix below covers every wolfssl_opts value used by the + # broker build matrix. The build jobs `needs:` this job, so by the time + # they run the cache is warm and each restores instead of rebuilding -- + # turning ~17 wolfSSL builds per run into 3, even on the first run. + wolfssl: + name: "Build wolfSSL (${{ matrix.label }})" + runs-on: ubuntu-22.04 + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + include: + - label: "enckeys" + config: "--enable-enckeys" + - label: "opensslcoexist" + config: "--enable-opensslcoexist" + - label: "opensslcoexist+enckeys" + config: "--enable-opensslcoexist --enable-enckeys" + steps: + - uses: actions/checkout@v4 + - name: Build and cache wolfSSL + uses: ./.github/actions/build-wolfssl + with: + config: ${{ matrix.config }} + build: + needs: wolfssl runs-on: ubuntu-22.04 timeout-minutes: 5 @@ -48,21 +78,14 @@ jobs: extra_deps: "libwebsockets-dev" wolfssl_opts: "--enable-opensslcoexist --enable-enckeys" # Maximum-QoS matrix. WOLFMQTT_MAX_QOS=2 is the default and runs - # the full broker.test. =1 and =0 caps compile out the QoS 2 - # state machine; broker.test exercises QoS 2 pub/sub (tests 3 - # and 11) which is intentionally rejected on capped builds, so - # those entries are build-only. + # the full broker.test. The =1 and =0 caps are build-only (they + # compile out the QoS 2 state machine, which broker.test + # intentionally exercises); their compile coverage is provided by + # cmake-build.yml's WOLFMQTT_MAX_QOS matrix, so they are not + # duplicated here. - name: "Broker MAX_QOS=2 (default, full QoS)" cflags: "" wolfmqtt_opts: "--enable-v5 --enable-broker --enable-max-qos=2" - - name: "Broker MAX_QOS=1 (build only)" - cflags: "" - wolfmqtt_opts: "--enable-v5 --enable-broker --enable-max-qos=1" - skip_broker_test: "yes" - - name: "Broker MAX_QOS=0 (build only)" - cflags: "" - wolfmqtt_opts: "--enable-v5 --enable-broker --enable-max-qos=0" - skip_broker_test: "yes" - name: "Broker v5 (ordering / Receive Maximum)" cflags: "" wolfmqtt_opts: "--enable-broker --enable-v5" @@ -92,24 +115,13 @@ jobs: sudo apt-get update sudo apt-get install -y mosquitto-clients ${{ matrix.extra_deps }} - - uses: actions/checkout@master + - uses: actions/checkout@v4 + + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure - working-directory: ./wolfssl - run: ./configure ${{ matrix.wolfssl_opts || '--enable-enckeys' }} - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install + config: ${{ matrix.wolfssl_opts || '--enable-enckeys' }} - - uses: actions/checkout@master - name: wolfmqtt autogen run: ./autogen.sh diff --git a/.github/workflows/cmake-build.yml b/.github/workflows/cmake-build.yml index b49a8f5d9..6f7769c92 100644 --- a/.github/workflows/cmake-build.yml +++ b/.github/workflows/cmake-build.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: @@ -34,22 +38,45 @@ jobs: sudo apt-get update sudo apt-get install -y cmake -#pull and build wolfssl - - uses: actions/checkout@master +#pull and build wolfssl (cached, keyed on the live wolfssl master commit) + - name: Resolve wolfSSL master SHA + id: wolfssl-sha + run: | + set -e + sha=$(git ls-remote https://github.com/wolfssl/wolfssl refs/heads/master | cut -f1) + if [ -z "$sha" ]; then echo "ERROR: failed to resolve wolfssl master SHA" >&2; exit 1; fi + echo "sha=$sha" >> "$GITHUB_OUTPUT" + + - name: Cache wolfSSL + id: cache-wolfssl + uses: actions/cache@v4 + with: + path: ~/wolfssl-install + key: wolfssl-cmake-${{ steps.wolfssl-sha.outputs.sha }} + + - uses: actions/checkout@v4 + if: steps.cache-wolfssl.outputs.cache-hit != 'true' with: repository: wolfssl/wolfssl path: wolfssl + ref: ${{ steps.wolfssl-sha.outputs.sha }} - name: Build wolfssl + if: steps.cache-wolfssl.outputs.cache-hit != 'true' working-directory: ./wolfssl run: | mkdir build cd build - cmake .. + cmake -DCMAKE_INSTALL_PREFIX=$HOME/wolfssl-install .. cmake --build . - sudo cmake --install . + cmake --install . + + - name: Install wolfSSL into /usr/local + run: | + sudo cp -a $HOME/wolfssl-install/. /usr/local/ + sudo ldconfig #pull wolfMQTT - - uses: actions/checkout@master + - uses: actions/checkout@v4 #build wolfMQTT - name: "Build wolfMQTT (${{ matrix.name }})" diff --git a/.github/workflows/docker-Espressif.yml b/.github/workflows/docker-Espressif.yml index ab50c625b..69eb0a55d 100644 --- a/.github/workflows/docker-Espressif.yml +++ b/.github/workflows/docker-Espressif.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: espressif_latest: name: latest Docker container diff --git a/.github/workflows/fsanitize-check.yml b/.github/workflows/fsanitize-check.yml index f10d138c5..f48b4d06f 100644 --- a/.github/workflows/fsanitize-check.yml +++ b/.github/workflows/fsanitize-check.yml @@ -6,11 +6,16 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-22.04 - timeout-minutes: 5 + # 10 min: runs 5 configure/make/make-check cycles under ASan. + timeout-minutes: 10 env: WOLFMQTT_NO_EXTERNAL_BROKER_TESTS: 1 @@ -36,23 +41,13 @@ jobs: sudo route sudo netstat -tulpan - - uses: actions/checkout@master + - uses: actions/checkout@v4 + + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure - working-directory: ./wolfssl - run: ./configure --enable-enckeys - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install - - uses: actions/checkout@master + config: "--enable-enckeys" + - name: autogen run: ./autogen.sh diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 1acd0377c..00659119f 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -2,7 +2,7 @@ name: Fuzz Testing on: schedule: - - cron: '0 4 * * 1' # Weekly Monday 4am UTC + - cron: '0 4 * * *' # Nightly 4am UTC workflow_dispatch: # Manual trigger pull_request: branches: [ '*' ] @@ -15,7 +15,7 @@ jobs: fail-fast: false matrix: include: - # Full fuzz run (weekly/manual) - 10 minutes + # Full fuzz run (nightly/manual) - 10 minutes - name: fuzz-full fuzz_time: 600 smoke_only: false @@ -32,7 +32,7 @@ jobs: run: sudo sysctl vm.mmap_rnd_bits=28 - name: Run fuzzer - if: ${{ !matrix.smoke_only || github.event_name == 'pull_request' }} + if: ${{ (matrix.smoke_only && github.event_name == 'pull_request') || (!matrix.smoke_only && github.event_name != 'pull_request') }} run: ./scripts/fuzz.sh ${{ matrix.fuzz_time }} - name: Upload crash artifacts diff --git a/.github/workflows/macos-check.yml b/.github/workflows/macos-check.yml index 1675ad27a..9b043ec86 100644 --- a/.github/workflows/macos-check.yml +++ b/.github/workflows/macos-check.yml @@ -9,6 +9,10 @@ on: env: WOLFMQTT_NO_EXTERNAL_BROKER_TESTS: 1 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: @@ -16,26 +20,49 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@master + + - name: Resolve wolfSSL master SHA + id: wolfssl-sha + run: | + set -e + sha=$(git ls-remote https://github.com/wolfssl/wolfssl refs/heads/master | cut -f1) + if [ -z "$sha" ]; then echo "ERROR: failed to resolve wolfssl master SHA" >&2; exit 1; fi + echo "sha=$sha" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@master with: repository: wolfssl/wolfssl path: wolfssl + ref: ${{ steps.wolfssl-sha.outputs.sha }} - name: brew run: | brew install automake libtool mosquitto coreutils echo "/usr/local/sbin/" >> $GITHUB_PATH echo "/usr/local/opt/mosquitto/sbin/" >> $GITHUB_PATH + # Cache the wolfSSL install (prefix build-dir) keyed on the live + # wolfssl master commit, so it is rebuilt only when master advances. + - name: Cache wolfSSL + id: cache-wolfssl + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/build-dir + key: wolfssl-macos-${{ steps.wolfssl-sha.outputs.sha }}-enckeys + - name: wolfssl autogen + if: steps.cache-wolfssl.outputs.cache-hit != 'true' working-directory: ./wolfssl run: ./autogen.sh - name: wolfssl configure + if: steps.cache-wolfssl.outputs.cache-hit != 'true' working-directory: ./wolfssl run: ./configure --enable-enckeys --prefix=$GITHUB_WORKSPACE/build-dir - name: wolfssl make + if: steps.cache-wolfssl.outputs.cache-hit != 'true' working-directory: ./wolfssl run: make - name: wolfssl make install + if: steps.cache-wolfssl.outputs.cache-hit != 'true' working-directory: ./wolfssl run: make install diff --git a/.github/workflows/mqtt-sn-check.yml b/.github/workflows/mqtt-sn-check.yml index e2c1f4c09..d29fd5d4d 100644 --- a/.github/workflows/mqtt-sn-check.yml +++ b/.github/workflows/mqtt-sn-check.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: @@ -59,24 +63,13 @@ jobs: sudo route sudo netstat -tulpan - - uses: actions/checkout@master + - uses: actions/checkout@v4 + + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure - working-directory: ./wolfssl - run: ./configure --enable-enckeys - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install + config: "--enable-enckeys" - - uses: actions/checkout@master - name: wolfmqtt autogen run: ./autogen.sh diff --git a/.github/workflows/multi-compiler.yml b/.github/workflows/multi-compiler.yml index 90a3b9997..95e29857c 100644 --- a/.github/workflows/multi-compiler.yml +++ b/.github/workflows/multi-compiler.yml @@ -18,12 +18,12 @@ jobs: strategy: fail-fast: false matrix: + # Range endpoints of each compiler family; the middle versions + # (gcc-12, clang-15) rarely surface anything the endpoints miss. include: - cc: gcc-11 - - cc: gcc-12 - cc: gcc-13 - cc: clang-14 - - cc: clang-15 - cc: clang-17 steps: @@ -34,28 +34,10 @@ jobs: sudo apt-get update sudo apt-get install -y ${{ matrix.cc }} autoconf automake libtool - - name: Cache wolfSSL - id: cache-wolfssl - uses: actions/cache@v4 + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - path: ~/wolfssl-install - key: wolfssl-ubuntu-latest-v2 - - - name: Build wolfSSL - if: steps.cache-wolfssl.outputs.cache-hit != 'true' - run: | - cd ~ - git clone --depth 1 https://github.com/wolfssl/wolfssl.git - cd wolfssl - ./autogen.sh - ./configure --enable-enckeys --prefix=$HOME/wolfssl-install - make -j$(nproc) - make install - - - name: Install wolfSSL - run: | - echo "$HOME/wolfssl-install/lib" | sudo tee /etc/ld.so.conf.d/wolfssl.conf - sudo ldconfig + config: "--enable-enckeys" - name: autogen run: ./autogen.sh diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 570791765..28e78ceae 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -20,13 +20,13 @@ jobs: strategy: fail-fast: false matrix: + # AddressSanitizer already performs leak detection at exit, so a + # standalone LeakSanitizer job would be largely redundant. include: - name: "ASan" sanitizer_flags: "-fsanitize=address" - name: "UBSan" sanitizer_flags: "-fsanitize=undefined -fno-sanitize-recover=all" - - name: "LeakSan" - sanitizer_flags: "-fsanitize=leak" steps: - name: Workaround high-entropy ASLR @@ -43,35 +43,22 @@ jobs: sudo service mosquitto stop sleep 1 - - name: Checkout wolfSSL - uses: actions/checkout@v4 - with: - repository: wolfssl/wolfssl - path: wolfssl - - - name: Build wolfSSL with ${{ matrix.name }} - working-directory: ./wolfssl - run: | - ./autogen.sh - ./configure CC="gcc ${{ matrix.sanitizer_flags }}" --enable-enckeys - make -j$(nproc) - sudo make install - sudo ldconfig - - name: Checkout wolfMQTT uses: actions/checkout@v4 + + - name: Build and install wolfSSL with ${{ matrix.name }} + uses: ./.github/actions/build-wolfssl with: - path: wolfmqtt + config: "--enable-enckeys" + cc: "gcc ${{ matrix.sanitizer_flags }}" - name: Build wolfMQTT with ${{ matrix.name }} - working-directory: ./wolfmqtt run: | ./autogen.sh ./configure CC="gcc ${{ matrix.sanitizer_flags }}" make -j$(nproc) - name: Run tests - working-directory: ./wolfmqtt run: make check - name: Upload failure logs @@ -80,7 +67,7 @@ jobs: with: name: wolfmqtt-${{ matrix.name }}-logs path: | - wolfmqtt/test-suite.log - wolfmqtt/scripts/*.log - wolfmqtt/config.log + test-suite.log + scripts/*.log + config.log retention-days: 5 diff --git a/.github/workflows/sec-websocket-test.yml b/.github/workflows/sec-websocket-test.yml index 5da4e0fd9..1a6f06217 100644 --- a/.github/workflows/sec-websocket-test.yml +++ b/.github/workflows/sec-websocket-test.yml @@ -8,6 +8,10 @@ on: branches: [ main, master ] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test-websocket: runs-on: ubuntu-latest diff --git a/.github/workflows/threadx.yml b/.github/workflows/threadx.yml index f700334f4..bd8a02993 100644 --- a/.github/workflows/threadx.yml +++ b/.github/workflows/threadx.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: diff --git a/.github/workflows/ubuntu-check-curl.yml b/.github/workflows/ubuntu-check-curl.yml index 860b9195d..e84ae9089 100644 --- a/.github/workflows/ubuntu-check-curl.yml +++ b/.github/workflows/ubuntu-check-curl.yml @@ -6,11 +6,16 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-22.04 - timeout-minutes: 5 + # 10 min: runs 4 configure/make/make-check cycles plus a curl build. + timeout-minutes: 10 # Serialize with every other workflow that runs awsiot.test against # AWS IoT under the hard-coded "demoDevice" client ID. Without this, # parallel runs from sibling workflows clobber each other's MQTT @@ -41,24 +46,14 @@ jobs: sudo route sudo netstat -tulpan - - uses: actions/checkout@master + - uses: actions/checkout@v4 + + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure - working-directory: ./wolfssl - run: ./configure --enable-curl - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install + config: "--enable-curl" - - uses: actions/checkout@master + - uses: actions/checkout@v4 with: repository: curl/curl path: curl @@ -75,7 +70,6 @@ jobs: working-directory: ./curl run: sudo make install - - uses: actions/checkout@master - name: wolfmqtt autogen run: ./autogen.sh diff --git a/.github/workflows/ubuntu-check.yml b/.github/workflows/ubuntu-check.yml index 19ad58bce..41dbd3cff 100644 --- a/.github/workflows/ubuntu-check.yml +++ b/.github/workflows/ubuntu-check.yml @@ -6,11 +6,17 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-22.04 - timeout-minutes: 5 + # 10 min: this job runs 7 full configure/make/make-check cycles + # (incl. a slow stress build); 5 min intermittently times out. + timeout-minutes: 10 # Serialize across all workflows that exercise the hard-coded # "demoDevice" MQTT client ID against AWS IoT. Parallel runs from # different workflows (ubuntu-check, ubuntu-check-curl, this file's @@ -42,24 +48,13 @@ jobs: sudo route sudo netstat -tulpan - - uses: actions/checkout@master + - uses: actions/checkout@v4 + + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure - working-directory: ./wolfssl - run: ./configure --enable-enckeys - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install + config: "--enable-enckeys" - - uses: actions/checkout@master - name: wolfmqtt autogen run: ./autogen.sh @@ -163,7 +158,9 @@ jobs: # WOLFSSL_NO_ASN_STRICT. The strict callback rejects the # unanchored chain. Expect FAIL. runs-on: ubuntu-22.04 - timeout-minutes: 10 + # Headroom for two (uncached) wolfSSL builds plus the awsiot.test + # transient-failure retry backoff. + timeout-minutes: 15 steps: - name: Install dependencies run: | @@ -175,25 +172,17 @@ jobs: sudo service mosquitto stop sleep 1 + # Check out wolfMQTT first so the local build-wolfssl action is + # available and so its source tree survives the wolfSSL rebuild + # (the action clones wolfSSL under $HOME, not the workspace). + - uses: actions/checkout@v4 + # --- case 1: wolfSSL built with DEFAULT strict ASN parsing --- - - uses: actions/checkout@master + - name: Build and install wolfSSL (strict ASN default) + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen (strict ASN default) - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure (strict ASN default) - working-directory: ./wolfssl - run: ./configure --enable-enckeys - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install + config: "--enable-enckeys" - - uses: actions/checkout@master - name: wolfmqtt autogen run: ./autogen.sh - name: case 1 - wolfmqtt configure (default bundle, strict ASN) @@ -204,26 +193,13 @@ jobs: run: ./scripts/awsiot.test # --- cases 2 + 3: wolfSSL rebuilt with WOLFSSL_NO_ASN_STRICT --- - # The wolfmqtt checkout above wiped the workspace, so the wolfssl - # source tree is gone even though /usr/local/lib/libwolfssl.* is - # still installed. Re-checkout to get a fresh source tree for the - # NO_ASN_STRICT rebuild. - - uses: actions/checkout@master + # The action reinstalls over /usr/local with the NO_ASN_STRICT build + # (separate cache key from the strict build above). + - name: Build and install wolfSSL (WOLFSSL_NO_ASN_STRICT) + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen (NO_ASN_STRICT build) - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure with -DWOLFSSL_NO_ASN_STRICT - working-directory: ./wolfssl - run: ./configure --enable-enckeys CFLAGS=-DWOLFSSL_NO_ASN_STRICT - - name: wolfssl rebuild - working-directory: ./wolfssl - run: make - - name: wolfssl reinstall - working-directory: ./wolfssl - run: sudo make install + config: "--enable-enckeys" + cflags: "-DWOLFSSL_NO_ASN_STRICT" - name: case 2 - wolfmqtt configure (default bundle, WOLFSSL_NO_ASN_STRICT) run: | @@ -242,6 +218,10 @@ jobs: - name: case 3 - wolfmqtt make run: make - name: case 3 - awsiot.test expect FAIL + # Expected to fail (legacy trust anchor rejected), so disable the + # transient-failure retry to keep the job fast. + env: + AWSIOT_RETRIES: 1 run: | if ./scripts/awsiot.test; then echo "case 3 unexpectedly PASSED - legacy VeriSign should not verify AWS IoT chain" diff --git a/.github/workflows/websocket-test.yml b/.github/workflows/websocket-test.yml index c637c86f9..a9d2a20ba 100644 --- a/.github/workflows/websocket-test.yml +++ b/.github/workflows/websocket-test.yml @@ -7,6 +7,10 @@ on: branches: [ main, master ] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test-websocket: runs-on: ubuntu-latest @@ -21,26 +25,10 @@ jobs: sudo apt-get install -y build-essential autoconf automake libtool sudo apt-get install -y libwebsockets-dev mosquitto mosquitto-clients - - uses: actions/checkout@master + - name: Build and install wolfSSL + uses: ./.github/actions/build-wolfssl with: - repository: wolfssl/wolfssl - path: wolfssl - - name: wolfssl autogen - working-directory: ./wolfssl - run: ./autogen.sh - - name: wolfssl configure with coexist for default libwebsocket - working-directory: ./wolfssl - run: ./configure --enable-opensslcoexist - - name: wolfssl make - working-directory: ./wolfssl - run: make - - name: wolfssl make install - working-directory: ./wolfssl - run: sudo make install - - - uses: actions/checkout@master - - name: wolfmqtt autogen - run: ./autogen.sh + config: "--enable-opensslcoexist" - name: Configure and build wolfMQTT run: | diff --git a/.github/workflows/windows-check.yml b/.github/workflows/windows-check.yml index 5b9bed0e5..6599df33e 100644 --- a/.github/workflows/windows-check.yml +++ b/.github/workflows/windows-check.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: # Path to the solution file relative to the root of the project. WOLFSSL_SOLUTION_FILE_PATH: wolfssl/wolfssl64.sln diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 8d7f351ee..babb2f69c 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -9,6 +9,10 @@ on: pull_request: branches: [ '*' ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: run_test: name: Build and run diff --git a/scripts/awsiot.test b/scripts/awsiot.test index ec65c8122..106a3e5d9 100755 --- a/scripts/awsiot.test +++ b/scripts/awsiot.test @@ -2,6 +2,16 @@ # AWS IoT Client test +# This test connects to a live AWS IoT endpoint using the hard-coded +# "demoDevice" client ID. Rapid sequential connects (and parallel runs from +# sibling CI jobs) can collide on that client ID, producing transient +# "Network (-8)" errors. To absorb those without masking real failures, each +# connection attempt is retried up to AWSIOT_RETRIES times with a backoff. A +# genuine trust-anchor/verification failure fails on every attempt, so the +# retries cannot hide a real regression. +AWSIOT_RETRIES=${AWSIOT_RETRIES:-3} +AWSIOT_RETRY_DELAY=${AWSIOT_RETRY_DELAY:-5} + # Check for application [ ! -x ./examples/aws/awsiot ] && echo -e "\n\nAWS IoT MQTT Client doesn't exist" && exit 1 @@ -12,17 +22,42 @@ if [ $? -eq 0 ]; then has_tls=yes fi -if test -n "$WOLFMQTT_NO_EXTERNAL_BROKER_TESTS" && test $has_tls == yes; then +# Run the AWS IoT client, retrying on transient failures. +run_awsiot() { + attempt=1 + while true; do + ./examples/aws/awsiot "$@" + rc=$? + if [ $rc -eq 0 ]; then + return 0 + fi + if [ $attempt -ge $AWSIOT_RETRIES ]; then + return $rc + fi + # Linear backoff: wait longer after each failure to give AWS IoT + # time to drop the prior same-client-ID session. + backoff=$((attempt * AWSIOT_RETRY_DELAY)) + echo -e "\nAWS IoT attempt $attempt failed (rc=$rc), retrying in ${backoff}s..." + sleep $backoff + attempt=$((attempt + 1)) + done +} + +if test -n "$WOLFMQTT_NO_EXTERNAL_BROKER_TESTS" || test "$has_tls" != "yes"; then echo "WOLFMQTT_NO_EXTERNAL_BROKER_TESTS set or no TLS, won't run" else def_args="-T -C 2000" # Run with TLS and QoS 0-1 - ./examples/aws/awsiot $def_args -t -q 0 $1 + run_awsiot $def_args -t -q 0 $1 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\n\nAWS IoT MQTT Client failed! TLS=On, QoS=0" && exit 1 - ./examples/aws/awsiot $def_args -t -q 1 $1 + # Settle so AWS IoT fully tears down the prior "demoDevice" session + # before the next connect with the same client ID. + sleep $AWSIOT_RETRY_DELAY + + run_awsiot $def_args -t -q 1 $1 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\n\nAWS IoT MQTT Client failed! TLS=On, QoS=1" && exit 1