Skip to content

fix: drop Nano S, repair CI and npm package, remove container pool - #643

Merged
jleni merged 4 commits into
mainfrom
fix/drop-nanos-ci-and-pool
Sep 8, 2026
Merged

fix: drop Nano S, repair CI and npm package, remove container pool#643
jleni merged 4 commits into
mainfrom
fix/drop-nanos-ci-and-pool

Conversation

@jleni

@jleni jleni commented Sep 8, 2026

Copy link
Copy Markdown
Member

Why

Three problems were hiding each other on main:

What changed

Nano S removed. TModel is now nanosp | nanox | stax | flex | apex_p, the default model is nanosp, and checkElf fails with a clear message when nanos is passed from JavaScript. Test fixtures are fresh Polymesh app builds (bin/app_s2.elf, app_x.elf, app_stax.elf, app_flex.elf, app_apex_p.elf).

CI. Dropped the invalid inputs; v6 reads Node/pnpm from .mise.toml and detects pnpm from the lockfile. Removed NODE_ENV=development from .mise.toml: it leaked into vitest and into mise-action on CI.

Container pool removed. It could not work outside this repo (relative dummy ELF path, no apex_p port range, fixed host ports, a Speculos "reset" endpoint that does not exist) and its stale-container sweep removed the containers of concurrent vitest workers. IStartOptions.disablePool stays as a deprecated no-op so existing option objects keep compiling.

Transport. getTransport() now honours statusList: a listed status word is returned, as in @ledgerhq/hw-transport. Any non-0x9000 status is still recorded so waitUntilScreenIs, waitForText and getEvents fail fast on critical codes. exchange() follows the same rule and no longer throws on its own. start() resets the recorded error; getLastTransportError() and clearTransportError() are public.

Lifecycle. start() copies the options object instead of mutating it, retries container creation with fresh ports when Docker reports a host port conflict, and removes the container on any failure after creation. stop() keeps its handle until removal succeeds and tolerates 304/404. Docker helpers and stopAllEmuContainers are Promise based; startGRPCServer returns the bound port and rejects on bind errors.

HTTP. Retries live on a dedicated axios instance in src/http.ts. Before, axiosRetry was applied to the global axios on every request, leaking interceptors and altering the consumer's own axios.

Tests. One parametrised basic.test.ts over all five models (start/close, main menu snapshots, app version, raw signing with signature verification, button navigation), a real error-handling.test.ts, and grpc.test.ts that loads the router from dist/ and drives Exchange through a gRPC client. globalsetup.ts is registered as vitest globalSetup; teardown only sweeps containers created by the current run.

Housekeeping. Removed the stale yarn.lock, README-npm.md, unused @ledgerhq/errors, and the tests/tmp* dirs. pnpm audit --prod is clean (was 49 advisories). Docs updated for the supported device list and defaults.

Breaking changes

  • nanos is gone from TModel.
  • Zemu.initializePool, enablePool, disablePool, isPoolEnabled, cleanupPool, getPoolStatus are removed.
  • getTransport().send(...) returns a Buffer for status words in statusList instead of throwing. exchange() no longer throws on non-0x9000.
  • stopAllEmuContainers() and startGRPCServer() return Promises.
  • WINDOW_APEX is 300x400 (was a copy of Flex).

Verification

  • pnpm build, pnpm check: clean.
  • Full suite passed 40/40 locally on the new fixtures. Later local runs on the same machine were disrupted by another session's zemu tests (its test:clean force-removes every zemu-* container); CI is the clean environment.
  • Published-package regression reproduced and fixed: dist/grpc/zemu.proto is now next to the router, and a test guards it.

- Drop nanos from TModel and constants; Speculos removed the model from the
  default emulator image. Default model is now nanosp.
- Replace test fixtures with Polymesh app builds for nanosp/nanox/stax/flex/apex_p.
- Fix ci-ts.yaml inputs so the zondax/_workflows v6 reusable workflow starts.
- Remove NODE_ENV from .mise.toml; it leaked into vitest.
- Copy zemu.proto next to the compiled gRPC router so startGRPCServer works
  from the published package.
- Remove the container pool: it never worked outside this repo and killed
  containers of concurrent workers.
- Use a dedicated axios instance for retries instead of the global one.
- getTransport() honours statusList; non-0x9000 status words are recorded for
  fail-fast waits.
- start() no longer mutates the caller's options; retries on host port conflicts.
- Promise-based Docker helpers and gRPC startup.
- Consolidate tests, register globalSetup, add dist-based gRPC test.
- Drop stale yarn.lock, README-npm.md, unused @ledgerhq/errors; audit clean.
- stop() keeps the container handle until removal succeeds, tolerates 304/404,
  and shares one in-flight operation between concurrent callers.
- start() removes the container on any failure after it was created,
  including the last port-conflict attempt and startup timeouts.
- startGRPCServer resolves with the bound port, shuts down a previous
  server first, and every gRPC failure rejects instead of throwing.
- Test teardown only sweeps containers created by the current run.
- Bounded overrides: ws ^8.21.0 and uuid ^11.1.1 (uuid 14 is ESM-only).
- test:watch builds first; gRPC tests exercise Exchange end to end;
  relaxed fail-fast timing bounds.
The reusable workflow's job requests pull-requests: write; a caller that
grants less makes the run fail at startup.
@jleni
jleni merged commit c255f25 into main Sep 8, 2026
5 checks passed
@jleni
jleni deleted the fix/drop-nanos-ci-and-pool branch September 8, 2026 16:54
jleni added a commit that referenced this pull request Sep 8, 2026
checkAndPullImage now rejects when the pull stream produces no progress
for DEFAULT_PULL_INACTIVITY_TIMEOUT (120 s) and destroys the stream. The
same value is set as the Docker client socket timeout, so a daemon that
accepts the request but never answers is covered as well. The timeout is
an optional second argument for callers that want a different bound.

Add regression tests for #564 that drive the real followProgress with a
fake pull stream, so they run without a Docker daemon: request failure,
stream error after progress, stall, slow-but-alive pull, and success.

Follow-up to #643 and #565 (thanks @turbocrime for the report).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant