Skip to content

introduce prodtest error codes#6829

Merged
TychoVrahe merged 5 commits into
mainfrom
tychovrahe/prodtest/error_codes
Jun 16, 2026
Merged

introduce prodtest error codes#6829
TychoVrahe merged 5 commits into
mainfrom
tychovrahe/prodtest/error_codes

Conversation

@TychoVrahe

Copy link
Copy Markdown
Contributor

Summary

  • Replaces prodtest CLI's string-based error codes with a stable integer system
  • Each cli_error() call site gets a unique code that survives refactoring, command addition/removal, and message edits
  • Wire format change: ERROR error "message" -> ERROR <int> "message"

Changes to cli.h / cli.c

  • cli_error() signature: const char* code -> int code
  • Framework codes (CLI_ERROR_INVALID_CMD etc.) converted from strings to integers 1?8
  • Generic CLI_ERROR "error" macro removed

Rules (encoded as comments in the header)

  • Codes are never reused - retired codes stay in the enum marked DEPRECATED
  • New errors are appended to the relevant block; gaps are never filled
  • 1000-code blocks allow 3-digit offsets per module (current largest: tropic at 100)

Breaking change

Host-side test scripts must be updated - the ERROR line now carries an integer instead of a string.

New file: prodtest_error_codes.h

Central prodtest_error_t enum with 326 unique codes across 24 module blocks of 1000:

Module Range
backup-ram 1000-1999
ble 2000-2999
bootloader 3000-3999
button 4000-4999
haptic 5000-5999
manufacturing-lock 6000-6999
nfc 7000-7999
nrf 8000-8999
optiga 9000-9999
otp 10000-10999
otp-variant 11000-11999
power-manager 12000-12999
rtc 13000-13999
sdcard 14000-14999
secrets 15000-15999
secure-channel 16000-16999
tamper 17000-17999
telemetry 18000-18999
touch 19000-19999
tropic 20000-20999
unit-test 21000-21999
wpc 22000-22999
common 23000-23999
prodtest 24000-24999

@coderabbitai

coderabbitai Bot commented Apr 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Introduces a comprehensive numeric error-code system for prodtest commands: adds prodtest_error_codes.h enum with module-block allocation (1000–25999), generates error_codes.json catalog mapping codes to names and modules, implements a Python code generator and validation tool (core/tools/prodtest_error_codes.py), updates the CLI API to accept integer error codes instead of string literals, converts framework error macros to integers, adds Makefile targets for generation and checking, integrates with build scripts, adds a debug-only syslog CLI command, and remaps error reporting across ~30 prodtest command handlers from generic CLI_ERROR to specific PRODTEST_ERR_* constants.

Sequence Diagram(s)

sequenceDiagram
  participant User as User/Test
  participant CLI as rtl/cli
  participant Cmd as prodtest command handler
  participant Codes as prodtest_error_codes.h
  User->>CLI: execute prodtest command
  CLI->>Cmd: invoke handler
  Cmd->>Codes: include & reference PRODTEST_ERR_* constant
  Cmd->>CLI: cli_error(code: int, message)
  CLI->>User: return ERROR <numeric_code> "<message>"
Loading
sequenceDiagram
  participant Dev as Developer
  participant Make as Makefile
  participant Tool as core/tools/prodtest_error_codes.py
  participant Header as prodtest_error_codes.h
  participant CliH as rtl/inc/rtl/cli.h
  participant Ver as version.h
  participant JSON as error_codes.json
  Dev->>Make: make gen (or gen_check)
  Make->>Tool: python3 prodtest_error_codes.py
  Tool->>Header: parse PRODTEST_ERR_* enum by module block
  Tool->>CliH: parse CLI_ERROR_* framework code constants
  Tool->>Ver: extract VERSION_MAJOR/MINOR/PATCH/BUILD
  Tool->>JSON: generate or verify catalog structure
  alt --check mode
    Tool->>JSON: compare generated vs stored
    Tool->>Make: exit non-zero if mismatch
  else default mode
    Tool->>JSON: write generated catalog
    Tool->>Make: exit success
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • trezor/trezor-firmware#6956: Modifies prodtest_tropic.c (tropic-benchmark handler) overlapping with this PR's Tropic error-code remapping.

Suggested reviewers

  • M-pasta
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'introduce prodtest error codes' clearly summarizes the main change: introducing a new error code system for prodtest CLI.
Description check ✅ Passed The description provides a comprehensive summary of changes including wire format changes, function signature updates, framework code conversions, and the new error code system with 24 module blocks and 326 codes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tychovrahe/prodtest/error_codes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@trezor-bot trezor-bot Bot added this to Firmware Apr 24, 2026
@github-project-automation github-project-automation Bot moved this to 🔎 Needs review in Firmware Apr 24, 2026
@github-actions

github-actions Bot commented Apr 24, 2026

Copy link
Copy Markdown

en main(all)

model device_test click_test persistence_test
T2T1 test(all) main(all) test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all) test(all) main(all)

Latest CI run: 27602807999

