PEP 752 – Implizite Namespaces für Paket-Repositories
- Autor:
- Ofek Lev <ofekmeister at gmail.com>, Jarek Potiuk <potiuk at apache.org>
- Sponsor:
- Barry Warsaw <barry at python.org>
- PEP-Delegate:
- Dustin Ingram <di at python.org>
- Discussions-To:
- Discourse thread
- Status:
- Entwurf
- Typ:
- Standards Track
- Thema:
- Packaging
- Erstellt:
- 13. August 2024
- Post-History:
- 18. August 2024, 07. September 2024
Zusammenfassung
Diese PEP spezifiziert eine Methode, mit der Organisationen Paketnamenspräfixe für zukünftige Uploads reservieren können.
„Namespaces sind eine verdammt gute Idee – lasst uns mehr davon machen!“ - PEP 20
Motivation
Das aktuelle Ökosystem bietet keine Möglichkeit für Projekte mit vielen Paketen, ein verifiziertes Eigentumsmuster zu signalisieren. Solche Projekte fallen in zwei Kategorien.
Die erste Kategorie sind Projekte [1], die die volle Kontrolle über ihren Namespace wünschen. Einige Beispiele
- Große Cloud-Anbieter wie Amazon, Google und Microsoft verwenden ein gemeinsames Präfix für die jeweiligen Pakete ihrer Funktionen [3]. Zum Beispiel sind die meisten Google-Pakete mit
google-cloud-präfixiert, z. B.google-cloud-computefür die Nutzung virtueller Maschinen. - OpenTelemetry ist ein offener Standard für Beobachtbarkeit mit offiziellen Paketen für die Kern-APIs und das SDK mit Contrib-Paketen zur Sammlung von Daten aus verschiedenen Quellen. Alle Pakete sind mit
opentelemetry-präfixiert, mit Unterpräfixen in der Formopentelemetry-<komponente>-<name>-. Die Contrib-Pakete befinden sich in einem zentralen Repository und nur sie haben die Möglichkeit zur Veröffentlichung. - Apache Airflow ist eine Plattform zur programmatischen Erstellung, Planung und Überwachung von Workflows. Es gibt Provider, wobei jedes Provider-Paket mit
apache-airflow-providers-präfixiert ist.
Die zweite Kategorie sind Projekte [2], die ihren Namespace teilen möchten, sodass einige Pakete offiziell gepflegt werden und Drittentwickler ermutigt werden, durch Veröffentlichung eigener Pakete teilzunehmen. Einige Beispiele
- Project Jupyter widmet sich der Entwicklung von Werkzeugen für die gemeinsame Nutzung interaktiver Dokumente. Sie unterstützen Erweiterungen, die in den meisten Fällen (und in allen Fällen für offiziell gepflegte Erweiterungen) mit
jupyter-präfixiert sind. - Django ist eines der am weitesten verbreiteten Webframeworks. Sie haben das Konzept der wiederverwendbaren Apps, die häufig über Drittanbieter-Pakete installiert werden, die eine Teilmenge von Funktionalitäten implementieren, um Django-basierte Websites zu erweitern. Diese Pakete sind per Konvention mit
django-oderdj-präfixiert.
Solche Projekte sind besonders anfällig für Name-Squatting-Angriffe, die letztendlich zu Dependency Confusion führen können.
Nehmen wir zum Beispiel an, ein neues Produkt wird veröffentlicht, für das Monitoring wertvoll wäre. Es wäre vernünftig anzunehmen, dass Datadog es irgendwann als offizielle Integration unterstützen würde. Es dauert nicht wenig Zeit, eine solche Integration zu liefern, aufgrund der Roadmap-Priorisierung und der benötigten Implementierungszeit. Es wäre unmöglich, jeden potenziellen Paketnamen zu reservieren, so dass ein Angreifer in der Zwischenzeit ein Paket erstellen könnte, das legitim erscheint und bösartigen Code zur Laufzeit ausführt. Nicht nur, dass Benutzer solche Pakete eher installieren, sondern das tut auch der Wahrnehmung des gesamten Projekts Abbruch.
Obwohl PEP 708 versucht, diesen Angriffsvektor anzugehen, befasst er sich speziell mit dem Fall mehrerer Repositories, die während der Abhängigkeitsauflösung berücksichtigt werden, und bietet keinen Schutz für die oben genannten Anwendungsfälle.
Namespacing würde auch die Häufigkeit von Typosquatting drastisch reduzieren, da Tippfehler im Präfix selbst liegen müssten, das normalisiert ist und wahrscheinlich eine kurze, bekannte Kennung wie aws- ist. In den letzten Jahren ist Typosquatting zu einem beliebten Angriffsvektor geworden [4].
Der aktuelle Schutz gegen Typosquatting, der von PyPI verwendet wird, besteht darin, ähnliche Zeichen zu normalisieren, was jedoch für diese Anwendungsfälle nicht ausreicht.
Ein weiteres Problem, das Namespacing lösen würde, ist die Wahl neuer Namen für Pakete, die den vereinbarten Benennungsmustern folgen. Oft (das ist zum Beispiel bei Apache Airflow der Fall) gibt es öffentliche Diskussionen, die der Entscheidung, ein neues Paket zu erstellen, vorausgehen. Die Entscheidung basiert auf dem vereinbarten Namen und folgt dem Muster bestehender Pakete. Wenn während der Diskussion mehr Paketnamen in Betracht gezogen werden, müssen alle Namen über eine PyPI-Schnittstelle reserviert werden, bevor die Diskussion öffentlich ist, andernfalls können die Namen von anderen Benutzern übernommen werden. Dies ist in der Vergangenheit geschehen, wie in der zugehörigen Diskussion erklärt wird.
Begründung
Andere Paket-Ökosysteme haben dieses Problem im Allgemeinen durch zwei Ansätze gelöst: entweder durch Minimierung oder durch Maximierung der Abwärtskompatibilität.
- NPM hat das Konzept der eingeschränkten Pakete (scoped packages), die eingeführt wurden, hauptsächlich um dem Mangel an verfügbaren guten Paketnamen (ob real oder wahrgenommen) entgegenzuwirken. Wenn sich ein Benutzer oder eine Organisation anmeldet, erhält sie einen Bereich (scope), der ihrem Namen entspricht. Zum Beispiel ist das Paket für die Nutzung von Google Cloud Storage
@google-cloud/storage, wobei@google-cloud/der Bereich ist. Normale Benutzerkonten (nicht-Organisation) können unbeschränkte Pakete für die öffentliche Nutzung veröffentlichen. Dieser Ansatz hat die geringste Abwärtskompatibilität, da jeder Installer und jedes Werkzeug angepasst werden muss, um Bereiche zu berücksichtigen. - NuGet hat das Konzept der Reservierung von Paket-ID-Präfixen, die eingeführt wurde, hauptsächlich um Benutzern, die wissen möchten, woher ein Paket stammt, entgegenzukommen. Ein Paketnamenspräfix kann für die Verwendung durch einen oder mehrere Besitzer reserviert werden. Jedes reservierte Paket hat eine spezielle Anzeige auf seiner Seite, um dies zu kommunizieren. Nach der Reservierung schlägt jeder Upload mit einem reservierten Präfix fehl, wenn der Benutzer kein Besitzer des Präfixes ist. Bestehende Pakete mit einem reservierten Präfix können weiterhin wie gewohnt veröffentlicht werden. Dieser Ansatz hat die höchste Abwärtskompatibilität, da nur Änderungen an Indizes wie PyPI erforderlich sind und Installer nicht geändert werden müssen.
Diese PEP spezifiziert den NuGet-Ansatz der autorisierten Reservierung über einen flachen Namespace. Jede Lösung, die neue Paketsyntax erfordert, muss auf dem bestehenden flachen Namespace aufbauen, und daher wären implizite Namespaces, die über einen Reservierungsmechanismus erworben werden, eine Voraussetzung für solche expliziten Namespaces.
Obwohl bestehende Pakete, die einem reservierten Namespace entsprechen, unberührt bleiben, würde die Verhinderung zukünftiger nicht autorisierter Uploads und die strategische Anwendung von PEP 541-Entfernungsanfragen für bösartige Fälle die Risiken für Benutzer auf ein vernachlässigbares Niveau reduzieren.
Terminologie
Die Schlüsselwörter „MUSS“, „DARF NICHT“, „ERFORDERLICH“, „SOLL“, „SOLL NICHT“, „EMPFOHLEN“, „KANN“ und „OPTIONAL“ in diesem Dokument sind wie in RFC 2119 beschrieben zu interpretieren.
- Organisation
- Organisationen sind Entitäten, die Projekte besitzen und verschiedene Benutzer mit ihnen assoziiert haben.
- Berechtigung
- Eine Berechtigung ist eine Reservierung eines Namespaces für ein Paket-Repository.
- Offener Namespace
- Ein offener Namespace erlaubt Uploads von jedem Projekteigentümer.
- Eingeschränkter Namespace
- Ein eingeschränkter Namespace erlaubt nur Uploads von einem Eigentümer des Namespaces.
- Eltern-Namespace
- Der Elternteil eines Namespaces bezieht sich auf den Namespace ohne die nachgestellte, durch Bindestrich getrennte Komponente, z. B. der Elternteil von
foo-baristfoo. - Kind-Namespace
- Das Kind eines Namespaces bezieht sich auf den Namespace mit zusätzlichen nachgestellten, durch Bindestrich getrennten Komponenten, z. B.
foo-barist ein gültiges Kind vonfoo, ebenso wiefoo-bar-baz.
Spezifikation
Organisationen
Jedes Paket-Repository, das die Erstellung von Projekten erlaubt (z. B. keine Spiegelungen), KANN das Konzept von Organisationen anbieten [6]. Organisationen sind Entitäten, die Projekte besitzen und verschiedene Benutzer mit ihnen assoziiert haben.
Organisationen KÖNNEN einen oder mehrere Namespaces reservieren. Solche Reservierungen verleihen weder Eigentum noch gewähren sie bestehenden Projekten besondere Privilegien.
Benennung
Ein Namespace MUSS ein gültiger Projektname sein und intern normalisiert werden, z. B. wird foo.bar zu foo-bar.
Semantik
Eine Namespace-Berechtigung überträgt das Eigentum über Folgendes
- Ein Projekt, das dem Namespace selbst entspricht, wie das Platzhalterpaket microsoft.
- Projekte, die mit dem Namespace beginnen, gefolgt von einem Bindestrich. Zum Beispiel entspricht der Namespace
foodem normalisierten Projektnamenfoo-bar, aber nicht dem Projektnamenfoobar.
Die Paketnamensprüfung erfolgt auf dem normalisierten Namespace.
Namespaces sind pro Paket-Repository und dürfen NICHT zwischen Repositories geteilt werden. Wenn beispielsweise PyPI einen Namespace microsoft hat, der dem Unternehmen Microsoft gehört, vermitteln Pakete, die mit microsoft- beginnen und von anderen Nicht-PyPI-Mirror-Repositories stammen, nicht das gleiche Vertrauensniveau.
Berechtigungen dürfen sich NICHT überschneiden. Wenn es beispielsweise eine bestehende Berechtigung für foo-bar gibt, wäre eine neue Berechtigung für foo verboten. Eine Überschneidung wird durch den Vergleich des normalisierten vorgeschlagenen Namespaces mit dem normalisierten Namespace jeder bestehenden Stammberechtigung bestimmt. Jeder Vergleich muss am Ende des vorgeschlagenen und des bestehenden Namespaces einen Bindestrich anhängen. Eine Überschneidung wird erkannt, wenn ein bestehender Namespace mit dem vorgeschlagenen Namespace beginnt.
Uploads
Wenn der Name eines hochgeladenen Pakets mit einem reservierten Namespace übereinstimmt und eines der folgenden Kriterien zutrifft
- Das Projekt existiert noch nicht.
- Das Projekt gehört nicht zu einer Organisation mit einer aktiven Berechtigung für den Namespace.
Dann MUSS der Upload mit einem HTTP-Statuscode 403 fehlschlagen.
Offene Namespaces
Der Inhaber einer Berechtigung kann anderen die Möglichkeit geben, neue Projekte mit dem zugehörigen Namespace zu veröffentlichen. Dies MUSS Uploads für neue Projekte, die dem Namespace entsprechen, von jedem Benutzer zulassen.
Es ist möglich, dass der Inhaber eines Namespaces ihn sowohl öffnet als auch anderen Organisationen die Nutzung der Berechtigung erlaubt. In diesem Fall haben die autorisierten Organisationen keine besonderen Berechtigungen und sind gleichwertig mit einer offenen Berechtigung ohne Eigentümerschaft.
Repository-Metadaten
Die Version der JSON-API wird von 1.2 auf 1.3 erhöht. Die folgenden API-Änderungen MÜSSEN von Repositories implementiert werden, die diese PEP unterstützen. Repositories, die diese PEP nicht unterstützen, DÜRFEN diese Änderungen NICHT implementieren, damit Verbraucher der API feststellen können, ob das Repository diese PEP unterstützt.
Projektdetails
Die Antwort für Projektdetails wird wie folgt modifiziert.
Der Schlüssel namespace MUSS null sein, wenn das Projekt keinem aktiven Namespace-Berechtigung entspricht. Wenn das Projekt einer Namespace-Berechtigung entspricht, MUSS der Wert ein Mapping mit den folgenden Schlüsseln sein
prefix: Dies ist der zugehörige normalisierte Namespace, z. B.foo-bar. Wenn der Eigentümer des Projekts mehrere passende Berechtigungen besitzt, MUSS dies der Namespace mit der höchsten Zeichenanzahl sein. Wenn der Projektname beispielsweise sowohlfoo-barals auchfoo-bar-bazentspricht, dann wäre dieser Schlüssel letzterer.authorized: Dies ist ein Boolean und ist true, wenn der Projekteigentümer eine Organisation ist und einer der aktuellen Inhaber der Berechtigung ist. Dies ist nützlich für Tools, die eine Unterscheidung zwischen offiziellen und Community-Paketen treffen möchten.open: Dies ist ein Boolean, der angibt, ob der Namespace offen ist.
Namespace-Details
Das Format dieser URL ist /namespace/<namespace>, wobei <namespace> der normalisierte Namespace ist. Zum Beispiel wäre die URL für den Namespace foo.bar /namespace/foo-bar.
Die Antwort ist ein Mapping mit den folgenden Schlüsseln
prefix: Dies ist die normalisierte Version des Namespaces, z. B.foo-bar.owner: Dies ist die Organisation, die für den Namespace verantwortlich ist.open: Dies ist ein Boolean, der angibt, ob der Namespace offen ist.parent: Dies ist der Eltern-Namespace, falls vorhanden. Wenn der Namespace beispielsweisefoo-barlautet und eine aktive Berechtigung fürfoobesteht, wäre dies"foo". Wenn kein Elternteil vorhanden ist, ist dieser Schlüsselnull.children: Dies ist ein Array von allen Kind-Namespaces. Wenn der Namespace beispielsweisefoolautet und aktive Berechtigungen fürfoo-barundfoo-bar-bazbestehen, wäre dies["foo-bar", "foo-bar-baz"].
Entfernung von Berechtigungen
Wenn ein reservierter Namespace nicht mehr beansprucht wird, MÜSSEN Repositories den Schlüssel namespace in der API auf null setzen.
Namespaces, die zuvor beansprucht, aber nun nicht mehr aktiv sind, SOLLTEN wieder von jeder Organisation beanspruchbar sein.
Community-Akzeptanz
Vertreter der folgenden Organisationen haben Unterstützung für diese PEP zum Ausdruck gebracht (mit Link zur Diskussion)
- Apache Airflow (erweitert)
- pytest
- Typeshed
- Project Jupyter (erweitert)
- Microsoft
- Sentry (zugunsten des NuGet-Ansatzes gegenüber anderen, aber nicht negativ von der aktuellen fehlenden Funktionalität betroffen)
- DataDog
Abwärtskompatibilität
Es gibt keine grundlegenden Bedenken, da immer noch ein flacher Namespace besteht und Installer keine Anpassungen benötigen. Zusätzlich haben viele Projekte bereits beschlossen, einen gemeinsamen Zweck mit einem Präfix zu signalisieren, wie es typeshed getan hat.
Sicherheitsimplikationen
- Es besteht die Möglichkeit, aufbauend auf PEP 740 und PEP 480 aufzubauen, so dass man kryptografisch beweisen könnte, dass eine bestimmte Version von einem Inhaber des zugehörigen Namespaces stammt. Diese PEP beschreibt nicht, wie dies geschehen wird, abgesehen davon, dass für die Zukunft Arbeit geplant ist.
Wie man das lehrt
Für Konsumenten von Paketen werden wir dokumentieren, wie Metadaten in der API bereitgestellt werden und möglicherweise in Zukunft Tools hervorheben, die Namespaces zur Bereitstellung zusätzlicher Sicherheitsgarantien während der Installation nutzen.
Referenzimplementierung
Eine vollständige Referenzimplementierung dieser PEP ist in PR #17691 verfügbar.
Abgelehnte Ideen
Zuteilung von Reservierungen an Benutzer
Da Paket-Repositories einen flachen Namespace haben, wäre es unzumutbar, jedem Benutzer die Reservierung eines Namespaces zu gestatten, nicht nur wegen der Konkurrenz um eine endliche Ressource, sondern auch, weil kein Repository genügend menschliche Betreiber hat, um die Prüfung einer beliebigen Anzahl von Benutzern zu verwalten.
Assoziation von Namespaces auf Artefakt-Ebene
Eine frühere Version dieser PEP schlug vor, Metadaten mit einzelnen Artefakten zum Zeitpunkt der Veröffentlichung zu verknüpfen. Dies wurde abgelehnt, da es zu Verwirrung bei Benutzern führen könnte, die erwarten würden, dass die Namespace-Autorisierungsgarantie auf Projektebene basierend auf aktuellen Berechtigungen besteht und nicht auf dem Zeitpunkt, zu dem eine bestimmte Version veröffentlicht wurde.
Organisation-Scoping
Die primäre Motivation für diese PEP ist die Reduzierung von Dependency-Confusion-Angriffen und NPM-ähnlichem Scoping. Mit einer Erlaubnis des Legacy-Flach-Namespaces würde das Risiko steigen. Wenn die Dokumentation einen Benutzer anweist, bar im Namespace foo zu installieren, muss der Benutzer darauf achten, @foo/bar und nicht foo-bar zu installieren, oder umgekehrt. Das Python-Paket-Ökosystem verfügt über Normalisierungsregeln für Namen, um die Einfachheit der Kommunikation zu maximieren, und dies wäre eine Rückschritt.
Die Laufzeitumgebung von Python ist auch nicht förderlich für Scoping. Während mehrere Versionen desselben JavaScript-Pakets koexistieren können, erlaubt Python nur einen einzigen globalen Namespace. Abgesehen von größeren Änderungen an der Sprache selbst ist dies nahezu unmöglich zu ändern. Darüber hinaus haben sich Benutzer daran gewöhnt, dass der Paketname normalerweise derselbe ist wie das, was sie importieren würden, und die Abschaffung des flachen Namespaces würde diese Konvention abschaffen.
Scoping wäre besonders betroffen von Organisationsänderungen, die im Laufe der Zeit zwangsläufig auftreten werden. Eine Organisation kann ihren Namen aufgrund interner Umstrukturierungen, einer Übernahme oder aus anderen Gründen ändern. Jedes Mal, wenn dies geschieht, wären alle von ihnen besessenen Projekte effektiv umbenannt, was zu unnötiger Verwirrung bei den Benutzern führen würde, und das häufig.
Schließlich wäre die Störung der Community massiv, da sie eine Aktualisierung von jedem Paketmanager, Sicherheitsscanner, IDE usw. erfordern würde. Neue Pakete, die mit Scoping veröffentlicht werden, wären mit älteren Tools inkompatibel und würden zu Verwirrung bei den Benutzern sowie zu Frustration bei den Wartungsleuten, die solche Beschwerden bearbeiten müssen, führen.
Förderung dedizierter Paket-Repositories
Entscheidend ist, dass dies eine Belastung für Projekte darstellt, ihre eigene Infrastruktur zu warten. Dies ist eine unrealistische Erwartung für die überwiegende Mehrheit der Unternehmen und ein absoluter Dealbreaker für Community-Projekte.
Dies hilft in den meisten Fällen nicht, da das Standardverhalten der meisten Paketmanager die Verwendung von PyPI ist, sodass Benutzer, die versuchen, eine einfache pip install-Anweisung auszuführen, bereits anfällig für bösartige Pakete wären.
In dieser theoretischen Zukunft muss jedes Projekt dokumentieren, wie sein Repository zur Abhängigkeitsauflösung hinzugefügt wird, was sich für jeden Paketmanager unterscheiden würde. Wenige Paketmanager können spezifische Abhängigkeiten aus spezifischen Repositories herunterladen und würden Benutzer dazu zwingen, in den meisten Fällen eine wortreiche Konfiguration zu verwenden.
Diejenigen, die dies nicht unterstützen, würden stattdessen ein bestimmtes Paket anhand einer geordneten Enumeration von Repositories finden, was zu Dependency Confusion führen würde. Angenommen, ein Benutzer möchte zwei Pakete aus zwei benutzerdefinierten Repositories X und Y. Wenn jedes Repository beide Pakete enthält, aber eines auf X bösartig ist und das andere auf Y, dann könnte der Benutzer seine Anforderungen nicht erfüllen, ohne auf ein bösartiges Paket zu stoßen.
Ausschließliche Abhängigkeit von Herkunftsangaben
Die Idee hier [5] wäre, eine allgemeine Methode für Clients zu entwerfen, um Herkunftsangaben zu machen und bestimmte Eigenschaften von Abhängigkeiten zu überprüfen, jeweils mit benutzerdefinierter Syntax. Einige Beispiele
- Das Paket wurde von einer bestimmten Organisation oder einem bestimmten Benutzernamen hochgeladen, z. B.
pip install "azure-loganalytics from microsoft" - Das Paket wurde von einem Inhaber einer bestimmten Domain-Namen hochgeladen, z. B.
pip install "google-cloud-compute from cloud.google.com" - Das Paket wurde von einem Benutzer mit einer bestimmten E-Mail-Adresse hochgeladen, z. B.
pip install "aws-cdk-lib from contact@amazon.com" - Das Paket, das einem Namespace entspricht, wurde von einer autorisierten Partei hochgeladen (diese PEP)
Ein grundlegender Nachteil ist, dass es nicht gut mit mehreren Repositories zusammenarbeitet. Wenn ein Benutzer beispielsweise das Paket azure-loganalytics möchte und sicherstellen möchte, dass es von der Organisation namens microsoft stammt. Wenn der Organisationsname von Microsoft auf PyPI microsoft lautet, könnte ein Paketmanager, der standardmäßig PyPI verwendet, azure-loganalytics from microsoft akzeptieren. Wenn jedoch mehrere Repositories zur Abhängigkeitsauflösung verwendet werden, müsste der Benutzer das Repository als Teil der Definition angeben, was aus den Gründen, die im dedizierten Abschnitt über die Bestätigung von Paketbesitzer-Namen erläutert werden, unrealistisch ist.
Eine weitere allgemeine Schwäche dieses Ansatzes ist, dass ein Benutzer, der eine einfache pip install-Anweisung ohne spezielle Syntax ausführen möchte, was der häufigste Fall ist, bereits anfällig für bösartige Pakete wäre. Um dies zu überwinden, müsste es einen standardmäßigen Vertrauensmechanismus geben, der in allen Fällen bestimmte UX- oder Resolver-Logiken auf jedes Tool anwendet.
Zum Beispiel könnten Paketmanager so geändert werden, dass der Benutzer bei der ersten Installation eines Pakets eine Bestätigungsaufforderung erhält, die die Herkunftsdetails anzeigt. Dies wäre sehr verwirrend und laut, insbesondere für neue Benutzer, und wäre eine rückwärts inkompatible UX-Änderung für bestehende Benutzer. Viele Installationsmethoden würden für dieses Szenario nicht funktionieren, wie z. B. die Ausführung in CI oder die Installation aus einer Anforderungen-Datei, bei der der Benutzer potenziell Hunderte von Aufforderungen erhalten würde.
Eine Lösung, um dies für Benutzer weniger störend zu machen, wäre die manuelle Pflege einer Liste vertrauenswürdiger Details (Organisations-/Benutzernamen, Domain-Namen, E-Mail-Adressen usw.). Diese könnten von Paketen bereitgestellt werden, die Entry Points anbieten, die Paketmanager erkennen lernen und die in Unternehmensumgebungen standardmäßig installiert werden könnten. Dies hat den großen Nachteil, keine automatischen Garantien zu bieten, was die Nützlichkeit für den durchschnittlichen Benutzer einschränkt, der eher betroffen ist.
Es gibt zwei Ideen, die verwendet werden könnten, um einen automatischen Schutz zu bieten, der auf PEP 740-Attestierungen oder einem neuen Mechanismus zur Nutzung von Drittanbieter-APIs, die die Metadaten hosten, basieren könnte.
Erstens könnte jedes Repository einen Dienst anbieten, der den Besitzer eines Pakets nach beliebigen Kriterien verifiziert. Nach der Verifizierung würde das Repository die Details zu einem dedizierten Paket hinzufügen, das standardmäßig installiert würde.
Dies würde eine dedizierte Wartung erfordern, die für die meisten Repositories unrealistisch ist, selbst für PyPI derzeit. Es ist unklar, wie Community-Projekte ohne Ressourcen für so etwas wie einen Domain-Namen unterstützt würden. Entscheidend ist, dass diese Lösung im Falle mehrerer Repositories zu zusätzlicher Verwirrung bei den Benutzern führen würde, da jedes seine eigenen Verifizierungsprozesse, Attestierungskriterien und Standardpakete mit den verifizierten Details haben könnte. Es wäre schwierig, die Akzeptanz in der Community zu erreichen, damit jeder Paketmanager das gewählte Verifizierungspaket jedes Repositorys kennt und dieses standardmäßig vor der Abhängigkeitsauflösung installiert.
Sollten digitale Bescheinigungen zum bevorzugten Mechanismus werden, liegt ein Nachteil darin, dass deren Implementierung in benutzerdefinierten Paket-Repositories mit erheblichem Aufwand verbunden wäre. Im Fall von PyPI kosteten die Vorarbeiten für Trusted Publishing und dann die PEP 740-Implementierung selbst die Arbeit eines Vollzeit-Ingenieurs über ein Jahr, deren Zeit von einem Unternehmenssponsor bezahlt wurde. Andere Organisationen werden unwahrscheinlich ähnliche Arbeiten durchführen, da einfachere Mechanismen reproduzierbare Builds ermöglichen. Wenn alles intern verwaltet wird, sind Bescheinigungen auch nicht sehr nützlich. Community-Projekte werden unwahrscheinlich diese Anstrengung auf sich nehmen, da ihnen wahrscheinlich die Ressourcen fehlen, die notwendige Infrastruktur selbst zu pflegen, und zudem gibt es erhebliche Nachteile bei der Förderung dedizierter Paket-Repositories.
Die andere Idee wäre, Herkunftsangaben extern zu hosten und mehr Logik clientseitig zu verschieben. Eine mögliche Implementierung könnte die Angabe einer Herkunfts-API sein, die unter einem bestimmten relativen Pfad wie /provenance gehostet werden könnte. Projekte in jedem Repository könnten dann so konfiguriert werden, dass sie auf eine bestimmte Domäne verweisen, und diese Informationen würden während der Installation an die Clients weitergegeben werden.
Obwohl dieser verteilte Ansatz eine geringere Infrastrukturbelastung für Repositories bedeutet, birgt er ein Sicherheitsrisiko. Wenn eine externe Herkunfts-API kompromittiert wird, könnte dies zur Installation bösartiger Pakete führen. Wenn eine externe API ausfällt, könnte dies dazu führen, dass die Paketinstallation fehlschlägt, oder Paketmanager geben möglicherweise nur Warnungen aus, in welchem Fall es keinen Sicherheitsvorteil gibt.
Darüber hinaus benachteiligt dies Community-Projekte, die nicht über die Ressourcen zur Wartung einer solchen API verfügen. Sie könnten kostenlose Hosting-Lösungen nutzen, wie es viele für Dokumentationen tun, aber sie besitzen technisch gesehen nicht die Infrastruktur und wären kompromittiert, sollten die großzügigen Angebote eingeschränkt werden.
Schließlich implizieren beide theoretischen Ansätze, obwohl sie noch nicht vorschreibend sind, Aussagen auf Artefakt-Ebene, was bereits eine abgelehnte Idee war.
Bestätigung von Paketbesitzer-Namen
Hierbei geht es darum zu bescheinigen, dass das Paket von einer bestimmten Organisation oder einem bestimmten Benutzernamen stammt. Es ähnelt stark der Idee des Organisation-Scoping, außer dass ein flacher Namespace die grundlegende Annahme ist.
Dies würde Änderungen an der JSON-API jedes unterstützten Repositorys erfordern und könnte durch die Bereitstellung zusätzlicher Metadaten oder als echte Herkunftsangaben implementiert werden.
Ähnlich wie bei der Organisation-Scoping-Idee wäre eine neue Syntax erforderlich, wie z. B. microsoft::azure-loganalytics, wobei microsoft die Organisation und azure-loganalytics das Paket ist. Obwohl dies im Vergleich gut mit dem bestehenden flachen Namespace harmoniert, behält es den kritischen Nachteil, eine Störung für die Community aufgrund der Anzahl der erforderlichen Änderungen zu sein.
Ein einzigartiger Nachteil ist, dass Namen ein Implementierungsdetail von Repositories sind. Auf PyPI sind die Namen von Organisationen von Benutzernamen getrennt, was zu Konflikten führen kann. Bei mehreren Repositories könnten Benutzer auf Fälle von Abhängigkeitsverwirrung stoßen, ähnlich wie am Ende der abgelehnten Idee Förderung dedizierter Paket-Repositories.
Um dies zu mildern, wurde vorgeschlagen, die Syntax zu erweitern, um auch die erwartete Repository-URL einzuschließen, wie microsoft@pypi.org::azure-loganalytics. Diese Syntax oder etwas Ähnliches ist so wortreich, dass sie zu Verwirrung bei den Benutzern führen kann, und noch schlimmer, zu Frustration, sollte sie bei denen, die in der Lage sind, dedizierte Infrastruktur zu unterhalten, eine zunehmende Verbreitung finden (Community-Projekte würden davon nicht profitieren).
Die erweiterte Syntax ist ein Versuch, das Resolver-Verhalten und die Konfiguration innerhalb von Abhängigkeitsspezifizierern zu standardisieren. Dies würde nicht nur die Benutzererfahrung von Werkzeugen vorschreiben, sondern auch in Paketmanagern für Sprachökosysteme mit oder ohne das Konzept von Paket-Repositories keine Präzedenzfälle aufweisen. In solchen Fällen ist die Resolver-Konfiguration von der Abhängigkeitsdefinition getrennt.
| Sprache | Werkzeug | Auflösungsverhalten |
|---|---|---|
| Rust | Cargo | Die Abhängigkeitsauflösung kann in Cargo.toml mit der Tabelle [patch] modifiziert werden. |
| JS | Yarn | Obwohl sie das Konzept von Protokollen (ähnlich den URL-Schemata unserer direkten Referenzen) haben, konfigurieren Benutzer das Feld resolutions in der Datei package.json. |
| JS | npm | Benutzer können das Feld overrides in der Datei package.json konfigurieren. |
| Ruby | Bundler | Die Datei Gemfile ermöglicht die Angabe einer expliziten Quelle für ein Gem. |
| C# | NuGet | Es ist möglich, Paketversionen zu überschreiben, indem die Datei Directory.Packages.props konfiguriert wird. |
| PHP | Composer | Die Datei composer.json ermöglicht die Angabe von Repository-Quellen für bestimmte Pakete. |
| Go | go | Die Datei go.mod ermöglicht die Angabe einer replace-Direktive. Beachten Sie, dass dies sowohl für direkte als auch für transitive Abhängigkeiten verwendet wird. |
Verwendung fester Präfixe
Die Idee hier wäre, ein oder mehrere feste Präfixe der obersten Ebene zu haben, die für Namensraumreservierungen verwendet werden
com-: Reserviert für Unternehmensorganisationen.org-: Reserviert für Community-Organisationen.
Organisationen würden dann einen Namensraum beantragen, der mit dem Typ ihrer Organisation präfigiert ist.
Dies würde zu ständigen Umbrüchen führen, da bei der Gründung von Projekten nicht bekannt ist, ob eine Benutzerbasis groß genug sein wird, um eine Namensraumreservierung zu rechtfertigen. Wann immer dies geschieht, müsste das Projekt umbenannt werden, was einen hohen Wartungsaufwand für die Projektverantwortlichen bedeuten würde und zu Verwirrung bei den Benutzern führen würde, die sich einen neuen Weg merken müssen, um auf die Pakete des Projekts zuzugreifen. Die Wahrscheinlichkeit, dass dies Projekte davon abhält, Namensräume überhaupt zu reservieren, ist hoch.
Ein weiteres Problem bei diesem Ansatz ist, dass Projekte oft ein bestimmtes Branding im Sinn haben (Beispiel) und zögern würden, ihre Paketnamen zu ändern.
Es ist unrealistisch zu erwarten, dass jedes Unternehmen und jedes Projekt seine bestehenden und zukünftigen Paketnamen freiwillig ändert.
Verwendung von DNS
Die Idee ist hier, ein neues Metadatenfeld zu Projekten in der API namens domain-authority hinzuzufügen. Repositories würden einen neuen Endpunkt zur Verifizierung der Domäne über HTTPS unterstützen. Clients würden dann Optionen unterstützen, um bestimmte Domänen zuzulassen.
Dies löst das Problem nicht für die Zielgruppe, die nicht prüft, woher ihre Pakete stammen, und dient eher der Überprüfung der Integrität von Uploads, was durch PEP 740 bereits auf sicherere Weise unterstützt wird.
Die meisten Projekte haben keine Domäne und könnten davon nicht profitieren, was Organisationen, die über die finanziellen Mittel zur Erwerbung einer solchen verfügen, ungerechtfertigt bevorzugt.
Offene Fragen
Derzeit keine.
Fußnoten
Urheberrecht
Dieses Dokument wird in die Public Domain oder unter die CC0-1.0-Universal-Lizenz gestellt, je nachdem, welche Lizenz permissiver ist.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0752.rst
Zuletzt geändert: 2025-03-29 21:57:33 GMT