fix: drop Nano S, repair CI and npm package, remove container pool - #643
Merged
Conversation
- 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.
This was referenced Sep 8, 2026
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Three problems were hiding each other on
main:ci-ts.yamlpassespackage_managerandnode_version, which_checks-ts.yaml@v6does not accept, so every run ends instartup_failure. fix(touch): guard DynamicTapButton against zero-coord events) #641 and build: Update default emulator image #642 merged without CI.8b3fcfb) no longer supports Nano S and requires an API level in the ELF metadata. None of the old test ELFs inbin/boot on it, so the suite was red on any machine.buildcopiedzemu.prototodist/src/grpc/while the router loads it fromdist/grpc/. Verified against the 0.67.4 tarball. The test imported fromsrc/, so it never noticed.What changed
Nano S removed.
TModelis nownanosp | nanox | stax | flex | apex_p, the default model isnanosp, andcheckElffails with a clear message whennanosis 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.tomland detects pnpm from the lockfile. RemovedNODE_ENV=developmentfrom.mise.toml: it leaked into vitest and intomise-actionon CI.Container pool removed. It could not work outside this repo (relative dummy ELF path, no
apex_pport 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.disablePoolstays as a deprecated no-op so existing option objects keep compiling.Transport.
getTransport()now honoursstatusList: a listed status word is returned, as in@ledgerhq/hw-transport. Any non-0x9000status is still recorded sowaitUntilScreenIs,waitForTextandgetEventsfail fast on critical codes.exchange()follows the same rule and no longer throws on its own.start()resets the recorded error;getLastTransportError()andclearTransportError()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 andstopAllEmuContainersare Promise based;startGRPCServerreturns the bound port and rejects on bind errors.HTTP. Retries live on a dedicated axios instance in
src/http.ts. Before,axiosRetrywas applied to the global axios on every request, leaking interceptors and altering the consumer's own axios.Tests. One parametrised
basic.test.tsover all five models (start/close, main menu snapshots, app version, raw signing with signature verification, button navigation), a realerror-handling.test.ts, andgrpc.test.tsthat loads the router fromdist/and drivesExchangethrough a gRPC client.globalsetup.tsis registered as vitestglobalSetup; teardown only sweeps containers created by the current run.Housekeeping. Removed the stale
yarn.lock,README-npm.md, unused@ledgerhq/errors, and thetests/tmp*dirs.pnpm audit --prodis clean (was 49 advisories). Docs updated for the supported device list and defaults.Breaking changes
nanosis gone fromTModel.Zemu.initializePool,enablePool,disablePool,isPoolEnabled,cleanupPool,getPoolStatusare removed.getTransport().send(...)returns a Buffer for status words instatusListinstead of throwing.exchange()no longer throws on non-0x9000.stopAllEmuContainers()andstartGRPCServer()return Promises.WINDOW_APEXis 300x400 (was a copy of Flex).Verification
pnpm build,pnpm check: clean.test:cleanforce-removes everyzemu-*container); CI is the clean environment.dist/grpc/zemu.protois now next to the router, and a test guards it.