@TychoVrahe TychoVrahe force-pushed the tychovrahe/prodtest/error_codes branch 2 times, most recently from a98e657 to 5217521 Compare May 4, 2026 08:16
@TychoVrahe TychoVrahe marked this pull request as ready for review May 4, 2026 13:42
@TychoVrahe TychoVrahe requested a review from obrusvit as a code owner May 4, 2026 13:42
@TychoVrahe TychoVrahe requested review from cepetr, kopecdav and onvej-sl May 4, 2026 13:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
core/embed/projects/prodtest/cmd/prodtest_ble.c (1)

206-221: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing return after cli_error causes double-response on failure paths.

prodtest_ble_erase_bonds_cmd has two cli_error calls without a following return:

  1. Line 207–208 (PRODTEST_ERR_BLE_STATE_UNKNOWN): execution falls through; if peer_count == 0 the function then calls cli_ok("No bonds to erase."), emitting both an error and a success response to the host.
  2. Lines 216–217 (PRODTEST_ERR_BLE_BONDS_ERASE): cli_trace and cli_ok are unconditionally reached after the error, so erase failures always also emit a success response.

Every other cli_error site in this file is followed by return. These two are the only exceptions and appear to be accidental omissions.

🐛 Proposed fix
   if (!state.state_known) {
     cli_error(cli, PRODTEST_ERR_BLE_STATE_UNKNOWN, "BLE state unknown.");
+    return;
   }

   if (state.peer_count == 0) {
     cli_ok(cli, "No bonds to erase.");
     return;
   }

   if (!prodtest_ble_erase_bonds(cli)) {
     cli_error(cli, PRODTEST_ERR_BLE_BONDS_ERASE, "Could not erase bonds.");
+    return;
   }

   cli_trace(cli, "Erased %d bonds.", state.peer_count);
   cli_ok(cli, "");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/embed/projects/prodtest/cmd/prodtest_ble.c` around lines 206 - 221, In
prodtest_ble_erase_bonds_cmd, the two cli_error calls for state.state_known and
prodtest_ble_erase_bonds failures must be followed by immediate returns to avoid
emitting subsequent cli_ok/cli_trace responses; update the branches that call
cli_error(PRODTEST_ERR_BLE_STATE_UNKNOWN, ...) and
cli_error(PRODTEST_ERR_BLE_BONDS_ERASE, ...) to return after logging (same
pattern used by other cli_error sites), ensuring state.state_known,
state.peer_count, and prodtest_ble_erase_bonds are left unchanged otherwise.
core/embed/rtl/cli.c (1)

161-191: ⚠️ Potential issue | 🔴 Critical

CLI_ERROR is still referenced in syslog.c after being removed by this PR.

The PR removes the generic CLI_ERROR macro, and core/embed/sys/dbg/syslog.c:289 still calls:

cli_error(cli, CLI_ERROR, "Failed to set log filter.");

CLI_ERROR is not defined in cli.h (only CLI_ERROR_INVALID_CMD through CLI_ERROR_INVALID_CRC remain defined). This undefined identifier will cause a compilation failure.

Replace CLI_ERROR with CLI_ERROR_FATAL or another appropriate code from cli.h:

Proposed fix
  if (!syslog_set_filter(filter, filter_len)) {
-   cli_error(cli, CLI_ERROR, "Failed to set log filter.");
+   cli_error(cli, CLI_ERROR_FATAL, "Failed to set log filter.");
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/embed/rtl/cli.c` around lines 161 - 191, The call to cli_error(...) uses
the removed identifier CLI_ERROR causing a compile error; update the invocation
of cli_error (the call site that currently does cli_error(cli, CLI_ERROR,
"Failed to set log filter.");) to use a valid code from cli.h such as
CLI_ERROR_FATAL (or another appropriate CLI_ERROR_* constant), i.e. replace
CLI_ERROR with CLI_ERROR_FATAL and keep the rest of the call unchanged so the
signature cli_error(cli, int, const char*, ...) remains correct.
core/embed/projects/prodtest/cmd/prodtest_tropic.c (1)

856-866: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN is semantically wrong for a key-invalidation failure

The operation at this site is lt_pairing_key_invalidate() (invalidating the factory pairing key slot), but the assigned error code name PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN describes certificate signing. Any host-side tooling or log triage that maps error code → description will receive a misleading signal.

Since the enum is introduced fresh in this PR, the correct fix is to rename the enum member to reflect the actual operation (e.g., PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE) and update this call site. Per the PR rules, once the code ships, the integer value must be retired and a new code appended.

🐛 Proposed fix (rename in `prodtest_error_codes.h` + update call site)

In prodtest_error_codes.h, rename the enum member:

-  PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN = <value>,
+  PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE = <value>,

In prodtest_tropic.c, line 861:

