From 690992b48f9e1cad3f5c12a0ae84641adafb4ebb Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 16 Mar 2022 10:39:08 -0700 Subject: [PATCH 01/15] 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 4ac0cc52f7e8f151e5149cc1bae37cb677885086 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 24 Jun 2022 15:27:03 -0700 Subject: [PATCH 02/15] 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 ba96b4b610d1f94fb1d0fd4deb7223f2f3345930 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 7 Sep 2022 14:51:41 -0700 Subject: [PATCH 03/15] 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 762a74188fa8566a5fa008697c42a8693f0b85a7 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 14 Sep 2022 15:35:30 -0700 Subject: [PATCH 04/15] 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 5b94f8f7ee157af383822e4fae782dd8cf20cdec Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 14 Oct 2022 08:58:15 -0700 Subject: [PATCH 05/15] 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 de1759d68d959a8d276cd808a9496cf3f04db22c Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 14 Oct 2022 10:18:25 -0700 Subject: [PATCH 06/15] 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 5cf4902aebba97eab4167eecc31c298bfc2661cb Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 7 Nov 2024 06:12:51 -0800 Subject: [PATCH 07/15] 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 38ae05deb41c2baafa09fb3ca4270a74bb00d2fa Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 13 Feb 2025 08:18:29 -0800 Subject: [PATCH 08/15] 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 9ab928a8f4a435fbcc034f8d89fde1cf724e3c39 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 18 Apr 2025 12:03:43 -0700 Subject: [PATCH 09/15] 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 0aa015da38bdb102e2feda48b678883f77d049ed Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 13:10:21 -0700 Subject: [PATCH 10/15] network: make clearing network blacklist a separate operation This adds a new API network_clear_blacklist() and removes this functionality from network_connected(). This is done to support BSS iteration when netconfig is enabled. Since a call to network_connected() will happen prior to netconfig completing we cannot clear the blacklist until netconfig has either passed or failed. --- src/network.c | 9 ++++++--- src/network.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/network.c b/src/network.c index 4602a110c..588ea5ae5 100644 --- a/src/network.c +++ b/src/network.c @@ -168,6 +168,11 @@ static bool network_secret_check_cacheable(void *data, void *user_data) return false; } +void network_clear_blacklist(struct network *network) +{ + l_queue_clear(network->blacklist, NULL); +} + void network_connected(struct network *network) { enum security security = network_get_security(network); @@ -198,8 +203,6 @@ void network_connected(struct network *network) l_queue_foreach_remove(network->secrets, network_secret_check_cacheable, network); - l_queue_clear(network->blacklist, NULL); - network->provisioning_hidden = false; } @@ -207,7 +210,7 @@ void network_disconnected(struct network *network) { network_settings_close(network); - l_queue_clear(network->blacklist, NULL); + network_clear_blacklist(network); if (network->provisioning_hidden) station_hide_network(network->station, network); diff --git a/src/network.h b/src/network.h index 849051dd1..061f47cac 100644 --- a/src/network.h +++ b/src/network.h @@ -74,6 +74,7 @@ bool network_bss_update(struct network *network, struct scan_bss *bss); const char *network_bss_get_path(const struct network *network, const struct scan_bss *bss); bool network_bss_list_isempty(struct network *network); +void network_clear_blacklist(struct network *network); const char *__network_path_append_bss(const char *network_path, const struct scan_bss *bss); From 3968b836b868e3bf709ec933a24f93d322ef70d8 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 13:10:22 -0700 Subject: [PATCH 11/15] station: fix DBus reply for Connect() with netconfig When netconfig is enabled the DBus reply was being sent in station_connect_ok(), before netconfig had even started. This would result in a call to Connect() succeeding from a DBus perspective but really netconfig still needed to complete before IWD transitioned to a connected state. Fixes: 72e7d3ceb83d ("station: Handle NETCONFIG_EVENT_FAILED") --- src/station.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/station.c b/src/station.c index 2b6a18f8b..4180b7a44 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, @@ -3581,13 +3588,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 From a7b8ab9c801f4b7122bd74a2892fb4029f597482 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 13:10:23 -0700 Subject: [PATCH 12/15] station: include netconfig as part of the BSS retry logic A netconfig failure results in a failed connection which restarts autoconnect and prevents IWD from retrying the connection on any other BSS's within the network as a whole. When autoconnect restarts IWD will scan and choose the "best" BSS which is likely the same as the prior attempt. If that BSS is somehow misconfigured as far as DHCP goes, it will likely fail indefinitely and in turn cause IWD to retry indefinitely. 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 | 85 +++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/src/station.c b/src/station.c index 4180b7a44..a4c3e7d1a 100644 --- a/src/station.c +++ b/src/station.c @@ -1795,6 +1795,8 @@ static void station_enter_state(struct station *station, periodic_scan_stop(station); break; case STATION_STATE_CONNECTED: + network_clear_blacklist(station->connected_network); + if (station->connect_pending) { struct l_dbus_message *reply = l_dbus_message_new_method_return( @@ -2221,6 +2223,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) @@ -2263,28 +2285,26 @@ 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); - - continue_autoconnect = station->state == STATION_STATE_CONNECTING_AUTO; + if (station_try_next_bss(station)) + return; - 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, @@ -2297,23 +2317,20 @@ static void station_netconfig_event_handler(enum netconfig_event event, 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); @@ -3416,26 +3433,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) { /* From 454ba2b5843bd97cf6122c20975bf08e6c2f3857 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 13:10:24 -0700 Subject: [PATCH 13/15] 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 bba90f607d8a91bf7b954391127a1c206e3c466b Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 13:10:25 -0700 Subject: [PATCH 14/15] auto-t: update several 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 eb8080adba0fa96178ec72a942f3a2282a7ac445 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 28 May 2025 13:10:26 -0700 Subject: [PATCH 15/15] 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