Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/buildcheck/tests/test_webuilicenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ def test_check_reports_a_changed_lockfile(self):
self.assertEqual(len(problems), 1)
self.assertIn("webui-licenses.py generate", problems[0])

def test_the_lockfile_digest_does_not_depend_on_the_line_ends(self):
lock = self.ui / "package-lock.json"
lf = (json.dumps(json.loads(lock.read_text(encoding="utf-8")), indent=2) + "\n").encode("utf-8")
lock.write_bytes(lf)
digest = webuilicenses.lockfile_digest(self.ui)
lock.write_bytes(lf.replace(b"\n", b"\r\n"))
self.assertEqual(webuilicenses.lockfile_digest(self.ui), digest)

def test_check_reports_a_new_import_of_a_package_the_lockfile_already_had(self):
self.generated()
(self.ui / "src/lib/more.ts").write_text("import { t } from 'testonly';\n")
Expand Down
8 changes: 7 additions & 1 deletion .github/buildcheck/webuilicenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@


def lockfile_digest(ui):
return hashlib.sha256((Path(ui) / "package-lock.json").read_bytes()).hexdigest()
"""SHA-256 of the lockfile as git stores it, with LF line ends.

A Windows checkout (`core.autocrlf`) has CRLF; hashing those bytes recorded a digest that the
Linux checkout of the same commit in CI never matched, and the release run of v6.0.0
(40238595195) failed on it.
"""
return hashlib.sha256((Path(ui) / "package-lock.json").read_bytes().replace(b"\r\n", b"\n")).hexdigest()


def imports(ui):
Expand Down
7 changes: 3 additions & 4 deletions .github/webui-licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""Generate or check the license texts of the npm packages in the embedded WebUI.