-      cli_error(cli, PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN,
+      cli_error(cli, PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE,
                 "`lt_pairing_key_invalidate()` failed for factory pairing key "
                 "with error '%s'",
                 lt_ret_verbose(ret));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/embed/projects/prodtest/cmd/prodtest_tropic.c` around lines 856 - 866,
The error enum used for a failed key-invalidation is misnamed: replace the enum
member PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN with a new, semantically correct
member (e.g., PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE) in the
prodtest_error_codes.h enum (do not reuse the old integer value; append a new
value per PR rules), then update the call site in prodtest_tropic.c that calls
lt_pairing_key_invalidate(tropic_handle, TROPIC_FACTORY_PAIRING_KEY_SLOT) to
pass the new PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE constant to cli_error
instead of PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN.
core/embed/projects/prodtest/cmd/common.c (1)

500-519: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing return false after SN-retrieval errors allows cert-chain validation to pass with an empty device serial number.

Both error paths that call cli_error (lines 502–503 and 511–513) fall through to the memcmp check. When both unit_properties_get_sn and get_name_attribute fail, device_sn_size and subject_sn_size are both 0, so subject_sn_size != device_sn_size is false and memcmp(…, 0) returns 0 — the comparison passes silently and check_cert_chain returns true. In production this is a security concern because a device whose serial number cannot be read will incorrectly validate its certificate chain.

This is pre-existing but is made visible by the PR touching these exact cli_error call sites.

🛡️ Proposed fix
  if (!unit_properties_get_sn(device_sn, sizeof(device_sn),
                              &device_sn_size) ||
      device_sn_size == 0) {
    cli_error(cli, PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN,
              "check_device_cert_chain, device_sn not set.");
+   return false;
  }

  ...

  if (!get_name_attribute(&subject, OID_SERIAL_NUMBER,
                          sizeof(OID_SERIAL_NUMBER), &subject_sn,
                          &subject_sn_size)) {
    cli_error(cli, PRODTEST_ERR_COMMON_CERT_CHAIN_SERIAL_NUM,
              "check_device_cert_chain, serialNumber not set.");
+   return false;
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/embed/projects/prodtest/cmd/common.c` around lines 500 - 519, The
serial-number retrieval failure paths in check_device_cert_chain currently call
cli_error but fall through, allowing both device_sn_size and subject_sn_size to
be 0 and the memcmp to erroneously succeed; after the unit_properties_get_sn
failure (the cli_error that logs PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN) and
after the get_name_attribute failure (the cli_error that logs
PRODTEST_ERR_COMMON_CERT_CHAIN_SERIAL_NUM), immediately return false to abort
validation — i.e., add a return false; after each cli_error so
check_device_cert_chain exits on SN retrieval errors.
🧹 Nitpick comments (2)
core/tools/prodtest_error_codes.py (2)

30-32: 💤 Low value

Ruff RUF001: ambiguous EN DASH in _MODULE_RE regex character class.

[–-] is correct (the trailing - before ] is treated as a literal hyphen), but the character class looks like an invalid range to both readers and the linter. An explicit escape clarifies intent:

