mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-20 01:35:19 +03:00
A submission from a team machine with four drives and 22 TiB reported
`disk=8880`, and the field was not wrong so much as meaningless: it was the
free space on the single largest mount, with no capacity anywhere and no total.
A content store is sized against capacity.
Storage now reports four things, because they answer different questions and
one number could not:
diskfree total free across every real filesystem
disksize total capacity
diskmax the largest single filesystem, which is the real ceiling for any
one store -- a dataset cannot be spread across drives
disks how many there are
The ambiguous `disk` key is gone rather than silently redefined, so old rows
stay readable as what they were. `Get-PSDrive` reports Free *and* Used and we
were reading only Free, hence no capacity on Windows at all.
Pseudo-filesystems are now excluded by *type* rather than by mount path. Path
filtering missed `/tmp` on a tmpfs, whose free space is RAM -- so 7 GiB of
memory was being added to a storage total, which is exactly the sort of number
a capacity plan gets built on.
## The real finding, which was not about disks
"We are working blind on Windows" is correct, and both Windows bugs this tool
has had prove it: a virtual display adapter reported as the GPU, and a URL
truncated at its first `&`. Both were in code that only runs on Windows, both
were found by a person reading the results channel, and neither could have been
found here -- the development machine is Linux and `xdg-open` never sees a
shell.
Two things about that, and the first is the one that generalises.
`OPENERS` is now a const with a test asserting the property that actually
matters: **never hand a URL to anything that will re-parse it.** No `cmd`, no
`sh`, no `powershell`, no `start` builtin, and no argument that looks like it
wants the URL interpolated into it. Unlike the bug, that is checkable on every
platform in a millisecond. Verified by reintroducing `cmd /C start "" <url>`
and confirming the test fails with the right message, then reverting.
And CI already runs a real Windows machine and a real macOS one -- we simply
were not looking at them. Each smoke-tested target now prints its full report
and JSON into a collapsed log group. Deliberately not `set -e`: this step is
for looking, and a probe that misbehaves on a runner must not fail a release.
It turns "working blind" into "looking at it once per release", which would
have shown the Parsec adapter problem the first time a Windows binary was ever
built.
Version to 0.2.2.
205 lines
8.4 KiB
YAML
205 lines
8.4 KiB
YAML
# Builds the binaries people actually download.
|
|
#
|
|
# `nesdoctor` is handed to strangers and asked to be trusted, so the release
|
|
# artefacts are built here and nowhere else: a binary someone produced on their
|
|
# laptop and uploaded is not auditable, however honest they are.
|
|
#
|
|
# Tag `nesdoctor-v0.1.0` to cut a release, or run it by hand to check the
|
|
# matrix still builds.
|
|
name: release nesdoctor
|
|
|
|
on:
|
|
push:
|
|
tags: ["nesdoctor-v*"]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
build:
|
|
name: ${{ matrix.target }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
# One broken target must not suppress the others: a Windows failure
|
|
# should still leave the Linux binary available to look at.
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# musl and not glibc, so one Linux binary runs on every distro
|
|
# regardless of its glibc version. Static linking is the whole reason
|
|
# this target is here.
|
|
- os: ubuntu-latest
|
|
target: x86_64-unknown-linux-musl
|
|
bin: nesdoctor
|
|
smoke: true
|
|
- os: windows-latest
|
|
target: x86_64-pc-windows-msvc
|
|
bin: nesdoctor.exe
|
|
smoke: true
|
|
- os: macos-latest
|
|
target: aarch64-apple-darwin
|
|
bin: nesdoctor
|
|
smoke: true
|
|
# Intel Macs are still a large installed base and they are clients,
|
|
# which is a category we want answers from. Cross-compiled from the
|
|
# arm64 runner rather than built on `macos-13`: that runner is being
|
|
# retired and a dispatch on 2026-09-02 sat queued indefinitely
|
|
# waiting for one, which is not a dependency a release should have.
|
|
#
|
|
# The cost is honest and stated: an x86_64 binary cannot be executed
|
|
# on an arm64 runner without Rosetta, which these images do not
|
|
# carry, so this is the one target whose smoke test cannot run. It
|
|
# ships cross-compiled and unexercised, and the release notes say so.
|
|
- os: macos-latest
|
|
target: x86_64-apple-darwin
|
|
bin: nesdoctor
|
|
smoke: false
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Rust toolchain
|
|
run: |
|
|
rustup toolchain install stable --profile minimal --no-self-update
|
|
rustup target add ${{ matrix.target }}
|
|
|
|
# `ring`, under rustls, compiles C. On musl that needs the musl C
|
|
# toolchain present or the build fails at link time with an error that
|
|
# does not mention TLS at all.
|
|
- name: musl toolchain
|
|
if: matrix.target == 'x86_64-unknown-linux-musl'
|
|
run: sudo apt-get update && sudo apt-get install -y musl-tools
|
|
|
|
- name: Build
|
|
run: cargo build --release -p nesdoctor --target ${{ matrix.target }}
|
|
|
|
# The binary is run here on purpose, and this step is the reason this
|
|
# workflow is worth having rather than a `cargo build` someone trusts.
|
|
#
|
|
# A static musl build resolves root certificates through the host trust
|
|
# store, so TLS can compile perfectly and then fail on the machine it is
|
|
# shipped to -- which would break the network test, the one feature
|
|
# anybody runs this for, silently and only for other people. Running the
|
|
# real thing here catches that class of failure before a tag exists.
|
|
- name: Smoke test — the whole run, network included
|
|
if: matrix.smoke
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
BIN="target/${{ matrix.target }}/release/${{ matrix.bin }}"
|
|
test -x "$BIN"
|
|
# --no-steam because a runner has no Steam and the consent prompt
|
|
# would block; stdin is closed so any prompt reads as a skip.
|
|
OUT="$("$BIN" --quiet --no-steam --json "$RUNNER_TEMP/nd.json" < /dev/null)"
|
|
echo "$OUT"
|
|
# The summary line must exist and must not have fallen back to
|
|
# "net=unmeasured", which is what a TLS or upload failure looks like.
|
|
grep -q "nesdoctor " <<<"$OUT"
|
|
if grep -q "net=unmeasured" <<<"$OUT"; then
|
|
echo "::error::network test did not run in the built binary — \
|
|
TLS or the upload sink failed at runtime, which is exactly the \
|
|
failure this step exists to catch"
|
|
exit 1
|
|
fi
|
|
test -s "$RUNNER_TEMP/nd.json"
|
|
|
|
# Eyes on the platforms the developer machine is not.
|
|
#
|
|
# Every Windows bug this tool has had was found by a person reading the
|
|
# results channel: a virtual display adapter reported as the GPU, and a
|
|
# URL truncated at its first `&`. Both were in code that only runs on
|
|
# Windows, and the development machine is Linux -- so nobody had ever
|
|
# seen what these probes return on the platform most of the audience
|
|
# uses.
|
|
#
|
|
# CI already runs a real Windows machine and a real macOS one. Printing
|
|
# the full report from each is nearly free and turns "we are working
|
|
# blind" into "we are looking at it once per release".
|
|
- name: Show what the probes actually return here
|
|
if: matrix.smoke
|
|
shell: bash
|
|
run: |
|
|
set -uo pipefail
|
|
BIN="target/${{ matrix.target }}/release/${{ matrix.bin }}"
|
|
echo "::group::${{ matrix.target }} — full report"
|
|
# Not `set -e`: this step is for looking, and a probe that fails on a
|
|
# runner must not fail the release.
|
|
"$BIN" --no-net --no-steam --json "$RUNNER_TEMP/probe.json" < /dev/null || true
|
|
echo "::endgroup::"
|
|
echo "::group::${{ matrix.target }} — JSON"
|
|
cat "$RUNNER_TEMP/probe.json" 2>/dev/null || echo "(no json written)"
|
|
echo "::endgroup::"
|
|
|
|
- name: Package
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p dist
|
|
NAME="nesdoctor-${{ matrix.target }}"
|
|
cp "target/${{ matrix.target }}/release/${{ matrix.bin }}" "dist/$NAME${{ matrix.bin == 'nesdoctor.exe' && '.exe' || '' }}"
|
|
cd dist
|
|
# Checksums beside the binary, because "download this and run it" is
|
|
# only a reasonable request if the file can be verified.
|
|
if command -v sha256sum >/dev/null; then
|
|
sha256sum * > "$NAME.sha256"
|
|
else
|
|
shasum -a 256 * > "$NAME.sha256"
|
|
fi
|
|
cat *.sha256
|
|
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: nesdoctor-${{ matrix.target }}
|
|
path: dist/*
|
|
if-no-files-found: error
|
|
|
|
release:
|
|
# Only on a tag. A manual run builds and smoke-tests the matrix without
|
|
# publishing anything, which is what you want while iterating.
|
|
if: startsWith(github.ref, 'refs/tags/nesdoctor-v')
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
path: dist
|
|
merge-multiple: true
|
|
|
|
- name: Collect checksums
|
|
run: |
|
|
cd dist
|
|
cat *.sha256 | sort -k2 > SHA256SUMS
|
|
rm -f nesdoctor-*.sha256
|
|
ls -la
|
|
cat SHA256SUMS
|
|
|
|
- uses: softprops/action-gh-release@v2
|
|
with:
|
|
# A draft, always. The binaries are attached and the notes are
|
|
# written, and a person reads both and presses publish -- which is
|
|
# the only step in this pipeline that is irreversible in public.
|
|
draft: true
|
|
files: dist/*
|
|
generate_release_notes: true
|
|
body: |
|
|
**nesdoctor** — checks whether this machine can host a Nestri box,
|
|
and measures what your connection actually does under load.
|
|
|
|
Nothing is uploaded. There is no server to upload to: the network
|
|
test talks to Cloudflare's public speed-test sink and to `1.1.1.1`,
|
|
neither of which is ours. The output is a line on your terminal that
|
|
you may choose to paste somewhere.
|
|
|
|
Download the file for your platform, verify it against
|
|
`SHA256SUMS`, and run it. On macOS and Linux you will need
|
|
`chmod +x` first. Source is in `apps/nesdoctor`.
|
|
|
|
The Intel macOS binary is cross-compiled and is the one target CI
|
|
cannot execute to test. Every other binary here was run by the
|
|
workflow that built it.
|
|
|
|
The number worth running it for is **added latency under load**.
|
|
Everybody knows their download speed; almost nobody has seen this
|
|
one, and for anything interactive it is the figure that decides it.
|