fix: robust equip-state detection and review follow-ups (v3.5.4)

Code-review follow-ups for v3.5.2/v3.5.1, plus a test flake found while
re-running the suites:

- F1: a half-initialized equip is no longer reported as success.  cmd2
  swallows exceptions raised inside the equip command (and prints no
  traceback by default), while PysimApp.equip() assigns card/rs before it
  registers the command sets - so app.card alone once let the "CommandSet ...
  is already installed" abort pass as done while /api/tree stayed broken.
  The auto-equip attempt now captures the output with cmd2 debug on (a
  swallowed error prints a traceback), requires the new profile's command-set
  instances to be installed (_app_equip_complete), and the manual
  /api/command equip branch applies the post-equip refresh only when that
  check passes (and reports it in the output when it does not).
- F3: SCARD_E_SHARING_VIOLATION is recoverable (a rebuild cannot free another
  process's claim) instead of transport-fatal.
- F4: SPI1 b2b1 = 11 (Digital Signature) is refused instead of building an
  unsigned packet; help notes RC is CRC-32 only (KID CRC-16 not offered).
- F5: _clear_app_card_state removes the muted stdout again when the app object
  had no stdout attribute.
- F7: the watchdog re-arm keeps its rate-limit window when the trigger is
  busy/disabled instead of consuming it.
- F2: stale docstring in _auto_equip_attempt.
- tests: equip-state units, half-equip and captured-traceback failures,
  unequip-on-failure, busy trigger, sharing violation, DS refusal.
- bonus: the MCC/MNC random-pick test could fail because a dict keyed by
  (mcc, mnc) keeps one of two entries (the bundled list carries both a real
  and an MVNO entry for 234/18 and 234/28); the picker was correct - the
  assertion now checks the pair against the non-MVNO pairs.

549 frontend / 421 Python green; version 3.5.4; sw cache simple-v256.
This commit is contained in:
2026-09-24 20:52:49 +03:00
parent 337e5df770
commit bed66c8ff8
9 changed files with 188 additions and 25 deletions
+1 -1
View File
@@ -303,7 +303,7 @@
<li><strong>AES-CBC</strong> encryption (zero ICV, zero-padded to 16), 16/24/32-byte keys (TS 102 225 &sect;5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
<li><strong>Retail MAC</strong> (ISO 9797-1 MAC algorithm 3) for the DES/3DES cryptographic checksum</li>
<li><strong>AES-CMAC</strong> (NIST SP 800-38B, truncated to 8 octets) for the AES cryptographic checksum (TS 102 225 &sect;5.1.3.1, KID <code class="font-mono text-sm">x2</code>)</li>
<li><strong>Redundancy Check (RC)</strong> &mdash; CRC-32 over the same header frame as the CC (TS 102 225 &sect;5.1.3.2; needs no key, SPI1 b2b1 = <code class="font-mono text-sm">01</code>)</li>
<li><strong>Redundancy Check (RC)</strong> &mdash; CRC-32 over the same header frame as the CC (TS 102 225 &sect;5.1.3.2; needs no key, SPI1 b2b1 = <code class="font-mono text-sm">01</code>). Only CRC-32 is implemented, matching pySim; the KID's CRC-16 coding is not offered.</li>
<li>AES requires a replay-protected counter: SPI1 bits b5&nbsp;b4 must be <code class="font-mono text-sm">10</code> (counter higher) or <code class="font-mono text-sm">11</code> (counter +1) per TS 102 225 &sect;5.1.2/&sect;5.1.3.1</li>
<li>Padding byte configurable (<code class="font-mono text-sm">00</code> default, or <code class="font-mono text-sm">FF</code>)</li>
</ul>