♻️ Suggested clarification
-_MODULE_RE = re.compile(r"//\s*===\s*(.+?)\s*\((\d+)\s*[–-]\s*(\d+)\)\s*")
+_MODULE_RE = re.compile(r"//\s*===\s*(.+?)\s*\((\d+)\s*[–\-]\s*(\d+)\)\s*")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/tools/prodtest_error_codes.py` around lines 30 - 32, The regex in
_MODULE_RE uses the character class [–-] which the linter flags as an ambiguous
range; update _MODULE_RE to explicitly match an en dash or a hyphen (e.g.,
replace the character class with an alternation like (?:–|-) or use an escaped
form such as [\u2013\-]) so the intent is unambiguous to readers and linters
while keeping the rest of the pattern the same.

46-76: 💤 Low value

Silent "module": null when a PRODTEST_ERR_* entry appears before any module comment.

current_module is initialised to None and is only set when a // === … (range) === marker is encountered. If a matching enum line appears before the first marker (e.g., due to a malformed header), the resulting JSON entry will have "module": null with no warning or error.

A guard would make this detectable early:

♻️ Suggested guard
         m = _ENUM_RE.match(line)
         if m:
+            if current_module is None:
+                print(
+                    f"warning: enum entry {m.group(1)} has no preceding module marker",
+                    file=sys.stderr,
+                )
             errors.append(
                 {
                     "code": int(m.group(2)),
                     "name": m.group(1),
                     "module": current_module,
                 }
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/tools/prodtest_error_codes.py` around lines 46 - 76, In
parse_prodtest_header, add a guard inside the block handling _ENUM_RE to detect
when current_module is still None (i.e., an enum appears before any module
marker) and fail fast: raise a clear ValueError (or RuntimeError) that includes
the matched enum name/code (from m.group(1)/m.group(2)) and the offending line
content so the malformed header is detectable, rather than appending an entry
with "module": None; reference parse_prodtest_header, current_module, and
_ENUM_RE when implementing this check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/embed/projects/prodtest/cmd/common.c`:
- Around line 586-588: In check_device_cert_chain, fix the cli_error call that
reports der_read_item 7 by removing the spurious "\"%d.\"\" argument so the
format string and arguments align: ensure cli_error is called with the format
"check_device_cert_chain, der_read_item 7, cert %d." and a single cert_count
argument (use the existing PRODTEST_ERR_COMMON_CERT_CHAIN_READ_SIG_ALG constant
and keep der_read_item reference unchanged); this removes the undefined behavior
caused by passing a const char* where an int was expected.

In `@core/embed/projects/prodtest/cmd/prodtest_power_manager.c`:
- Around line 125-126: In prodtest_pm_charge_disable, the log/error messages are
copy-pasted for the opposite action; update the cli_trace and cli_error calls
(references: prodtest_pm_charge_disable, pm_charging_disable, cli_trace,
cli_error) to say "Disabling battery charging" and "Failed to disable battery
charging" respectively so the messages match the actual pm_charging_disable call
and behavior.

In `@core/embed/projects/prodtest/cmd/prodtest_secure_channel.c`:
- Around line 60-73: The function prodtest_secure_channel_handshake_2 currently
falls through after error reporting; add immediate returns after the two
cli_error calls so execution stops there: after the cli_error that reports
PRODTEST_ERR_SECURE_CHANNEL_INPUT_LEN (when input_length !=
SECURE_CHANNEL_INPUT_SIZE) return from the function instead of continuing to
call secure_channel_handshake_2, and after the cli_error that reports
PRODTEST_ERR_SECURE_CHANNEL_HANDSHAKE_FINISH (when
secure_channel_handshake_2(input) fails) return instead of falling through to
cli_ok; this ensures no further processing or an extra cli_ok() is emitted for
the same command.

---

Outside diff comments:
In `@core/embed/projects/prodtest/cmd/common.c`:
- Around line 500-519: The serial-number retrieval failure paths in
check_device_cert_chain currently call cli_error but fall through, allowing both
device_sn_size and subject_sn_size to be 0 and the memcmp to erroneously
succeed; after the unit_properties_get_sn failure (the cli_error that logs
PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN) and after the get_name_attribute
failure (the cli_error that logs PRODTEST_ERR_COMMON_CERT_CHAIN_SERIAL_NUM),
immediately return false to abort validation — i.e., add a return false; after
each cli_error so check_device_cert_chain exits on SN retrieval errors.

In `@core/embed/projects/prodtest/cmd/prodtest_ble.c`:
- Around line 206-221: In prodtest_ble_erase_bonds_cmd, the two cli_error calls
for state.state_known and prodtest_ble_erase_bonds failures must be followed by
immediate returns to avoid emitting subsequent cli_ok/cli_trace responses;
update the branches that call cli_error(PRODTEST_ERR_BLE_STATE_UNKNOWN, ...) and
cli_error(PRODTEST_ERR_BLE_BONDS_ERASE, ...) to return after logging (same
pattern used by other cli_error sites), ensuring state.state_known,
state.peer_count, and prodtest_ble_erase_bonds are left unchanged otherwise.

In `@core/embed/projects/prodtest/cmd/prodtest_tropic.c`:
- Around line 856-866: The error enum used for a failed key-invalidation is
misnamed: replace the enum member PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN with a new,
semantically correct member (e.g., PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE) in
the prodtest_error_codes.h enum (do not reuse the old integer value; append a
new value per PR rules), then update the call site in prodtest_tropic.c that
calls lt_pairing_key_invalidate(tropic_handle, TROPIC_FACTORY_PAIRING_KEY_SLOT)
to pass the new PRODTEST_ERR_TROPIC_PAIR_KEY_INVALIDATE constant to cli_error
instead of PRODTEST_ERR_TROPIC_PAIR_CERT_SIGN.

In `@core/embed/rtl/cli.c`:
- Around line 161-191: The call to cli_error(...) uses the removed identifier
CLI_ERROR causing a compile error; update the invocation of cli_error (the call
site that currently does cli_error(cli, CLI_ERROR, "Failed to set log
filter.");) to use a valid code from cli.h such as CLI_ERROR_FATAL (or another
appropriate CLI_ERROR_* constant), i.e. replace CLI_ERROR with CLI_ERROR_FATAL
and keep the rest of the call unchanged so the signature cli_error(cli, int,
const char*, ...) remains correct.

---

Nitpick comments:
In `@core/tools/prodtest_error_codes.py`:
- Around line 30-32: The regex in _MODULE_RE uses the character class [–-] which
the linter flags as an ambiguous range; update _MODULE_RE to explicitly match an
en dash or a hyphen (e.g., replace the character class with an alternation like
(?:–|-) or use an escaped form such as [\u2013\-]) so the intent is unambiguous
to readers and linters while keeping the rest of the pattern the same.
- Around line 46-76: In parse_prodtest_header, add a guard inside the block
handling _ENUM_RE to detect when current_module is still None (i.e., an enum
appears before any module marker) and fail fast: raise a clear ValueError (or
RuntimeError) that includes the matched enum name/code (from
m.group(1)/m.group(2)) and the offending line content so the malformed header is
detectable, rather than appending an entry with "module": None; reference
parse_prodtest_header, current_module, and _ENUM_RE when implementing this
check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a7a47f6-82e1-4bc9-a61a-62e0bf317a38

📥 Commits

Reviewing files that changed from the base of the PR and between 108189e and 5217521.

📒 Files selected for processing (32)
  • Makefile
  • core/embed/projects/prodtest/.changelog.d/6829.added
  • core/embed/projects/prodtest/cmd/common.c
  • core/embed/projects/prodtest/cmd/common.h
  • core/embed/projects/prodtest/cmd/prodtest_backup_ram.c
  • core/embed/projects/prodtest/cmd/prodtest_ble.c
  • core/embed/projects/prodtest/cmd/prodtest_bootloader.c
  • core/embed/projects/prodtest/cmd/prodtest_button.c
  • core/embed/projects/prodtest/cmd/prodtest_haptic.c
  • core/embed/projects/prodtest/cmd/prodtest_manufacturing_lock.c
  • core/embed/projects/prodtest/cmd/prodtest_nfc.c
  • core/embed/projects/prodtest/cmd/prodtest_nrf.c
  • core/embed/projects/prodtest/cmd/prodtest_optiga.c
  • core/embed/projects/prodtest/cmd/prodtest_otp_batch.c
  • core/embed/projects/prodtest/cmd/prodtest_otp_variant.c
  • core/embed/projects/prodtest/cmd/prodtest_power_manager.c
  • core/embed/projects/prodtest/cmd/prodtest_prodtest.c
  • core/embed/projects/prodtest/cmd/prodtest_rtc.c
  • core/embed/projects/prodtest/cmd/prodtest_sdcard.c
  • core/embed/projects/prodtest/cmd/prodtest_secrets.c
  • core/embed/projects/prodtest/cmd/prodtest_secure_channel.c
  • core/embed/projects/prodtest/cmd/prodtest_tamper.c
  • core/embed/projects/prodtest/cmd/prodtest_telemetry.c
  • core/embed/projects/prodtest/cmd/prodtest_touch.c
  • core/embed/projects/prodtest/cmd/prodtest_tropic.c
  • core/embed/projects/prodtest/cmd/prodtest_unit_test.c
  • core/embed/projects/prodtest/cmd/prodtest_wpc.c
  • core/embed/projects/prodtest/error_codes.json
  • core/embed/projects/prodtest/prodtest_error_codes.h
  • core/embed/rtl/cli.c
  • core/embed/rtl/inc/rtl/cli.h
  • core/tools/prodtest_error_codes.py

Comment thread core/embed/projects/prodtest/cmd/common.c
Comment thread core/embed/projects/prodtest/cmd/prodtest_power_manager.c Outdated
Comment thread core/embed/projects/prodtest/cmd/prodtest_secure_channel.c
@TychoVrahe TychoVrahe removed the request for review from obrusvit May 4, 2026 14:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/embed/projects/prodtest/cmd/common.c (1)

499-519: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Both SN-check error paths fall through without returning, allowing cert-chain validation to silently succeed when neither SN can be retrieved.

When unit_properties_get_sn fails (line 499) and get_name_attribute fails (line 508), both cli_error paths continue without a return false. At that point device_sn_size == 0, subject_sn == NULL, subject_sn_size == 0. The subsequent guard:

if (subject_sn_size != device_sn_size ||          // 0 != 0 → false
    memcmp(subject_sn, device_sn, device_sn_size)  // memcmp(NULL, buf, 0)

…is never taken, so the SN comparison trivially passes despite both lookups having failed. memcmp with a NULL pointer and size 0 is also technically UB in C (§7.1.4 requires valid pointers regardless of n). The net result is that the cert-chain check proceeds as if SN validation succeeded on an unprovisioned or misconfigured device.

Even if this is intentional for unprovisioned devices, the silent success is dangerous; the two error codes (PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN / _SERIAL_NUM) emit an error but do not abort — conflicting signal to callers. At minimum, each failure branch should return false to be consistent with every other error path in this function.

🐛 Proposed fix
     if (!unit_properties_get_sn(device_sn, sizeof(device_sn),
                                 &device_sn_size) ||
         device_sn_size == 0) {
       cli_error(cli, PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN,
                 "check_device_cert_chain, device_sn not set.");
+      return false;
     }

     const uint8_t* subject_sn = NULL;
     size_t subject_sn_size = 0;
     if (!get_name_attribute(&subject, OID_SERIAL_NUMBER,
                             sizeof(OID_SERIAL_NUMBER), &subject_sn,
                             &subject_sn_size)) {
       cli_error(cli, PRODTEST_ERR_COMMON_CERT_CHAIN_SERIAL_NUM,
                 "check_device_cert_chain, serialNumber not set.");
+      return false;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/embed/projects/prodtest/cmd/common.c` around lines 499 - 519, The error
branches after unit_properties_get_sn and get_name_attribute call cli_error but
do not abort, allowing check_device_cert_chain to continue with device_sn_size
== 0 and subject_sn == NULL; add an immediate return false after each cli_error
that logs PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN and
PRODTEST_ERR_COMMON_CERT_CHAIN_SERIAL_NUM respectively so failures in
unit_properties_get_sn or get_name_attribute stop processing (this prevents the
subsequent memcmp(NULL, ..., 0) UB and fixes the silent-success cert-chain
validation in check_device_cert_chain).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@core/embed/projects/prodtest/cmd/common.c`:
- Around line 499-519: The error branches after unit_properties_get_sn and
get_name_attribute call cli_error but do not abort, allowing
check_device_cert_chain to continue with device_sn_size == 0 and subject_sn ==
NULL; add an immediate return false after each cli_error that logs
PRODTEST_ERR_COMMON_CERT_CHAIN_DEVICE_SN and
PRODTEST_ERR_COMMON_CERT_CHAIN_SERIAL_NUM respectively so failures in
unit_properties_get_sn or get_name_attribute stop processing (this prevents the
subsequent memcmp(NULL, ..., 0) UB and fixes the silent-success cert-chain
validation in check_device_cert_chain).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11517aa8-5ecc-47d9-977e-8ecd19358650

📥 Commits

Reviewing files that changed from the base of the PR and between 5217521 and e6b8491.

📒 Files selected for processing (3)
  • core/embed/projects/prodtest/cmd/common.c
  • core/embed/projects/prodtest/cmd/prodtest_power_manager.c
  • core/embed/projects/prodtest/cmd/prodtest_secure_channel.c
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/embed/projects/prodtest/cmd/prodtest_secure_channel.c
  • core/embed/projects/prodtest/cmd/prodtest_power_manager.c

@TychoVrahe TychoVrahe marked this pull request as draft June 3, 2026 08:03
@TychoVrahe TychoVrahe force-pushed the tychovrahe/prodtest/error_codes branch from e6b8491 to 05aab3f Compare June 3, 2026 08:04
Comment thread core/embed/projects/prodtest/.changelog.d/6829.added
@github-project-automation github-project-automation Bot moved this from 🔎 Needs review to 🏃‍♀️ In progress in Firmware Jun 3, 2026
Comment thread core/embed/projects/prodtest/cmd/prodtest_button.c Outdated
@TychoVrahe

Copy link
Copy Markdown
Contributor Author

On request from production guys, prodtest error codes for each group start from xx10, the 0-9 are reserved.

@TychoVrahe TychoVrahe marked this pull request as ready for review June 4, 2026 11:01

@cepetr cepetr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

Comment thread core/embed/rtl/inc/rtl/cli.h Outdated
Comment thread core/tools/prodtest_error_codes.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
core/embed/projects/prodtest/README.md (1)

44-46: 💤 Low value

Consider adding language identifiers to fenced code blocks.

The static analysis tool flags missing language specifiers for these code blocks. Adding ```shell or ```console identifiers would improve markdown rendering and syntax highlighting.

Also applies to: 639-644, 673-678

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/projects/prodtest/README.md` around lines 44 - 46, The fenced code
blocks in README.md that contain console output like ERROR 11 "Expecting
x-coordinate." (and the other blocks at the ranges you noted) lack a language
identifier; update each opening triple-backtick to include a language specifier
such as ```shell or ```console so the snippets render and highlight correctly —
locate the code blocks around the shown ERROR line and the other reported ranges
(639-644, 673-678) and replace ``` with ```shell or ```console as appropriate.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@core/embed/projects/prodtest/README.md`:
- Around line 44-46: The fenced code blocks in README.md that contain console
output like ERROR 11 "Expecting x-coordinate." (and the other blocks at the
ranges you noted) lack a language identifier; update each opening
triple-backtick to include a language specifier such as ```shell or ```console
so the snippets render and highlight correctly — locate the code blocks around
the shown ERROR line and the other reported ranges (639-644, 673-678) and
replace ``` with ```shell or ```console as appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 23ee7c3d-44ec-48eb-ad05-e466ece9e1d4

📥 Commits

Reviewing files that changed from the base of the PR and between 93e24aa and 243a538.

📒 Files selected for processing (3)
  • core/embed/projects/prodtest/README.md
  • core/embed/projects/prodtest/error_codes.json
  • core/embed/rtl/inc/rtl/cli.h
💤 Files with no reviewable changes (1)
  • core/embed/projects/prodtest/error_codes.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/embed/rtl/inc/rtl/cli.h

@TychoVrahe TychoVrahe force-pushed the tychovrahe/prodtest/error_codes branch from 243a538 to b66535e Compare June 15, 2026 14:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
Makefile (1)

202-210: ⚡ Quick win

Declare new generation targets as phony.

Please add .PHONY entries for prodtest_error_codes, prodtest_error_codes_check, gen, and gen_check to prevent accidental file-name shadowing from skipping recipes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 202 - 210, Add a .PHONY declaration in the Makefile to
mark the new generation targets as phony targets. Declare prodtest_error_codes,
prodtest_error_codes_check, gen, and gen_check as phony targets by adding them
to a .PHONY line (either a new line or appended to an existing .PHONY
declaration if one exists in the file). This prevents Make from treating these
as file targets and ensures the recipes always execute even if files with those
names exist.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/embed/projects/prodtest/README.md`:
- Line 578: In the error description text on line 578 of the README.md file, fix
the spelling error where "occured" is misspelled. Change it to the correct
spelling "occurred" (with double 'r') in the user-facing error message that
describes the I/O error codes 14011-14015.

