name: Tests on: workflow_dispatch: push: branches: - 'main' - '3.*' pull_request: branches: - 'main' - '3.*' permissions: contents: read concurrency: # https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency # 'group' must be a key uniquely representing a PR or push event. # github.workflow is the workflow name # github.actor is the user invoking the workflow # github.head_ref is the source branch of the PR or otherwise blank # github.run_id is a unique number for the current run group: ${{ github.workflow }}-${{ github.actor }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true env: FORCE_COLOR: 1 jobs: build-context: name: Change detection # To use boolean outputs from this job, parse them as JSON. # Here's some examples: # # if: fromJSON(needs.build-context.outputs.run-docs) # # ${{ # fromJSON(needs.build-context.outputs.run-tests) # && 'truthy-branch' # || 'falsy-branch' # }} # uses: ./.github/workflows/reusable-context.yml check-docs: name: Docs needs: build-context if: fromJSON(needs.build-context.outputs.run-docs) uses: ./.github/workflows/reusable-docs.yml check-autoconf-regen: name: 'Check if Autoconf files are up to date' # Don't use ubuntu-latest but a specific version to make the job # reproducible: to get the same tools versions (autoconf, aclocal, ...) runs-on: ubuntu-24.04 container: image: ghcr.io/python/autoconf:2025.01.02.12581854023 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' steps: - name: Install Git run: | apt update && apt install git -yq git config --global --add safe.directory "$GITHUB_WORKSPACE" - uses: actions/checkout@v4 with: fetch-depth: 1 persist-credentials: false - name: Check Autoconf and aclocal versions run: | grep "Generated by GNU Autoconf 2.72" configure grep "aclocal 1.16.5" aclocal.m4 grep -q "runstatedir" configure grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 - name: Regenerate autoconf files # Same command used by Tools/build/regen-configure.sh ($AUTORECONF) run: autoreconf -ivf -Werror - name: Check for changes run: | git add -u changes=$(git status --porcelain) # Check for changes in regenerated files if test -n "$changes"; then echo "Generated files not up to date." echo "Perhaps you forgot to run make regen-configure ;)" echo "configure files must be regenerated with a specific version of autoconf." echo "$changes" echo "" git diff --staged || true exit 1 fi check-generated-files: name: 'Check if generated files are up to date' # Don't use ubuntu-latest but a specific version to make the job # reproducible: to get the same tools versions (autoconf, aclocal, ...) runs-on: ubuntu-24.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - name: Configure CPython run: | # Build Python with the libpython dynamic library ./configure --config-cache --with-pydebug --enable-shared - name: Build CPython run: | make -j4 regen-all make regen-stdlib-module-names regen-sbom - name: Check for changes run: | git add -u changes=$(git status --porcelain) # Check for changes in regenerated files if test -n "$changes"; then echo "Generated files not up to date." echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)" echo "configure files must be regenerated with a specific version of autoconf." echo "$changes" echo "" git diff --staged || true exit 1 fi - name: Check exported libpython symbols run: make smelly - name: Check limited ABI symbols run: make check-limited-abi - name: Check for unsupported C global variables if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME run: make check-c-globals build-windows: name: >- Windows ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} needs: build-context if: fromJSON(needs.build-context.outputs.run-windows-tests) strategy: fail-fast: false matrix: arch: - x64 - Win32 - arm64 free-threading: - false - true exclude: # Skip Win32 on free-threaded builds - { arch: Win32, free-threading: true } uses: ./.github/workflows/reusable-windows.yml with: arch: ${{ matrix.arch }} free-threading: ${{ matrix.free-threading }} build-windows-msi: # ${{ '' } is a hack to nest jobs under the same sidebar category. name: Windows MSI${{ '' }} # zizmor: ignore[obfuscation] needs: build-context if: fromJSON(needs.build-context.outputs.run-windows-msi) strategy: fail-fast: false matrix: arch: - x86 - x64 - arm64 uses: ./.github/workflows/reusable-windows-msi.yml with: arch: ${{ matrix.arch }} build-macos: name: >- macOS ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} needs: build-context if: needs.build-context.outputs.run-tests == 'true' strategy: fail-fast: false matrix: # macos-14 is M1, macos-15-intel is Intel. # macos-15-intel only runs tests against the GIL-enabled CPython. os: - macos-14 - macos-15-intel free-threading: - false - true exclude: - os: macos-15-intel free-threading: true uses: ./.github/workflows/reusable-macos.yml with: free-threading: ${{ matrix.free-threading }} os: ${{ matrix.os }} build-ubuntu: name: >- Ubuntu ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} ${{ fromJSON(matrix.bolt) && '(bolt)' || '' }} needs: build-context if: needs.build-context.outputs.run-tests == 'true' strategy: fail-fast: false matrix: bolt: - false - true free-threading: - false - true os: - ubuntu-24.04 - ubuntu-24.04-arm exclude: # Do not test BOLT with free-threading, to conserve resources - bolt: true free-threading: true # BOLT currently crashes during instrumentation on aarch64 - os: ubuntu-24.04-arm bolt: true uses: ./.github/workflows/reusable-ubuntu.yml with: bolt-optimizations: ${{ matrix.bolt }} free-threading: ${{ matrix.free-threading }} os: ${{ matrix.os }} build-ubuntu-ssltests-openssl: name: 'Ubuntu SSL tests with OpenSSL' runs-on: ${{ matrix.os }} timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' strategy: fail-fast: false matrix: os: [ubuntu-24.04] # Keep 1.1.1w in our list despite it being upstream EOL and otherwise # unsupported as it most resembles other 1.1.1-work-a-like ssl APIs # supported by important vendors such as AWS-LC. openssl_ver: [1.1.1w, 3.0.18, 3.2.6, 3.3.5, 3.4.3, 3.5.4] # See Tools/ssl/make_ssl_data.py for notes on adding a new version env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }} LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - name: 'Restore OpenSSL build' id: cache-openssl uses: actions/cache@v4 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - name: Install OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - name: Configure CPython run: ./configure CFLAGS="-fdiagnostics-format=json" --config-cache --enable-slower-safety --with-pydebug --with-openssl="$OPENSSL_DIR" - name: Build CPython run: make -j4 - name: Display build info run: make pythoninfo - name: SSL tests run: ./python Lib/test/ssltests.py build-ubuntu-ssltests-awslc: name: 'Ubuntu SSL tests with AWS-LC' runs-on: ${{ matrix.os }} timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' strategy: fail-fast: false matrix: os: [ubuntu-24.04] awslc_ver: [1.55.0] env: AWSLC_VER: ${{ matrix.awslc_ver}} MULTISSL_DIR: ${{ github.workspace }}/multissl OPENSSL_DIR: ${{ github.workspace }}/multissl/aws-lc/${{ matrix.awslc_ver }} LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/aws-lc/${{ matrix.awslc_ver }}/lib steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure SSL lib env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/aws-lc/${AWSLC_VER}" >> "$GITHUB_ENV" echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/aws-lc/${AWSLC_VER}/lib" >> "$GITHUB_ENV" - name: 'Restore AWS-LC build' id: cache-aws-lc uses: actions/cache@v4 with: path: ./multissl/aws-lc/${{ matrix.awslc_ver }} key: ${{ matrix.os }}-multissl-aws-lc-${{ matrix.awslc_ver }} - name: Install AWS-LC if: steps.cache-aws-lc.outputs.cache-hit != 'true' run: | python3 Tools/ssl/multissltests.py \ --steps=library \ --base-directory "$MULTISSL_DIR" \ --awslc ${{ matrix.awslc_ver }} \ --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - name: Configure CPython run: | ./configure CFLAGS="-fdiagnostics-format=json" \ --config-cache \ --enable-slower-safety \ --with-pydebug \ --with-openssl="$OPENSSL_DIR" \ --with-builtin-hashlib-hashes=blake2 \ --with-ssl-default-suites=openssl - name: Build CPython run: make -j - name: Display build info run: make pythoninfo - name: Verify python is linked to AWS-LC run: ./python -c 'import ssl; print(ssl.OPENSSL_VERSION)' | grep AWS-LC - name: SSL tests run: ./python Lib/test/ssltests.py build-android: name: Android (${{ matrix.arch }}) needs: build-context if: needs.build-context.outputs.run-tests == 'true' timeout-minutes: 60 strategy: fail-fast: false matrix: include: - arch: aarch64 runs-on: macos-14 - arch: x86_64 runs-on: ubuntu-24.04 runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Build and test run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android build-ios: name: iOS needs: build-context if: needs.build-context.outputs.run-tests == 'true' timeout-minutes: 60 runs-on: macos-15 steps: - uses: actions/checkout@v4 with: persist-credentials: false # GitHub recommends explicitly selecting the desired Xcode version: # https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140 # This became a necessity as a result of # https://github.com/actions/runner-images/issues/12541 and # https://github.com/actions/runner-images/issues/12751. - name: Select Xcode version run: | sudo xcode-select --switch /Applications/Xcode_16.4.app - name: Build and test run: python3 Apple ci iOS --fast-ci --simulator 'iPhone 16e,OS=18.5' build-wasi: name: 'WASI' needs: build-context if: needs.build-context.outputs.run-tests == 'true' uses: ./.github/workflows/reusable-wasi.yml test-hypothesis: name: "Hypothesis tests on Ubuntu" runs-on: ubuntu-24.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' env: OPENSSL_VER: 3.0.18 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - name: 'Restore OpenSSL build' id: cache-openssl uses: actions/cache@v4 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - name: Install OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV" echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV" - name: Create directories for read-only out-of-tree builds run: mkdir -p "$CPYTHON_RO_SRCDIR" "$CPYTHON_BUILDDIR" - name: Bind mount sources read-only run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR" - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | ../cpython-ro-srcdir/configure \ --config-cache \ --with-pydebug \ --enable-slower-safety \ --with-openssl="$OPENSSL_DIR" - name: Build CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: make -j4 - name: Display build info working-directory: ${{ env.CPYTHON_BUILDDIR }} run: make pythoninfo - name: Remount sources writable for tests # some tests write to srcdir, lack of pyc files slows down testing run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV" - name: "Create hypothesis venv" working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | VENV_LOC=$(realpath -m .)/hypovenv VENV_PYTHON=$VENV_LOC/bin/python echo "HYPOVENV=${VENV_LOC}" >> "$GITHUB_ENV" echo "VENV_PYTHON=${VENV_PYTHON}" >> "$GITHUB_ENV" ./python -m venv "$VENV_LOC" && "$VENV_PYTHON" -m pip install -r "${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt" - name: 'Restore Hypothesis database' id: cache-hypothesis-database uses: actions/cache@v4 with: path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/ key: hypothesis-database-${{ github.head_ref || github.run_id }} restore-keys: | hypothesis-database- - name: "Run tests" working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | # Most of the excluded tests are slow test suites with no property tests # # (GH-104097) test_sysconfig is skipped because it has tests that are # failing when executed from inside a virtual environment. "${VENV_PYTHON}" -m test \ -W \ --slowest \ -j4 \ --timeout 900 \ -x test_asyncio \ -x test_multiprocessing_fork \ -x test_multiprocessing_forkserver \ -x test_multiprocessing_spawn \ -x test_concurrent_futures \ -x test_socket \ -x test_subprocess \ -x test_signal \ -x test_sysconfig - uses: actions/upload-artifact@v4 if: always() with: name: hypothesis-example-db path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/examples/ build-asan: name: 'Address sanitizer' runs-on: ${{ matrix.os }} timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' strategy: fail-fast: false matrix: os: [ubuntu-24.04] env: OPENSSL_VER: 3.0.18 PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Set up GCC-10 for ASAN uses: egor-tensin/setup-gcc@v1 with: version: 10 - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - name: 'Restore OpenSSL build' id: cache-openssl uses: actions/cache@v4 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - name: Install OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - name: Configure CPython run: ./configure --config-cache --with-address-sanitizer --without-pymalloc - name: Build CPython run: make -j4 - name: Display build info run: make pythoninfo - name: Tests run: xvfb-run make ci build-san: # ${{ '' } is a hack to nest jobs under the same sidebar category. name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation] needs: build-context if: needs.build-context.outputs.run-tests == 'true' strategy: fail-fast: false matrix: check-name: - Thread free-threading: - false - true sanitizer: - TSan include: - check-name: Undefined behavior sanitizer: UBSan free-threading: false uses: ./.github/workflows/reusable-san.yml with: sanitizer: ${{ matrix.sanitizer }} free-threading: ${{ matrix.free-threading }} cross-build-linux: name: Cross build Linux runs-on: ubuntu-latest timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Set build dir run: # an absolute path outside of the working directoy echo "BUILD_DIR=$(realpath ${{ github.workspace }}/../build)" >> "$GITHUB_ENV" - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure host build run: ./configure --prefix="$BUILD_DIR/host-python" - name: Install host Python run: make -j8 install - name: Run test subset with host build run: | "$BUILD_DIR/host-python/bin/python3" -m test test_sysconfig test_site test_embed - name: Configure cross build run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3" - name: Install cross Python run: make -j8 install - name: Run test subset with host build run: | "$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed # CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/ cifuzz: name: CIFuzz runs-on: ubuntu-latest timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-ci-fuzz == 'true' permissions: security-events: write strategy: fail-fast: false matrix: sanitizer: [address, undefined, memory] steps: - name: Build fuzzers (${{ matrix.sanitizer }}) id: build uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: cpython3 sanitizer: ${{ matrix.sanitizer }} - name: Run fuzzers (${{ matrix.sanitizer }}) uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: fuzz-seconds: 600 oss-fuzz-project-name: cpython3 output-sarif: true sanitizer: ${{ matrix.sanitizer }} - name: Upload crash if: failure() && steps.build.outcome == 'success' uses: actions/upload-artifact@v4 with: name: ${{ matrix.sanitizer }}-artifacts path: ./out/artifacts - name: Upload SARIF if: always() && steps.build.outcome == 'success' uses: github/codeql-action/upload-sarif@v3 with: sarif_file: cifuzz-sarif/results.sarif checkout_path: cifuzz-sarif all-required-green: # This job does nothing and is only used for the branch protection name: All required checks pass runs-on: ubuntu-latest timeout-minutes: 5 needs: - build-context # Transitive dependency, needed to access `run-tests` value - check-docs - check-autoconf-regen - check-generated-files - build-windows - build-windows-msi - build-macos - build-ubuntu - build-ubuntu-ssltests-awslc - build-ubuntu-ssltests-openssl - build-android - build-ios - build-wasi - test-hypothesis - build-asan - build-san - cross-build-linux - cifuzz if: always() steps: - name: Check whether the needed jobs succeeded or failed uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe with: allowed-failures: >- build-windows-msi, build-ubuntu-ssltests-awslc, build-ubuntu-ssltests-openssl, test-hypothesis, cifuzz, allowed-skips: >- ${{ !fromJSON(needs.build-context.outputs.run-docs) && ' check-docs, ' || '' }} ${{ needs.build-context.outputs.run-tests != 'true' && ' check-autoconf-regen, check-generated-files, build-macos, build-ubuntu, build-ubuntu-ssltests-awslc, build-ubuntu-ssltests-openssl, build-android, build-ios, build-wasi, test-hypothesis, build-asan, build-san, cross-build-linux, ' || '' }} ${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && ' build-windows, ' || '' }} ${{ !fromJSON(needs.build-context.outputs.run-ci-fuzz) && ' cifuzz, ' || '' }} jobs: ${{ toJSON(needs) }}