From 5bc87d6556abc585713f9a3fc834f2917e71ae3f Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 16 Mar 2022 10:39:08 -0700 Subject: [PATCH 01/13] Workflow's for syncing with upstream, build, unit test, and test-runner --- .github/workflows/ci.yml | 236 +++++++++++++++++++++++++++ .github/workflows/pw-to-pr-email.txt | 16 ++ .github/workflows/pw-to-pr.json | 14 ++ .github/workflows/schedule_work.yml | 43 +++++ 4 files changed, 309 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/pw-to-pr-email.txt create mode 100644 .github/workflows/pw-to-pr.json create mode 100644 .github/workflows/schedule_work.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..8e140ad8c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,236 @@ +name: IWD CI + +# +# The basic flow of the CI is as follows: +# +# 1. Get all inputs, or default values, and set as 'setup' job output +# 2. Find any cached binaries (hostapd, wpa_supplicant, kernel etc) +# 3. Checkout all dependent repositories +# 4. Tar all local files. This is an unfortunate requirement since github jobs +# cannot share local files. Since there are multiple CI's acting on the same +# set of repositories it makes more sense to retain these and re-download +# them for each CI job. +# 5. Run each CI, currently 'main' and 'musl'. +# * 'main' is the default IWD CI which runs all the build steps as well +# as test-runner +# * 'musl' uses an alpine docker image to test the build on musl-libc +# +# Both CI's use the 'iwd-ci-v2' repo which calls into 'ci-docker'. The +# 'ci-docker' action essentially re-implements the native Github docker +# action but allows arbitrary options to be passed in (e.g. privileged or +# mounting non-standard directories) +# + +on: + pull_request: + workflow_dispatch: + inputs: + tests: + description: Tests to run (comma separated, no spaces) + default: all + kernel: + description: Kernel version + default: '5.16' + hostapd_version: + description: Hostapd and wpa_supplicant version + default: '2_10' + ell_ref: + description: ELL reference + default: refs/heads/workflow + + repository_dispatch: + types: [ell-dispatch] + +jobs: + setup: + runs-on: ubuntu-22.04 + outputs: + tests: ${{ steps.inputs.outputs.tests }} + kernel: ${{ steps.inputs.outputs.kernel }} + hostapd_version: ${{ steps.inputs.outputs.hostapd_version }} + ell_ref: ${{ steps.inputs.outputs.ell_ref }} + repository: ${{ steps.inputs.outputs.repository }} + ref_branch: ${{ steps.inputs.outputs.ref_branch }} + steps: + # + # This makes CI inputs consistent depending on how the CI was invoked: + # * pull_request trigger won't have any inputs, so these need to be set + # to default values. + # * workflow_dispatch sets all inputs from the user input + # * repository_dispatch sets all inputs based on the JSON payload of + # the request. + # + - name: Setup Inputs + id: inputs + run: | + if [ ${{ github.event_name }} == 'workflow_dispatch' ] + then + TESTS=${{ github.event.inputs.tests }} + KERNEL=${{ github.event.inputs.kernel }} + HOSTAPD_VERSION=${{ github.event.inputs.hostapd_version }} + ELL_REF=${{ github.event.inputs.ell_ref }} + REF="$GITHUB_REF" + REPO="$GITHUB_REPOSITORY" + elif [ ${{ github.event_name }} == 'repository_dispatch' ] + then + TESTS=all + KERNEL=5.16 + HOSTAPD_VERSION=2_10 + ELL_REF=${{ github.event.client_payload.ref }} + REF=$ELL_REF + REPO=${{ github.event.client_payload.repo }} + else + TESTS=all + KERNEL=5.16 + HOSTAPD_VERSION=2_10 + ELL_REF="refs/heads/workflow" + REF="$GITHUB_REF" + REPO="$GITHUB_REPOSITORY" + fi + + # + # Now that the inputs are sorted, set the output of this step to these + # values so future jobs can refer to them. + # + echo ::set-output name=tests::$TESTS + echo ::set-output name=kernel::$KERNEL + echo ::set-output name=hostapd_version::$HOSTAPD_VERSION + echo ::set-output name=ell_ref::$ELL_REF + echo ::set-output name=repository::$REPO + echo ::set-output name=ref_branch::$REF + + - name: Cache UML Kernel + id: cache-uml-kernel + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/cache/um-linux-${{ steps.inputs.outputs.kernel }} + key: um-linux-${{ steps.inputs.outputs.kernel }}_ubuntu22 + + - name: Cache Hostapd + id: cache-hostapd + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/hostapd_${{ steps.inputs.outputs.hostapd_version }} + ${{ github.workspace }}/cache/hostapd_cli_${{ steps.inputs.outputs.hostapd_version }} + key: hostapd_${{ steps.inputs.outputs.hostapd_version }}_ssl3 + + - name: Cache WpaSupplicant + id: cache-wpas + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }} + ${{ github.workspace }}/cache/wpa_cli_${{ steps.inputs.outputs.hostapd_version }} + key: wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }}_ssl3 + + - name: Checkout IWD + uses: actions/checkout@v3 + with: + path: iwd + repository: IWDTestBot/iwd + token: ${{ secrets.ACTION_TOKEN }} + + - name: Checkout ELL + uses: actions/checkout@v3 + with: + path: ell + repository: IWDTestBot/ell + ref: ${{ steps.inputs.outputs.ell_ref }} + + - name: Checkout CiBase + uses: actions/checkout@v3 + with: + repository: IWDTestBot/cibase + path: cibase + + - name: Checkout CI + uses: actions/checkout@v3 + with: + repository: IWDTestBot/iwd-ci-v2 + path: iwd-ci + + - name: Tar files + run: | + tar -cvf archive.tar \ + ${{ github.workspace }}/cache/um-linux-${{ steps.inputs.outputs.kernel }} \ + ${{ github.workspace }}/cache/hostapd_${{ steps.inputs.outputs.hostapd_version }} \ + ${{ github.workspace }}/cache/hostapd_cli_${{ steps.inputs.outputs.hostapd_version }} \ + ${{ github.workspace }}/cache/wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }} \ + ${{ github.workspace }}/cache/wpa_cli_${{ steps.inputs.outputs.hostapd_version }} \ + iwd \ + ell \ + cibase \ + iwd-ci \ + cache + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: iwd-artifacts + path: | + archive.tar + + iwd-alpine-ci: + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: iwd-artifacts + + - name: Untar + run: tar -xf archive.tar + + - name: Modprobe pkcs8_key_parser + run: | + sudo modprobe pkcs8_key_parser + + - name: Alpine CI + uses: IWDTestBot/iwd-ci-v2@master + with: + ref_branch: ${{ needs.setup.outputs.ref_branch }} + repository: ${{ needs.setup.outputs.repository }} + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + ci: musl + + iwd-ci: + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: iwd-artifacts + + - name: Untar + run: tar -xf archive.tar + + - name: Modprobe pkcs8_key_parser + run: | + sudo modprobe pkcs8_key_parser + echo ${{ needs.setup.outputs.ref_branch }} + echo ${{ needs.setup.outputs.repository }} + + - name: Run CI + uses: IWDTestBot/iwd-ci-v2@master + with: + ref_branch: ${{ needs.setup.outputs.ref_branch }} + repository: ${{ needs.setup.outputs.repository }} + tests: ${{ needs.setup.outputs.tests }} + kernel: ${{ needs.setup.outputs.kernel }} + hostapd_version: ${{ needs.setup.outputs.hostapd_version }} + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + ci: main + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-runner-logs + path: ${{ github.workspace }}/log diff --git a/.github/workflows/pw-to-pr-email.txt b/.github/workflows/pw-to-pr-email.txt new file mode 100644 index 000000000..0ad6d7659 --- /dev/null +++ b/.github/workflows/pw-to-pr-email.txt @@ -0,0 +1,16 @@ +This is an automated email and please do not reply to this email. + +Dear Submitter, + +Thank you for submitting the patches to the IWD mailing list. +While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository. + +----- Output ----- +{} + +Please resolve the issue and submit the patches again. + + +--- +Regards, +IWDTestBot diff --git a/.github/workflows/pw-to-pr.json b/.github/workflows/pw-to-pr.json new file mode 100644 index 000000000..b4491413c --- /dev/null +++ b/.github/workflows/pw-to-pr.json @@ -0,0 +1,14 @@ +{ + "email": { + "enable": true, + "server": "smtp.gmail.com", + "port": 587, + "user": "iwd.ci.bot@gmail.com", + "starttls": true, + "default-to": "prestwoj@gmail.com", + "only-maintainers": false, + "maintainers": [ + "prestwoj@gmail.com" + ] + } +} diff --git a/.github/workflows/schedule_work.yml b/.github/workflows/schedule_work.yml new file mode 100644 index 000000000..cfc14fba9 --- /dev/null +++ b/.github/workflows/schedule_work.yml @@ -0,0 +1,43 @@ +name: Sync Upstream +on: + schedule: + - cron: "*/15 * * * *" + workflow_dispatch: + +jobs: + repo-sync: + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v2 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Manage Repo + uses: IWDTestBot/action-manage-repo@master + with: + src_repo: "https://git.kernel.org/pub/scm/network/wireless/iwd.git" + src_branch: "master" + dest_branch: "master" + workflow_branch: "workflow" + github_token: ${{ secrets.GITHUB_TOKEN }} + + create_pr: + needs: repo-sync + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Patchwork to PR + uses: IWDTestBot/action-patchwork-to-pr@master + with: + pw_key_str: "user" + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + config: https://raw.githubusercontent.com/IWDTestBot/iwd/workflow/.github/workflows/pw-to-pr.json + patchwork_id: "408" + email_message: https://raw.githubusercontent.com/IWDTestBot/iwd/workflow/.github/workflows/pw-to-pr-email.txt From 3683df771996971bd8802b63fe5d573b448ad1f7 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 24 Jun 2022 15:27:03 -0700 Subject: [PATCH 02/13] workflow: use newer commit for hostapd --- .github/workflows/ci.yml | 61 +++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e140ad8c..4bf5b1347 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ on: default: '5.16' hostapd_version: description: Hostapd and wpa_supplicant version - default: '2_10' + default: '09a281e52a25b5461c4b08d261f093181266a554' ell_ref: description: ELL reference default: refs/heads/workflow @@ -75,14 +75,14 @@ jobs: then TESTS=all KERNEL=5.16 - HOSTAPD_VERSION=2_10 + HOSTAPD_VERSION=09a281e52a25b5461c4b08d261f093181266a554 ELL_REF=${{ github.event.client_payload.ref }} REF=$ELL_REF REPO=${{ github.event.client_payload.repo }} else TESTS=all KERNEL=5.16 - HOSTAPD_VERSION=2_10 + HOSTAPD_VERSION=09a281e52a25b5461c4b08d261f093181266a554 ELL_REF="refs/heads/workflow" REF="$GITHUB_REF" REPO="$GITHUB_REPOSITORY" @@ -152,17 +152,25 @@ jobs: - name: Tar files run: | - tar -cvf archive.tar \ - ${{ github.workspace }}/cache/um-linux-${{ steps.inputs.outputs.kernel }} \ - ${{ github.workspace }}/cache/hostapd_${{ steps.inputs.outputs.hostapd_version }} \ - ${{ github.workspace }}/cache/hostapd_cli_${{ steps.inputs.outputs.hostapd_version }} \ - ${{ github.workspace }}/cache/wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }} \ - ${{ github.workspace }}/cache/wpa_cli_${{ steps.inputs.outputs.hostapd_version }} \ - iwd \ - ell \ - cibase \ - iwd-ci \ - cache + FILES="iwd ell cibase iwd-ci cache" + + if [ "${{ steps.cache-uml-kernel.outputs.cache-hit }}" == 'true' ] + then + FILES+=" ${{ github.workspace }}/cache/um-linux-${{ steps.inputs.outputs.kernel }}" + fi + + if [ "${{ steps.cache-hostapd.outputs.cache-hit }}" == 'true' ] + then + FILES+=" ${{ github.workspace }}/cache/hostapd_${{ steps.inputs.outputs.hostapd_version }}" + FILES+=" ${{ github.workspace }}/cache/hostapd_cli_${{ steps.inputs.outputs.hostapd_version }}" + fi + if [ "${{ steps.cache-wpas.outputs.cache-hit }}" == 'true' ] + then + FILES+=" ${{ github.workspace }}/cache/wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }}" + FILES+=" ${{ github.workspace }}/cache/wpa_cli_${{ steps.inputs.outputs.hostapd_version }}" + fi + + tar -cvf archive.tar $FILES - name: Upload artifacts uses: actions/upload-artifact@v3 @@ -209,6 +217,31 @@ jobs: - name: Untar run: tar -xf archive.tar + - name: Cache UML Kernel + id: cache-uml-kernel + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/cache/um-linux-${{ needs.setup.outputs.kernel }} + key: um-linux-${{ needs.setup.outputs.kernel }}_ubuntu22 + + - name: Cache Hostapd + id: cache-hostapd + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/hostapd_${{ needs.setup.outputs.hostapd_version }} + ${{ github.workspace }}/cache/hostapd_cli_${{ needs.setup.outputs.hostapd_version }} + key: hostapd_${{ needs.setup.outputs.hostapd_version }}_ssl3 + + - name: Cache WpaSupplicant + id: cache-wpas + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/wpa_supplicant_${{ needs.setup.outputs.hostapd_version }} + ${{ github.workspace }}/cache/wpa_cli_${{ needs.setup.outputs.hostapd_version }} + key: wpa_supplicant_${{ needs.setup.outputs.hostapd_version }}_ssl3 + - name: Modprobe pkcs8_key_parser run: | sudo modprobe pkcs8_key_parser From b93275e927f918e896d10491a25690c3e1594fcf Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 7 Sep 2022 14:51:41 -0700 Subject: [PATCH 03/13] ci: remove cache/ from tar file list This is taken care of by the individual cache items and if none exist, tar fails. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4bf5b1347..09bbb2961 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,7 +152,7 @@ jobs: - name: Tar files run: | - FILES="iwd ell cibase iwd-ci cache" + FILES="iwd ell cibase iwd-ci" if [ "${{ steps.cache-uml-kernel.outputs.cache-hit }}" == 'true' ] then From db3cac2c4e805c936b035246f1f9eace4e32ba9f Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 14 Sep 2022 15:35:30 -0700 Subject: [PATCH 04/13] ci: use kernel 5.19 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09bbb2961..20b2e8419 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ on: default: all kernel: description: Kernel version - default: '5.16' + default: '5.19' hostapd_version: description: Hostapd and wpa_supplicant version default: '09a281e52a25b5461c4b08d261f093181266a554' @@ -74,14 +74,14 @@ jobs: elif [ ${{ github.event_name }} == 'repository_dispatch' ] then TESTS=all - KERNEL=5.16 + KERNEL=5.19 HOSTAPD_VERSION=09a281e52a25b5461c4b08d261f093181266a554 ELL_REF=${{ github.event.client_payload.ref }} REF=$ELL_REF REPO=${{ github.event.client_payload.repo }} else TESTS=all - KERNEL=5.16 + KERNEL=5.19 HOSTAPD_VERSION=09a281e52a25b5461c4b08d261f093181266a554 ELL_REF="refs/heads/workflow" REF="$GITHUB_REF" From b9f5e9690a1a7ccf79999c7f58d07031f8bcce76 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 14 Oct 2022 08:58:15 -0700 Subject: [PATCH 05/13] ci: use iwd-ci after renaming to remove -v2 --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20b2e8419..3f9d6981a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ name: IWD CI # as test-runner # * 'musl' uses an alpine docker image to test the build on musl-libc # -# Both CI's use the 'iwd-ci-v2' repo which calls into 'ci-docker'. The +# Both CI's use the 'iwd-ci' repo which calls into 'ci-docker'. The # 'ci-docker' action essentially re-implements the native Github docker # action but allows arbitrary options to be passed in (e.g. privileged or # mounting non-standard directories) @@ -147,7 +147,7 @@ jobs: - name: Checkout CI uses: actions/checkout@v3 with: - repository: IWDTestBot/iwd-ci-v2 + repository: IWDTestBot/iwd-ci path: iwd-ci - name: Tar files @@ -196,7 +196,7 @@ jobs: sudo modprobe pkcs8_key_parser - name: Alpine CI - uses: IWDTestBot/iwd-ci-v2@master + uses: IWDTestBot/iwd-ci@master with: ref_branch: ${{ needs.setup.outputs.ref_branch }} repository: ${{ needs.setup.outputs.repository }} @@ -249,7 +249,7 @@ jobs: echo ${{ needs.setup.outputs.repository }} - name: Run CI - uses: IWDTestBot/iwd-ci-v2@master + uses: IWDTestBot/iwd-ci@master with: ref_branch: ${{ needs.setup.outputs.ref_branch }} repository: ${{ needs.setup.outputs.repository }} From 09a8a0df10d5b3e2400d7754b8f831a153d4580e Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 14 Oct 2022 10:18:25 -0700 Subject: [PATCH 06/13] ci: remove set-output use, now deprecated --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f9d6981a..393341c27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,12 +92,12 @@ jobs: # Now that the inputs are sorted, set the output of this step to these # values so future jobs can refer to them. # - echo ::set-output name=tests::$TESTS - echo ::set-output name=kernel::$KERNEL - echo ::set-output name=hostapd_version::$HOSTAPD_VERSION - echo ::set-output name=ell_ref::$ELL_REF - echo ::set-output name=repository::$REPO - echo ::set-output name=ref_branch::$REF + echo "tests=$TESTS" >> $GITHUB_OUTPUT + echo "kernel=$KERNEL" >> $GITHUB_OUTPUT + echo "hostapd_version=$HOSTAPD_VERSION" >> $GITHUB_OUTPUT + echo "ell_ref=$ELL_REF" >> $GITHUB_OUTPUT + echo "repository=$REPO" >> $GITHUB_OUTPUT + echo "ref_branch=$REF" >> $GITHUB_OUTPUT - name: Cache UML Kernel id: cache-uml-kernel From 948fba5fb8bc27f93f2520e311d307d82223138b Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 7 Nov 2024 06:12:51 -0800 Subject: [PATCH 07/13] Update kernel to 6.2 and hostapd/wpa_s to 2.11 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 393341c27..993ce662d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,10 +30,10 @@ on: default: all kernel: description: Kernel version - default: '5.19' + default: '6.2' hostapd_version: description: Hostapd and wpa_supplicant version - default: '09a281e52a25b5461c4b08d261f093181266a554' + default: 'hostapd_2_11' ell_ref: description: ELL reference default: refs/heads/workflow From d8ada384142e15402ef032fb49d822d69f1c17a5 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 13 Feb 2025 08:18:29 -0800 Subject: [PATCH 08/13] Update upload/download-artifact to v4 --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 993ce662d..a9582eb14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -173,7 +173,7 @@ jobs: tar -cvf archive.tar $FILES - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: iwd-artifacts path: | @@ -184,7 +184,7 @@ jobs: needs: setup steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: iwd-artifacts @@ -210,7 +210,7 @@ jobs: needs: setup steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: iwd-artifacts @@ -263,7 +263,7 @@ jobs: - name: Upload Logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: test-runner-logs path: ${{ github.workspace }}/log From 1d299088536ef4dfd65b4160ae5b7440c90aef9f Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 18 Apr 2025 12:03:43 -0700 Subject: [PATCH 09/13] Add coverity Github action --- .github/workflows/coverity.yml | 86 ++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .github/workflows/coverity.yml diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml new file mode 100644 index 000000000..91f9073d3 --- /dev/null +++ b/.github/workflows/coverity.yml @@ -0,0 +1,86 @@ +name: Coverity Scan and Submit +description: Runs a coverity scan, then sends results to the cloud +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + scan-and-submit: + runs-on: ubuntu-22.04 + steps: + - name: Lookup latest tool + id: cache-lookup + run: | + hash=$(curl https://scan.coverity.com/download/cxx/linux64 \ + --data "token=${{ secrets.COVERITY_IWD_TOKEN }}&project=IWD&md5=1"); + echo "hash=${hash}" >> $GITHUB_OUTPUT + + - name: Get cached coverity tool + id: build-cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/cov-analysis + key: cov-build-cxx-linux64-${{ steps.cache-lookup.outputs.hash }} + + - name: Download Coverity Build Tool + if: steps.build-cache.outputs.cache-hit != 'true' + run: | + curl https://scan.coverity.com/download/cxx/linux64 \ + --no-progress-meter \ + --output cov-analysis.tar.gz \ + --data "token=${{ secrets.COVERITY_IWD_TOKEN }}&project=IWD" + shell: bash + working-directory: ${{ github.workspace }} + + - if: steps.build-cache.outputs.cache-hit != 'true' + run: mkdir cov-analysis + shell: bash + working-directory: ${{ github.workspace }} + + - if: steps.build-cache.outputs.cache-hit != 'true' + run: tar -xzf cov-analysis.tar.gz --strip 1 -C cov-analysis + shell: bash + working-directory: ${{ github.workspace }} + + - name: Checkout IWD + uses: actions/checkout@v3 + with: + path: ${{ github.workspace }}/iwd + repository: IWDTestBot/iwd + token: ${{ secrets.ACTION_TOKEN }} + + - name: Checkout ELL + uses: actions/checkout@v3 + with: + path: ${{ github.workspace }}/ell + repository: IWDTestBot/ell + token: ${{ secrets.ACTION_TOKEN }} + + - name: Configure IWD + run: | + cd ${{ github.workspace }}/iwd + ./bootstrap-configure --disable-manual-pages + + - name: Build with cov-build + run: | + export PATH="${{ github.workspace }}/cov-analysis/bin:${PATH}" + cov-build --dir cov-int make -j4 + shell: bash + working-directory: ${{ github.workspace }}/iwd + + - name: Tar results + run: tar -czvf cov-int.tgz cov-int + shell: bash + working-directory: ${{ github.workspace }}/iwd + + - name: Submit results to Coverity Scan + if: ${{ ! inputs.dry_run }} + run: | + curl \ + --form token="${{ secrets.COVERITY_IWD_TOKEN }}" \ + --form email="iwd.ci.bot@gmail.com" \ + --form file=@cov-int.tgz \ + "https://scan.coverity.com/builds?project=IWD" + shell: bash + working-directory: ${{ github.workspace }}/iwd From 606be0647f976b3af4d71cfa471a4aa24cd02767 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 07:27:47 -0700 Subject: [PATCH 10/13] station: treat netconfig failures as connection failures Currently the netconfig functionality is somewhat separated from IWD's "connection" process. Regardless if netconfig is enabled the method return from Connect() will happen after IWD has completed the 4-way handshake. If netconfig fails its shows externally as an IWD state change rather than part of the method return from Connect(). Overall this doesn't pose a significant problem since a netconfig failure essentially appears as if IWD became disconnected but more critical is that IWD will not iteratively try more BSS's if netconfig fails. For example a BSS may be misconfigured, or not able to communicate to the DHCP server. IWD could connect to it, and fail netconfig thereby restarting the autoconnect logic. IWD will then choose the "best" BSS which may be the one it just failed on. This would then repeat indefinitely or until a better BSS comes around which could be never. To improve this netconfig has been adopted into the IWD's BSS retry logic. If netconfig fails this will not result in IWD transitioning to a disconnected state, and instead the BSS will be network blacklisted and the next will be tried. Only once all BSS's have been tried will IWD go into a disconnected state and start autoconnect over. --- src/station.c | 104 +++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/src/station.c b/src/station.c index 2b6a18f8b..81c1e595b 100644 --- a/src/station.c +++ b/src/station.c @@ -1795,6 +1795,13 @@ static void station_enter_state(struct station *station, periodic_scan_stop(station); break; case STATION_STATE_CONNECTED: + if (station->connect_pending) { + struct l_dbus_message *reply = + l_dbus_message_new_method_return( + station->connect_pending); + dbus_pending_reply(&station->connect_pending, reply); + } + l_dbus_object_add_interface(dbus, netdev_get_path(station->netdev), IWD_STATION_DIAGNOSTIC_INTERFACE, @@ -2214,6 +2221,26 @@ static void station_early_neighbor_report_cb(struct netdev *netdev, int err, &station->roam_freqs); } +static bool station_try_next_bss(struct station *station) +{ + struct scan_bss *next; + int ret; + + next = network_bss_select(station->connected_network, false); + + if (!next) + return false; + + ret = __station_connect_network(station, station->connected_network, + next, station->state); + if (ret < 0) + return false; + + l_debug("Attempting to connect to next BSS "MAC, MAC_STR(next->addr)); + + return true; +} + static bool station_can_fast_transition(struct station *station, struct handshake_state *hs, struct scan_bss *bss) @@ -2256,28 +2283,28 @@ static bool station_can_fast_transition(struct station *station, return true; } -static void station_disconnect_on_error_cb(struct netdev *netdev, bool success, - void *user_data) +static void station_disconnect_on_netconfig_failed(struct netdev *netdev, + bool success, + void *user_data) { struct station *station = user_data; - bool continue_autoconnect; - station_enter_state(station, STATION_STATE_DISCONNECTED); + if (station_try_next_bss(station)) + return; - continue_autoconnect = station->state == STATION_STATE_CONNECTING_AUTO; + network_disconnected(station->connected_network); - if (continue_autoconnect) { - if (station_autoconnect_next(station) < 0) { - l_debug("Nothing left on autoconnect list"); - station_enter_state(station, - STATION_STATE_AUTOCONNECT_FULL); - } + if (station->connect_pending) { + struct l_dbus_message *reply = dbus_error_failed( + station->connect_pending); - return; + dbus_pending_reply(&station->connect_pending, reply); } - if (station->autoconnect) - station_enter_state(station, STATION_STATE_AUTOCONNECT_QUICK); + station_reset_connection_state(station); + + station_enter_state(station, STATION_STATE_DISCONNECTED); + station_enter_state(station, STATION_STATE_AUTOCONNECT_FULL); } static void station_netconfig_event_handler(enum netconfig_event event, @@ -2287,26 +2314,24 @@ static void station_netconfig_event_handler(enum netconfig_event event, switch (event) { case NETCONFIG_EVENT_CONNECTED: + network_connected(station->connected_network); station_enter_state(station, STATION_STATE_CONNECTED); break; case NETCONFIG_EVENT_FAILED: - if (station->connect_pending) { - struct l_dbus_message *reply = dbus_error_failed( - station->connect_pending); + station_debug_event(station, "netconfig-failed"); - dbus_pending_reply(&station->connect_pending, reply); - } + netconfig_reset(station->netconfig); if (station->state == STATION_STATE_NETCONFIG) network_connect_failed(station->connected_network, false); + network_blacklist_add(station->connected_network, + station->connected_bss); + netdev_disconnect(station->netdev, - station_disconnect_on_error_cb, + station_disconnect_on_netconfig_failed, station); - station_reset_connection_state(station); - - station_enter_state(station, STATION_STATE_DISCONNECTING); break; default: l_error("station: Unsupported netconfig event: %d.", event); @@ -3409,26 +3434,6 @@ static void station_event_channel_switched(struct station *station, network_bss_update(network, station->connected_bss); } -static bool station_try_next_bss(struct station *station) -{ - struct scan_bss *next; - int ret; - - next = network_bss_select(station->connected_network, false); - - if (!next) - return false; - - ret = __station_connect_network(station, station->connected_network, - next, station->state); - if (ret < 0) - return false; - - l_debug("Attempting to connect to next BSS "MAC, MAC_STR(next->addr)); - - return true; -} - static bool station_retry_owe_default_group(struct station *station) { /* @@ -3581,13 +3586,6 @@ static void station_connect_ok(struct station *station) l_debug(""); - if (station->connect_pending) { - struct l_dbus_message *reply = - l_dbus_message_new_method_return( - station->connect_pending); - dbus_pending_reply(&station->connect_pending, reply); - } - /* * Get a neighbor report now so future roams can avoid waiting for * a report at that time @@ -3598,8 +3596,6 @@ static void station_connect_ok(struct station *station) l_warn("Could not request neighbor report"); } - network_connected(station->connected_network); - if (station->netconfig) { if (hs->fils_ip_req_ie && hs->fils_ip_resp_ie) { struct ie_fils_ip_addr_response_info info; @@ -3639,8 +3635,10 @@ static void station_connect_ok(struct station *station) return; station_enter_state(station, STATION_STATE_NETCONFIG); - } else + } else { + network_connected(station->connected_network); station_enter_state(station, STATION_STATE_CONNECTED); + } } static void station_connect_cb(struct netdev *netdev, enum netdev_result result, From 432ede5bc398c86d59bddb0dab6d710a99d67222 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 07:27:48 -0700 Subject: [PATCH 11/13] auto-t: allow configurable DBus timeout/callbacks on connect{_bssid} Let the caller specify the method timeout if there is an expectation that it could take a long time. For the conventional connect call (not the "bssid" debug variant) let them pass their own callback handlers. This is useful if we don't want to wait for the connect call to finish, but later get some indication that it did finish either successfully or not. --- autotests/util/iwd.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/autotests/util/iwd.py b/autotests/util/iwd.py index 9091807a3..37eb49434 100755 --- a/autotests/util/iwd.py +++ b/autotests/util/iwd.py @@ -112,8 +112,8 @@ def _failure(self, ex): self._is_completed = True self._exception = _convert_dbus_ex(ex) - def _wait_for_async_op(self): - ctx.non_block_wait(lambda s: s._is_completed, 30, self, exception=None) + def _wait_for_async_op(self, timeout=50): + ctx.non_block_wait(lambda s: s._is_completed, timeout, self, exception=None) self._is_completed = False if self._exception is not None: @@ -280,8 +280,15 @@ def _event_handler(self, event, data): def autoconnect(self): return self._properties['AutoConnect'] - def connect_bssid(self, address): - self._iface.ConnectBssid(dbus.ByteArray.fromhex(address.replace(':', ''))) + def connect_bssid(self, address, wait=True): + self._iface.ConnectBssid( + dbus.ByteArray.fromhex(address.replace(':', '')), + reply_handler=self._success, + error_handler=self._failure + ) + + if wait: + self._wait_for_async_op() def roam(self, address): self._iface.Roam(dbus.ByteArray.fromhex(address.replace(':', ''))) @@ -870,8 +877,8 @@ def start_adhoc(self, ssid, psk=None): def stop_adhoc(self): self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station') - def connect_bssid(self, address): - self._station_debug.connect_bssid(address) + def connect_bssid(self, address, wait=True): + self._station_debug.connect_bssid(address, wait=wait) def roam(self, address): self._station_debug.roam(address) @@ -999,7 +1006,7 @@ def connected(self): def extended_service_set(self): return self._properties['ExtendedServiceSet'] - def connect(self, wait=True): + def connect(self, wait=True, timeout=50, reply_handler=None, error_handler=None): ''' Connect to the network. Request the device implied by the object path to connect to specified network. @@ -1014,12 +1021,19 @@ def connect(self, wait=True): @rtype: void ''' + if not reply_handler: + reply_handler = self._success + + if not error_handler: + error_handler = self._failure + self._iface.Connect(dbus_interface=self._iface_name, - reply_handler=self._success, - error_handler=self._failure) + reply_handler=reply_handler, + error_handler=error_handler, + timeout=timeout) if wait: - self._wait_for_async_op() + self._wait_for_async_op(timeout=timeout) def __str__(self, prefix = ''): return prefix + 'Network:\n' \ From 410e9f4db43068748592a8ececa47d031d82cc4c Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 07:27:49 -0700 Subject: [PATCH 12/13] auto-t: update serveral tests to work with netconfig refactor Since the method return to Connect() and ConnectBssid() come after netconfig some tests needed to be updated since they were waiting for the method return before continuing. For timeout-based tests specifically this caused them to fail since before they expected the return to come before the connection was actually completed. --- autotests/testNetconfig/static_test.py | 15 +++----- autotests/testNetconfig/timeout_test.py | 35 +++++++++++++------ .../testNetconfigRoam/netconfig_roam_test.py | 2 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/autotests/testNetconfig/static_test.py b/autotests/testNetconfig/static_test.py index 94307a8c8..61037e0ee 100644 --- a/autotests/testNetconfig/static_test.py +++ b/autotests/testNetconfig/static_test.py @@ -91,16 +91,11 @@ def test_connection_success(self): # using the same static config. The new client's ACD client should # detect an IP conflict and not allow the device to reach the # "connected" state although the DBus .Connect call will succeed. - ordered_network.network_object.connect() - self.assertEqual(dev2.state, iwd.DeviceState.connecting) - try: - # We should either stay in "connecting" indefinitely or move to - # "disconnecting" - condition = 'obj.state != DeviceState.connecting' - iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21) - self.assertEqual(dev2.state, iwd.DeviceState.disconnecting) - except TimeoutError: - dev2.disconnect() + with self.assertRaises(iwd.FailedEx): + ordered_network.network_object.connect(timeout=500) + + condition = 'obj.state == DeviceState.disconnected' + iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21) iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1) del dev2 diff --git a/autotests/testNetconfig/timeout_test.py b/autotests/testNetconfig/timeout_test.py index a15706e3b..00b03df43 100644 --- a/autotests/testNetconfig/timeout_test.py +++ b/autotests/testNetconfig/timeout_test.py @@ -8,6 +8,8 @@ from iwd import NetworkType class Test(unittest.TestCase): + def connect_failure(self, ex): + self.failure_triggered = True def test_netconfig_timeout(self): IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk') @@ -27,23 +29,34 @@ def test_netconfig_timeout(self): condition = 'not obj.connected' wd.wait_for_object_condition(ordered_network.network_object, condition) - ordered_network.network_object.connect() + self.failure_triggered = False - condition = 'obj.state == DeviceState.connecting' - wd.wait_for_object_condition(device, condition) + # Set our error handler here so we can check if it fails + ordered_network.network_object.connect( + wait=False, + timeout=1000, + error_handler=self.connect_failure + ) + + # IWD should attempt to try both BSS's with both failing netconfig. + # Then the autoconnect list should be exhausted, and IWD should + # transition to a disconnected state, then proceed to full autoconnect. + device.wait_for_event("netconfig-failed", timeout=1000) + device.wait_for_event("netconfig-failed", timeout=1000) + device.wait_for_event("disconnected") - device.wait_for_event("connecting (netconfig)") + device.wait_for_event("autoconnect_full") - # Netconfig should fail, and IWD should disconnect - from_condition = 'obj.state == DeviceState.connecting' - to_condition = 'obj.state == DeviceState.disconnecting' - wd.wait_for_object_change(device, from_condition, to_condition, max_wait=60) + # The connect call should have failed + self.assertTrue(self.failure_triggered) - # Autoconnect should then try again - condition = 'obj.state == DeviceState.connecting' + condition = "obj.scanning" + wd.wait_for_object_condition(device, condition) + condition = "not obj.scanning" wd.wait_for_object_condition(device, condition) - device.wait_for_event("connecting (netconfig)") + # IWD should attempt to connect, but it will of course fail again. + device.wait_for_event("netconfig-failed", timeout=1000) device.disconnect() condition = 'obj.state == DeviceState.disconnected' diff --git a/autotests/testNetconfigRoam/netconfig_roam_test.py b/autotests/testNetconfigRoam/netconfig_roam_test.py index 63e5eabfb..b7a7012fc 100644 --- a/autotests/testNetconfigRoam/netconfig_roam_test.py +++ b/autotests/testNetconfigRoam/netconfig_roam_test.py @@ -19,7 +19,7 @@ def test_roam_before_netconfig(self): device = wd.list_devices(1)[0] device.get_ordered_network('TestFT', full_scan=True) - device.connect_bssid(self.bss_hostapd[1].bssid) + device.connect_bssid(self.bss_hostapd[1].bssid, wait=False) self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}') device.wait_for_event("connecting (netconfig)") From 68f081c4667c8a8b978458a4512c8967f84747ea Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 07:27:50 -0700 Subject: [PATCH 13/13] doc: add note about timeouts to Network.Connect() Since netconfig is now part of the Connect() call from a DBus perspective add a note indicating that this method has the potential to take a very long time if there are issues with DHCP. --- doc/network-api.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/network-api.txt b/doc/network-api.txt index 8bc6eea6f..d96fcede7 100644 --- a/doc/network-api.txt +++ b/doc/network-api.txt @@ -11,6 +11,12 @@ Methods void Connect() the object path to connect to specified network. Connecting to WEP networks is not supported. + Note: When [General].EnableNetworkConfiguration is set + to true a call to Connect() has the potential to take + a significant amount of time. Specifically if DHCP is + either slow, or is unable to complete. The timeout for + DHCP is roughly 30 seconds per BSS. + Possible errors: net.connman.iwd.Aborted net.connman.iwd.Busy net.connman.iwd.Failed