In `@core/tools/prodtest_error_codes.py`:
- Around line 178-181: The current code initializes framework_codes as an empty
list and only populates it if the --cli-header file exists, which allows the
program to continue with degraded output when the required file is missing. Fix
this by adding explicit error handling that raises an exception or exits the
program when args.cli_header does not exist, rather than silently continuing
with an empty framework_codes list. Remove or modify the conditional check to
ensure the parse_cli_header function is always called and any missing file will
cause the program to fail fast.
- Around line 52-76: The parse_prodtest_header() function is missing validation
to enforce catalog invariants when parsing error codes. When appending entries
to the errors list in the section where it matches _ENUM_RE, add checks to
ensure: (1) the error code (obtained from m.group(2)) falls within the current
module's range_start and range_end, and (2) the error code has not already been
added to the errors list (no duplicates). If either check fails, raise an
appropriate exception with a descriptive message to prevent invalid catalogs
from being silently generated and committed.

---

Nitpick comments:
In `@Makefile`:
- Around line 202-210: Add a .PHONY declaration in the Makefile to mark the new
generation targets as phony targets. Declare prodtest_error_codes,
prodtest_error_codes_check, gen, and gen_check as phony targets by adding them
to a .PHONY line (either a new line or appended to an existing .PHONY
declaration if one exists in the file). This prevents Make from treating these
as file targets and ensures the recipes always execute even if files with those
names exist.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 053068be-6e62-4b87-a105-8fa1cf48ecbe

