From 257e1ae1c8fb7aa099ce9a98e52a4c6606832398 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 17:11:21 +0200 Subject: [PATCH 01/12] test: reenable Coldcard singlesig transaction signing Restrict the Coldcard transaction cases to singlesig inputs, which do not require multisig wallets to be preloaded in the simulator. --- test/test_coldcard.py | 6 +++--- test/test_device.py | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/test_coldcard.py b/test/test_coldcard.py index ca64aa523..7d568ca80 100755 --- a/test/test_coldcard.py +++ b/test/test_coldcard.py @@ -147,9 +147,9 @@ def coldcard_test_suite(simulator, bitcoind, interface): dev_emulator = ColdcardSimulator(simulator) signtx_cases = [ - (["legacy"], ["legacy"], False, False), - (["segwit"], ["segwit"], False, False), - (["legacy", "segwit"], ["legacy", "segwit"], False, False), + (["legacy"], [], False, False), + (["segwit"], [], False, False), + (["legacy", "segwit"], [], False, False), ] # Generic device tests diff --git a/test/test_device.py b/test/test_device.py index 0b0fe45ba..5a55185a4 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -591,10 +591,6 @@ def _test_signtx(self, input_types, multisig_types, external, op_return: bool): # Test wrapper to avoid mixed-inputs signing for Ledger def test_signtx(self): - if self.emulator.type == "coldcard": - # https://github.com/bitcoin-core/HWI/pull/795#issuecomment-3112271927 - raise unittest.SkipTest("Coldcard sign test temporarily disabled") - for addrtypes, multisig_types, external, op_return in self.signtx_cases: with self.subTest(addrtypes=addrtypes, multisig_types=multisig_types, external=external, op_return=op_return): self._test_signtx(addrtypes, multisig_types, external, op_return) From 893818a3f6421a2125260f0c81c68702b79e9ae0 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 14:03:53 +0200 Subject: [PATCH 02/12] test: bump Coldcard firmware to 5.6.0 Drop note to keep COLDCARD_VERSION in sync, because the install action consumes the simulator artifact built by setup_environment.sh. --- test/setup_environment.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/setup_environment.sh b/test/setup_environment.sh index ac76242d9..54d9207aa 100755 --- a/test/setup_environment.sh +++ b/test/setup_environment.sh @@ -72,8 +72,7 @@ KEEPKEY_VERSION="v7.10.0" SPECULOS_VERSION="ed952a54801f59a71399462b5422976d84c817bb" # Requires Python >=3.10 (v0.25.11+) JADE_VERSION="1.0.36" -# Keep COLDCARD_VERSION in sync with .github/actions/install-sim/action.yml -COLDCARD_VERSION="2025-09-30T1238-v5.4.4" +COLDCARD_VERSION="2026-07-31T0519-v5.6.0" if [[ -n ${build_trezor_1} || -n ${build_trezor_t} ]]; then # Clone trezor-firmware if it doesn't exist, or update it if it does @@ -163,7 +162,7 @@ if [[ -n ${build_coldcard} ]]; then coldcard_setup_needed=true fi fi - # Apply patch to make simulator work in linux environments + # Add multisig fixtures used by the Coldcard multisig display tests. git am ../../data/coldcard-multisig.patch # Build the simulator. This is cached, but it is also fast @@ -172,7 +171,7 @@ if [[ -n ${build_coldcard} ]]; then cd unix if [ "$coldcard_setup_needed" == true ] ; then pushd ../external/micropython - # Apply Ubuntu 24.04 compiler warning fixes (included in ColdCard firmware v5.4.4+) + # Do not treat new warnings from Ubuntu 24.04's compiler as errors. git apply ../../ubuntu24_mpy.patch popd pushd ../external/micropython/mpy-cross/ From 9b420ea7240bc11a720bdea0b2a20a842cea5899 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 14:17:07 +0200 Subject: [PATCH 03/12] test: limit Coldcard simulator checkout Initialize only the firmware submodules needed by simulator setup instead of recursively fetching unrelated embedded dependencies. Build against the system libffi rather than MicroPython's bundled copy, which current Autoconf rejects. Apply the multisig fixture with git apply rather than git am, so updating the firmware checkout does not require resetting a fixed number of commits. --- test/setup_environment.sh | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/test/setup_environment.sh b/test/setup_environment.sh index 54d9207aa..72876b8c3 100755 --- a/test/setup_environment.sh +++ b/test/setup_environment.sh @@ -140,30 +140,20 @@ if [[ -n ${build_coldcard} ]]; then # Clone coldcard firmware if it doesn't exist, or update it if it does coldcard_setup_needed=false if [ ! -d "firmware" ]; then - # Note: cannot use --shallow-submodules because lwip submodule on git.savannah.gnu.org doesn't support it - git clone --recursive --depth 1 --branch ${COLDCARD_VERSION} https://github.com/Coldcard/firmware.git + git clone --depth 1 --branch ${COLDCARD_VERSION} https://github.com/Coldcard/firmware.git cd firmware + # Simulator setup initializes the required nested dependencies. + git submodule update --init coldcard_setup_needed=true else cd firmware - git reset --hard HEAD~3 # Undo git-am for checking and updating - git fetch - - # Determine if we need to pull. From https://stackoverflow.com/a/3278427 - UPSTREAM=${1:-'@{u}'} - LOCAL=$(git rev-parse @) - REMOTE=$(git rev-parse "$UPSTREAM") - BASE=$(git merge-base @ "$UPSTREAM") - - if [ $LOCAL = $REMOTE ]; then - echo "Up-to-date" - elif [ $LOCAL = $BASE ]; then - git pull - coldcard_setup_needed=true - fi + git fetch --tags origin + git checkout --force "${COLDCARD_VERSION}" + git submodule update --init --force + coldcard_setup_needed=true fi # Add multisig fixtures used by the Coldcard multisig display tests. - git am ../../data/coldcard-multisig.patch + git apply ../../data/coldcard-multisig.patch # Build the simulator. This is cached, but it is also fast poetry run pip install -r requirements.txt @@ -177,8 +167,12 @@ if [[ -n ${build_coldcard} ]]; then pushd ../external/micropython/mpy-cross/ make popd - make setup + # Skip make setup, which builds MicroPython's bundled libffi and + # fails with current Autoconf. The simulator links system libffi. + # Initialize its only required MicroPython submodule directly. + git -C ../external/micropython submodule update --init lib/berkeley-db-1.xx make ngu-setup + ln -sf ../external/micropython/ports/unix/coldcard-mpy . fi make cd ../.. From 57b062ee12a5bdf3773a509a203d58aa95c287ae Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 13:36:22 +0200 Subject: [PATCH 04/12] test: factor out Coldcard firmware setup Extract the Coldcard firmware setup into a helper for reuse by other firmware variants. Review hint: git show --color-moved=dimmed-zebra \ --color-moved-ws=allow-indentation-change --- test/setup_environment.sh | 82 +++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/test/setup_environment.sh b/test/setup_environment.sh index 72876b8c3..d2e8dec6e 100755 --- a/test/setup_environment.sh +++ b/test/setup_environment.sh @@ -137,45 +137,53 @@ if [[ -n ${build_trezor_1} || -n ${build_trezor_t} ]]; then fi if [[ -n ${build_coldcard} ]]; then - # Clone coldcard firmware if it doesn't exist, or update it if it does - coldcard_setup_needed=false - if [ ! -d "firmware" ]; then - git clone --depth 1 --branch ${COLDCARD_VERSION} https://github.com/Coldcard/firmware.git - cd firmware - # Simulator setup initializes the required nested dependencies. - git submodule update --init - coldcard_setup_needed=true - else - cd firmware - git fetch --tags origin - git checkout --force "${COLDCARD_VERSION}" - git submodule update --init --force - coldcard_setup_needed=true - fi - # Add multisig fixtures used by the Coldcard multisig display tests. - git apply ../../data/coldcard-multisig.patch + do_coldcard_firmware() { + local coldcard_version="$1" + local coldcard_dir="$2" + + # Clone coldcard firmware if it doesn't exist, or update it if it does + coldcard_setup_needed=false + if [ ! -d "${coldcard_dir}" ]; then + git clone --depth 1 --branch "${coldcard_version}" https://github.com/Coldcard/firmware.git "${coldcard_dir}" + cd "${coldcard_dir}" + # Simulator setup initializes the required nested dependencies. + git submodule update --init + coldcard_setup_needed=true + else + cd "${coldcard_dir}" + git fetch --tags origin + git checkout --force "${coldcard_version}" + git submodule update --init --force + coldcard_setup_needed=true + fi - # Build the simulator. This is cached, but it is also fast - poetry run pip install -r requirements.txt - pip install -r requirements.txt - cd unix - if [ "$coldcard_setup_needed" == true ] ; then - pushd ../external/micropython - # Do not treat new warnings from Ubuntu 24.04's compiler as errors. - git apply ../../ubuntu24_mpy.patch - popd - pushd ../external/micropython/mpy-cross/ + # Add multisig fixtures used by the Coldcard multisig display tests. + git apply ../../data/coldcard-multisig.patch + + # Build the simulator. This is cached, but it is also fast + poetry run pip install -r requirements.txt + pip install -r requirements.txt + cd unix + if [ "$coldcard_setup_needed" == true ] ; then + pushd ../external/micropython + # Do not treat new warnings from Ubuntu 24.04's compiler as errors. + git apply ../../ubuntu24_mpy.patch + popd + pushd ../external/micropython/mpy-cross/ + make + popd + # Skip make setup, which builds MicroPython's bundled libffi and + # fails with current Autoconf. The simulator links system libffi. + # Initialize its only required MicroPython submodule directly. + git -C ../external/micropython submodule update --init lib/berkeley-db-1.xx + make ngu-setup + ln -sf ../external/micropython/ports/unix/coldcard-mpy . + fi make - popd - # Skip make setup, which builds MicroPython's bundled libffi and - # fails with current Autoconf. The simulator links system libffi. - # Initialize its only required MicroPython submodule directly. - git -C ../external/micropython submodule update --init lib/berkeley-db-1.xx - make ngu-setup - ln -sf ../external/micropython/ports/unix/coldcard-mpy . - fi - make - cd ../.. + cd ../.. + } + + do_coldcard_firmware "${COLDCARD_VERSION}" firmware fi if [[ -n ${build_bitbox01} ]]; then From 8dc9a6f796f58728a05c24b5c6218af700d386aa Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 14:06:13 +0200 Subject: [PATCH 05/12] ci: build Coldcard Edge simulator Add an Edge target to simulator setup and include its output in the Coldcard simulator build matrix. Reuse Edge's valid multisig policy under the HWI fixture name. Co-authored-by: scgbckbone --- .github/sim-build-map.json | 3 +++ .github/workflows/ci.yml | 9 +++++++++ .github/workflows/prepare-sim-matrices.yml | 6 +++++- test/data/coldcard-edge-multisig.patch | 10 ++++++++++ test/setup_environment.sh | 22 +++++++++++++++++----- 5 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 test/data/coldcard-edge-multisig.patch diff --git a/.github/sim-build-map.json b/.github/sim-build-map.json index c5ad49fb0..5d83fc4c0 100644 --- a/.github/sim-build-map.json +++ b/.github/sim-build-map.json @@ -6,6 +6,9 @@ "coldcard": [ { "name": "coldcard", "archive": "coldcard-firmware", "paths": "test/work/firmware" } ], + "coldcard_edge": [ + { "name": "coldcard-edge", "archive": "coldcard-edge-firmware", "paths": "test/work/firmware" } + ], "bitbox": [ { "name": "bitbox01", "archive": "mcu", "paths": "test/work/mcu" }, { "name": "bitbox02", "archive": "bitbox02", "paths": "test/work/bitbox02-firmware/build-build-noasan/bin/simulator" } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91b8fd52c..1ce50fa58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,6 +125,15 @@ jobs: include: ${{ needs.prepare-sim-matrices.outputs.coldcard }} runs-on: ubuntu-latest + sim-builder-coldcard-edge: + name: Coldcard Edge sim builder + needs: prepare-sim-matrices + uses: ./.github/workflows/sim-builder.yml + with: + sim: coldcard-edge + include: ${{ needs.prepare-sim-matrices.outputs.coldcard_edge }} + runs-on: ubuntu-latest + sim-builder-bitbox: name: Bitbox sim builder needs: prepare-sim-matrices diff --git a/.github/workflows/prepare-sim-matrices.yml b/.github/workflows/prepare-sim-matrices.yml index 4f2d71841..63ce31bc2 100644 --- a/.github/workflows/prepare-sim-matrices.yml +++ b/.github/workflows/prepare-sim-matrices.yml @@ -8,6 +8,9 @@ on: coldcard: description: JSON include array for coldcard value: ${{ jobs.prepare.outputs.coldcard }} + coldcard_edge: + description: JSON include array for Coldcard Edge + value: ${{ jobs.prepare.outputs.coldcard_edge }} bitbox: description: JSON include array for bitbox value: ${{ jobs.prepare.outputs.bitbox }} @@ -28,6 +31,7 @@ jobs: outputs: trezor: ${{ steps.gen.outputs.trezor }} coldcard: ${{ steps.gen.outputs.coldcard }} + coldcard_edge: ${{ steps.gen.outputs.coldcard_edge }} bitbox: ${{ steps.gen.outputs.bitbox }} jade: ${{ steps.gen.outputs.jade }} ledger: ${{ steps.gen.outputs.ledger }} @@ -40,7 +44,7 @@ jobs: set -euo pipefail sudo apt-get install -y jq map_file=".github/sim-build-map.json" - for sim in trezor coldcard bitbox jade ledger keepkey; do + for sim in trezor coldcard coldcard_edge bitbox jade ledger keepkey; do include=$(jq -c --arg s "$sim" '.[$s]' "$map_file") if [[ -z "$include" || "$include" == "null" ]]; then echo "Missing entry for $sim in $map_file" >&2 diff --git a/test/data/coldcard-edge-multisig.patch b/test/data/coldcard-edge-multisig.patch new file mode 100644 index 000000000..29cca3cdf --- /dev/null +++ b/test/data/coldcard-edge-multisig.patch @@ -0,0 +1,10 @@ +diff --git a/unix/variant/sim_settings.py b/unix/variant/sim_settings.py +--- a/unix/variant/sim_settings.py ++++ b/unix/variant/sim_settings.py +@@ -71,5 +71,5 @@ if '--ms' in sys.argv: + sim_defaults['miniscript'] = [['CC-2-of-4', 'sh(wsh(sortedmulti(2,@0/**,@1/**,@2/**,@3/**)))', ['[0f056943/48h/1h/0h/1h]tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP', '[6ba6cfd0/48h/1h/0h/1h]tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax', '[747b698e/48h/1h/0h/1h]tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM', '[7bb026be/48h/1h/0h/1h]tpubDFiuHYSJhNbHaGtB5skiuDLg12tRboh2uVZ6KGXxr8WVr28pLcS7F3gv8SsHFa2tm1jtx3VAuw56YfgRkdo6DXyfp51oygTKY3nJFT5jBMt'], {'af': 26, 'm_n': (2, 4), 'b67': 1, 'ct': 'XTN'}]] + else: + # P2SH: 2of4 using BIP39 passwords: "Me", "Myself", "and I", and (empty string) on simulator +- sim_defaults['miniscript'] = [['MeMyself', 'sh(sortedmulti(2,@0/**,@1/**,@2/**,@3/**))', ['[6ba6cfd0/45h]tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9', '[747b698e/45h]tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc', '[7bb026be/45h]tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa', '[0f056943/45h]tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n'], {'af': 8, 'm_n': (2, 4), 'b67': 1, 'ct': 'XTN'}]] ++ sim_defaults['miniscript'] = [['mstest', 'sh(sortedmulti(2,@0/**,@1/**,@2/**,@3/**))', ['[6ba6cfd0/45h]tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9', '[747b698e/45h]tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc', '[7bb026be/45h]tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa', '[0f056943/45h]tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n'], {'af': 8, 'm_n': (2, 4), 'b67': 1, 'ct': 'XTN'}]] + sim_defaults['fee_limit'] = -1 diff --git a/test/setup_environment.sh b/test/setup_environment.sh index d2e8dec6e..bec5755b3 100755 --- a/test/setup_environment.sh +++ b/test/setup_environment.sh @@ -14,6 +14,10 @@ while [[ $# -gt 0 ]]; do build_coldcard=1 shift ;; + --coldcard-edge) + build_coldcard_edge=1 + shift + ;; --bitbox01) build_bitbox01=1 shift @@ -73,6 +77,7 @@ SPECULOS_VERSION="ed952a54801f59a71399462b5422976d84c817bb" # Requires Python > JADE_VERSION="1.0.36" COLDCARD_VERSION="2026-07-31T0519-v5.6.0" +COLDCARD_EDGE_VERSION="2026-07-31T1609-v6.6.0X" if [[ -n ${build_trezor_1} || -n ${build_trezor_t} ]]; then # Clone trezor-firmware if it doesn't exist, or update it if it does @@ -136,10 +141,12 @@ if [[ -n ${build_trezor_1} || -n ${build_trezor_t} ]]; then cd .. fi -if [[ -n ${build_coldcard} ]]; then +if [[ -n ${build_coldcard} || -n ${build_coldcard_edge} ]]; then do_coldcard_firmware() { local coldcard_version="$1" local coldcard_dir="$2" + local coldcard_requirements="$3" + local coldcard_multisig_patch="$4" # Clone coldcard firmware if it doesn't exist, or update it if it does coldcard_setup_needed=false @@ -158,11 +165,11 @@ if [[ -n ${build_coldcard} ]]; then fi # Add multisig fixtures used by the Coldcard multisig display tests. - git apply ../../data/coldcard-multisig.patch + git apply "../../data/${coldcard_multisig_patch}" # Build the simulator. This is cached, but it is also fast - poetry run pip install -r requirements.txt - pip install -r requirements.txt + poetry run pip install -r "${coldcard_requirements}" + pip install -r "${coldcard_requirements}" cd unix if [ "$coldcard_setup_needed" == true ] ; then pushd ../external/micropython @@ -183,7 +190,12 @@ if [[ -n ${build_coldcard} ]]; then cd ../.. } - do_coldcard_firmware "${COLDCARD_VERSION}" firmware + if [[ -n ${build_coldcard} ]]; then + do_coldcard_firmware "${COLDCARD_VERSION}" firmware requirements.txt coldcard-multisig.patch + fi + if [[ -n ${build_coldcard_edge} ]]; then + do_coldcard_firmware "${COLDCARD_EDGE_VERSION}" firmware unix/requirements.txt coldcard-edge-multisig.patch + fi fi if [[ -n ${build_bitbox01} ]]; then From 2cda52a024e304be4b6db88c7d8bf946ffcd09c8 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 14:06:18 +0200 Subject: [PATCH 06/12] test: support Coldcard Edge in device tests Expose the Edge simulator through the device test runner and account for its unsupported multisig display behavior. Co-authored-by: scgbckbone --- test/run_tests.py | 13 +++++++++++-- test/test_coldcard.py | 11 ++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/test/run_tests.py b/test/run_tests.py index 80300db1f..c415462d7 100755 --- a/test/run_tests.py +++ b/test/run_tests.py @@ -32,6 +32,10 @@ coldcard_group.add_argument('--no-coldcard', dest='coldcard', help='Do not run Coldcard test with simulator', action='store_false') coldcard_group.add_argument('--coldcard', dest='coldcard', help='Run Coldcard test with simulator', action='store_true') +coldcard_edge_group = parser.add_mutually_exclusive_group() +coldcard_edge_group.add_argument('--no-coldcard-edge', dest='coldcard_edge', help='Do not run Coldcard Edge test with simulator', action='store_false') +coldcard_edge_group.add_argument('--coldcard-edge', dest='coldcard_edge', help='Run Coldcard Edge test with simulator', action='store_true') + ledger_group = parser.add_mutually_exclusive_group() ledger_group.add_argument('--no-ledger', dest='ledger', help='Do not run Ledger test with emulator', action='store_false') ledger_group.add_argument('--ledger', dest='ledger', help='Run Ledger test with emulator', action='store_true') @@ -59,6 +63,7 @@ parser.add_argument('--trezor-1-path', dest='trezor_1_path', help='Path to Trezor 1 emulator', default='work/trezor-firmware/legacy/firmware/trezor.elf') parser.add_argument('--trezor-t-path', dest='trezor_t_path', help='Path to Trezor T emulator', default='work/trezor-firmware/core/emu.sh') parser.add_argument('--coldcard-path', dest='coldcard_path', help='Path to Coldcard simulator', default='work/firmware/unix/simulator.py') +parser.add_argument('--coldcard-edge-path', dest='coldcard_edge_path', help='Path to Coldcard Edge simulator', default='work/firmware/unix/simulator.py') parser.add_argument('--keepkey-path', dest='keepkey_path', help='Path to Keepkey emulator', default='work/keepkey-firmware/bin/kkemu') parser.add_argument('--bitbox01-path', dest='bitbox01_path', help='Path to Digital Bitbox simulator', default='work/mcu/build/bin/simulator') parser.add_argument('--ledger-path', dest='ledger_path', help='Path to Ledger emulator', default='work/speculos/speculos.py') @@ -71,7 +76,7 @@ parser.add_argument("--device-only", help="Only run device tests", action="store_true") -parser.set_defaults(trezor_1=None, trezor_t=None, coldcard=None, keepkey=None, bitbox01=None, ledger=None, ledger_legacy=None, jade=None, bitbox02=None) +parser.set_defaults(trezor_1=None, trezor_t=None, coldcard=None, coldcard_edge=None, keepkey=None, bitbox01=None, ledger=None, ledger_legacy=None, jade=None, bitbox02=None) args = parser.parse_args() @@ -93,6 +98,7 @@ args.trezor_1 = True if args.trezor_1 is None else args.trezor_1 args.trezor_t = True if args.trezor_t is None else args.trezor_t args.coldcard = True if args.coldcard is None else args.coldcard + args.coldcard_edge = True if args.coldcard_edge is None else args.coldcard_edge args.keepkey = True if args.keepkey is None else args.keepkey args.bitbox01 = True if args.bitbox01 is None else args.bitbox01 args.ledger = True if args.ledger is None else args.ledger @@ -104,6 +110,7 @@ args.trezor_1 = False if args.trezor_1 is None else args.trezor_1 args.trezor_t = False if args.trezor_t is None else args.trezor_t args.coldcard = False if args.coldcard is None else args.coldcard + args.coldcard_edge = False if args.coldcard_edge is None else args.coldcard_edge args.keepkey = False if args.keepkey is None else args.keepkey args.bitbox01 = False if args.bitbox01 is None else args.bitbox01 args.ledger = False if args.ledger is None else args.ledger @@ -111,7 +118,7 @@ args.jade = False if args.jade is None else args.jade args.bitbox02 = False if args.bitbox02 is None else args.bitbox02 -if args.trezor_1 or args.trezor_t or args.coldcard or args.ledger or args.ledger_legacy or args.keepkey or args.bitbox01 or args.jade or args.bitbox02: +if args.trezor_1 or args.trezor_t or args.coldcard or args.coldcard_edge or args.ledger or args.ledger_legacy or args.keepkey or args.bitbox01 or args.jade or args.bitbox02: # Start bitcoind bitcoind = Bitcoind.create(args.bitcoind) @@ -119,6 +126,8 @@ success &= digitalbitbox_test_suite(args.bitbox01_path, bitcoind, args.interface) if success and args.coldcard: success &= coldcard_test_suite(args.coldcard_path, bitcoind, args.interface) + if success and args.coldcard_edge: + success &= coldcard_test_suite(args.coldcard_edge_path, bitcoind, args.interface, is_edge=True) if success and args.trezor_1: success &= trezor_test_suite(args.trezor_1_path, bitcoind, args.interface, '1') if success and args.trezor_t: diff --git a/test/test_coldcard.py b/test/test_coldcard.py index 7d568ca80..5eca2c104 100755 --- a/test/test_coldcard.py +++ b/test/test_coldcard.py @@ -25,7 +25,7 @@ ) class ColdcardSimulator(DeviceEmulator): - def __init__(self, simulator): + def __init__(self, simulator, is_edge=False): try: os.unlink("coldcard-emulator.stdout") except FileNotFoundError: @@ -38,7 +38,7 @@ def __init__(self, simulator): self.fingerprint = "0f056943" self.master_xpub = "tpubDCiHGUNYdRRBPNYm7CqeeLwPWfeb2ZT2rPsk4aEW3eUoJM93jbBa7hPpB1T9YKtigmjpxHrB1522kSsTxGm9V6cqKqrp1EDaYaeJZqcirYB" self.password = "" - self.supports_ms_display = True + self.supports_ms_display = not is_edge self.supports_xpub_ms_display = False self.supports_unsorted_ms = False self.supports_taproot = False @@ -143,8 +143,8 @@ def test_getxpub(self): self.assertEqual(result['chaincode'], '806b26507824f73bc331494afe122f428ef30dde80b2c1ce025d2d03aff411e7') self.assertEqual(result['pubkey'], '0368000bdff5e0b71421c37b8514de8acd4d98ba9908d183d9da56d02ca4fcfd08') -def coldcard_test_suite(simulator, bitcoind, interface): - dev_emulator = ColdcardSimulator(simulator) +def coldcard_test_suite(simulator, bitcoind, interface, is_edge=False): + dev_emulator = ColdcardSimulator(simulator, is_edge) signtx_cases = [ (["legacy"], [], False, False), @@ -173,9 +173,10 @@ def coldcard_test_suite(simulator, bitcoind, interface): parser.add_argument('simulator', help='Path to the Coldcard simulator') parser.add_argument('bitcoind', help='Path to bitcoind binary') parser.add_argument('--interface', help='Which interface to send commands over', choices=['library', 'cli', 'bindist'], default='library') + parser.add_argument('--edge', help='Test Coldcard Edge behavior', action='store_true') args = parser.parse_args() # Start bitcoind bitcoind = Bitcoind.create(args.bitcoind) - sys.exit(not coldcard_test_suite(args.simulator, bitcoind, args.interface)) + sys.exit(not coldcard_test_suite(args.simulator, bitcoind, args.interface, is_edge=args.edge)) From 454e36e3b32816c4bd0ad6269b03a2e3947d16f3 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 13:37:33 +0200 Subject: [PATCH 07/12] ci: parameterize device test matrix Keep the existing test modes while allowing callers to select Python versions. --- .github/workflows/device-test.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/device-test.yml b/.github/workflows/device-test.yml index 2aff297a0..ef25dc557 100644 --- a/.github/workflows/device-test.yml +++ b/.github/workflows/device-test.yml @@ -9,6 +9,10 @@ on: required: false type: string default: ubuntu-latest + python_versions: + required: false + type: string + default: '["3.10", "3.11", "3.12", "3.13", "3.14"]' jobs: test-device: @@ -18,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python-version: ${{ fromJSON(inputs.python_versions) }} device: - ${{ inputs.device }} test: From 534468cf1f79523d736dae1718116cb5933a8cdf Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 14:06:34 +0200 Subject: [PATCH 08/12] ci: run Coldcard Edge simulator tests Install the cached Edge simulator in GitHub Actions and run all source and distribution test modes on Python 3.14. Co-authored-by: scgbckbone --- .github/actions/install-sim/action.yml | 18 ++++++++++++++---- .github/workflows/ci.yml | 8 ++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/actions/install-sim/action.yml b/.github/actions/install-sim/action.yml index f6630e6f1..2642456e3 100644 --- a/.github/actions/install-sim/action.yml +++ b/.github/actions/install-sim/action.yml @@ -18,18 +18,28 @@ runs: apt-get install -y libsdl2-image-2.0-0 libusb-1.0-0 tar -xvf trezor-firmware.tar.gz - - if: inputs.device == 'coldcard' + - if: startsWith(inputs.device, 'coldcard') shell: bash run: | apt-get update apt-get install -y libpcsclite-dev libusb-1.0-0 swig + archive=coldcard-firmware + if [[ "${{ inputs.device }}" == "coldcard-edge" ]]; then + archive=coldcard-edge-firmware + fi # Extract the archive - this includes the full firmware directory - tar -xvf coldcard-firmware.tar.gz + tar -xvf "${archive}.tar.gz" - poetry run pip install -r test/work/firmware/requirements.txt - pip install -r test/work/firmware/requirements.txt + requirements="test/work/firmware/requirements.txt" + if [[ "${{ inputs.device }}" == "coldcard-edge" ]]; then + # Edge's full firmware requirements pin legacy development tools that + # are not needed to run the simulator and do not build on modern Python. + requirements="test/work/firmware/unix/requirements.txt" + fi + poetry run pip install -r "${requirements}" poetry run pip install pysdl2-dll + pip install -r "${requirements}" pip install pysdl2-dll - if: inputs.device == 'bitbox01' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ce50fa58..75eeedf14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -224,6 +224,14 @@ jobs: device: coldcard runs-on: ubuntu-latest + test-coldcard-edge: + uses: ./.github/workflows/device-test.yml + needs: [sim-builder-coldcard-edge, bitcoind-builder, dist-builder] + with: + device: coldcard-edge + runs-on: ubuntu-latest + python_versions: '["3.14"]' + test-bitbox01: uses: ./.github/workflows/device-test.yml needs: [sim-builder-bitbox, bitcoind-builder, dist-builder] From e5aa9ccba5c93ad567a29f6e64b466dba202e8e5 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 18 Aug 2026 13:26:00 +0200 Subject: [PATCH 09/12] coldcard: display singlesig taproot address on EDGE Co-authored-by: scgbckbone --- hwilib/devices/coldcard.py | 5 ++++- test/test_coldcard.py | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/hwilib/devices/coldcard.py b/hwilib/devices/coldcard.py index 4f5e5586d..83cb3762d 100644 --- a/hwilib/devices/coldcard.py +++ b/hwilib/devices/coldcard.py @@ -43,6 +43,7 @@ AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH, + AF_P2TR, ) from .._base58 import ( get_xpub_fingerprint, @@ -267,7 +268,9 @@ def display_singlesig_address( elif addr_type == AddressType.LEGACY: addr_fmt = AF_CLASSIC elif addr_type == AddressType.TAP: - raise UnavailableActionError("Coldcard does not support displaying Taproot addresses yet") + if not self.is_edge: + raise UnavailableActionError("Coldcard does not support displaying Taproot addresses yet. Use EDGE.") + addr_fmt = AF_P2TR else: raise BadArgumentError("Unknown address type") diff --git a/test/test_coldcard.py b/test/test_coldcard.py index 5eca2c104..aa29cc3ef 100755 --- a/test/test_coldcard.py +++ b/test/test_coldcard.py @@ -11,6 +11,7 @@ import unittest from hwilib._cli import process_commands +from hwilib import _bech32 as bech32 from test_device import ( Bitcoind, DeviceEmulator, @@ -41,7 +42,7 @@ def __init__(self, simulator, is_edge=False): self.supports_ms_display = not is_edge self.supports_xpub_ms_display = False self.supports_unsorted_ms = False - self.supports_taproot = False + self.supports_taproot = is_edge self.strict_bip48 = False self.include_xpubs = False self.supports_device_multiple_multisig = True @@ -143,6 +144,22 @@ def test_getxpub(self): self.assertEqual(result['chaincode'], '806b26507824f73bc331494afe122f428ef30dde80b2c1ce025d2d03aff411e7') self.assertEqual(result['pubkey'], '0368000bdff5e0b71421c37b8514de8acd4d98ba9908d183d9da56d02ca4fcfd08') +class TestColdcardEdgeDisplayAddress(DeviceTestCase): + def test_display_taproot_address(self): + descriptors = self.do_command(self.dev_args + [ + 'getkeypool', '--addr-type', 'tap', '0', '0' + ]) + expected = self.rpc.deriveaddresses(descriptors[0]['desc'], [0, 0])[0] + + result = self.do_command(self.dev_args + [ + 'displayaddress', '--addr-type', 'tap', '--path', 'm/86h/1h/0h/0/0' + ]) + self.assertNotIn('error', result) + self.assertIn('address', result) + displayed_witness = bech32.decode('tb', result['address']) + expected_witness = bech32.decode('bcrt', expected) + self.assertEqual(displayed_witness, expected_witness) + def coldcard_test_suite(simulator, bitcoind, interface, is_edge=False): dev_emulator = ColdcardSimulator(simulator, is_edge) @@ -164,6 +181,8 @@ def coldcard_test_suite(simulator, bitcoind, interface, is_edge=False): suite.addTest(DeviceTestCase.parameterize(TestSignMessage, bitcoind, emulator=dev_emulator, interface=interface)) suite.addTest(DeviceTestCase.parameterize(TestSignTx, bitcoind, emulator=dev_emulator, interface=interface, signtx_cases=signtx_cases)) suite.addTest(DeviceTestCase.parameterize(TestRegisterDescriptor, bitcoind, emulator=dev_emulator, interface=interface, returns_registration=False)) + if is_edge: + suite.addTest(DeviceTestCase.parameterize(TestColdcardEdgeDisplayAddress, bitcoind, emulator=dev_emulator, interface=interface)) result = unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(suite) return result.wasSuccessful() From f8bd2942aae917f17c453308888bfe96aa7996e7 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 19 Aug 2026 11:00:22 +0200 Subject: [PATCH 10/12] coldcard: preserve PSBTv2 when supported --- hwilib/devices/coldcard.py | 19 ++++++++++++++++++- test/run_tests.py | 3 ++- test/test_coldcard.py | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/hwilib/devices/coldcard.py b/hwilib/devices/coldcard.py index 83cb3762d..8b627e5f6 100644 --- a/hwilib/devices/coldcard.py +++ b/hwilib/devices/coldcard.py @@ -80,6 +80,15 @@ # Using the simulator: https://github.com/Coldcard/firmware/blob/master/unix/README.md +def _firmware_version_supports_psbt_v2(version: str) -> bool: + if version.endswith(("Q", "X")): + return True + try: + return tuple(int(part) for part in version.split(".")) >= (5, 2, 0) + except ValueError: + return False + + def coldcard_exception(f: Callable[..., Any]) -> Callable[..., Any]: @wraps(f) def func(*args: Any, **kwargs: Any) -> Any: @@ -123,6 +132,12 @@ def is_edge(self): return self._is_edge + def _supports_psbt_v2(self) -> bool: + if self.device.is_simulator or self.is_edge: + return True + version = self.device.firmware_version()[1] + return _firmware_version_supports_psbt_v2(version) + @coldcard_exception def get_pubkey_at_path(self, path: str) -> ExtendedKey: self.device.check_mitm() @@ -165,9 +180,11 @@ def sign_tx(self, tx: PSBT) -> PSBT: if our_keys > passes: passes = our_keys + if tx.version == 2 and not self._supports_psbt_v2(): + tx.convert_to_v0() + for _ in range(passes): # Get psbt in hex and then make binary - tx.convert_to_v0() fd = io.BytesIO(base64.b64decode(tx.serialize())) # learn size (portable way) diff --git a/test/run_tests.py b/test/run_tests.py index c415462d7..28d8f7a95 100755 --- a/test/run_tests.py +++ b/test/run_tests.py @@ -7,7 +7,7 @@ from test_base58 import TestBase58 from test_bech32 import TestSegwitAddress from test_bip32 import TestBIP32 -from test_coldcard import coldcard_test_suite +from test_coldcard import coldcard_test_suite, TestColdcardFirmware from test_descriptor import TestDescriptor from test_device import Bitcoind from test_psbt import TestPSBT @@ -89,6 +89,7 @@ suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(TestPSBT)) suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(TestBase58)) suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(TestBIP32)) + suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(TestColdcardFirmware)) if sys.platform.startswith("linux"): suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(TestUdevRulesInstaller)) success = unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(suite).wasSuccessful() diff --git a/test/test_coldcard.py b/test/test_coldcard.py index aa29cc3ef..2c2adf064 100755 --- a/test/test_coldcard.py +++ b/test/test_coldcard.py @@ -12,6 +12,7 @@ from hwilib._cli import process_commands from hwilib import _bech32 as bech32 +from hwilib.devices.coldcard import _firmware_version_supports_psbt_v2 from test_device import ( Bitcoind, DeviceEmulator, @@ -25,6 +26,25 @@ TestSignTx, ) + +class TestColdcardFirmware(unittest.TestCase): + def test_psbt_v2_support(self): + versions = { + "5.1.4": False, + "5.2.0": True, + "5.6.0": True, + "1.0.0Q": True, + "6.6.0X": True, + "unknown": False, + } + for version, expected in versions.items(): + with self.subTest(version=version): + self.assertEqual( + _firmware_version_supports_psbt_v2(version), + expected, + ) + + class ColdcardSimulator(DeviceEmulator): def __init__(self, simulator, is_edge=False): try: From 90b7b0a6d498641704acefc920bbe1a772bdf799 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 19 Aug 2026 11:41:02 +0200 Subject: [PATCH 11/12] ci: bump GitHub Actions versions Update checkout and artifact actions to their latest major versions. This avoids the Node.js 20 fallback warning on current runners. --- .github/actions/build-bitcoind/action.yml | 2 +- .github/actions/build-sim/action.yml | 2 +- .github/actions/install-sim/action.yml | 4 ++-- .github/actions/test-device/action.yml | 2 +- .github/actions/test-dist/action.yml | 4 ++-- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/device-test.yml | 2 +- .github/workflows/ledger-app-builder.yml | 2 +- .github/workflows/ledger-legacy-app-builder.yml | 2 +- .github/workflows/prepare-sim-matrices.yml | 2 +- .github/workflows/sim-builder.yml | 2 +- .github/workflows/type-check.yml | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/actions/build-bitcoind/action.yml b/.github/actions/build-bitcoind/action.yml index e4befd42e..4fc591cf3 100644 --- a/.github/actions/build-bitcoind/action.yml +++ b/.github/actions/build-bitcoind/action.yml @@ -31,7 +31,7 @@ runs: path: ${{ env.CCACHE_DIR }} key: ${{ github.job }}-ccache-${{ github.run_id }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: bitcoind path: bitcoind.tar.gz diff --git a/.github/actions/build-sim/action.yml b/.github/actions/build-sim/action.yml index 2968a9f40..f124af659 100644 --- a/.github/actions/build-sim/action.yml +++ b/.github/actions/build-sim/action.yml @@ -46,7 +46,7 @@ runs: done tar -czf "${{ inputs.archive }}.tar.gz" ${{ inputs.paths }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: ${{ inputs.name }}-sim path: ${{ inputs.archive }}.tar.gz diff --git a/.github/actions/install-sim/action.yml b/.github/actions/install-sim/action.yml index 2642456e3..6e18f6fc2 100644 --- a/.github/actions/install-sim/action.yml +++ b/.github/actions/install-sim/action.yml @@ -7,7 +7,7 @@ inputs: runs: using: composite steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: ${{ inputs.device == 'ledger-legacy' && 'ledger' || inputs.device }}-sim @@ -73,7 +73,7 @@ runs: pip install -e test/work/speculos - if: startsWith(inputs.device, 'ledger') - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: ${{ inputs.device == 'ledger-legacy' && 'ledger_app_legacy' || 'ledger_app' }} diff --git a/.github/actions/test-device/action.yml b/.github/actions/test-device/action.yml index 2fc72beda..2152d1343 100644 --- a/.github/actions/test-device/action.yml +++ b/.github/actions/test-device/action.yml @@ -8,7 +8,7 @@ runs: pip install poetry poetry install - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: bitcoind diff --git a/.github/actions/test-dist/action.yml b/.github/actions/test-dist/action.yml index 6675fe34e..a517c0bb0 100644 --- a/.github/actions/test-dist/action.yml +++ b/.github/actions/test-dist/action.yml @@ -7,7 +7,7 @@ runs: run: | pip install poetry - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist path: dist/ @@ -30,7 +30,7 @@ runs: run: | poetry install; cd dist; tar -xvf hwi*linux*.tar.gz; cd .. - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: bitcoind diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75eeedf14..cb66eea51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest container: python:3.12 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - run: | pip install poetry @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest container: python:3.12 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - run: | pip install poetry @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: docker/build-push-action@v6 with: @@ -78,7 +78,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: docker/build-push-action@v6 with: @@ -98,7 +98,7 @@ jobs: find dist -type f -exec sha256sum {} \; " - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: dist path: dist/ @@ -186,7 +186,7 @@ jobs: name: bitcoind builder runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-bitcoind test-trezor-1: diff --git a/.github/workflows/device-test.yml b/.github/workflows/device-test.yml index ef25dc557..ccfd477c0 100644 --- a/.github/workflows/device-test.yml +++ b/.github/workflows/device-test.yml @@ -34,7 +34,7 @@ jobs: - {script: 'Bindist'} container: python:${{ matrix.python-version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: run test if: ${{ matrix.test.interface }} uses: ./.github/actions/test-device diff --git a/.github/workflows/ledger-app-builder.yml b/.github/workflows/ledger-app-builder.yml index 19cb9cd0a..d2cab7345 100644 --- a/.github/workflows/ledger-app-builder.yml +++ b/.github/workflows/ledger-app-builder.yml @@ -19,7 +19,7 @@ jobs: git clone --branch 2.5.0 --depth 1 https://github.com/LedgerHQ/app-bitcoin.git cd app-bitcoin make DEBUG=1 COIN=bitcoin_testnet BOLOS_SDK=$NANOX_SDK - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: ledger_app path: app-bitcoin/bin/app.elf diff --git a/.github/workflows/ledger-legacy-app-builder.yml b/.github/workflows/ledger-legacy-app-builder.yml index 28d7a2d45..821696621 100644 --- a/.github/workflows/ledger-legacy-app-builder.yml +++ b/.github/workflows/ledger-legacy-app-builder.yml @@ -19,7 +19,7 @@ jobs: git clone --depth 1 https://github.com/LedgerHQ/app-bitcoin-legacy.git -b legacy-1.6.6 cd app-bitcoin-legacy make DEBUG=1 BOLOS_SDK=$NANOSP_SDK - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: ledger_app_legacy path: app-bitcoin-legacy/bin/app.elf diff --git a/.github/workflows/prepare-sim-matrices.yml b/.github/workflows/prepare-sim-matrices.yml index 63ce31bc2..3e30277e3 100644 --- a/.github/workflows/prepare-sim-matrices.yml +++ b/.github/workflows/prepare-sim-matrices.yml @@ -37,7 +37,7 @@ jobs: ledger: ${{ steps.gen.outputs.ledger }} keepkey: ${{ steps.gen.outputs.keepkey }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - id: gen shell: bash run: | diff --git a/.github/workflows/sim-builder.yml b/.github/workflows/sim-builder.yml index 708ec61b8..b2b09a56f 100644 --- a/.github/workflows/sim-builder.yml +++ b/.github/workflows/sim-builder.yml @@ -22,7 +22,7 @@ jobs: matrix: include: ${{ fromJSON(inputs.include) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-sim with: name: ${{ matrix.name }} diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index 09a04c08c..679844c08 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest container: python:3.12 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - run: | pip install poetry From aa3e73359c9d49140015f1e55ec61241ed39e313 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 19 Aug 2026 11:41:42 +0200 Subject: [PATCH 12/12] ci: add finite APT connection timeouts/retries GitHub-hosted runners can hang while accessing the prioritized Azure Ubuntu mirror. Retry transient failures, bound connections to 30 seconds, and bound the full update and install commands. --- .github/actions/build-sim/action.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/actions/build-sim/action.yml b/.github/actions/build-sim/action.yml index f124af659..ebc6c9897 100644 --- a/.github/actions/build-sim/action.yml +++ b/.github/actions/build-sim/action.yml @@ -16,8 +16,13 @@ runs: - name: Install dependencies shell: bash run: | - sudo apt-get update - sudo apt-get install -y gcc-arm-linux-gnueabihf libsdl2-image-dev libslirp-dev libpcsclite-dev ninja-build libltdl-dev + apt_options=( + -o Acquire::Retries=3 + -o Acquire::http::Timeout=30 + -o Acquire::https::Timeout=30 + ) + timeout 5m sudo apt-get "${apt_options[@]}" update + timeout 30m sudo apt-get "${apt_options[@]}" install -y gcc-arm-linux-gnueabihf libsdl2-image-dev libslirp-dev libpcsclite-dev ninja-build libltdl-dev pip install poetry uv wget https://github.com/protocolbuffers/protobuf/releases/download/v22.0/protoc-22.0-linux-x86_64.zip sudo unzip protoc-22.0-linux-x86_64.zip -d /usr/local