Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
49587cc
release(7.15.0): consolidated release delta over upstream develop
BitHighlander Jul 17, 2026
f6cd678
fix review findings in Hive and Zcash
BitHighlander Jul 17, 2026
8d414e4
fix(clearsign): harden EVM/THOR/Hive/Solana signing against hidden-fi…
BitHighlander Jul 17, 2026
3febf3c
style: clang-format the clearsign hardening changes
BitHighlander Jul 17, 2026
bb9b7da
fix(clearsign): page full raw memo on native THOR/MAYA, harden Solana…
BitHighlander Jul 17, 2026
5da843e
fix(thortx): recognize both native-ETH conventions; don't reject amou…
BitHighlander Jul 17, 2026
0a25a1b
fix(clearsign): Solana withdrawal destinations, unchecked-SPL gating,…
BitHighlander Jul 17, 2026
e85eae2
fix(solana): audit-driven completeness — sign-slice, OOB, display gap…
BitHighlander Jul 17, 2026
33184d7
feat(solana): verify signed token definitions (firmware side, reuses …
BitHighlander Jul 17, 2026
e1ea5af
fix(solana): gate the ed25519 self-verify out of the zcash-privacy build
BitHighlander Jul 17, 2026
aac74e7
fix(solana): harden signed token-definition verification (review foll…
BitHighlander Jul 17, 2026
8853a6c
fix(solana): disclose acted-on accounts; gate Token-2022; fix vote-va…
BitHighlander Jul 17, 2026
8d536da
fix(solana): disclose priority fee in SOL, remaining acted-on account…
BitHighlander Jul 17, 2026
3cdc36c
fix(solana): overflow-safe priority fee + single verified-tx confirm …
BitHighlander Jul 17, 2026
27a794d
test(report): PDF is primary proof — un-skip native MAYA, capture hiv…
BitHighlander Jul 18, 2026
b6edd56
Merge pull request #311 from BitHighlander/release/7.15.0-consolidated
BitHighlander Jul 18, 2026
6edc195
fix(thorchain): clear-sign deposits on every pinned EVM chain, not ju…
BitHighlander Jul 18, 2026
675bc9b
fix(review-r12): memo-disclosure gaps, CI shipped-config leg, pre-tag…
BitHighlander Jul 18, 2026
2db4c08
Merge pull request #313 from BitHighlander/fix/review-round12
BitHighlander Jul 18, 2026
57cbe6e
fix(zcash): smooth 45s progress ramp + fill-front glint
BitHighlander Jul 18, 2026
e3b261b
style: clang-format
BitHighlander Jul 18, 2026
74f13ac
fix(zcash): draw the signing screen the instant a confirm is approved
BitHighlander Jul 18, 2026
5c175d1
Merge pull request #314 from BitHighlander/fix/zcash-progress-front-g…
BitHighlander Jul 18, 2026
eda7b95
feat(hive): clear-sign 11 more operations (phase 3)
BitHighlander Jul 19, 2026
67b7609
chore: bump python-keepkey pin (phase-3 hive op device tests)
BitHighlander Jul 19, 2026
e78713a
style(hive): match asset accessor param names to their declarations
BitHighlander Jul 20, 2026
c402926
fix(eip712): drop sscanf — it cost 6KB of ROM the zcash-privacy build…
BitHighlander Jul 20, 2026
8febed1
style(hive): drop the unreachable break after the convert case
BitHighlander Jul 20, 2026
f36f151
fix(eip712): reduce ctr/assetToken scope — cppcheck flagged them post…
BitHighlander Jul 20, 2026
5e634d5
fix(osmosis): stop rounding amounts on the confirm screen — drop the …
BitHighlander Jul 20, 2026
23ef39c
Merge pull request #315 from BitHighlander/feat/hive-clearsign-ops-ph…
BitHighlander Jul 20, 2026
caa4993
fix(hive): serialize assets with the wire symbols the chain uses
BitHighlander Jul 21, 2026
38238b5
chore(deps): pin python-keepkey to reconcile/upstream-sync
BitHighlander Jul 21, 2026
1aa44ef
Merge pull request #316 from BitHighlander/fix/hive-wire-symbols
BitHighlander Jul 21, 2026
4e5fc88
test: repin python-keepkey for phase-2/3 Hive screenshot capture
BitHighlander Jul 21, 2026
3f4139d
test: repin python-keepkey — G36 screenshot hint removed (rejection-o…
BitHighlander Jul 21, 2026
7d4eeb4
test: repin python-keepkey — Osmosis confirm-screen device tests + sc…
BitHighlander Jul 21, 2026
1715df9
test: repin python-keepkey — Osmosis MsgSend client fix
BitHighlander Jul 21, 2026
e422edc
test: repin python-keepkey — osmo1 fixture derived from the device
BitHighlander Jul 21, 2026
81a3b87
test: repin python-keepkey — osmosis_get_address returns a str
BitHighlander Jul 21, 2026
d185713
test: repin python-keepkey — MsgSend denom fence + review corrections
BitHighlander Jul 21, 2026
f7eacc3
fix(security): harden signing and authenticator confirmations
BitHighlander Jul 21, 2026
e215eca
fix(security): remediate RC17 audit blockers
BitHighlander Jul 22, 2026
9f4920e
test(ethereum): pin liquidity fixture addresses
BitHighlander Jul 22, 2026
a3d64f9
fix(security): remediate second RC17 audit blockers
BitHighlander Jul 22, 2026
a8ec50a
test(ethereum): repin typed-hash policy coverage
BitHighlander Jul 22, 2026
422780f
fix(security): close Osmosis RC17 blockers
BitHighlander Jul 22, 2026
f0b9efd
fix(osmosis): sign canonical non-native denominations
BitHighlander Jul 23, 2026
ac83649
style(osmosis): apply clang-format
BitHighlander Jul 23, 2026
c546658
test(osmosis): include secp256k1 curve fixture
BitHighlander Jul 23, 2026
12b463f
test(osmosis): include secp256k1 declaration
BitHighlander Jul 23, 2026
277968e
test(osmosis): repin denomination binding coverage
BitHighlander Jul 23, 2026
f746c52
fix(ci): pin exact python-keepkey revision
BitHighlander Jul 23, 2026
532d16f
docs(rc17): record physical Osmosis QA evidence
BitHighlander Jul 23, 2026
411b008
docs(rc17): record LP cancellation proof
BitHighlander Jul 23, 2026
686a6e1
docs(rc17): confirm physical OLED boundaries
BitHighlander Jul 23, 2026
f3bfca3
docs(tendermint): plan generalized direct signing
BitHighlander Jul 23, 2026
a86903b
docs(rc17): narrow physical QA to smoke gate
BitHighlander Jul 23, 2026
afe4415
Merge pull request #317 from BitHighlander/agent/firmware-security-ha…
BitHighlander Jul 23, 2026
d10d09d
fix(release): support RC tags and selective submodules
BitHighlander Jul 23, 2026
59569ca
Merge pull request #318 from BitHighlander/agent/release-rc-tag-pipeline
BitHighlander Jul 23, 2026
ac4e637
fix: render multiline signed messages as text
BitHighlander Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 102 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
# └─ check-submodules verify all deps present
#
# Stage 2: BUILD (parallel, gated by Stage 1)
# ├─ build-emulator Docker image → artifact
# └─ build-arm-firmware cross-compile → .bin/.elf (downloadable)
# ├─ build-emulator Docker image → artifact [matrix: full / bitcoin-only / zcash-privacy]
# └─ build-arm-firmware cross-compile → .bin/.elf (downloadable) [same matrix]
#
# Stage 3: TEST (parallel, gated by Stage 2)
# ├─ unit-tests GoogleTest (make xunit)
# └─ python-integration full test suite
# ├─ unit-tests GoogleTest (make xunit) [same matrix — proves each
# │ variant's coin/token gating actually compiles+passes]
# └─ python-integration full test suite (full/default variant only)
#
# Stage 4: PUBLISH (manual trigger, all tests must pass)
# └─ publish-emulator DockerHub push (workflow_dispatch only)
# └─ publish-emulator DockerHub push, full/default variant only (workflow_dispatch only)

name: CI

Expand Down Expand Up @@ -99,7 +100,7 @@ jobs:

static-analysis:
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -212,9 +213,29 @@ jobs:
# ═══════════════════════════════════════════════════════════

build-emulator:
name: build-emulator${{ matrix.label }}
needs: [lint-format, static-analysis, check-submodules, secret-scan]
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
# The emulator CMake default is KK_ZCASH_PRIVACY=ON (what the published
# dylib/Docker image include), so an empty-flag full leg builds
# byte-identical to the zcash-privacy leg and the SHIPPED device
# configuration (multi-coin, privacy OFF) is never unit-tested. Pin the
# full leg to the shipped config; publish-emulator ships the
# zcash-privacy image (the same bytes the old full leg produced).
- variant: full
label: ""
cmake_flags: "-DKK_ZCASH_PRIVACY=OFF"
- variant: bitcoin-only
label: " (bitcoin-only)"
cmake_flags: "-DKK_BITCOIN_ONLY=ON"
- variant: zcash-privacy
label: " (zcash-privacy)"
cmake_flags: "-DKK_ZCASH_PRIVACY=ON"
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -250,27 +271,42 @@ jobs:
if: steps.cache-base.outputs.cache-hit == 'true'
run: docker load -i /tmp/base-image.tar

- name: Build emulator image
- name: Build emulator image (${{ matrix.variant }})
run: |
docker build \
-t ${{ env.EMU_IMAGE }} \
-t ${{ env.EMU_IMAGE }}-${{ matrix.variant }} \
--build-arg coinsupport="${{ matrix.cmake_flags }}" \
-f scripts/emulator/Dockerfile \
.

- name: Save emulator image
run: docker save ${{ env.EMU_IMAGE }} -o /tmp/emu-image.tar
run: docker save ${{ env.EMU_IMAGE }}-${{ matrix.variant }} -o /tmp/emu-image.tar

- name: Upload emulator image artifact
uses: actions/upload-artifact@v7
with:
name: emu-image
name: emu-image-${{ matrix.variant }}
path: /tmp/emu-image.tar
retention-days: 1

build-arm-firmware:
name: build-arm-firmware${{ matrix.label }}
needs: [lint-format, static-analysis, check-submodules, secret-scan]
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- variant: full
label: ""
cmake_flags: ""
- variant: bitcoin-only
label: " (bitcoin-only)"
cmake_flags: "-DKK_BITCOIN_ONLY=ON"
- variant: zcash-privacy
label: " (zcash-privacy)"
cmake_flags: "-DKK_ZCASH_PRIVACY=ON"
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -312,70 +348,105 @@ jobs:
echo "git_short=${GIT_SHORT}" >> "$GITHUB_OUTPUT"
echo "Firmware version: ${FW_VERSION} (${GIT_SHORT})"

- name: Cross-compile firmware for ARM
- name: Cross-compile firmware for ARM (${{ matrix.variant }})
run: |
docker run --rm \
-v ${{ github.workspace }}:/root/keepkey-firmware:z \
${{ env.BASE_IMAGE }} /bin/sh -c "\
mkdir /root/build && cd /root/build && \
cmake -C /root/keepkey-firmware/cmake/caches/device.cmake /root/keepkey-firmware \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_COLOR_MAKEFILE=ON && \
-DCMAKE_COLOR_MAKEFILE=ON \
${{ matrix.cmake_flags }} && \
make && \
mkdir -p /root/keepkey-firmware/bin && \
cp bin/*.bin /root/keepkey-firmware/bin/ && \
cp bin/*.elf /root/keepkey-firmware/bin/ && \
cp bin/*.map /root/keepkey-firmware/bin/ 2>/dev/null || true && \
arm-none-eabi-size -A bin/firmware.keepkey.elf > /root/keepkey-firmware/bin/firmware.keepkey.size.txt 2>/dev/null || true && \
find . -name '*.su' -print0 | tar czf /root/keepkey-firmware/bin/stack-usage.tgz --null -T - && \
chmod -R a+rw /root/keepkey-firmware/bin"

# SRAM budget gate — RC7's zcash-privacy variant hard-faulted on boot
# because static SRAM left an 11.2 KB gap while msg_write() carried a
# 12.4 KB stack frame. keepkey.ld now ASSERTs a 16 KiB reserve at link
# time; this step reports the numbers and enforces the frame margin
# (tools/sram-budgets.json).
- name: SRAM budget gate (${{ matrix.variant }})
run: |
pip install --quiet pyelftools
python3 tools/check_sram_budget.py \
--elf bin/firmware.keepkey.elf \
--su-tar bin/stack-usage.tgz \
--budgets tools/sram-budgets.json \
--variant "${{ matrix.variant }}"

- name: Rename firmware artifacts
run: |
cd bin
for f in *.bin; do
[ -f "$f" ] || continue
mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${f}"
mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }}-${f}"
done
for f in *.elf; do
[ -f "$f" ] || continue
mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${f}"
mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }}-${f}"
done
ls -lh
echo "::notice::Firmware v${{ steps.version.outputs.fw_version }} built successfully"
echo "::notice::Firmware v${{ steps.version.outputs.fw_version }} (${{ matrix.variant }}) built successfully"

