Skip to content

[crypto] Harden RSA modexp subroutine. #3598

[crypto] Harden RSA modexp subroutine.

[crypto] Harden RSA modexp subroutine. #3598

Workflow file for this run

# Copyright lowRISC contributors (OpenTitan project).
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: CI
on:
pull_request:
push:
branches-ignore:
- "backport-*"
tags:
- "*"
permissions:
contents: read
# Needed for workload identity federation
id-token: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
VIVADO_VERSION: "2021.1"
# Release tag from https://github.com/lowRISC/lowrisc-toolchains/releases
TOOLCHAIN_VERSION: 20220210-1
jobs:
quick_lint:
name: Lint (quick)
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required so we can lint commit messages.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Show environment
run: ./ci/scripts/show-env.sh
- name: Commit metadata
run: ./ci/scripts/lint-commits.sh "$GITHUB_BASE_REF"
if: ${{ github.event_name == 'pull_request' }}
- name: License headers
run: ./ci/scripts/check-licence-headers.sh "$GITHUB_BASE_REF"
if: ${{ github.event_name == 'pull_request' }}
- name: Executable bits
run: ./ci/scripts/exec-check.sh
- name: Non-ASCII characters
run: ./ci/scripts/check-ascii.sh
- name: Python (flake8)
run: ./ci/scripts/python-lint.sh "$GITHUB_BASE_REF"
if: ${{ github.event_name == 'pull_request' }}
- name: Python (mypy)
run: ./ci/scripts/mypy.sh
- name: Validate testplans with schema
run: ./ci/scripts/validate_testplans.sh
- name: C/C++ formatting
run: ./bazelisk.sh test //quality:clang_format_check
- name: Rust formatting
run: ./bazelisk.sh test //quality:rustfmt_check
- name: Shellcheck
run: ./bazelisk.sh test //quality:shellcheck_check
- name: Header guards
run: ./ci/scripts/include-guard.sh "$GITHUB_BASE_REF"
if: ${{ github.event_name == 'pull_request' }}
- name: Trailing whitespace
run: ./ci/scripts/whitespace.sh "$GITHUB_BASE_REF"
if: ${{ github.event_name == 'pull_request' }}
- name: Broken links
run: ./ci/scripts/check-links.sh
- name: Generated documentation
run: ./ci/scripts/check-cmdgen.sh
slow_lint:
name: Lint (slow)
runs-on: ubuntu-22.04
needs: quick_lint
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Bitstream cache requires all commits.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Countermeasures implemented (earlgrey)
run: ./ci/scripts/check-countermeasures.sh earlgrey
continue-on-error: true
- name: Countermeasures implemented (englishbreakfast)
run: ./ci/scripts/check-countermeasures.sh englishbreakfast
continue-on-error: true
- name: Bazel test suite tags
run: ./ci/scripts/check_bazel_test_suites.py
continue-on-error: true
# See #21973: disabled until Verilator tags are fixed.
# - name: Check Bazel tags
# run: ./ci/scripts/check-bazel-tags.sh
# continue-on-error: true
- name: Banned Bazel rules
run: ./ci/scripts/check-bazel-banned-rules.sh
- name: Bazel target names
run: ./ci/scripts/check_bazel_target_names.py
continue-on-error: true
- name: DV software images
run: ./ci/scripts/check_dv_sw_images.sh
continue-on-error: true
- name: Generated files
run: ./ci/scripts/check-generated.sh
env:
OT_DESTRUCTIVE: 1 # Required by the script to clean up.
- name: Buildifier
run: ./bazelisk.sh test //quality:buildifier_check
- name: Vendored files
run: ./ci/scripts/check-vendoring.sh
- name: Verible RTL
run: ./ci/scripts/verible-lint.sh rtl
- name: Verible DV
run: ./ci/scripts/verible-lint.sh dv
- name: Verible FPV
run: ./ci/scripts/verible-lint.sh fpv
build_docs:
name: Build documentation
runs-on: ubuntu-22.04
needs: quick_lint
env:
BUCKET: gold-hybrid-255313-prod
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Bitstream cache requires all commits.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Build documentation
run: util/site/build-docs.sh build
- name: Upload files
if: ${{ github.event_name != 'pull_request' && github.ref_name == 'master' }}
run: |
echo "::group::Upload all uncompressed files"
gcloud storage cp -R --gzip-in-flight=js,css,html "build-site/*" gs://$BUCKET
echo "::endgroup::"
# This script compresses the searchindex files, replacing the originals in-place.
# (This is how 'content-encoding'-tagged files should be uploaded to gcloud buckets)
util/site/post-build.sh compress_br
search_indexes=$(find build-site/ -type f -name '*searchindex.json')
for f in $search_indexes; do
echo "Uploading compressed file ${f}"
# Get directory of file, relative to the build directory.
# - var=${var#*//} # removes stuff from the begining up to //
dir=$(dirname "${f#*build-site/}")
# When serving from gcloud buckets, file should be uploaded with an identical name as the
# original, but compressed and with the matching 'content-encoding' and 'content-type' tags applied.
gcloud storage cp \
--content-encoding=br \
--content-type=application/json \
-R \
"$f" "gs://$BUCKET/${dir}/"
done
airgapped_build:
name: Airgapped build
runs-on: ubuntu-22.04
needs: quick_lint
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Bitstream cache requires all commits.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
configure-bazel: false
- name: Free disk space
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Check disk space
run: |
df -h
- name: Prepare airgapped environment
run: ./util/prep-bazel-airgapped-build.sh
- name: Check disk space
run: |
df -h
- name: Build in the airgapped environment
run: ./ci/scripts/test-airgapped-build.sh
verible_lint:
name: Verible lint
runs-on: ubuntu-24.04
needs: quick_lint
if: ${{ github.event_name == 'pull_request' }}
env:
verible_config: hw/lint/tools/veriblelint/lowrisc-styleguide.rules.verible_lint
verible_version: v0.0-3430-g060bde0f
steps:
- uses: actions/checkout@v4
- name: Prepare Verible config
run: |
echo "Concatenating Verible waivers"
find . -type f -name '*.vbl' -exec cat {} \; >> verible_waiver
echo "::group::Verible config"
cat "$verible_config"
echo "::endgroup::"
echo "::group::Verible waiver"
cat "verible_waiver"
echo "::endgroup::"
- name: Run Verible linter action
uses: chipsalliance/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
verible_version: ${{ env.verible_version }}
reviewdog_reporter: 'github-pr-check'
suggest_fixes: 'false'
config_file: ${{ env.verible_config }}
extra_args: "--waiver_files=verible_waiver"
otbn_standalone_tests:
name: Run OTBN smoke Test
needs: quick_lint
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Bitstream cache requires all commits.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Install toolchain
run: |
TOOLCHAIN_PATH=/tools/riscv
sudo util/get-toolchain.py \
--install-dir="$TOOLCHAIN_PATH" \
--release-version="$TOOLCHAIN_VERSION" \
--update
echo "$TOOLCHAIN_PATH/bin" >> $GITHUB_PATH
- name: Display environment
run: |
python3 --version
fusesoc --version
verilator --version
- name: OTBN ISS test
run: make -C hw/ip/otbn/dv/otbnsim test
- name: OBTN smoke test
run: ./hw/ip/otbn/dv/smoke/run_smoke.sh
- name: Assemble & link code snippets
run: make -C hw/ip/otbn/util asm-check
otbn_crypto_tests:
name: Run OTBN crypto tests
needs: quick_lint
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Bitstream cache requires all commits.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Execute tests
run: ./bazelisk.sh test --test_tag_filters=-nightly //sw/otbn/crypto/...
verilator_englishbreakfast:
name: Verilated English Breakfast
runs-on: ubuntu-22.04
needs: quick_lint
steps:
- uses: actions/checkout@v4
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Build simulator with Verilator
run: ./ci/scripts/build-chip-verilator.sh englishbreakfast
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: verilated_englishbreakfast
path: build-bin/hw/top_englishbreakfast/Vchip_englishbreakfast_verilator
overwrite: true
- name: Test
run: ./ci/scripts/run-english-breakfast-verilator-tests.sh
verilator_earlgrey:
name: Verilated Earl Grey
runs-on: ubuntu-20.04
needs: quick_lint
timeout-minutes: 240
steps:
- uses: actions/checkout@v4
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Run fast Verilator tests
run: ./ci/scripts/run-verilator-tests.sh
- name: Publish Bazel test results
uses: ./.github/actions/publish-bazel-test-results
if: ${{ !cancelled() }}
with:
artifact-name: verilator_earlgrey-test-results
# Build CW305 variant of the English Breakfast toplevel design using Vivado
chip_englishbreakfast_cw305:
name: CW305's Bitstream
runs-on: ubuntu-22.04-vivado
needs: quick_lint
steps:
- uses: actions/checkout@v4
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Build bitstream
run: |
# Build CW305 test rom required by `build-bitstream-vivado.sh`
rom_path="sw/device/lib/testing/test_rom"
./bazelisk.sh build "//${rom_path}:test_rom_fpga_cw305" \
--features=-rv32_bitmanip \
--copt=-DOT_IS_ENGLISH_BREAKFAST_REDUCED_SUPPORT_FOR_INTERNAL_USE_ONLY_
vmem="$(./bazelisk.sh cquery --output=files "//${rom_path}:test_rom_fpga_cw305" \
--features=-rv32_bitmanip \
--copt=-DOT_IS_ENGLISH_BREAKFAST_REDUCED_SUPPORT_FOR_INTERNAL_USE_ONLY_
)"
mkdir -p "build-bin/${rom_path}"
cp "$vmem" "build-bin/${rom_path}"
module load "xilinx/vivado/${VIVADO_VERSION}"
ci/scripts/build-bitstream-vivado.sh top_englishbreakfast cw305
- name: Upload bitstream
uses: actions/upload-artifact@v4
with:
name: chip_englishbreakfast_cw305
path: build-bin/hw/top_englishbreakfast/lowrisc_systems_chip_englishbreakfast_cw305_0.1.bit
overwrite: true
chip_earlgrey_cw310:
name: Earl Grey for CW310
needs: quick_lint
uses: ./.github/workflows/bitstream.yml
secrets: inherit
with:
top_name: earlgrey
design_suffix: cw310
chip_earlgrey_cw310_hyperdebug:
name: Earl Grey for CW310 Hyperdebug
needs: quick_lint
uses: ./.github/workflows/bitstream.yml
secrets: inherit
with:
top_name: earlgrey
design_suffix: cw310_hyperdebug
chip_earlgrey_cw340:
name: Earl Grey for CW340
needs: quick_lint
uses: ./.github/workflows/bitstream.yml
secrets: inherit
with:
top_name: earlgrey
design_suffix: cw340
cache_bitstreams:
name: Cache bitstreams to GCP
runs-on: ubuntu-22.04
if: ${{ github.event_name != 'pull_request' }}
needs:
- chip_earlgrey_cw310
- chip_earlgrey_cw310_hyperdebug
- chip_earlgrey_cw340
steps:
- uses: actions/checkout@v4
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Download partial build-bin
uses: ./.github/actions/download-partial-build-bin
with:
job-patterns: chip_earlgrey_{cw310,cw310_hyperdebug,cw340}
- name: Create bitstream cache archive
run: |
shopt -s globstar # Allow use of **
./bazelisk.sh build //util/py/scripts:bitstream_cache_create
./bazelisk.sh run //util/py/scripts:bitstream_cache_create -- \
--schema $PWD/rules/scripts/bitstreams_manifest.schema.json \
--stamp-file $PWD/bazel-out/volatile-status.txt \
--out $PWD/build-bin/bitstream-cache \
$PWD/build-bin/**/manifest.json
- name: Upload bitstreams to GCP bucket
run: |
BUCKET_URI=gs://opentitan-bitstreams/${{ github.ref_name }}
printf "$(date -u +%Y-%m-%dT%H:%M:%S)\n${{ github.sha }}" > latest.txt
gcloud storage cp build-bin/bitstream-cache/bitstream-cache.tar.gz $BUCKET_URI/bitstream-${{ github.sha }}.tar.gz
gcloud storage cp latest.txt $BUCKET_URI/latest.txt
gcloud storage cp $BUCKET_URI/bitstream-${{ github.sha }}.tar.gz $BUCKET_URI/bitstream-latest.tar.gz
# CW310 FPGA jobs.
execute_test_rom_fpga_tests_cw310:
name: CW310 Test ROM Tests
needs: chip_earlgrey_cw310
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_test_rom_fpga_tests_cw310
bitstream: chip_earlgrey_cw310
board: cw310
interface: cw310
tag_filters: cw310_test_rom
execute_rom_fpga_tests_cw310:
name: CW310 ROM Tests
needs: chip_earlgrey_cw310
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_rom_fpga_tests_cw310
bitstream: chip_earlgrey_cw310
board: cw310
interface: cw310
tag_filters: "cw310_rom_with_fake_keys,cw310_rom_with_real_keys,-manuf"
timeout: 90
execute_rom_ext_fpga_tests_cw310:
name: CW310 ROM_EXT Tests
needs: chip_earlgrey_cw310
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_rom_ext_fpga_tests_cw310
bitstream: chip_earlgrey_cw310
board: cw310
interface: cw310
tag_filters: cw310_rom_ext
execute_sival_fpga_tests_cw310:
name: CW310 SiVal Tests
needs: chip_earlgrey_cw310_hyperdebug
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_sival_fpga_tests_cw310
bitstream: chip_earlgrey_cw310_hyperdebug
board: cw310
interface: hyper310
tag_filters: "cw310_sival,-manuf"
execute_sival_rom_ext_fpga_tests_cw310:
name: CW310 SiVal ROM_EXT Tests
needs: chip_earlgrey_cw310_hyperdebug
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_sival_rom_ext_fpga_tests_cw310
bitstream: chip_earlgrey_cw310_hyperdebug
board: cw310
interface: hyper310
tag_filters: cw310_sival_rom_ext
execute_manuf_fpga_tests_cw310:
name: CW310 Manufacturing Tests
needs: chip_earlgrey_cw310_hyperdebug
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_manuf_fpga_tests_cw310
bitstream: chip_earlgrey_cw310_hyperdebug
board: cw310
interface: hyper310
tag_filters: "manuf,-cw340"
# CW340 FPGA jobs
execute_test_rom_fpga_tests_cw340:
name: CW340 Test ROM Tests
needs: chip_earlgrey_cw340
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_test_rom_fpga_tests_cw340
bitstream: chip_earlgrey_cw340
board: cw340
interface: cw340
tag_filters: cw340_test_rom
execute_rom_fpga_tests_cw340:
name: CW340 ROM Tests
needs: chip_earlgrey_cw340
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_rom_fpga_tests_cw340
bitstream: chip_earlgrey_cw340
board: cw340
interface: cw340
tag_filters: "cw340_rom_with_fake_keys,cw340_rom_with_real_keys,-manuf"
execute_rom_ext_fpga_tests_cw340:
name: CW340 ROM_EXT Tests
needs: chip_earlgrey_cw340
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_rom_ext_fpga_tests_cw340
bitstream: chip_earlgrey_cw340
board: cw340
interface: cw340
tag_filters: cw340_rom_ext
execute_sival_fpga_tests_cw340:
name: CW340 SiVal Tests
needs: chip_earlgrey_cw340
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_sival_fpga_tests_cw340
bitstream: chip_earlgrey_cw340
board: cw340
interface: cw340
tag_filters: "cw340_sival,-manuf"
execute_sival_rom_ext_fpga_tests_cw340:
name: CW340 SiVal ROM_EXT Tests
needs: chip_earlgrey_cw340
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_sival_rom_ext_fpga_tests_cw340
bitstream: chip_earlgrey_cw340
board: cw340
interface: cw340
tag_filters: cw340_sival_rom_ext
execute_manuf_fpga_tests_cw340:
name: CW340 Manufacturing Tests
needs: chip_earlgrey_cw340
uses: ./.github/workflows/fpga.yml
secrets: inherit
with:
job_name: execute_manuf_fpga_tests_cw340
bitstream: chip_earlgrey_cw340
board: cw340
interface: cw340
tag_filters: "manuf,-hyper310"
verify_fpga_jobs:
name: Verify FPGA jobs
runs-on: ubuntu-22.04
needs:
- execute_test_rom_fpga_tests_cw310
- execute_rom_fpga_tests_cw310
- execute_rom_ext_fpga_tests_cw310
- execute_sival_fpga_tests_cw310
- execute_sival_rom_ext_fpga_tests_cw310
- execute_manuf_fpga_tests_cw310
- execute_test_rom_fpga_tests_cw340
- execute_rom_fpga_tests_cw340
- execute_rom_ext_fpga_tests_cw340
- execute_sival_fpga_tests_cw340
- execute_sival_rom_ext_fpga_tests_cw340
- execute_manuf_fpga_tests_cw340
if: success() || failure()
steps:
- uses: actions/checkout@v4
- name: Download target pattern files
uses: actions/download-artifact@v4
with:
pattern: execute_*-targets
path: verify_fpga_jobs
- name: List all target pattern files
run: |
find verify_fpga_jobs
- name: Checking for duplicate test runs
run: |
# Find and display all duplicates:
# - for each target file and each line, print '<job_name> <target>'
# - then sort by the target name
# - then keep all duplicated lines
pattern_files=$(find verify_fpga_jobs -name target_pattern_file.txt)
awk '{ print(gensub(/.*\/(.+)\/target_pattern_file.txt/, "\\1", "g", FILENAME) " " $0) }' $pattern_files | sort -k2 | uniq -D -f1 > duplicates.txt
if [ -s duplicates.txt ]; then
echo "The following tests ran in two or more jobs:"
cat duplicates.txt
false
fi
- name: Checking for missing test runs
if: success() || failure()
run: |
# Find and display tests that did not run:
./ci/scripts/run-bazel-test-query.sh all_fpga.txt fpga,-manual,-broken,-skip_in_ci //... @manufacturer_test_hooks//...
sort -o all_fpga.txt all_fpga.txt
pattern_files=$(find verify_fpga_jobs -name target_pattern_file.txt)
sort $pattern_files > all_run.txt
comm -23 all_fpga.txt all_run.txt > missing.txt
if [ -s missing.txt ]; then
echo "The following tests did not run in any job:"
cat missing.txt
false
fi
build_docker_containers:
name: Build Docker Containers
runs-on: ubuntu-22.04
needs: quick_lint
steps:
- uses: actions/checkout@v4
- name: Build Developer Utility Container
uses: docker/build-push-action@v6
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
with:
context: .
file: util/container/Dockerfile
continue-on-error: true
- name: Build Documentation Redirector Container
uses: docker/build-push-action@v6
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
with:
context: site/redirector/landing
sw_build_test:
name: Build and test software
runs-on: ubuntu-22.04-vivado
timeout-minutes: 120
needs: quick_lint
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for bitstream cache to work.
- name: Prepare environment
uses: ./.github/actions/prepare-env
with:
service_account_json: '${{ secrets.BAZEL_CACHE_CREDS }}'
- name: Check Bazel build graph
run: |
# Test the graph with both an empty and filled bitstream cache.
./ci/scripts/test-empty-bitstream-cache.sh
./bazelisk.sh build --nobuild //...
- name: Select software targets
run: |
target_pattern_file="$(mktemp)"
echo "target_pattern_file=${target_pattern_file}" >> "$GITHUB_ENV"
# Start with building the whole graph.
echo '//...' > "$target_pattern_file"
# Exclude some targets:
#
# 1. `//hw/...` is out of scope.
# 2. `//quality/...` is tested by the lint jobs.
# 3. `//sw/otbn/crypto/...` is tested by the OTBN job.
# 4. `//third_party/...` which is not our code.
printf "%s\n" \
"-//hw/..." \
"-//quality/..." \
"-//sw/otbn/crypto/..." \
"-//third_party/..." \
>> "$target_pattern_file"
# Exclude anything that requires a bitstream splice.
./bazelisk.sh cquery \
--noinclude_aspects \
--output=starlark \
--starlark:expr='"-{}".format(target.label)' \
--define DISABLE_VERILATOR_BUILD=true \
-- "rdeps(//..., kind(bitstream_splice, //...))" \
>> "$target_pattern_file"
- name: Build software targets
run: |
# Build everything we selected, excluding some tags.
./bazelisk.sh build \
--build_tests_only=false \
--define DISABLE_VERILATOR_BUILD=true \
--test_tag_filters=-broken,-cw310,-verilator,-dv \
--target_pattern_file="$target_pattern_file"
- name: Run software unit tests
run: |
./bazelisk.sh test \
--build_tests_only=false \
--test_output=errors \
--define DISABLE_VERILATOR_BUILD=true \
--test_tag_filters=-broken,-cw310,-verilator,-dv,-silicon \
--target_pattern_file="$target_pattern_file"
- name: Publish Bazel test results
uses: ./.github/actions/publish-bazel-test-results
if: ${{ !cancelled() }}
with:
artifact-name: sw_build_test-test-results
- name: Check for unrunnable tests
run: ./ci/scripts/check-unrunnable-tests.sh
continue-on-error: true