📥 Commits

Reviewing files that changed from the base of the PR and between 243a538 and b66535e.

📒 Files selected for processing (38)
  • Makefile
  • core/SConscript.prodtest
  • core/SConscript.prodtest_emu
  • core/embed/projects/prodtest/.changelog.d/6829.added
  • core/embed/projects/prodtest/README.md
  • core/embed/projects/prodtest/build.rs
  • core/embed/projects/prodtest/cmd/common.c
  • core/embed/projects/prodtest/cmd/common.h
  • core/embed/projects/prodtest/cmd/prodtest_backup_ram.c
  • core/embed/projects/prodtest/cmd/prodtest_ble.c
  • core/embed/projects/prodtest/cmd/prodtest_bootloader.c
  • core/embed/projects/prodtest/cmd/prodtest_button.c
  • core/embed/projects/prodtest/cmd/prodtest_haptic.c
  • core/embed/projects/prodtest/cmd/prodtest_manufacturing_lock.c
  • core/embed/projects/prodtest/cmd/prodtest_nfc.c
  • core/embed/projects/prodtest/cmd/prodtest_nrf.c
  • core/embed/projects/prodtest/cmd/prodtest_optiga.c
  • core/embed/projects/prodtest/cmd/prodtest_otp_batch.c
  • core/embed/projects/prodtest/cmd/prodtest_otp_variant.c
  • core/embed/projects/prodtest/cmd/prodtest_power_manager.c
  • core/embed/projects/prodtest/cmd/prodtest_prodtest.c
  • core/embed/projects/prodtest/cmd/prodtest_rtc.c
  • core/embed/projects/prodtest/cmd/prodtest_sdcard.c
  • core/embed/projects/prodtest/cmd/prodtest_secrets.c
  • core/embed/projects/prodtest/cmd/prodtest_secure_channel.c
  • core/embed/projects/prodtest/cmd/prodtest_syslog.c
  • core/embed/projects/prodtest/cmd/prodtest_tamper.c
  • core/embed/projects/prodtest/cmd/prodtest_telemetry.c
  • core/embed/projects/prodtest/cmd/prodtest_touch.c
  • core/embed/projects/prodtest/cmd/prodtest_tropic.c
  • core/embed/projects/prodtest/cmd/prodtest_unit_test.c
  • core/embed/projects/prodtest/cmd/prodtest_wpc.c
  • core/embed/projects/prodtest/error_codes.json
  • core/embed/projects/prodtest/prodtest_error_codes.h
  • core/embed/rtl/cli.c
  • core/embed/rtl/inc/rtl/cli.h
  • core/embed/sys/dbg/syslog.c
  • core/tools/prodtest_error_codes.py
