Licencje i noty stron trzecich¶
Co ta strona twierdzi, a czego nie
Każdy komponent, który niosą dwa publikowane obrazy, jest wymieniony wraz ze swoją licencją i dowodem na nią, a każde zobowiązanie, które te licencje nakładają, jest albo spełnione w sposób nazwany na tej stronie, albo zapisane jako otwarte ustalenie z issue, które je trzyma. Nie mówi ona „wszystkie licencje są zgodne”: w chwili pisania otwarte jest jedno ustalenie i jest wypisane poniżej, a nie uśrednione. Dwa kolejne zostały przejrzane i rozstrzygnięte — komponent na AGPL, który ma własną sekcję, i obraz Redisa, który został wymieniony.
Sam AgenticOS jest na Apache-2.0 (LICENSE, NOTICE). To, co faktycznie
uruchamia wdrożenie, to ten kod plus mniej więcej pięćset pakietów stron
trzecich, dwa obrazy oparte na Debianie, garść fontów i ikon oraz te usługi
i modele, które wdrożenie podłączy. Ta strona jest przeglądem tego wszystkiego:
co jest w zakresie, jak powstaje inwentarz, o co prosi każda rodzina licencji
i jak jest to zaspokojone oraz co zrobić, gdy zmienia się zależność albo model.
Co jest w zakresie¶
| Warstwa | Skąd bierze się inwentarz | Dystrybuowane przez ten projekt? |
|---|---|---|
| Dystrybucje Pythona backendu | backend/uv.lock, rozwiązany dla Linuksa przez uv export --no-dev |
Tak, w agenticos-backend |
| Pakiety npm frontendu | produkcyjne domknięcie frontend/package.json, z frontend/bun.lock |
Tak, w agenticos-frontend |
| Obrazy bazowe i pakiety Debiana, które instaluje obraz backendu | backend/Dockerfile, frontend/Dockerfile |
Tak, jako warstwy obu obrazów |
| Fonty, glify marki, dołączone pliki danych | frontend/src/app/fonts/, NOTICE, backend/app/core/catalog/ |
Tak |
| Obrazy usług, które wdrożenie uruchamia obok tych dwóch powyżej | pliki compose | Nie: pobiera je operator |
| Wagi modeli | wybierane per wdrożenie w profilu modelu | Nie: nigdy nie są dostarczane |
| Hostowani providerzy i usługi | konfigurowani per wdrożenie poświadczeniem w vaulcie | Nie: to umowa między wdrożeniem a providerem |
Narzędzi deweloperskich i dokumentacyjnych (uv sync --dev, grupa zależności
docs, devDependencies) nie ma ani w obrazach, ani w notach. Narzędzia
budowania, które działają w etapie buildera i których nie ma w warstwie końcowej,
takie jak uv, są zapisane w licenses/components.toml jako niedystrybuowane.
Inwentarz¶
Niosą go dwa pliki, a skrypt pilnuje, żeby były uczciwe.
THIRD_PARTY_NOTICES.md
jest generowany i commitowany. Dla każdej dystrybucji w którymkolwiek z obrazów
zapisuje nazwę, wersję, wyrażenie licencyjne SPDX, URL źródła oraz dowód, z
którego odczytano licencję: nagłówek License-Expression, klasyfikator, treść
samego pliku licencji, indeks pakietów albo override zapisany przez człowieka.
Wypisuje też najpierw otwarte ustalenia, liczbę komponentów na licencję oraz
komponenty zapisane ręcznie.
licenses/policy.toml trzyma decyzje. Wpis override to licencja, którą
człowiek ustalił dla komponentu, którego metadane jej nie podają, wraz z dowodem,
który przeczytał; obowiązuje tylko dopóki metadane milczą. Wpis notices to
właściciel praw autorskich pakietu, który nie niesie pliku licencji i nie wymienia
autora. Wpis review to decyzja dla komponentu na licencji typu copyleft,
share-alike albo nieotwartej: accepted, mówiąca jak zobowiązanie jest spełnione,
albo open, wskazująca issue, które je trzyma. licenses/components.toml
zapisuje to, czego nie wie żaden lockfile: obrazy, pakiety Debiana, fonty, glify,
pliki danych i obrazy usług, każde ze statusem i swoim zobowiązaniem.
scripts/license_inventory.py czyta wszystkie trzy. make licenses regeneruje
noty; make licenses-check, uruchamiany przez job security i przez
make check, regeneruje je w pamięci i wywala się, gdy:
- zacommitowane noty różnią się od tego, do czego rozwiązują się teraz lockfile'e, w którymkolwiek komponencie, wersji, licencji albo źródle (komórka z dowodem nie jest porównywana: dwa wheele jednego wydania mogą nieść różne metadane, a ona zapisuje, skąd licencję odczytała ta konkretna maszyna);
- metadane komponentu nie wymieniają żadnej licencji i żaden override jej nie zapisuje albo override jest zapisany dla komponentu, którego metadane teraz jednak licencję wymieniają;
- pakiet nie niesie pliku licencji i albo nie wymienia autora (a żaden wpis
noticesnie zapisuje właściciela praw), albo deklaruje licencję, której tekstu nie ma podfrontend/licenses/texts/; - komponent jest na licencji ze zbioru do przeglądu i nie ma decyzji;
- decyzję podjęto o innej licencji niż ta, którą komponent niesie teraz, bo zmieniła ją aktualizacja;
- decyzja wymienia komponent, którego lockfile'e już nie rozwiązują.
Otwarte ustalenie, które jest śledzone, nie wywala checku. Linia werdyktu je
zlicza: LICENSES: REVIEWED - 518 components, 1 open finding(s).
Nieznane u skanera to pytanie, a nie zgoda
Skrypt nigdy nie zgaduje. Samo BSD w polu License nie jest rozwiązywane do
liczby klauzul na podstawie założenia; decyduje plik licencji, a jeśli i on
jest nieczytelny, check wywala się dopóty, dopóki ktoś go nie przeczyta i nie
zapisze odpowiedzi. Kolumna z dowodem w notach jest tym, co pozwala
recenzentowi odróżnić licencję zadeklarowaną od wywnioskowanej.
Inwentarz jest tym, co instaluje wdrożenie, a nie tym, co ma maszyna uruchamiająca skrypt. Markery środowiskowe są ewaluowane dla Linuksa na obu architekturach, pod które budowane są obrazy, pakiety npm zależne od platformy są zachowywane tylko wtedy, gdy budują się dla Linuksa z glibc na x64 albo arm64, a pakietowi, którego maszyna nie ma, metadane są odczytywane z PyPI albo z rejestru npm. Nieudane odpytanie jest awarią całego przebiegu.
O co proszą licencje i jak jest to zaspokojone¶
Liczby poniżej pochodzą z not w chwili pisania; aktualną wartością jest sam plik not.
| Rodzina licencji | Komponentów | Zobowiązanie | Jak jest spełnione |
|---|---|---|---|
| MIT, ISC, BSD-2-Clause, BSD-3-Clause, 0BSD, MIT-0, MIT-CMU, Unlicense | około 400 | Zachować notę o prawach autorskich i tekst licencji przy kopiach | Plik licencji każdego pakietu jedzie w obrazie, obok kodu: każde *.dist-info/ wheela w obrazie backendu, plik licencji każdego pakietu pod /app/licenses/node_modules/<name>/ w obrazie frontendu. Noty je indeksują |
| Apache-2.0 | około 90 | Tekst licencji, informacja o zmianach, każdy plik NOTICE, który niesie pakiet |
Jak wyżej; nic nie jest modyfikowane, więc nie ma zmian, o których trzeba informować |
| PSF-2.0, CNRI-Python, Zlib, CC0-1.0 | kilka | Atrybucja albo nic | Jak wyżej |
MPL-2.0 (certifi, pathspec, tqdm, część orjson) |
4 | Copyleft na poziomie plików: objęte pliki zostają na MPL, a ich źródła są dostępne | Używane bez modyfikacji; tekst licencji jedzie w obrazie; noty linkują źródła |
LGPL-3.0-or-later (psycopg2-binary, @img/sharp-libvips-linux-*) |
3 | Tekst licencji, dostępność źródeł i możliwość podmiany biblioteki | Oba to osobno instalowane binaria ładowane dynamicznie, bez modyfikacji, wymienialne przez reinstalację; źródła zalinkowane w notach. Pakiety libvips nie publikują pliku licencji, więc obraz kładzie tekst LGPL obok nich |
Artistic-1.0-Perl albo GPL-2.0-or-later (text-unidecode) |
1 | Podwójna; wzięta na Artistic License: nota i tekst | Plik licencji z wheela jedzie w obrazie |
CC-BY-4.0 (caniuse-lite) |
1 | Atrybucja i link do źródła | Wymieniony wraz ze źródłem w notach |
AGPL-3.0-only (pymupdf) |
1 | Copyleft sieciowy: obraz jest przekazywany na warunkach AGPL-3.0, a zmodyfikowane wdrożenie jest winne swoim użytkownikom zmodyfikowane źródła (art. 13) | Utrzymany świadomie, warunki nazwane: sekcja poniżej i plik COPYING wheela w obrazie |
| OFL-1.1 (Inter, Bricolage Grotesque, Geist Mono) | 3 rodziny | Tekst licencji i noty o prawach autorskich przy fontach; zakaz sprzedaży samych fontów; zakaz używania zastrzeżonych nazw dla zmodyfikowanych fontów | frontend/src/app/fonts/OFL.txt niesie wszystkie trzy noty; fonty są serwowane bez modyfikacji |
| CC0-1.0, CC-BY-4.0, MIT (glify marki) | 3 źródła | Atrybucja dla ikon Font Awesome; znaki pozostają znakami towarowymi swoich właścicieli | NOTICE wymienia źródła i stanowisko wobec znaków towarowych |
Pakietowi, który nie publikuje pliku licencji, nie da się jej skopiować. Kilka
pakietów npm w domknięciu jest właśnie takich, wśród nich
@img/sharp-libvips-linux-x64 i jego bliźniak na arm64: biblioteka na LGPL bez
kopii LGPL w tarballu. Takich jest też dziewięć wheeli, wśród nich tokenizers
i liteparse. Dla każdego pakietu npm frontend/scripts/collect-licenses.ts
zapisuje NOTICE wymieniające pakiet, jego zadeklarowaną licencję, autora
i repozytorium, oraz kopiuje tekst każdej licencji z jego wyrażenia
z frontend/licenses/texts/. Obraz backendu niesie te same teksty pod
/app/licenses/texts/, a METADATA każdego wheela i tak wymienia jego licencję
i autora. Licencja, której tekstu tam nie ma, wywala build obrazu frontendu,
a make licenses-check wywala się wcześniej, na pull requeście, dla obu obrazów.
Pakiet, który nie wymienia też autora, client-only, ma właściciela praw
zapisanego w licenses/policy.toml pod notices, wraz z dowodem, i noty go niosą.
Obrazy bazowe zasługują na własne zdanie. python:3.12-slim i oven/bun:1 to
Debian, czyli setki pakietów na warunkach GPL, LGPL, MIT i BSD. Debian trzyma
licencję każdego pakietu w /usr/share/doc/<package>/copyright wewnątrz obrazu
i publikuje odpowiadające źródła dla każdego binarium, które wysyła, i to na tym
opiera się źródłowe zobowiązanie GPL i LGPL dla redystrybuowanego obrazu. Obraz
backendu dokłada LibreOffice (MPL-2.0) i Tesseract (Apache-2.0) jako pakiety
Debiana, używane bez modyfikacji jako osobne procesy. SBOM per wydanie zaplanowany
w #1415 zapisze dokładny
zbiór pakietów każdego obrazu; zanim to nastąpi, inwentarzem tej warstwy są
Dockerfile'e i digesty obrazów bazowych.
Komponent na AGPL¶
Jeden komponent w obrazie backendu jest na copylefcie sieciowym i jest to jedyna licencja w tym zbiorze, która prosi o coś wdrożenie, a nie tylko nas.
pymupdf jest licencjonowany podwójnie: AGPL-3.0-only albo komercyjna licencja
Artifex. Jest domyślnym parserem PDF-ów i jedynym z trzech, który wyciąga osadzone
obrazy do opisania. AGPL jest jednokierunkowo kompatybilny z Apache-2.0: nasz kod
wolno z nim łączyć, a powstały obraz jest wtedy przekazywany na warunkach
AGPL-3.0.
#1602 ważył porzucenie go na rzecz LiteParse (Apache-2.0, i tak już zależność), schowanie go za świadome włączenie i utrzymanie go z nazwanymi warunkami. Jest utrzymany, a warunki są nazwane tutaj. Co to znaczy w praktyce:
- Uruchamianie niezmodyfikowanego wydania. Nic się nie należy. AgenticOS jest publiczny i na Apache-2.0, więc źródła, na które wskazywałaby oferta z art. 13, są już opublikowane.
- Modyfikowanie platformy i serwowanie jej przez sieć — przypadek, na który produkt self-hosted wprost zaprasza. Art. 13 AGPL-3.0 zobowiązuje takie wdrożenie do zaoferowania swoim użytkownikom zmodyfikowanych źródeł całości. To jest zobowiązanie, które trzeba przeczytać przed prywatnym forkiem, i to o nie zapyta przegląd bezpieczeństwa.
- Wdrożenie, które nie może przyjąć tych warunków ma trzy wyjścia: kupić
komercyjną licencję Artifex, ustawić parser PDF-ów kolekcji na
liteparsei usunąć zależność w prywatnym buildzie albo trzymać swoje zmiany nieopublikowane, ale dostępne dla własnych użytkowników, o co art. 13 tak naprawdę prosi.
Nic innego w żadnym z obrazów nie niesie copyleftu sięgającego poza własne pliki.
Otwarte ustalenia¶
Każde ma issue; każde zostanie na tej liście, i na początku not, dopóki issue się
nie zamknie i wpis w policy nie przejdzie na accepted albo komponentu nie będzie.
Jedno ustalenie zostało zamknięte przez wymianę komponentu, a nie przez jego
przyjęcie. redis:7-alpine rozwiązuje się do Redisa 7.4, a od 7.4.0 Redis jest na
RSALv2 albo SSPL-1.0, a nie BSD-3-Clause — żadna z nich nie jest zatwierdzona
przez OSI. Nic przez to nie zostało złamane: obraz pobiera operator, zamiast być
redystrybuowanym stąd, a RSALv2 pozwala uruchamiać Redisa wewnątrz własnej
aplikacji, czyli robić to, co robi ten stos. Ustalenie było takie, że domyślne
docker compose up startowało komponent nieotwarty, nic o tym nie mówiąc.
#1603 wymieniło go na
valkey/valkey:8-alpine, fork Redisa 7.2 spod Linux Foundation na BSD-3-Clause.
Valkey mówi tym samym protokołem, więc nazwa usługi, port, schemat URL-i redis://
i każde ustawienie REDIS_* pozostają bez zmian.
Runtime workbench sandboksa jest budowany na wdrożeniu z
sandbox_runtimes.json: Python, Node, LibreOffice, poppler-utils (GPL) i lista
pakietów PyPI rozwiązywana w czasie budowania. Nie jest nigdy publikowany przez
ten projekt, więc nie ma czego redystrybuować, a narzędzia na GPL działają jako
osobne procesy. Jest zapisany jako deployment-review: wdrożenie, które
zbudowany obraz jednak opublikuje, jest winne oferty źródeł do niego.
Usługi hostowane i warunki providerów¶
API providera modeli, Logfire, Tavily, Brave, Exa, LlamaParse, Mem0, Daytona, Google Drive i S3 nie są oprogramowaniem, które ten projekt dystrybuuje, i nie mają licencji w powyższym sensie. Każde z nich to umowa o świadczenie usług między wdrożeniem a providerem, zawierana wtedy, gdy administrator zapisze poświadczenie tego providera w vaulcie. Warunki, które mają znaczenie dla przeglądu, to warunki providera: co dzieje się z promptami i dokumentami, które do niego trafiają, czy trenuje on na nich, gdzie dane są przetwarzane i jak długo są trzymane.
To jest pytanie o ochronę danych, a nie o licencje, i odpowiada się na nie per wdrożenie, a nie tutaj. SDK, które rozmawiają z tymi usługami, są zwykłymi pakietami w notach: klienci Anthropic, OpenAI, Google, Mistral, Cohere, Groq i xAI są wszyscy na MIT albo Apache-2.0.
Wagi modeli¶
W żadnym z dwóch obrazów nie ma wag modeli. Wdrożenie wybiera modele w profilach modeli; model zamknięty jest osiągany przez API swojego providera na warunkach tego providera, a model z otwartymi wagami jest pobierany przez wdrożenie na licencji, którą przypiął mu wydawca. Te licencje różnią się między sobą bardziej niż licencje oprogramowania i kilka z nich nie jest otwartoźródłowych w rozumieniu definicji OSI, nawet gdy wagi da się swobodnie pobrać.
| Rodzina | Licencja, jak opublikowana wraz z wagami | Co sprawdzić przed wyborem |
|---|---|---|
| Qwen 2.5 i 3 (większość rozmiarów), Mistral 7B i Nemo, GPT-OSS, DeepSeek V3 i R1, Phi-4 | Apache-2.0 albo MIT | Tylko atrybucja. Niektóre większe rozmiary Qwen 2.5 niosą zamiast tego licencję Qwen; przeczytaj kartę modelu |
| Llama 3.x | Llama Community License | Nie jest otwartoźródłowa: polityka dopuszczalnego użycia, atrybucja „Built with Llama” i osobna licencja powyżej progu miesięcznych aktywnych użytkowników |
| Gemma | Gemma Terms of Use | Nie jest otwartoźródłowa: polityka zakazanych zastosowań, która spływa na pochodne |
| Mistral Large i niektóre wydania Codestral | Mistral Research License albo licencja komercyjna | Tylko użycie badawcze i niekomercyjne, chyba że wykupiona licencja |
Tabela jest orientacją, a nie dowodem: licencje modeli zmieniają się między wydaniami, a dokumentem, który rządzi, jest karta modelu od wydawcy. Strona jak wybrać model ma inżynierską stronę tej samej decyzji.
Zapisz decyzję tam, gdzie model jest konfigurowany
Opis profilu modelu to dobre miejsce, żeby nazwać licencję, na której wzięto wagi, i datę, kiedy to sprawdzono. Jedzie razem z profilem do każdego środowiska i do każdego agenta, który go używa.
Komponenty specyficzne dla klienta¶
Własny stos wdrożenia dołoży komponenty, których ten inwentarz nie widzi: model,
który wdrożenie hostuje samo, serwery MCP, które podłącza, zarządzaną bazę danych
albo Redisa w miejsce usług z compose, reverse proxy, dostawcę tożsamości. Każdy
potrzebuje tych samych trzech rzeczy, które mają tabele powyżej — komponent,
licencja, zobowiązanie — zanim przegląd wdrożenia będzie kompletny. Domyślne
elementy ścieżki compose są zapisane w licenses/components.toml pod
deployment-review i service image, i tam właśnie należą też własne wiersze
wdrożenia, w jego forku albo w jego repozytorium wdrożeniowym.
Jak to zostaje prawdą¶
Check działa przy każdym pull requeście w jobie security i w make check, więc
workflow utrzymaniowy to w większości check odmawiający przepuszczenia.
Zmienia się zależność. Dependabot albo make deps-upgrade rusza lockfile; job
security wywala się z THIRD_PARTY_NOTICES.md is stale. Uruchom make licenses,
przeczytaj diff, zacommituj. Jeśli diff dokłada komponent bez licencji albo taki ze
zbioru do przeglądu, check nazwie wpis w policy do napisania, a pull request
poniesie decyzję obok aktualizacji, która jej potrzebowała.
Zmienia się licencja. Komponent przejrzany na jednej licencji po aktualizacji
rozwiązuje się na inną; check mówi reviewed as X but resolves to Y - review it
again. Stara decyzja nie przeżywa sama z siebie.
Zamyka się ustalenie. Wpis w policy przechodzi z open na accepted wraz
z fulfilled_by albo komponent znika i check prosi o usunięcie wpisu. Zregeneruj
noty; ustalenie schodzi z góry pliku.
Zmienia się model albo usługa. Nic w lockfile'ach się nie rusza, więc nic się nie wywala. Do aktualizacji są tabela modeli powyżej, opis profilu modelu i własne wiersze komponentów wdrożenia, a tym, co o to prosi, jest checklista wydania.
Zmienia się obraz. Nowy tag bazowy, dołożony pakiet Debiana, nowa usługa
compose: licenses/components.toml jest edytowany w tej samej zmianie, a
scripts/docs_drift.py przypomina, gdy Dockerfile się ruszył, a ta strona nie.
Checklista wydania¶
Zanim wydanie zostanie wycięte, i jako dowód do niego dołączony:
- [ ]
make licenses-checkprzeszedł na commicie wydania; linia werdyktu jest w podsumowaniu jobasecurity - [ ]
THIRD_PARTY_NOTICES.mdna tym commicie jest notami tego wydania; oba obrazy niosą swoje pliki licencji (/app/THIRD_PARTY_NOTICES.mdoraz.venv/**/*.dist-info/i/app/licenses/texts/w obrazie backendu;/app/licenses/we frontendowym, zNOTICE,OFL.txti jednym katalogiem na pakiet) - [ ] Otwarte ustalenia w notach to te, które wymienia ta strona, każde z issue, które nadal jest tym właściwym
- [ ]
licenses/components.tomlwymienia tagi obrazów i usługi compose, których wydanie faktycznie używa - [ ] Jeśli do katalogu albo do tabeli modeli powyżej dołożono rodzinę modeli, jej licencję odczytano z aktualnej karty modelu
- [ ] Gdy będzie już istniał SBOM per wydanie z #1415: jest dołączony do wydania, a jego zbiór komponentów zgadza się z notami dla dwóch obrazów
Podsumowanie¶
- Obrazy niosą około pięciuset pakietów stron trzecich, niemal wszystkie na MIT,
Apache-2.0 albo BSD; plik licencji każdego pakietu jedzie razem z nim, a
THIRD_PARTY_NOTICES.mdjest generowanym indeksem. - Decyzje mieszkają w
licenses/policy.tomlilicenses/components.toml; check wywala się na wszystkim, co nie ma decyzji, i na decyzji podjętej o licencji, która od tego czasu się zmieniła. - Otwarte i śledzone jest jedno ustalenie: runtime sandboksa budowany na wdrożeniu. Dwa kolejne zostały rozstrzygnięte, a nie zostawione otwarte — AGPL PyMuPDF-a, przejrzany i utrzymany, z własną sekcją, oraz obraz Redisa, wymieniony na Valkey.
- Wagi modeli i hostowani providerzy są wybierani per wdrożenie na warunkach wydawcy albo providera; ta strona mówi, co sprawdzić, a wdrożenie zapisuje, co wybrało.