fix(startos): audit packaging — drop stale sdk-build, add aarch64, complete i18n - #1
Conversation
…mplete i18n This fork maintains only the StartOS wrapper: it consumes the image upstream publishes and never builds or pushes one of its own. Changes are confined to startos/, the build files, and CI; no application code is touched. Build: - Delete sdk-build/. Its build script copied startos/*.ts in before bundling, but 19 of those copies were also committed, frozen at 0.1.1:0 / image tag 0.5.2 while startos/ said 0.5.3. Build startos/ directly instead: the SDK and ncc move to the root package.json as startos:check / startos:build, with the packaging tsconfig and a commonjs marker beside the source. The marker is load-bearing — the app root is "type": "module", and `s9pk pack` require()s the bundle. - The package cannot use the SDK's s9pk.mk, which needs `npm run build` to be the ncc step while here it is the Vite build, so the Makefile stays bespoke. - Bump @start9labs/start-sdk 2.0.6 -> 2.0.9; pack with an assets dir. CI — stop publishing images: - Both release.yml and test-build.yml built the app and pushed it to ghcr.io/<this repo>. Drop those jobs entirely; each workflow now only packs an s9pk against the tag named in the manifest. Nothing in CI writes to a container registry. - test-build.yml previously rebuilt the released tag as amd64-only on every push to main and force-pushed it over the multi-arch image, plus :latest. That is how 0.5.2 lost its arm64 layer. Removing the job removes the hazard. - Release and artifact names now derive from the packed manifest, with ':' replaced by '_' since git refs cannot contain it. Package: - arch was ['x86_64'] although the published image is amd64+arm64, excluding ARM servers entirely. Now ['x86_64', 'aarch64']. - Drop the alerts block: it no longer exists in the SDK 2.0 types, passes typecheck only because setupManifest infers its generic from the argument, and is discarded at pack time. - packageRepo now points at this fork, which is where the packaging lives; upstreamRepo and marketingUrl stay on the application's own repo. - Remove a dead duplicate setInterfaces from index.ts; start-core reads only main/init/uninit/createBackup/manifest/actions from the bundle. - Drop four migration-less version files and set other: []. The packed manifest still reports canMigrateFrom "<=0.5.3:1". - main.ts defers to the image CMD via sdk.useEntrypoint() rather than restating it. - The long description still advertised "BraiinsOS+ / CGMiner API", predating the asic-rs rewrite. i18n: translations.ts was an empty stub. Populate es_ES/de_DE/pl_PL/fr_FR for all six keys and add those locales to the descriptions and release notes. Docs: startos/README.md was a scaffold citing a manifest.yaml that does not exist and StartOS 0.4.0.x; rewritten against writing-readmes.md, with instructions.md rewritten against writing-instructions.md. Both now state that no data is written to the mounted volume — all state is browser localStorage, so backups capture nothing. Verified on StartOS 0.4.0.1 (x86_64): installs, daemon starts, health green, UI reachable over LAN, LAN egress from the container works, a real /24 scan completes, stop/restart clean, /data empty.
a4225ad to
30e58eb
Compare
|
Thanks @heatpunk — that's exactly the gap this review turned up, and it's now merged into this branch. Your commit is carried here with authorship intact, so #2 is closed as superseded. Two small things I fixed on the way in:
The implementation itself looks right — What's needed to actually switch this on — one job, on your side. Nothing changes for StartOS users yet. StartOS installs a prebuilt Blisspoint, and the one it installs today was built before your change, so there is still nowhere for it to save to. We confirmed that on a real server: asking it for the saved settings returns "not found", and the storage folder is empty. Please publish a new Blisspoint release with this change in it, then let us know it's out. That's the whole ask. Once it exists we will:
One thing worth deciding before it ships: miner passwords are currently only kept in the browser. After this change they are saved on the server as plain text, and they will be included in backups. That is a reasonable trade for settings that survive, but it should be stated plainly in the docs so nobody is surprised. |
d6114ea to
30e58eb
Compare
|
Upstream image |
Upstream published 0.5.4 with a state-persistence backend, so the package can
finally deliver working backups. Bump the image tag and version, and rewrite
the documentation that described the old behaviour.
- dockerTag -> 0.5.4 (verified multi-arch: linux/amd64 + linux/arm64).
- Version -> 0.5.4:0; the upstream component moved, so the revision resets.
- The Node server now writes all user state to /data/state.json via tmp+rename,
and the browser's localStorage becomes a cache and offline fallback rather
than the system of record. The README's Volume and Backups sections said the
opposite and are rewritten.
- Two limitations replace the three that this fixes: miner API passwords are
now on disk in plaintext and therefore inside every backup, and concurrent
edits from two devices are last-write-wins with no merge. Both are stated in
the user-facing instructions too, since a password landing in a backup is
something the operator should know without reading the README.
No application code is carried here — the persistence work is upstream's, and
this package consumes the image it publishes.
Verified on StartOS 0.4.0.1 (x86_64), upgrading 0.5.3:1 -> 0.5.4:0: health goes
green; GET /api/state returns {} on a fresh volume; POST creates
/data/state.json and reads back byte-identical; the file survives a service
restart; DELETE removes it; LAN egress from the container and the proxy health
check still pass.
d6114ea to
12c5bed
Compare
|
Confirmed Your persistence work is doing exactly what it should. Tested on a real StartOS server, upgrading from the previous version:
The wording that warned people their miner list wasn't included in backups is gone, replaced with two things they should know instead: miner passwords are saved as ordinary text and therefore end up inside backups, and if two people change settings from different phones at the same moment the last one to save wins. One note on how we work with this repo going forward: we keep our copy limited to the StartOS packaging only, so we no longer carry your app changes here — we just point at the version you publish. If we ever need something changed in the app itself, we'll open a pull request on your repo rather than change it on our side. That keeps our copy easy to keep in step with yours. |
MattDHill
left a comment
There was a problem hiding this comment.
Approved. Packaging audit plus adoption of upstream 0.5.4, verified end-to-end on a StartOS 0.4.0.1 box: health green, state persists to /data/state.json and survives a restart, LAN egress intact, both arches pack.
Wrapper-only, as intended — no application code in this branch.
|
Merged. Thanks @heatpunk — the persistence work landed the same day it was needed, and Blisspoint now backs up properly on StartOS and runs on ARM servers as well as x86. How we'll work together from hereThis repository is the StartOS packaging only. We don't change the app here. If we find something that needs fixing in the app itself — the interface, the Node server, You publish, we point at it. Nothing here builds or publishes a container image any more; both workflows just package against the version you publish to
Please keep releasing multi-architecture builds (both amd64 and arm64, as you did for 0.5.4). A lot of StartOS servers are ARM, and if a release is amd64-only those users can't install it at all. One thing to watch. Earlier today four release builds for the same version ran at once and raced to publish the same tag. It worked out, but if two finish together it's luck which one wins. Letting one finish before starting another avoids that. Worth knowing about the change you just madeMiner passwords are now saved on the server as ordinary text, so they're inside every backup of Blisspoint. That's a fair trade for settings that survive, and it's written plainly in both the packaging notes and the instructions people see in StartOS — but if you ever want to encrypt or stop storing them, that would be a genuine improvement. Also, when someone with no miners yet taps Scan, it only sweeps Neither is blocking anything — just the two things most likely to generate questions. |
Full audit of the StartOS packaging ahead of Community Registry listing. This fork maintains only the StartOS wrapper: it consumes the image upstream publishes and never builds or pushes one of its own. Changes are confined to
startos/, the build files, and CI — no application code is touched, so the fork stays cleanly rebasable on upstream.What was broken
sdk-build/shipped stale duplicate source. Its build script copiedstartos/*.tsin before bundling, but 19 of those copies were also committed, frozen at version0.1.1:0and image tag0.5.2whilestartos/said0.5.3. Deleted; the package now buildsstartos/directly.CI was publishing container images from this fork. Both
release.ymlandtest-build.ymlbuilt the app and pushed it toghcr.io/<this repo>. This fork maintains only the StartOS wrapper, so both jobs are gone: each workflow now just packs an s9pk against the tag named in the manifest, and nothing in CI writes to a container registry.That also removes a destructive bug.
test-build.ymlrebuilt the released tag as amd64-only on every push tomainand force-pushed it over the multi-arch image, plus:latest— which is why0.5.2in GHCR has no arm64 layer while0.5.3still does.The manifest locked out ARM.
arch: ['x86_64'], although the published0.5.3image is genuinely amd64 + arm64 — which excluded every ARM server. Now['x86_64', 'aarch64'], verified by packing the aarch64 s9pk.A dead duplicate
setInterfacesinindex.ts.start-corereads onlymain/init/uninit/createBackup/manifest/actionsfrom the bundle, so it was never invoked. Restored to canonical plumbing.Four version files with no-op migrations.
v0_4_2/v0_4_7/v0_5_0/v0_5_2all had emptyup. Removed,other: []. The packed manifest still reportscanMigrateFrom: "<=0.5.3:1", so every prior install upgrades in one hop.The
alertsblock no longer exists in SDK 2.0. It passed typecheck only becausesetupManifestinfers its generic from the argument, and was discarded at pack time regardless. Removed.The marketplace long description was factually wrong — it advertised "BraiinsOS+ / CGMiner API", predating the asic-rs rewrite.
i18n was a scaffold, not an implementation.
translations.tswas an empty stub. Nowes_ES/de_DE/pl_PL/fr_FRacross all six keys, plus those locales on the manifest descriptions and release notes.startos/README.mdwas a dead scaffold citing amanifest.yamlthat does not exist and StartOS 0.4.0.x. Rewritten against the packaging guide'swriting-readmes.md;instructions.mdrewritten againstwriting-instructions.md.Also: SDK
2.0.6→2.0.9,main.tsdefers to the imageCMDviasdk.useEntrypoint()instead of duplicating it,packageRepopoints at this fork, and stale release steps corrected inCONTRIBUTING.mdandCLAUDE.md.Known limitation, documented — and being fixed upstream
The service writes nothing to its mounted volume. All user state — miner list, names, captured power ceilings, and saved miner API passwords — lives in the browser's
localStorage(blisspoint.state.v2). Somainmounts at/dataand stays empty, andBackups.ofVolumes('main')captures nothing: a restore yields an empty miner list. Confirmed empirically on the box, and documented in both the README limitations and the user-facing instructions rather than leaving the backup silently implying it works.#2 addresses exactly this, and is merged into this branch:
server/serve.cjsgainsGET/POST/DELETE /api/statewriting atomically to/data/state.json, and the Zustand store gets a storage adapter that prefers the server copy and falls back tolocalStorage.It is inert until a new image ships. That change is application code baked into the container, and the manifest pins the currently published tag, which predates it — verified against the running install, where
GET /api/statereturns 404 and/datais still empty. So the volume and backup documentation in this PR stays as written, because it describes the artifact this PR actually produces.Sequencing to land the feature:
dockerTaginstartos/manifest/index.tsand the version instartos/versions/current.ts.startos/README.md, and the Limitations ininstructions.md. Note that miner API passwords then move from browser-only storage into/data/state.jsonin plaintext, and into backups — that is a real change in posture and should be stated./data/state.jsonappears, survives a restart, and that a restore repopulates the miner list.Two fixes were needed on top of #2 as merged:
pnpm-lock.yaml. The repo is npm —package-lock.jsonis the lockfile and both the Dockerfile and CI runnpm ci. A second lockfile from another package manager only invites drift.npm run lint. Four barecatch (_) {}blocks in the storage adapter are hardno-emptyerrors, andci.ymlruns lint on every PR, so feat(persistence): add backend state persistence to /data/state.json for StartOS backups #2 as submitted would have failed CI. Now optional catch bindings with a note on why each failure is safe to swallow.Test plan
Verified on a real StartOS 0.4.0.1 box (x86_64):
make x86→ builds and packsblisspoint_x86_64.s9pkatv0.5.3:1, sdk 2.0.9.make armalso packs, confirming the arm64 image resolves.start-cli package install -s blisspoint_x86_64.s9pk→ installs as0.5.3:1.start-cli package start blisspoint→ daemon starts; logs showBlisspoint serving on :80.{"result": "success", "message": "The web interface is ready"}.node server/serve.cjson0.0.0.0:80andproxy-rson127.0.0.1:8081only./24. This is the whole premise of the service.GET /api/scan?subnet=<lan>swept a real/24and returned cleanly./api/healthboth work end-to-end.stopis immediate and clean (no PID-1 signal hang, sorunAsInitis not needed);startreturns to green./dataconfirmed empty after install, start, restart and a scan.Not covered: miner control itself — pause/resume and power-target were not exercised against real hardware, as no ASIC was available on the test network. The transport around them is verified; the control paths are not.