💤 Files with no reviewable changes (1)
  • core/embed/sys/dbg/syslog.c
✅ Files skipped from review due to trivial changes (4)
  • core/embed/projects/prodtest/cmd/common.h
  • core/embed/projects/prodtest/cmd/prodtest_prodtest.c
  • core/embed/projects/prodtest/.changelog.d/6829.added
  • core/embed/projects/prodtest/error_codes.json
🚧 Files skipped from review as they are similar to previous changes (28)
  • core/SConscript.prodtest
  • core/embed/projects/prodtest/build.rs
  • core/embed/projects/prodtest/cmd/prodtest_telemetry.c
  • core/embed/projects/prodtest/cmd/prodtest_bootloader.c
  • core/embed/rtl/cli.c
  • core/SConscript.prodtest_emu
  • core/embed/projects/prodtest/cmd/prodtest_button.c
  • core/embed/projects/prodtest/cmd/prodtest_secure_channel.c
  • core/embed/projects/prodtest/cmd/prodtest_tamper.c
  • core/embed/projects/prodtest/cmd/prodtest_rtc.c
  • core/embed/rtl/inc/rtl/cli.h
  • core/embed/projects/prodtest/cmd/prodtest_wpc.c
  • core/embed/projects/prodtest/cmd/prodtest_backup_ram.c
  • core/embed/projects/prodtest/cmd/prodtest_otp_batch.c
  • core/embed/projects/prodtest/cmd/prodtest_power_manager.c
  • core/embed/projects/prodtest/cmd/prodtest_unit_test.c
  • core/embed/projects/prodtest/cmd/prodtest_touch.c
  • core/embed/projects/prodtest/prodtest_error_codes.h
  • core/embed/projects/prodtest/cmd/prodtest_nfc.c
  • core/embed/projects/prodtest/cmd/prodtest_nrf.c
  • core/embed/projects/prodtest/cmd/prodtest_ble.c
  • core/embed/projects/prodtest/cmd/prodtest_sdcard.c
  • core/embed/projects/prodtest/cmd/prodtest_manufacturing_lock.c
  • core/embed/projects/prodtest/cmd/common.c
  • core/embed/projects/prodtest/cmd/prodtest_secrets.c
  • core/embed/projects/prodtest/cmd/prodtest_otp_variant.c
  • core/embed/projects/prodtest/cmd/prodtest_optiga.c
  • core/embed/projects/prodtest/cmd/prodtest_tropic.c

