What changed, and why it matters
This commit only adds time limits to automated GitHub Actions CI/CD jobs so they stop automatically if they run too long. It does not change any Trezor firmware code, wallet logic, cryptography, or user-facing behavior. There is no security vulnerability being fixed or introduced here.
No security action required. This is a routine CI maintenance change. Reviewers may verify the chosen timeout values are reasonable for normal job durations to avoid unnecessary CI failures.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit adds timeout-minutes directives to GitHub Actions workflow jobs across 16 workflow files. These timeouts cap how long CI jobs may run before GitHub cancels them, which helps prevent runaway jobs and resource waste. The change is purely operational CI hardening; it does not modify source code, build outputs, secrets handling, permissions, or any product security boundary.
Changed components
GitHub Actions CI/CD workflows onlyInspect captured patch +63 / −0
### .github/workflows/bot-auto-assign.yml
@@ -12,6 +12,7 @@ jobs:
# run only in 'trezor/trezor-firmware' repository, skipped for bots
if: github.repository == 'trezor/trezor-firmware' && !endsWith(github.event.pull_request.user.login, '[bot]')
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- name: Assign PR author to PR
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # actions/github-script@v8.0.0
### .github/workflows/bot-common-sync.yml
@@ -11,6 +11,7 @@ permissions:
jobs:
sync-common:
runs-on: ubuntu-latest
+ timeout-minutes: 5
env:
BOT_USERNAME: "trezor-bot[bot]"
BOT_EMAIL: "208941332+trezor-bot[bot]@users.noreply.github.com"
### .github/workflows/bot-needs-qa.yml
@@ -14,6 +14,7 @@ jobs:
# run only in 'trezor/trezor-firmware' repository
if: github.repository == 'trezor/trezor-firmware'
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- name: Generate GitHub App token
id: trezor-bot-token
### .github/workflows/bot-project-automation.yml
@@ -17,6 +17,7 @@ jobs:
# run only in 'trezor/trezor-firmware' repository
if: github.repository == 'trezor/trezor-firmware'
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- name: Generate GitHub App token
id: trezor-bot-token
### .github/workflows/bot-tropic-emulator.yml
@@ -32,6 +32,7 @@ jobs:
pr_comment:
name: Post a comment to the pull request
runs-on: ubuntu-latest
+ timeout-minutes: 5
if: github.event.action == 'opened' || github.event.action == 'synchronize'
permissions:
pull-requests: write # needed to post a comment
@@ -57,6 +58,7 @@ jobs:
issue_open:
name: Open an issue for trezor-user-env
runs-on: ubuntu-latest
+ timeout-minutes: 5
if: github.event.action == 'closed' && github.event.merged == true && github.repository == 'trezor/trezor-firmware'
env:
URL: ${{ github.event.pull_request.html_url }}
### .github/workflows/cflite.yml
@@ -18,6 +18,7 @@ jobs:
# run only in public repositories - fuzzer will fail in private forks (missing auth)
if: github.event.repository.private == false
runs-on: ubuntu-latest
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
### .github/workflows/common.yml
@@ -23,6 +23,7 @@ jobs:
crypto_build:
name: Crypto library
runs-on: ubuntu-latest
+ timeout-minutes: 15
env:
CC: gcc
ADDRESS_SANITIZER: 1
@@ -50,6 +51,7 @@ jobs:
name: Crypto test
needs: [crypto_build]
runs-on: ubuntu-latest
+ timeout-minutes: 15
env:
ASAN_OPTIONS: "verify_asan_link_order=0"
CK_TIMEOUT_MULTIPLIER: 5
@@ -72,6 +74,7 @@ jobs:
python_test:
name: Python test
runs-on: ubuntu-latest
+ timeout-minutes: 15
env:
LC_ALL: C.UTF-8
LANG: C.UTF-8
@@ -86,6 +89,7 @@ jobs:
rust_test:
name: Rust crates test
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
@@ -97,6 +101,7 @@ jobs:
name: Storage test
# TODO: only for changes in storage/
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
@@ -109,6 +114,7 @@ jobs:
docs_build:
name: Docs build
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
- uses: ./.github/actions/environment
@@ -130,6 +136,7 @@ jobs:
# scheduled, manual runs, push to release branches
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
+ timeout-minutes: 45
strategy:
fail-fast: false
matrix:
### .github/workflows/core-hw.yml
@@ -31,6 +31,7 @@ jobs:
param:
name: Determine pipeline parameters
runs-on: ubuntu-latest
+ timeout-minutes: 5
# No scheduled runs on forks.
if: github.repository == 'trezor/trezor-firmware' || github.event_name != 'schedule'
outputs:
@@ -118,6 +119,7 @@ jobs:
runs-on:
- self-hosted
- ${{ matrix.model == 'T2B1' && 'hw-t2b1' || matrix.model == 'T3T1' && 'hw-t3t1' || matrix.model == 'T3B1' && 'hw-t3b1' || matrix.model == 'T3W1' && 'hw-t3w1' || 'hw-t2t1' }}
+ timeout-minutes: 360
if: needs.param.outputs.core_models != '[]' && false # FIXME https://github.com/trezor/trezor-firmware/issues/3128
strategy:
fail-fast: false
@@ -163,6 +165,7 @@ jobs:
runs-on:
- self-hosted
- hw-t1b1
+ timeout-minutes: 240
if: needs.param.outputs.run_legacy == '1'
strategy:
fail-fast: false
### .github/workflows/core.yml
@@ -34,6 +34,7 @@ jobs:
param:
name: Determine pipeline parameters
runs-on: ubuntu-latest
+ timeout-minutes: 5
outputs:
test_lang: ${{ steps.set_vars.outputs.test_lang }}
asan: ${{ steps.set_vars.outputs.asan }}
@@ -49,6 +50,7 @@ jobs:
core_firmware:
name: Build firmware (${{ matrix.model }}, ${{ matrix.coins }}, ${{ matrix.type }}${{matrix.n1w1 && ', n1w1' || '' }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
strategy:
fail-fast: false
matrix:
@@ -114,6 +116,7 @@ jobs:
core_emu:
name: Build emu (${{ matrix.model }}, ${{ matrix.coins }}, ${{ matrix.type }}, ${{ matrix.asan }}${{matrix.n1w1 && ', n1w1' || '' }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs: param
strategy:
fail-fast: false
@@ -164,6 +167,7 @@ jobs:
if: github.event_name == 'schedule'
name: Build emu ARM (${{ matrix.model }}, ${{ matrix.coins }}, ${{ matrix.type }}, ${{ matrix.asan }}${{matrix.n1w1 && ', n1w1' || '' }})
runs-on: ubuntu-latest-arm64
+ timeout-minutes: 15
needs: param
strategy:
fail-fast: false
@@ -237,6 +241,7 @@ jobs:
core_unit_python_test:
name: Python unit tests (${{ matrix.model }}, ${{ matrix.coins }}, ${{ matrix.asan }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs: param
strategy:
fail-fast: false
@@ -265,6 +270,7 @@ jobs:
core_unit_rust_test:
name: Rust unit tests (${{ matrix.model }}, ${{ matrix.asan }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs:
- param
- core_emu
@@ -291,6 +297,7 @@ jobs:
core_rust_client_test:
name: Rust trezor-client tests
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs: core_emu
strategy:
fail-fast: false
@@ -523,6 +530,7 @@ jobs:
if: false # XXX currently failing
continue-on-error: true
runs-on: ubuntu-latest
+ timeout-minutes: 60
needs: core_emu
strategy:
fail-fast: false
@@ -552,6 +560,7 @@ jobs:
name: Memory allocation report
if: false # NOTE manual job, comment out to run
runs-on: ubuntu-latest
+ timeout-minutes: 60
env:
TREZOR_MODEL: T2T1
TREZOR_MEMPERF: 1
@@ -582,6 +591,7 @@ jobs:
core_flash_size_check:
name: Flash size check
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs: core_firmware
strategy:
fail-fast: false
@@ -602,6 +612,7 @@ jobs:
core_monero_test:
name: Monero test (${{ matrix.model }}, ${{ matrix.asan }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs:
- param
- core_emu
@@ -641,6 +652,7 @@ jobs:
core_u2f_test:
name: U2F test (${{ matrix.model }}, ${{ matrix.asan }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs:
- param
- core_emu
@@ -676,6 +688,7 @@ jobs:
core_fido2_test:
name: FIDO2 test (${{ matrix.model }}, ${{ matrix.asan }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs:
- param
- core_emu
@@ -710,6 +723,7 @@ jobs:
core_coverage_report:
name: Coverage report
runs-on: ubuntu-latest
+ timeout-minutes: 20
needs:
- core_emu
- core_click_test
@@ -754,6 +768,7 @@ jobs:
binaries_size_report:
name: Binaries' size report
runs-on: ubuntu-latest
+ timeout-minutes: 5
needs:
- core_firmware
steps:
@@ -776,6 +791,7 @@ jobs:
# run UI comment job only for 'trezor/trezor-firmware' scheduled workflows and internal PRs (see #5381)
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.repository == 'trezor/trezor-firmware'
runs-on: ubuntu-latest
+ timeout-minutes: 10
needs:
- param
steps:
@@ -806,6 +822,7 @@ jobs:
name: Upload emulator binaries
if: github.event_name == 'schedule' && github.repository == 'trezor/trezor-firmware'
runs-on: ubuntu-latest
+ timeout-minutes: 10
needs:
- core_emu
- core_emu_arm
@@ -838,6 +855,7 @@ jobs:
# Not building it for nightly CI
if: github.event_name != 'schedule' && github.repository == 'trezor/trezor-firmware'
runs-on: ubuntu-latest
+ timeout-minutes: 10
needs:
# Do not include ARM, they are only built on nightly
- core_emu
@@ -873,6 +891,7 @@ jobs:
rust_deps_check:
name: Rust dependencies check
runs-on: ubuntu-latest
+ timeout-minutes: 20
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
@@ -885,6 +904,7 @@ jobs:
name: Unsigned firmware archive # for release QA purposes
if: github.event_name == 'push' # release branches only, only those currently trigger push
runs-on: ubuntu-latest
+ timeout-minutes: 60
needs: core_firmware
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
@@ -916,6 +936,7 @@ jobs:
name: Upload nightly firmware
if: github.event_name == 'schedule' # scheduled nightly runs only
runs-on: ubuntu-latest
+ timeout-minutes: 20
needs: core_firmware
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
### .github/workflows/crowdin-pull.yml
@@ -25,6 +25,7 @@ concurrency:
jobs:
crowdin-pull-and-pr:
runs-on: ubuntu-latest
+ timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
### .github/workflows/crowdin-push.yml
@@ -15,6 +15,7 @@ jobs:
name: Split and upload sources
if: github.ref_name == 'main' # run only when dispatched from main
runs-on: ubuntu-latest
+ timeout-minutes: 20
environment: crowdin
steps:
- name: Checkout
### .github/workflows/crowdin-ui-check-reuse.yml
@@ -18,6 +18,7 @@ jobs:
core_context_tests:
name: Context tests (${{ matrix.model }}, universal, noasan, ${{ matrix.language }})
runs-on: ubuntu-latest
+ timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -60,6 +61,7 @@ jobs:
core_ui_comment:
name: Comment with UI flows
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
### .github/workflows/crowdin-ui-check.yml
@@ -25,6 +25,7 @@ jobs:
core_emu:
name: Build emulator (${{ matrix.model }}, universal, debuglink, noasan)
runs-on: ubuntu-latest
+ timeout-minutes: 20
strategy:
fail-fast: false
matrix:
@@ -56,6 +57,8 @@ jobs:
if: ${{ !inputs.all-languages }}
permissions:
id-token: write # for fetching OIDC token for AWS in reusable workflow jobs
+ # A reusable-workflow call cannot declare `timeout-minutes` -- the called
+ # workflow's jobs carry them. TODO: pass it as a `workflow_call` input.
uses: ./.github/workflows/crowdin-ui-check-reuse.yml
with:
languages: '["en", "${{ inputs.language }}"]'
@@ -65,6 +68,8 @@ jobs:
if: ${{ inputs.all-languages }}
permissions:
id-token: write # for fetching OIDC token for AWS in reusable workflow jobs
+ # A reusable-workflow call cannot declare `timeout-minutes` -- the called
+ # workflow's jobs carry them. TODO: pass it as a `workflow_call` input.
uses: ./.github/workflows/crowdin-ui-check-reuse.yml
with:
languages: '["en", "cs", "fr", "de", "es", "pt"]'
### .github/workflows/legacy.yml
@@ -38,6 +38,7 @@ jobs:
legacy_firmware:
name: Firmware
runs-on: ubuntu-latest
+ timeout-minutes: 20
strategy:
matrix:
coins: [universal, btconly]
@@ -64,6 +65,7 @@ jobs:
legacy_emu:
name: Emulator
runs-on: ubuntu-latest
+ timeout-minutes: 20
strategy:
matrix:
coins: [universal, btconly]
@@ -95,6 +97,7 @@ jobs:
if: github.event_name == 'schedule'
name: Emulator arm
runs-on: ubuntu-latest-arm64
+ timeout-minutes: 20
strategy:
matrix:
coins: [universal]
@@ -184,6 +187,7 @@ jobs:
if: false # XXX currently failing
continue-on-error: true
runs-on: ubuntu-latest
+ timeout-minutes: 30
needs: legacy_emu
env:
EMULATOR: 1
@@ -206,6 +210,7 @@ jobs:
name: Upload emulator binaries
if: github.event_name == 'schedule' && github.repository == 'trezor/trezor-firmware'
runs-on: ubuntu-latest
+ timeout-minutes: 15
needs:
- legacy_emu
- legacy_emu_arm
### .github/workflows/prebuild.yml
@@ -20,6 +20,7 @@ jobs:
name: Block fixup
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
- name: Block Fixup Commit Merge
@@ -32,6 +33,7 @@ jobs:
style_check:
name: Style check
runs-on: ubuntu-latest
+ timeout-minutes: 20
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
- name: Initialize and update ts-tvl
@@ -49,6 +51,7 @@ jobs:
defs_check:
name: Defs check
runs-on: ubuntu-latest
+ timeout-minutes: 20
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
@@ -61,6 +64,7 @@ jobs:
gen_check:
name: Gen check
runs-on: ubuntu-latest
+ timeout-minutes: 20
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
@@ -73,6 +77,7 @@ jobs:
uvlock_check:
name: uv.lock check
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
@@ -89,6 +94,7 @@ jobs:
name: Changelog check
if: ${{ github.ref != 'main' && github.event_name == 'pull_request' }}
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout@v6.0.2
with:
### .github/workflows/release-emu.yml
@@ -32,6 +32,7 @@ jobs:
get_models:
name: Get models
runs-on: ubuntu-latest
+ timeout-minutes: 5
outputs:
models: ${{ steps.get_models.outputs.models }}
version: ${{ steps.get_models.outputs.version }}
@@ -59,6 +60,7 @@ jobs:
name: Build emu
needs: get_models
runs-on: ubuntu-latest
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
@@ -84,6 +86,7 @@ jobs:
name: Build core emu arm
needs: get_models
runs-on: ubuntu-latest-arm64
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
@@ -110,6 +113,7 @@ jobs:
name: Build legacy emu
needs: get_models
runs-on: ubuntu-latest
+ timeout-minutes: 20
strategy:
matrix:
coins: [universal]
@@ -133,6 +137,7 @@ jobs:
name: Build legacy emu arm
needs: get_models
runs-on: ubuntu-latest-arm64
+ timeout-minutes: 20
strategy:
matrix:
coins: [universal]Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.