webui-licenses.py generate <llama.cpp>/tools/ui llama/legal/natives/webui-npm
webui-licenses.py check <llama.cpp>/tools/ui llama/legal/natives/webui-npm [--warn-only]
webui-licenses.py check <llama.cpp>/tools/ui llama/legal/natives/webui-npm
"""

import argparse
Expand All @@ -19,18 +19,17 @@ def main():
parser.add_argument("command", choices=("generate", "check"))
parser.add_argument("ui", help="llama.cpp's tools/ui directory at the pinned commit")
parser.add_argument("out", help="llama/legal/natives/webui-npm")
parser.add_argument("--warn-only", action="store_true", help="report a stale list as a warning")
args = parser.parse_args()
if args.command == "generate":
packages = generate(args.ui, args.out)
print(f"{len(packages)} packages written to {args.out}")
return 0
problems = check(args.ui, args.out)
for problem in problems:
print(f"::{'warning' if args.warn_only else 'error'}::{problem}")
print(f"::error::{problem}")
if not problems:
print("WebUI license texts match tools/ui/package-lock.json")
return 1 if problems and not args.warn_only else 0
return 1 if problems else 0


if __name__ == "__main__":
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -615,11 +615,12 @@ jobs:
cache-dependency-path: llamacpp-ui/tools/ui/package-lock.json
# The bundle strips every legal comment, so the texts of its npm packages travel in
# llama/legal/natives/webui-npm/ (every natives jar carries them). They were generated from one
# package-lock.json; a llama.cpp bump that changes it must regenerate them before a release.
# package-lock.json; a llama.cpp bump that changes it regenerates them in the same pull request.
# Fails on every run: it only warned outside a release tag until the release run of v6.0.0
# (40238595195) failed on it hours after the cause. webui-licenses.yml runs the same check in
# every pull request and push, where Publish is usually cancelled at the start gate.
- name: Check the WebUI license texts against this package-lock.json
run: >
python3 .github/webui-licenses.py check llamacpp-ui/tools/ui llama/legal/natives/webui-npm
${{ !startsWith(github.ref, 'refs/tags/v') && '--warn-only' || '' }}
run: python3 .github/webui-licenses.py check llamacpp-ui/tools/ui llama/legal/natives/webui-npm
- name: Build WebUI (Svelte/Vite)
working-directory: llamacpp-ui/tools/ui
env:
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/webui-licenses.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

name: WebUI license texts
on:
push:
pull_request:
workflow_dispatch:

# The license texts of the WebUI's npm packages (llama/legal/natives/webui-npm/, in every natives
# jar) must have been generated from the package-lock.json of the pinned llama.cpp. publish.yml's
# build-webui checks the same, but the Publish runs of pull requests and pushes are usually
# cancelled at the start gate, so a stale list surfaced only in the release run of v6.0.0
# (40238595195) -- hours after the cause, the llama.cpp bump that changed the lockfile. This job
# needs no npm and no build: a sparse checkout and the stdlib-only check, under a minute.
permissions:
contents: read

jobs:
webui-licenses:
name: WebUI license texts match the pinned package-lock.json
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Resolve the pinned llama.cpp commit from CMakeLists.txt
id: tag
run: |
# The rule of publish.yml's build-webui: JLLAMA_GIT_TAG is the number, JLLAMA_GIT_COMMIT
# the commit it names; the checkout takes the commit when it is set.
TAG=$(grep -oE '^set\(JLLAMA_GIT_TAG[[:space:]]+b[0-9]+\)' llama/CMakeLists.txt | grep -oE 'b[0-9]+' | head -1)
if [ -z "$TAG" ]; then
echo "could not resolve llama.cpp JLLAMA_GIT_TAG (b<nnnn>) from CMakeLists.txt" >&2
exit 1
fi
COMMIT=$(grep -oE '^set\(JLLAMA_GIT_COMMIT[[:space:]]+"[0-9a-f]{40}"\)' llama/CMakeLists.txt | grep -oE '[0-9a-f]{40}' | head -1 || true)
echo "ref=${COMMIT:-$TAG}" >> "$GITHUB_OUTPUT"
echo "Pinned llama.cpp: $TAG${COMMIT:+ (commit $COMMIT)}"
- name: Checkout llama.cpp tools/ui at the pinned commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
repository: ggml-org/llama.cpp
ref: ${{ steps.tag.outputs.ref }}
path: llamacpp-ui
sparse-checkout: tools/ui
sparse-checkout-cone-mode: true
- name: Check the WebUI license texts against this package-lock.json
run: python3 .github/webui-licenses.py check llamacpp-ui/tools/ui llama/legal/natives/webui-npm
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ rejects anything else loudly.
| `patches.py` | `check-patches.py` (`code-style`) | every hunk of `llama/patches/*.patch` declares exactly the lines it carries -- the half `git apply --check` does not see (see "Local llama.cpp source patches"); and `docs/patches.md` is what `check-patches.py --render` generates from the patch headers (a stale page fails) |
| `nativedeps.py` | `verify-native-deps.py` (`package`, `package-android-aar`) | dependency allowlists, 16 KB Android alignment |
| `hipoffload.py` | `verify-hip-offload-compressed.py` (the two ROCm jobs) | no uncompressed GPU code bundle |
| `webuilicenses.py` | `webui-licenses.py` (`build-webui`) | the WebUI's npm license texts cover the pinned lockfile and its imports |
| `webuilicenses.py` | `webui-licenses.py` (`build-webui`, and `webui-licenses.yml` on every pull request and push) | the WebUI's npm license texts cover the pinned lockfile (digest over LF line ends) and its imports; it fails every run -- until the release run of v6.0.0 it only warned outside a release tag, and a stale list surfaced there first |

| Action (bernardladenthin/actions) | Job here | What it checks or does |
|---|---|---|
Expand Down
6 changes: 4 additions & 2 deletions docs/upgrade/llama-cpp-version-bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ for each:
## License texts on a bump

`llama/legal/natives/` holds the license texts of everything compiled into the natives, taken from
the pinned commit. On a bump: regenerate the WebUI's npm texts (`build-webui` warns on a changed
`tools/ui/package-lock.json` and fails on a release tag),
the pinned commit. On a bump: regenerate the WebUI's npm texts whenever
`tools/ui/package-lock.json` changed (the `WebUI license texts` workflow fails the pull request
otherwise, and so does `build-webui`; the digest is taken over LF line ends, so a Windows checkout
records the same one as CI),

```bash
python3 .github/webui-licenses.py generate <llama.cpp at the new pin>/tools/ui llama/legal/natives/webui-npm
Expand Down
2 changes: 1 addition & 1 deletion llama/legal/natives/webui-npm/LOCKFILE.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ca12fa34cf60965e260b4f00d6dfada6de1e6d683a18ef097f7a24c21f1aa2d0 tools/ui/package-lock.json
d4f8f7d8b556120c93dd6225e6c7fc3f4a130a6b29b37b5289ec8a585c236a2c tools/ui/package-lock.json
Loading