fix(fleet): capture local self-update helper errors (#495)

The helper container that runs `docker compose up --force-recreate` was
spawned with `docker run -d`, so the command returned immediately with
just the container ID. Any failure happening INSIDE the helper (bad
compose file, image mismatch, permission issue, socket problem) was
invisible: execFile's callback only fired for `docker run` command
errors, never for errors inside the detached helper. The UI fell back to
the generic 3-minute "Local update did not complete" heuristic with no
actionable information.

The helper now runs attached, so execFile's callback receives the
helper's exit code and stderr directly for any failure that happens
before the recreate kills this process. Additionally, the helper
persists exit code + stderr to `/app/data/.sencho-update-error` before
exiting, so the error survives the gateway's own death. On startup,
`SelfUpdateService.recoverPreviousError()` reads and deletes that file,
routing the real error through the existing `getLastError()` path so the
freshly booted gateway reports exactly why the previous attempt failed
instead of the generic timeout.
This commit is contained in:
Anso
2026-04-10 17:39:01 -04:00
committed by GitHub
parent fea8b98cb5
commit 4003e7c047
2 changed files with 65 additions and 13 deletions
+1
View File
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
* **fleet:** surface real errors from failed local self-updates. Previously the helper container that runs `docker compose up --force-recreate` was launched with `docker run -d`, so `docker run` returned the container ID immediately and any failure happening inside the helper (bad compose file, image mismatch, permission issue) was invisible. The UI only saw the generic 3-minute "Local update did not complete" heuristic fallback. The helper now runs attached so `execFile` captures its exit code and stderr directly, AND it persists failure details to `/app/data/.sencho-update-error` before exiting so the error survives the gateway's death. On startup, `SelfUpdateService.recoverPreviousError()` reads that file, surfaces the real error through `getLastError()`, and deletes it, so the freshly restarted gateway reports exactly why the previous attempt failed instead of the generic timeout message.
* **deps:** migrate SSO OIDC integration from `openid-client` v5 to v6. The v5 `Issuer` / `Client` / `generators` API was removed upstream; the service now uses `Configuration`, `discovery`, `buildAuthorizationUrl`, `authorizationCodeGrant`, and `fetchUserInfo`. Discovery metadata is cached for 5 minutes via `CacheService` so a single login flow does not pay the HTTPS round trip twice, and the cache is invalidated on every SSO config write. `fetchUserInfo` failures now log the underlying error instead of silently falling back to id_token claims.
## [0.43.0](https://github.com/AnsoCode/Sencho/compare/v0.42.7...v0.43.0) (2026-04-10)