- name: Upload firmware artifacts
uses: actions/upload-artifact@v7
with:
name: firmware-v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}
name: firmware-v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }}
path: |
bin/*.bin
bin/*.elf
bin/*.map
bin/*.size.txt
bin/stack-usage.tgz
retention-days: 90

# ═══════════════════════════════════════════════════════════
# STAGE 3: TEST — run only after builds succeed
# ═══════════════════════════════════════════════════════════

unit-tests:
name: unit-tests${{ matrix.label }}
needs: build-emulator
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- variant: full
label: ""
cmake_flags: ""
- variant: bitcoin-only
label: " (bitcoin-only)"
cmake_flags: "-DKK_BITCOIN_ONLY=ON"
- variant: zcash-privacy
label: " (zcash-privacy)"
cmake_flags: "-DKK_ZCASH_PRIVACY=ON"
steps:
- name: Download emulator image
uses: actions/download-artifact@v8
with:
name: emu-image
name: emu-image-${{ matrix.variant }}
path: /tmp

- name: Load emulator image
run: docker load -i /tmp/emu-image.tar

- name: Run unit tests
- name: Run unit tests (${{ matrix.variant }})
run: |
# make xunit returns non-zero if any test fails — capture
# exit code so JUnit XML still gets copied for reporting
docker run --rm \
-v ${{ github.workspace }}/test-reports:/kkemu/test-reports \
--entrypoint /bin/sh \
${{ env.EMU_IMAGE }} \
${{ env.EMU_IMAGE }}-${{ matrix.variant }} \
-c "mkdir -p /kkemu/test-reports/firmware-unit && \
make xunit; RC=\$?; \
cp -r unittests/*.xml /kkemu/test-reports/firmware-unit/ 2>/dev/null; \
Expand All @@ -385,7 +456,7 @@ jobs:
uses: actions/upload-artifact@v7
if: always()
with:
name: unit-test-results
name: unit-test-results-${{ matrix.variant }}
path: test-reports/firmware-unit/
retention-days: 30

Expand Down Expand Up @@ -684,7 +755,10 @@ jobs:
uses: actions/download-artifact@v4
continue-on-error: true
with:
name: unit-test-results
# Report covers the full/default variant only — bitcoin-only and
# zcash-privacy are built and unit-tested in their own matrix legs
# but don't get a PDF (see unit-tests / build-arm-firmware).
name: unit-test-results-full
path: test-reports/firmware-unit/

- name: Download python test results
Expand Down Expand Up @@ -744,7 +818,11 @@ jobs:
- name: Download emulator image
uses: actions/download-artifact@v8
with:
name: emu-image
# Publish the zcash-privacy variant: it matches the emulator's CMake
# default (privacy engine ON — what vault and auditors run), which
# the "full" leg no longer builds now that it pins the shipped
# device configuration (privacy OFF).
name: emu-image-zcash-privacy
path: /tmp

- name: Load emulator image
Expand All @@ -759,8 +837,8 @@ jobs:

- name: Tag images for publish
run: |
docker tag ${{ env.EMU_IMAGE }} kktech/kkemu:latest
docker tag ${{ env.EMU_IMAGE }} kktech/kkemu:v${{ steps.version.outputs.fw_version }}
docker tag ${{ env.EMU_IMAGE }}-full kktech/kkemu:latest
docker tag ${{ env.EMU_IMAGE }}-full kktech/kkemu:v${{ steps.version.outputs.fw_version }}

- name: Login to DockerHub
uses: docker/login-action@v4
Expand Down
Loading
Loading