You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
os/v3/puppy: Lemonade boots with no API key on a dd-written stick (05onboard-data pre-creates lemond.conf, so 10lemonade never mints) #867
A stick written with dd alone boots Lemonade on 0.0.0.0:13305 with no API key at all, and it keeps
booting that way: 10lemonade's "mint one on first boot" never fires because 05onboard-data has already
created the file empty.
05onboard-data runs first (name order 05 < 10) and does:
is false for an empty file, . "$CONF" exports nothing, and lemond starts unauthenticated.
Measured on the cycle-13 image in QEMU (~/wt/puppy-out-c13/1bit-os-puppy.img, sha256 dcc619ff…),
booted from a plain dd copy with no prepare-stick:
# /data/lemonade/lemond.conf: 0 bytes, /etc/1bit/lemond.conf -> it
# sed -n 's/^LEMONADE_API_KEY=//p' /etc/1bit/lemond.conf | wc -c -> 0
/var/log/lemond-onebit.log:
[Warn] (Server) Serving on non-loopback host '0.0.0.0' without an API key. All endpoints, including the
/internal/* control endpoints, are reachable from other machines unauthenticated. ...
# GET /api/v1/models with no Authorization header -> 200 (same on the LAN: the firewall opens 13305)
Second boot, same stick: still 0 bytes, still 200 without a key. So it is not a first-boot race.
Writing a key by hand and restarting works, which is what the docs will tell users to do:
# printf 'LEMONADE_API_KEY=%s\n' "$key" > /data/lemonade/lemond.conf; /etc/init.d/10lemonade restart
# no key -> 401, wrong key -> 401, right key -> 200, /v1 no key -> 401
Fix
Either mint on emptiness (test [ ! -s "$CONF" ], or test for a LEMONADE_API_KEY= line) in 10lemonade, or let 05onboard-data mint it when it creates the file. The comment in 10lemonade says
"so the appliance is never open without it" — with the current ordering it always is, on any stick that
did not go through prepare-stick --mint.
Two related notes for the same lane:
prepare-stick --mint is what saves the shipped protocol, so docs/install.md (this lane) now says
plainly that a dd-only stick has no key and that Lemonade logs the warning.
Worth deciding whether the appliance should refuse to bind 0.0.0.0 with no key rather than warn: the
firewall opens 13305 to the whole LAN by design (zz-onboard-ports), so the warning is the only thing
between a dd-written stick and an open LLM on the network.
Found while verifying docs/clients.md and docs/install.md (lane pi-rlk); transcript in ~/wt/rlk-vm/results.txt (phases 1 and 2b).
Triaged at origin/main692cfa25c, verified on PR #828's branch head 5a310e89 (the init scripts are on that branch only). Confirmed exactly as reported, and the blast radius is larger than the warn line suggests.
05onboard-data:66 [ -f "$DATA/lemonade/lemond.conf" ] || : > "$DATA/lemonade/lemond.conf" <- creates it EMPTY
05onboard-data:68 ln -sfn "$DATA/lemonade/lemond.conf" /etc/1bit/lemond.conf
10lemonade:43 if [ ! -f "$CONF" ]; then # mint a key -> false for a 0-byte file
10lemonade:52-53 . "$CONF" ; export LEMONADE_API_KEY -> exports nothing
05 < 10 is name order, so the file always exists before the guard runs. The guard tests for the file, the failure is an empty file — [ ! -s "$CONF" ] (or a ^LEMONADE_API_KEY= grep, which is the idiom os/mini/prepare-stick.sh:254 already uses) is the whole fix.
Two facts the report does not state, both from the branch
The only mint in the tree is prepare-stick.sh's, and it lives in a different module: git grep -n 'LEMONADE_API_KEY' pr828 -- os/v3/puppy finds 10lemonade:27,47,51,53 and README/vm-check rows and no build-time mint — os/v3/puppy/mkimage.sh never writes a key. The mint is os/mini/prepare-stick.sh:74,248-278. So "a dd-written stick has no key" is not an edge case: it is every stick that did not go through prepare-stick --mint, and 10lemonade:27's own header ("minted at build time, or here on first boot") describes a build step that does not exist in the os/v3 image. Either mint in 05onboard-data (the writer owns the file) or add the build-time mint to mkimage.sh — but the first-boot mint must be repaired either way, because the file being empty is the state a fresh image ships in.
The reachability is real, not theoretical: zz-onboard-ports:26-36 inserts iptables -I INPUT 1 -p tcp --dport 13305 -j ACCEPTafter Puppy's -P INPUT DROP, precisely so the appliance answers on the LAN (U3). With no key, lemond serves /api/v1/*and the /internal/* control endpoints to every machine on that LAN unauthenticated. That is not "a warning at boot"; it is an open model + admin API on the network, on the default path.
So my reading of the last question in the report: fail closed. Mint on emptiness (cheap, keeps U3 working and keeps the key out of the image), and if a key still cannot be minted, bind 127.0.0.1 rather than warn and bind 0.0.0.0 — an appliance whose U3 row fails is a bug report; an unauthenticated control plane on a LAN is a security report. If you would rather decide that policy than take it from me, the mint fix alone closes this issue and the binding question becomes its own row.
Next action:[ ! -s "$CONF" ] in 10lemonade (or mint in 05onboard-data:66, which is where the file is created), plus one vm-check.sh row that a fresh dd image answers 401 without a key — the existing U3 key row at vm-check.sh:371 greps /etc/1bit/lemond.conf for a key line, which a 0-byte file... let me not guess that one: it is in the branch and the c13 boot's own vm-check transcript in ~/wt/rlk-vm/results.txt is where to read whether it passed vacuously. That row is the check this bug needs and it is worth reading before fixing. Owner pi-os3; bucket A (closes on #828 or a stack of it).
On a keyless boot U3 keyfails (no key-on-data), and U3 api local would still print http=200 — because an unauthenticated lemond answers 200 to a request that carries a bogus Bearer header. So the row that would have caught this is not vacuous; it simply never saw the case, because the gate's own path (mkimage.sh → prepare-stick.sh --mint) always mints before it boots. That is the third instance this week of the same shape (with #709's secureboot SKIP and #866): the gate does not exercise the artifact the user has.
So the verification for the fix is two rows, both already expressible in vm-check.sh's table: boot a plain dd copy (no prepare-stick), and assert U3 key → key-on-dataand an unauthenticated GET /api/v1/models → http=401. The second one is the row the table is missing today.
Re-adjudicated after #934 (4b5ef507, 03:03Z) and #936 (e8bd2b30, 03:43Z) merged — the fix this issue asks for has
been reversed by an owner decision, so the row's action is now a one-word close, not a mint.
The owner's cycle-20 decision (~20:1x, quoted in #934's body): the appliance ships like stock Lemonade, no LEMONADE_API_KEY by default, and a key is something a person turns on. Verified at main:
os/v3/puppy/embed/etc/init.d/10lemonade:46-60 no mint at all; keyed mode when a key LINE exists, blank mode otherwise
an EMPTY assignment still counts as none <- this issue's third state, still refused
the mode is logged
os/v3/puppy/embed/usr/local/bin/1bit-webapp-proxy:73-77 Origin that is not the loopback page -> 403, before the key is attached
os/mini/release-check.sh the lemonade row asserts the MODE's contract (blank: 200 + model list with no auth header;
keyed: 401 without the key, 200 with it) + 5 self-test cases
os/v3/puppy/vm-check.sh U3 key / U3 auth / U3 webapp key / data key follow the mode; new U3 proxy row (cross-origin=403)
The premise I recorded here ("05onboard-data pre-creates an empty conf so 10lemonade never mints") is still true of
the c19 tree and is now moot by design: nothing mints, deliberately, and the empty-file trap this issue identified is
what 10lemonade:52-58 explicitly refuses, so the class is guarded even though the mint is gone. In blank mode 13305
stays open to the LAN — that is the decision, not an oversight (LAN clients are the point), which also answers this
issue's closing question ("refuse to bind 0.0.0.0 with no key, or warn-and-bind"): warn-and-bind, with console item 1
as the toggle and the proxy's Origin guard as the borrowed-key defence.
So the two rows this issue said a fix needs now exist: release-check.sh asserts the shipped mode's contract, and vm-check.sh's U3 auth/U3 proxy rows assert it on a plain dd copy (prepare-stick.shwithout--mint: 7/7
PASS; vm-check.sh blank copy: 47 PASS / 0 FAIL / 3 SKIP).
Owner: one word and this closes. Either close as superseded by the cycle-20 blank-key decision (my read — the
issue's filed fix is the thing that decision removed), or say you still want a mint-on-first-boot default and I will
re-scope the row to #936's image instead. I am not closing it myself: it is your behaviour decision, and the row is now
bucket B (owner word), not A.
Resolved on main by the cycle-20 owner decision, verified at a083e31 — the fix this issue asked for is not a mint; the third state it named is refused and the shipped mode is the owner's.
os/v3/puppy/embed/etc/init.d/05onboard-data:67-73 no longer pre-creates an empty lemond.conf; the comment cites this issue and says why the rule stays: "a file that exists and is empty reads as 'keyed' to every script that greps for the line and as 'no key' to lemond (measured on a dd-written stick: 200 without an Authorization header, on the second boot too)". It creates the directory and the symlink only.
os/v3/puppy/embed/etc/init.d/10lemonade:43-62 has no mint at all (owner decision 2026-11-03): blank mode is the default and is logged, an empty LEMONADE_API_KEY= is treated as none, and keyed mode requires a real key line.
os/v3/puppy/embed/usr/local/bin/1bit-webapp-proxy:74-78 refuses a non-loopback Origin with 403 before any key is attached, so the open endpoint cannot be driven from a foreign page.
vm-check.sh's U3 rows are the gate: key-on-data fails on a keyless boot rather than the run passing, which is what this issue's comment established.
Closing per the issue's own last comment ("the row's action is now a one-word close, not a mint"). The residual — an application-layer default of blank mode — is the owner's decision, not a defect.
Activity
docs: install 1bit OS (stick, disk, USB) and connect a client to Lemo…
bong-water-water-bong commentedon Nov 3, 2026
Triaged at
origin/main692cfa25c, verified on PR #828's branch head5a310e89(the init scripts are on that branch only). Confirmed exactly as reported, and the blast radius is larger than the warn line suggests.05<10is name order, so the file always exists before the guard runs. The guard tests for the file, the failure is an empty file —[ ! -s "$CONF" ](or a^LEMONADE_API_KEY=grep, which is the idiomos/mini/prepare-stick.sh:254already uses) is the whole fix.Two facts the report does not state, both from the branch
prepare-stick.sh's, and it lives in a different module:git grep -n 'LEMONADE_API_KEY' pr828 -- os/v3/puppyfinds10lemonade:27,47,51,53and README/vm-checkrows and no build-time mint —os/v3/puppy/mkimage.shnever writes a key. The mint isos/mini/prepare-stick.sh:74,248-278. So "a dd-written stick has no key" is not an edge case: it is every stick that did not go throughprepare-stick --mint, and10lemonade:27's own header ("minted at build time, or here on first boot") describes a build step that does not exist in the os/v3 image. Either mint in05onboard-data(the writer owns the file) or add the build-time mint tomkimage.sh— but the first-boot mint must be repaired either way, because the file being empty is the state a fresh image ships in.zz-onboard-ports:26-36insertsiptables -I INPUT 1 -p tcp --dport 13305 -j ACCEPTafter Puppy's-P INPUT DROP, precisely so the appliance answers on the LAN (U3). With no key,lemondserves/api/v1/*and the/internal/*control endpoints to every machine on that LAN unauthenticated. That is not "a warning at boot"; it is an open model + admin API on the network, on the default path.So my reading of the last question in the report: fail closed. Mint on emptiness (cheap, keeps U3 working and keeps the key out of the image), and if a key still cannot be minted, bind
127.0.0.1rather than warn and bind0.0.0.0— an appliance whose U3 row fails is a bug report; an unauthenticated control plane on a LAN is a security report. If you would rather decide that policy than take it from me, the mint fix alone closes this issue and the binding question becomes its own row.Next action:
[ ! -s "$CONF" ]in10lemonade(or mint in05onboard-data:66, which is where the file is created), plus onevm-check.shrow that a freshddimage answers 401 without a key — the existingU3 keyrow atvm-check.sh:371greps/etc/1bit/lemond.conffor a key line, which a 0-byte file... let me not guess that one: it is in the branch and the c13 boot's ownvm-checktranscript in~/wt/rlk-vm/results.txtis where to read whether it passed vacuously. That row is the check this bug needs and it is worth reading before fixing. Owner pi-os3; bucket A (closes on #828 or a stack of it).bong-water-water-bong commentedon Nov 3, 2026
Correction to the last paragraph above, now read from the branch instead of hedged — and the answer is the interesting one:
vm-check.sh:371-373is the right row already:On a keyless boot
U3 keyfails (nokey-on-data), andU3 api localwould still printhttp=200— because an unauthenticatedlemondanswers 200 to a request that carries a bogusBearerheader. So the row that would have caught this is not vacuous; it simply never saw the case, because the gate's own path (mkimage.sh→prepare-stick.sh --mint) always mints before it boots. That is the third instance this week of the same shape (with #709'ssecurebootSKIP and #866): the gate does not exercise the artifact the user has.So the verification for the fix is two rows, both already expressible in
vm-check.sh's table: boot a plainddcopy (noprepare-stick), and assertU3 key→key-on-dataand an unauthenticatedGET /api/v1/models→http=401. The second one is the row the table is missing today.docs/install: both installed-disk fixes are in main, and a dd-only st…
bong-water-water-bong commentedon Nov 4, 2026
Re-adjudicated after
#934(4b5ef507, 03:03Z) and#936(e8bd2b30, 03:43Z) merged — the fix this issue asks for hasbeen reversed by an owner decision, so the row's action is now a one-word close, not a mint.
The owner's cycle-20 decision (
~20:1x, quoted in #934's body): the appliance ships like stock Lemonade, noLEMONADE_API_KEYby default, and a key is something a person turns on. Verified atmain:The premise I recorded here ("
05onboard-datapre-creates an empty conf so10lemonadenever mints") is still true ofthe c19 tree and is now moot by design: nothing mints, deliberately, and the empty-file trap this issue identified is
what
10lemonade:52-58explicitly refuses, so the class is guarded even though the mint is gone. In blank mode13305stays open to the LAN — that is the decision, not an oversight (LAN clients are the point), which also answers this
issue's closing question ("refuse to bind
0.0.0.0with no key, or warn-and-bind"): warn-and-bind, with console item 1as the toggle and the proxy's Origin guard as the borrowed-key defence.
So the two rows this issue said a fix needs now exist:
release-check.shasserts the shipped mode's contract, andvm-check.sh'sU3 auth/U3 proxyrows assert it on a plainddcopy (prepare-stick.shwithout--mint: 7/7PASS;
vm-check.shblank copy: 47 PASS / 0 FAIL / 3 SKIP).Owner: one word and this closes. Either close as superseded by the cycle-20 blank-key decision (my read — the
issue's filed fix is the thing that decision removed), or say you still want a mint-on-first-boot default and I will
re-scope the row to #936's image instead. I am not closing it myself: it is your behaviour decision, and the row is now
bucket B (owner word), not A.
docs: the appliance ships with no API key (cycle 20), and the console…
bong-water-water-bong commentedon Nov 6, 2026
Resolved on
mainby the cycle-20 owner decision, verified ata083e31— the fix this issue asked for is not a mint; the third state it named is refused and the shipped mode is the owner's.os/v3/puppy/embed/etc/init.d/05onboard-data:67-73no longer pre-creates an emptylemond.conf; the comment cites this issue and says why the rule stays: "a file that exists and is empty reads as 'keyed' to every script that greps for the line and as 'no key' to lemond (measured on a dd-written stick: 200 without an Authorization header, on the second boot too)". It creates the directory and the symlink only.os/v3/puppy/embed/etc/init.d/10lemonade:43-62has no mint at all (owner decision 2026-11-03): blank mode is the default and is logged, an emptyLEMONADE_API_KEY=is treated as none, and keyed mode requires a real key line.os/v3/puppy/embed/usr/local/bin/1bit-webapp-proxy:74-78refuses a non-loopbackOriginwith 403 before any key is attached, so the open endpoint cannot be driven from a foreign page.vm-check.sh's U3 rows are the gate:key-on-datafails on a keyless boot rather than the run passing, which is what this issue's comment established.Closing per the issue's own last comment ("the row's action is now a one-word close, not a mint"). The residual — an application-layer default of blank mode — is the owner's decision, not a defect.
docs: 1bit OS is the Puppy Linux appliance, and os/mini is a CI/VM ta…