Comment thread core/embed/projects/prodtest/README.md Outdated
Comment on lines +52 to +76
for line in path.read_text(encoding="utf-8").splitlines():
m = _MODULE_RE.search(line)
if m:
# Extract the module name, stripping any trailing note after " — "
raw_name = m.group(1).strip()
name = raw_name.split(" — ")[0].strip()
range_start = int(m.group(2))
range_end = int(m.group(3))
current_module = name
modules.append(
{"module": name, "range_start": range_start, "range_end": range_end}
)
continue

m = _ENUM_RE.match(line)
if m:
errors.append(
{
"code": int(m.group(2)),
"name": m.group(1),
"module": current_module,
}
)

return modules, errors

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce catalog invariants during generation (range + uniqueness).

parse_prodtest_header() currently accepts enum entries without checking duplicate numeric codes or whether each code belongs to the active module range. That allows invalid catalogs to be generated and committed silently.

Suggested fix
 def parse_prodtest_header(path: Path) -> tuple[list[dict], list[dict]]:
@@
-    current_module: str | None = None
+    current_module: str | None = None
+    current_range: tuple[int, int] | None = None
+    seen_codes: set[int] = set()
@@
         if m:
@@
             range_start = int(m.group(2))
             range_end = int(m.group(3))
             current_module = name
+            current_range = (range_start, range_end)
             modules.append(
                 {"module": name, "range_start": range_start, "range_end": range_end}
             )
             continue
@@
         if m:
+            code = int(m.group(2))
+            if current_module is None or current_range is None:
+                raise ValueError(f"{path}: enum {m.group(1)} declared outside a module block")
+            if code in seen_codes:
+                raise ValueError(f"{path}: duplicate code {code} ({m.group(1)})")
+            if not (current_range[0] <= code <= current_range[1]):
+                raise ValueError(
+                    f"{path}: code {code} ({m.group(1)}) out of range for module {current_module} "
+                    f"[{current_range[0]}-{current_range[1]}]"
+                )
+            seen_codes.add(code)
             errors.append(
                 {
-                    "code": int(m.group(2)),
+                    "code": code,
                     "name": m.group(1),
                     "module": current_module,
                 }
             )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/tools/prodtest_error_codes.py` around lines 52 - 76, The
parse_prodtest_header() function is missing validation to enforce catalog
invariants when parsing error codes. When appending entries to the errors list
in the section where it matches _ENUM_RE, add checks to ensure: (1) the error
code (obtained from m.group(2)) falls within the current module's range_start
and range_end, and (2) the error code has not already been added to the errors
list (no duplicates). If either check fails, raise an appropriate exception with
a descriptive message to prevent invalid catalogs from being silently generated
and committed.

Comment on lines +178 to +181
framework_codes: list[dict] = []
if args.cli_header.exists():
framework_codes = parse_cli_header(args.cli_header)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail fast when --cli-header is missing to avoid partial catalogs.

On Line 179, missing cli.h currently yields an empty framework_codes list and still succeeds. For this rollout, that silently degrades the output contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/tools/prodtest_error_codes.py` around lines 178 - 181, The current code
initializes framework_codes as an empty list and only populates it if the
--cli-header file exists, which allows the program to continue with degraded
output when the required file is missing. Fix this by adding explicit error
handling that raises an exception or exits the program when args.cli_header does
not exist, rather than silently continuing with an empty framework_codes list.
Remove or modify the conditional check to ensure the parse_cli_header function
is always called and any missing file will cause the program to fail fast.

@TychoVrahe TychoVrahe force-pushed the tychovrahe/prodtest/error_codes branch from b66535e to 81a15a0 Compare June 16, 2026 07:54
@TychoVrahe TychoVrahe merged commit 5e97e32 into main Jun 16, 2026
110 checks passed
@TychoVrahe TychoVrahe deleted the tychovrahe/prodtest/error_codes branch June 16, 2026 11:34
@trezor-bot trezor-bot Bot moved this from 🏃‍♀️ In progress to 🤝 Needs QA in Firmware Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🤝 Needs QA

Development

Successfully merging this pull request may close these issues.

4 participants