Skip to content

os: prove the API key is enforced in 1bit-release-check, do not infer it - #569

Merged
bong-water-water-bong merged 1 commit into
mainfrom
1bit/release-check-keyless
Oct 25, 2026
Merged

bong-water-water-bong merged 1 commit into
mainfrom
1bit/release-check-keyless

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

1bit-release-check's lemonade row could false-PASS on an unprepared stick: with no LEMONADE_API_KEY in force the
keyless probe returns an empty body, and the row counted "empty body" as "refused" —

PASS  lemonade : answers on http://127.0.0.1:13305 with the API key, and without it ()

Found by pi osinstall while running the owner's live-USB gate on the candidate (~/briefs/TOSINSTALL-STATE.md, "Finding
for the release lane").

Fix: decide the row from HTTP status codes, not from whether a body came back.

keyed request keyless request row
200 + a model list 401 / 403 PASS — refused without the key
200 + a model list 200 FAIL — answers WITHOUT the key
200 + a model list 000 (no answer) / empty body / 5xx FAIL — the key is not proved to be enforced
200 but not a model list any FAIL
000 / non-200 any FAIL

The verdict is a pure function (lemonade_verdict <keyed status> <keyed body> <keyless status>), and the script gained
an --self-test that asserts seven cases — including the unprepared-stick one (200 + list with the key, empty body
without it) and the "no server at all" case. I added it to ctest as release_check_row, so CI runs it with no device
and no NPU:

$ os/mini/release-check.sh --self-test
ok   PASS answers on http://127.0.0.1:13305 with the API key, and refuses it without (status 401)
ok   PASS answers on http://127.0.0.1:13305 with the API key, and refuses it without (status 403)
ok   FAIL answers on http://127.0.0.1:13305, but also answers WITHOUT the key (status 200)
ok   FAIL the keyless probe answered 000, not a refusal: the key is not proved to be enforced
ok   FAIL no answer with the key from /data/lemonade/lemond.conf (status 000; see /tmp/lemond.log)
ok   FAIL the keyed request answered 200 but not a model list:
ok   FAIL the server answered 500 with the key (wanted 200)
release-check self-test PASS

os/mini/release-check.sh is POSIX sh (busybox in the image); the status probe uses curl -w when present and falls
back to wget -S header parsing. python3 tools/copyright.py --check rc=0. Not merged here.

🤖 Generated with Claude Code

The lemonade row passed on an unprepared stick: with no key enforced, the keyless probe returns an empty
body, and the row read "empty body" as "refused" and printed PASS with an empty bracket to show for it.

Decide the row from HTTP status codes instead of the presence of a body: 200 with a model list from the
keyed request, and 401/403 from the keyless one. Anything else on the keyless side - 200, 000 for no
answer, 5xx, an empty body - is a FAIL that says the key is not proved to be enforced, and the same goes
for a keyed 200 that is not a model list.

The verdict is a pure function (lemonade_verdict) with an --self-test that asserts the seven cases,
including the unprepared-stick one (200 + list with the key, empty body without it) and the server that is
not running at all. ctest runs it as release_check_row, so CI keeps it honest without a device.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Incorrect Key Enforcement Logic

The previous logic incorrectly inferred that a lack of response body meant the API key was enforced, which allowed unprepared sticks to false-PASS. The new implementation correctly uses HTTP status codes to determine if the key is enforced, fixing the false-PASS scenario.

if [ -z "$KEY" ]; then
    fail lemonade "no LEMONADE_API_KEY in /data/lemonade/lemond.conf: a network-facing server without a key"
else
    MODELS=$(got --header="Authorization: Bearer $KEY" "$API/api/v1/models")
    WITH=$(status --header="Authorization: Bearer $KEY" "$API/api/v1/models")
    BODY=$(got "$API/api/v1/models")
    WITHOUT=$(status "$API/api/v1/models")
    case "$(lemonade_verdict "$WITH" "$MODELS" "$WITHOUT")" in
        PASS*) pass lemonade "$(printf '%s' "$(lemonade_verdict "$WITH" "$MODELS" "$WITHOUT")" | sed 's/^PASS //')";;
        *) fail lemonade "$(printf '%s' "$(lemonade_verdict "$WITH" "$MODELS" "$WITHOUT")" | sed 's/^FAIL //')";;
    esac
    : "$BODY"
fi

@bong-water-water-bong
bong-water-water-bong merged commit a6e5ec3 into main Oct 25, 2026
8 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the 1bit/release-check-keyless branch October 25, 2026 14:46
bong-water-water-bong pushed a commit that referenced this pull request Oct 25, 2026
… comment

Rebased onto main (0d0c846) and reviewed against the current packaging, image and release check
(#556, #563, #569):

- docs/releases.md conflicted on the pins table and the NPU paragraph: the branch put the private
  repositories' names back into a public file ("gpu-kernels (private, HIP)", "npu-kernels (private,
  signed)", "npu-runtime (private)"), which main had scrubbed. Resolved keeping main's wording
  ("private kernel add-on (HIP)", "private NPU kernel set (signed)", "private NPU runtime") and the
  new shape.
- scripts/weekly.sh package_checks: the set's manifest is now derived from `rel` once, instead of
  rebuilding the path with `${f%/npu/kernels/*}` plus `cut` (which can leave a double slash). Checked
  that the derived path resolves for <pkg>/npu/kernels/<set>/<id>/layer1.elf.
- os/mini/init.sh: comment wrapped.

Not marked ready: the package stage stages nothing against the pins in this tree (see the PR comment).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant