CINXE.COM
PEP 752 – Implicit namespaces for package repositories | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 752 – Implicit namespaces for package repositories | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0752/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 752 – Implicit namespaces for package repositories | peps.python.org'> <meta property="og:description" content="This PEP specifies a way for organizations to reserve package name prefixes for future uploads."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0752/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP specifies a way for organizations to reserve package name prefixes for future uploads."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 752</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 752 – Implicit namespaces for package repositories</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Ofek Lev <ofekmeister at gmail.com>, Jarek Potiuk <potiuk at apache.org></dd> <dt class="field-even">Sponsor<span class="colon">:</span></dt> <dd class="field-even">Barry Warsaw <barry at python.org></dd> <dt class="field-odd">PEP-Delegate<span class="colon">:</span></dt> <dd class="field-odd">Dustin Ingram <di at python.org></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/63192">Discourse thread</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Proposal under active discussion and revision">Draft</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Topic<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="../topic/packaging/">Packaging</a></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">13-Aug-2024</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/61227" title="Discourse thread">18-Aug-2024</a>, <a class="reference external" href="https://discuss.python.org/t/63192" title="Discourse thread">07-Sep-2024</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#terminology">Terminology</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#organizations">Organizations</a></li> <li><a class="reference internal" href="#naming">Naming</a></li> <li><a class="reference internal" href="#semantics">Semantics</a></li> <li><a class="reference internal" href="#uploads">Uploads</a></li> <li><a class="reference internal" href="#open-namespaces">Open Namespaces</a></li> <li><a class="reference internal" href="#hidden-grants">Hidden Grants</a></li> <li><a class="reference internal" href="#repository-metadata">Repository Metadata</a><ul> <li><a class="reference internal" href="#project-detail">Project Detail</a></li> <li><a class="reference internal" href="#namespace-detail">Namespace Detail</a></li> </ul> </li> <li><a class="reference internal" href="#grant-removal">Grant Removal</a></li> </ul> </li> <li><a class="reference internal" href="#community-buy-in">Community Buy-in</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#artifact-level-namespace-association">Artifact-level Namespace Association</a></li> <li><a class="reference internal" href="#organization-scoping">Organization Scoping</a></li> <li><a class="reference internal" href="#encourage-dedicated-package-repositories">Encourage Dedicated Package Repositories</a></li> <li><a class="reference internal" href="#exclusive-reliance-on-provenance-assertions">Exclusive Reliance on Provenance Assertions</a></li> <li><a class="reference internal" href="#asserting-package-owner-names">Asserting Package Owner Names</a></li> <li><a class="reference internal" href="#use-fixed-prefixes">Use Fixed Prefixes</a></li> <li><a class="reference internal" href="#use-dns">Use DNS</a></li> </ul> </li> <li><a class="reference internal" href="#open-issues">Open Issues</a></li> <li><a class="reference internal" href="#footnotes">Footnotes</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP specifies a way for organizations to reserve package name prefixes for future uploads.</p> <blockquote> <div>“Namespaces are one honking great idea – let’s do more of those!” - <a class="pep reference internal" href="../pep-0020/" title="PEP 20 – The Zen of Python">PEP 20</a></div></blockquote> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>The current ecosystem lacks a way for projects with many packages to signal a verified pattern of ownership. Such projects fall into two categories.</p> <p>The first category is projects <a class="footnote-reference brackets" href="#id43" id="id1">[1]</a> that want complete control over their namespace. A few examples:</p> <ul class="simple"> <li>Major cloud providers like Amazon, Google and Microsoft have a common prefix for each feature’s corresponding package <a class="footnote-reference brackets" href="#id45" id="id2">[3]</a>. For example, most of Google’s packages are prefixed by <code class="docutils literal notranslate"><span class="pre">google-cloud-</span></code> e.g. <code class="docutils literal notranslate"><span class="pre">google-cloud-compute</span></code> for <a class="reference external" href="https://cloud.google.com/products/compute">using virtual machines</a>.</li> <li><a class="reference external" href="https://opentelemetry.io">OpenTelemetry</a> is an open standard for observability with <a class="reference external" href="https://github.com/open-telemetry/opentelemetry-python">official packages</a> for the core APIs and SDK with <a class="reference external" href="https://github.com/open-telemetry/opentelemetry-python-contrib">contrib packages</a> to collect data from various sources. All packages are prefixed by <code class="docutils literal notranslate"><span class="pre">opentelemetry-</span></code> with child prefixes in the form <code class="docutils literal notranslate"><span class="pre">opentelemetry-<component>-<name>-</span></code>. The contrib packages live in a central repository and they are the only ones with the ability to publish.</li> <li><a class="reference external" href="https://airflow.apache.org">Apache Airflow</a> is a platform to programmatically author, schedule and monitor workflows. It has providers, where each provider package is prefixed by <code class="docutils literal notranslate"><span class="pre">apache-airflow-providers-</span></code>.</li> </ul> <p>The second category is projects <a class="footnote-reference brackets" href="#id44" id="id5">[2]</a> that want to share their namespace such that some packages are officially maintained and third-party developers are encouraged to participate by publishing their own. Some examples:</p> <ul class="simple"> <li><a class="reference external" href="https://jupyter.org">Project Jupyter</a> is devoted to the development of tooling for sharing interactive documents. They support <a class="reference external" href="https://jupyterlab.readthedocs.io/en/stable/user/extensions.html">extensions</a> which in most cases (and in all cases for officially maintained extensions) are prefixed by <code class="docutils literal notranslate"><span class="pre">jupyter-</span></code>.</li> <li><a class="reference external" href="https://www.djangoproject.com">Django</a> is one of the most widely used web frameworks in existence. They have the concept of <a class="reference external" href="https://docs.djangoproject.com/en/5.1/intro/reusable-apps/">reusable apps</a>, which are commonly installed via <a class="reference external" href="https://djangopackages.org">third-party packages</a> that implement a subset of functionality to extend Django-based websites. These packages are by convention prefixed by <code class="docutils literal notranslate"><span class="pre">django-</span></code> or <code class="docutils literal notranslate"><span class="pre">dj-</span></code>.</li> </ul> <p>Such projects are uniquely vulnerable to name-squatting attacks which can ultimately result in <a class="reference external" href="https://www.activestate.com/resources/quick-reads/dependency-confusion/">dependency confusion</a>.</p> <p>For example, say a new product is released for which monitoring would be valuable. It would be reasonable to assume that <a class="reference external" href="https://www.datadoghq.com">Datadog</a> would eventually support it as an official integration. It takes a nontrivial amount of time to deliver such an integration due to roadmap prioritization and the time required for implementation. It would be impossible to reserve the name of every potential package so in the interim an attacker may create a package that appears legitimate which would execute malicious code at runtime. Not only are users more likely to install such packages but doing so taints the perception of the entire project.</p> <p>Although <a class="pep reference internal" href="../pep-0708/" title="PEP 708 – Extending the Repository API to Mitigate Dependency Confusion Attacks">PEP 708</a> attempts to address this attack vector, it is specifically about the case of multiple repositories being considered during dependency resolution and does not offer any protection to the aforementioned use cases.</p> <p>Namespacing also would drastically reduce the incidence of <a class="reference external" href="https://en.wikipedia.org/wiki/Typosquatting">typosquatting</a> because typos would have to be in the prefix itself which is <a class="reference internal" href="#naming">normalized</a> and likely to be a short, well-known identifier like <code class="docutils literal notranslate"><span class="pre">aws-</span></code>. In recent years, typosquatting has become a popular attack vector <a class="footnote-reference brackets" href="#id46" id="id9">[4]</a>.</p> <p>The <a class="reference external" href="https://github.com/pypi/warehouse/blob/8615326918a180eb2652753743eac8e74f96a90b/warehouse/migrations/versions/d18d443f89f0_ultranormalize_name_function.py#L29-L42">current protection</a> against typosquatting used by PyPI is to normalize similar characters but that is insufficient for these use cases.</p> <p>Another problem that namespacing would solve is the issue of choosing new names for packages following the agreed patterns of naming. Often (this is the case for Apache Airflow for example), there are public discussions that precede the decision to create a new package. The decision is based on the agreed name and follow the pattern of the existing packages. If more package names are considered during the discussion, all the names have to be reserved via a PyPI interface before the discussion is public, otherwise the names can be taken by other users. This has happened in the past as explained in the associated <a class="reference external" href="https://discuss.python.org/t/pep-752-implicit-namespaces-for-package-repositories/63192/80">discussion</a>.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Other package ecosystems have generally solved this problem by taking one of two approaches: either minimizing or maximizing backwards compatibility.</p> <ul class="simple"> <li><a class="reference external" href="https://www.npmjs.com">NPM</a> has the concept of <a class="reference external" href="https://docs.npmjs.com/about-scopes">scoped packages</a> which were <a class="reference external" href="https://blog.npmjs.org/post/116936804365/solving-npms-hard-problem-naming-packages">introduced</a> primarily to combat there being a dearth of available good package names (whether a real or perceived phenomenon). When a user or organization signs up they are given a scope that matches their name. For example, the <a class="reference external" href="https://www.npmjs.com/package/@google-cloud/storage">package</a> for using Google Cloud Storage is <code class="docutils literal notranslate"><span class="pre">@google-cloud/storage</span></code> where <code class="docutils literal notranslate"><span class="pre">@google-cloud/</span></code> is the scope. Regular user accounts (non-organization) may publish <a class="reference external" href="https://docs.npmjs.com/package-scope-access-level-and-visibility">unscoped</a> packages for public use. This approach has the lowest amount of backwards compatibility because every installer and tool has to be modified to account for scopes.</li> <li><a class="reference external" href="https://www.nuget.org">NuGet</a> has the concept of <a class="reference external" href="https://learn.microsoft.com/en-us/nuget/nuget-org/id-prefix-reservation">package ID prefix reservation</a> which was <a class="reference external" href="https://devblogs.microsoft.com/nuget/Package-identity-and-trust/">introduced</a> primarily to satisfy users wishing to know where a package came from. A package name prefix may be reserved for use by one or more owners. Every reserved package has a special indication <a class="reference external" href="https://www.nuget.org/packages/Google.Cloud.Storage.V1">on its page</a> to communicate this. After reservation, any upload with a reserved prefix will fail if the user is not an owner of the prefix. Existing packages that have a prefix that is owned may continue to release as usual. This approach has the highest amount of backwards compatibility because only modifications to indices like PyPI are required and installers do not need to change.</li> </ul> <p>This PEP specifies the NuGet approach of authorized reservation across a flat namespace. Any solution that requires new package syntax must be built atop the existing flat namespace and therefore implicit namespaces acquired via a reservation mechanism would be a prerequisite to such explicit namespaces.</p> <p>Although existing packages matching a reserved namespace would be untouched, preventing future unauthorized uploads and strategically applying <a class="pep reference internal" href="../pep-0541/" title="PEP 541 – Package Index Name Retention">PEP 541</a> takedown requests for malicious cases would reduce risks to users to a negligible level.</p> </section> <section id="terminology"> <h2><a class="toc-backref" href="#terminology" role="doc-backlink">Terminology</a></h2> <p>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in <span class="target" id="index-0"></span><a class="rfc reference external" href="https://datatracker.ietf.org/doc/html/rfc2119.html"><strong>RFC 2119</strong></a>.</p> <dl class="simple"> <dt>Organization</dt><dd><a class="reference internal" href="#orgs">Organizations</a> are entities that own projects and have various users associated with them.</dd> <dt>Grant</dt><dd>A grant is a reservation of a namespace for a package repository.</dd> <dt>Open Namespace</dt><dd>An <a class="reference internal" href="#open-namespaces">open</a> namespace allows for uploads from any project owner.</dd> <dt>Restricted Namespace</dt><dd>A restricted namespace only allows uploads from an owner of the namespace.</dd> <dt>Parent Namespace</dt><dd>A namespace’s parent refers to the namespace without the trailing hyphenated component e.g. the parent of <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> is <code class="docutils literal notranslate"><span class="pre">foo</span></code>.</dd> <dt>Child Namespace</dt><dd>A namespace’s child refers to the namespace with additional trailing hyphenated components e.g. <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> is a valid child of <code class="docutils literal notranslate"><span class="pre">foo</span></code> as is <code class="docutils literal notranslate"><span class="pre">foo-bar-baz</span></code>.</dd> </dl> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="organizations"> <span id="orgs"></span><h3><a class="toc-backref" href="#organizations" role="doc-backlink">Organizations</a></h3> <p>Any package repository that allows for the creation of projects (e.g. non-mirrors) MAY offer the concept of <a class="reference external" href="https://blog.pypi.org/posts/2023-04-23-introducing-pypi-organizations/">organizations</a>. Organizations are entities that own projects and have various users associated with them.</p> <p>Organizations MAY reserve one or more namespaces. Such reservations neither confer ownership nor grant special privileges to existing projects.</p> </section> <section id="naming"> <span id="id16"></span><h3><a class="toc-backref" href="#naming" role="doc-backlink">Naming</a></h3> <p>A namespace MUST be a <a class="reference external" href="https://packaging.python.org/en/latest/specifications/name-normalization/#name-format">valid</a> project name and <a class="reference external" href="https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization">normalized</a> internally e.g. <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code> would become <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code>.</p> </section> <section id="semantics"> <h3><a class="toc-backref" href="#semantics" role="doc-backlink">Semantics</a></h3> <p>A namespace grant bestows ownership over the following:</p> <ol class="arabic simple"> <li>A project matching the namespace itself such as the placeholder package <a class="reference external" href="https://pypi.org/project/microsoft/">microsoft</a>.</li> <li>Projects that start with the namespace followed by a hyphen. For example, the namespace <code class="docutils literal notranslate"><span class="pre">foo</span></code> would match the normalized project name <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> but not the project name <code class="docutils literal notranslate"><span class="pre">foobar</span></code>.</li> </ol> <p>Package name matching acts upon the <a class="reference internal" href="#naming">normalized</a> namespace.</p> <p>Namespaces are per-package repository and SHALL NOT be shared between repositories. For example, if PyPI has a namespace <code class="docutils literal notranslate"><span class="pre">microsoft</span></code> that is owned by the company Microsoft, packages starting with <code class="docutils literal notranslate"><span class="pre">microsoft-</span></code> that come from other non-PyPI mirror repositories do not confer the same level of trust.</p> <p>Grants MUST NOT overlap. For example, if there is an existing grant for <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> then a new grant for <code class="docutils literal notranslate"><span class="pre">foo</span></code> would be forbidden. An overlap is determined by comparing the <a class="reference internal" href="#naming">normalized</a> proposed namespace with the normalized namespace of every existing root grant. Every comparison must append a hyphen to the end of the proposed and existing namespace. An overlap is detected when any existing namespace starts with the proposed namespace.</p> </section> <section id="uploads"> <span id="id19"></span><h3><a class="toc-backref" href="#uploads" role="doc-backlink">Uploads</a></h3> <p>If the following criteria are all true for a given upload:</p> <ol class="arabic simple"> <li>The project does not yet exist.</li> <li>The name matches a reserved namespace.</li> <li>The project is not owned by an organization with an active grant for the namespace.</li> </ol> <p>Then the upload MUST fail with a 403 HTTP status code.</p> </section> <section id="open-namespaces"> <span id="id20"></span><h3><a class="toc-backref" href="#open-namespaces" role="doc-backlink">Open Namespaces</a></h3> <p>The owner of a grant may choose to allow others the ability to release new projects with the associated namespace. Doing so MUST allow <a class="reference internal" href="#uploads">uploads</a> for new projects matching the namespace from any user.</p> <p>It is possible for the owner of a namespace to both make it open and allow other organizations to use the grant. In this case, the authorized organizations have no special permissions and are equivalent to an open grant without ownership.</p> </section> <section id="hidden-grants"> <span id="id21"></span><h3><a class="toc-backref" href="#hidden-grants" role="doc-backlink">Hidden Grants</a></h3> <p>Repositories MAY create hidden grants that are not visible to the public which prevent their namespaces from being claimed by others. Such grants MUST NOT be <a class="reference internal" href="#open-namespaces">open</a> and SHOULD NOT be exposed in the <a class="reference internal" href="#repository-metadata">API</a>.</p> <p>Hidden grants are useful for repositories that wish to enforce upload restrictions without the need to expose the namespace to the public.</p> </section> <section id="repository-metadata"> <span id="id22"></span><h3><a class="toc-backref" href="#repository-metadata" role="doc-backlink">Repository Metadata</a></h3> <p>The <a class="pep reference internal" href="../pep-0691/" title="PEP 691 – JSON-based Simple API for Python Package Indexes">JSON API</a> version will be incremented from <code class="docutils literal notranslate"><span class="pre">1.2</span></code> to <code class="docutils literal notranslate"><span class="pre">1.3</span></code>. The following API changes MUST be implemented by repositories that support this PEP. Repositories that do not support this PEP MUST NOT implement these changes so that consumers of the API are able to determine whether the repository supports this PEP.</p> <section id="project-detail"> <span id="id23"></span><h4><a class="toc-backref" href="#project-detail" role="doc-backlink">Project Detail</a></h4> <p>The <a class="pep reference internal" href="../pep-0691/#project-detail" title="PEP 691 – JSON-based Simple API for Python Package Indexes § Project Detail">project detail</a> response will be modified as follows.</p> <p>The <code class="docutils literal notranslate"><span class="pre">namespace</span></code> key MUST be <code class="docutils literal notranslate"><span class="pre">null</span></code> if the project does not match an active namespace grant. If the project does match a namespace grant, the value MUST be a mapping with the following keys:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">prefix</span></code>: This is the associated <a class="reference internal" href="#naming">normalized</a> namespace e.g. <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code>. If the owner of the project owns multiple matching grants then this MUST be the namespace with the most number of characters. For example, if the project name matched both <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> and <code class="docutils literal notranslate"><span class="pre">foo-bar-baz</span></code> then this key would be the latter.</li> <li><code class="docutils literal notranslate"><span class="pre">authorized</span></code>: This is a boolean and will be true if the project owner is an organization and is one of the current owners of the grant. This is useful for tools that wish to make a distinction between official and community packages.</li> <li><code class="docutils literal notranslate"><span class="pre">open</span></code>: This is a boolean indicating whether the namespace is <a class="reference internal" href="#open-namespaces">open</a>.</li> </ul> </section> <section id="namespace-detail"> <h4><a class="toc-backref" href="#namespace-detail" role="doc-backlink">Namespace Detail</a></h4> <p>The format of this URL is <code class="docutils literal notranslate"><span class="pre">/namespace/<namespace></span></code> where <code class="docutils literal notranslate"><span class="pre"><namespace></span></code> is the <a class="reference internal" href="#naming">normalized</a> namespace. For example, the URL for the namespace <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code> would be <code class="docutils literal notranslate"><span class="pre">/namespace/foo-bar</span></code>.</p> <p>The response will be a mapping with the following keys:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">prefix</span></code>: This is the <a class="reference internal" href="#naming">normalized</a> version of the namespace e.g. <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code>.</li> <li><code class="docutils literal notranslate"><span class="pre">owner</span></code>: This is the organization that is responsible for the namespace.</li> <li><code class="docutils literal notranslate"><span class="pre">open</span></code>: This is a boolean indicating whether the namespace is <a class="reference internal" href="#open-namespaces">open</a>.</li> <li><code class="docutils literal notranslate"><span class="pre">parent</span></code>: This is the parent namespace if it exists. For example, if the namespace is <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> and there is an active grant for <code class="docutils literal notranslate"><span class="pre">foo</span></code>, then this would be <code class="docutils literal notranslate"><span class="pre">"foo"</span></code>. If there is no parent then this key will be <code class="docutils literal notranslate"><span class="pre">null</span></code>.</li> <li><code class="docutils literal notranslate"><span class="pre">children</span></code>: This is an array of any child namespaces. For example, if the namespace is <code class="docutils literal notranslate"><span class="pre">foo</span></code> and there are active grants for <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code> and <code class="docutils literal notranslate"><span class="pre">foo-bar-baz</span></code> then this would be <code class="docutils literal notranslate"><span class="pre">["foo-bar",</span> <span class="pre">"foo-bar-baz"]</span></code>.</li> </ul> </section> </section> <section id="grant-removal"> <h3><a class="toc-backref" href="#grant-removal" role="doc-backlink">Grant Removal</a></h3> <p>When a reserved namespace becomes unclaimed, repositories MUST set the <code class="docutils literal notranslate"><span class="pre">namespace</span></code> key to <code class="docutils literal notranslate"><span class="pre">null</span></code> in the <a class="reference internal" href="#project-detail">API</a>.</p> <p>Namespaces that were previously claimed but are now not SHOULD be eligible for claiming again by any organization.</p> </section> </section> <section id="community-buy-in"> <h2><a class="toc-backref" href="#community-buy-in" role="doc-backlink">Community Buy-in</a></h2> <p>Representatives from the following organizations have expressed support for this PEP (with a link to the discussion):</p> <ul class="simple"> <li><a class="reference external" href="https://github.com/apache/airflow/discussions/41657#discussioncomment-10412999">Apache Airflow</a> (<a class="reference external" href="https://discuss.python.org/t/63191/75">expanded</a>)</li> <li><a class="reference external" href="https://discuss.python.org/t/63192/68">pytest</a></li> <li><a class="reference external" href="https://discuss.python.org/t/1609/37">Typeshed</a></li> <li><a class="reference external" href="https://discuss.python.org/t/61227/16">Project Jupyter</a> (<a class="reference external" href="https://discuss.python.org/t/61227/48">expanded</a>)</li> <li><a class="reference external" href="https://discuss.python.org/t/63191/40">Microsoft</a></li> <li><a class="reference external" href="https://discuss.python.org/t/63192/67">Sentry</a> (in favor of the NuGet approach over others but not negatively impacted by the current lack of capability)</li> <li><a class="reference external" href="https://discuss.python.org/t/63191/53">DataDog</a></li> </ul> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>There are no intrinsic concerns because there is still a flat namespace and installers need no modification. Additionally, many projects have already chosen to signal a shared purpose with a prefix like <a class="reference external" href="https://github.com/python/typeshed/issues/2491#issuecomment-578456045">typeshed has done</a>.</p> </section> <section id="security-implications"> <span id="id25"></span><h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2> <ul class="simple"> <li>There is an opportunity to build on top of <a class="pep reference internal" href="../pep-0740/" title="PEP 740 – Index support for digital attestations">PEP 740</a> and <a class="pep reference internal" href="../pep-0480/" title="PEP 480 – Surviving a Compromise of PyPI: End-to-end signing of packages">PEP 480</a> so that one could prove cryptographically that a specific release came from an owner of the associated namespace. This PEP makes no effort to describe how this will happen other than that work is planned for the future.</li> </ul> </section> <section id="how-to-teach-this"> <h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to Teach This</a></h2> <p>For consumers of packages we will document how metadata is exposed in the <a class="reference internal" href="#repository-metadata">API</a> and potentially in future note tooling that supports utilizing namespaces to provide extra security guarantees during installation.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>None at this time.</p> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="artifact-level-namespace-association"> <span id="artifact-level-association"></span><h3><a class="toc-backref" href="#artifact-level-namespace-association" role="doc-backlink">Artifact-level Namespace Association</a></h3> <p>An earlier version of this PEP proposed that metadata be associated with individual artifacts at the point of release. This was rejected because it had the potential to cause confusion for users who would expect the namespace authorization guarantee to be at the project level based on current grants rather than the time at which a given release occurred.</p> </section> <section id="organization-scoping"> <span id="id26"></span><h3><a class="toc-backref" href="#organization-scoping" role="doc-backlink">Organization Scoping</a></h3> <p>The primary motivation for this PEP is to reduce dependency confusion attacks and NPM-style scoping with an allowance of the legacy flat namespace would increase the risk. If documentation instructed a user to install <code class="docutils literal notranslate"><span class="pre">bar</span></code> in the namespace <code class="docutils literal notranslate"><span class="pre">foo</span></code> then the user must be careful to install <code class="docutils literal notranslate"><span class="pre">@foo/bar</span></code> and not <code class="docutils literal notranslate"><span class="pre">foo-bar</span></code>, or vice versa. The Python packaging ecosystem has normalization rules for names in order to maximize the ease of communication and this would be a regression.</p> <p>The runtime environment of Python is also not conducive to scoping. Whereas multiple versions of the same JavaScript package may coexist, Python only allows a single global namespace. Barring major changes to the language itself, this is nearly impossible to change. Additionally, users have come to expect that the package name is usually the same as what they would import and eliminating the flat namespace would do away with that convention.</p> <p>Scoping would be particularly affected by organization changes which are bound to happen over time. An organization may change their name due to internal shuffling, an acquisition, or any other reason. Whenever this happens every project they own would in effect be renamed which would cause unnecessary confusion for users, frequently.</p> <p>Finally, the disruption to the community would be massive because it would require an update from every package manager, security scanner, IDE, etc. New packages released with the scoping would be incompatible with older tools and would cause confusion for users along with frustration from maintainers having to triage such complaints.</p> </section> <section id="encourage-dedicated-package-repositories"> <span id="dedicated-repositories"></span><h3><a class="toc-backref" href="#encourage-dedicated-package-repositories" role="doc-backlink">Encourage Dedicated Package Repositories</a></h3> <p>Critically, this imposes a burden on projects to maintain their own infra. This is an unrealistic expectation for the vast majority of companies and a complete non-starter for community projects.</p> <p>This does not help in most cases because the default behavior of most package managers is to use PyPI so users attempting to perform a simple <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span></code> would already be vulnerable to malicious packages.</p> <p>In this theoretical future every project must document how to add their repository to dependency resolution, which would be different for each package manager. Few package managers are able to download specific dependencies from specific repositories and would require users to use verbose configuration in the common case.</p> <p>The ones that do not support this would instead find a given package using an ordered enumeration of repositories, leading to dependency confusion. For example, say a user wants two packages from two custom repositories <code class="docutils literal notranslate"><span class="pre">X</span></code> and <code class="docutils literal notranslate"><span class="pre">Y</span></code>. If each repository has both packages but one is malicious on <code class="docutils literal notranslate"><span class="pre">X</span></code> and the other is malicious on <code class="docutils literal notranslate"><span class="pre">Y</span></code> then the user would be unable to satisfy their requirements without encountering a malicious package.</p> </section> <section id="exclusive-reliance-on-provenance-assertions"> <span id="provenance-assertions"></span><h3><a class="toc-backref" href="#exclusive-reliance-on-provenance-assertions" role="doc-backlink">Exclusive Reliance on Provenance Assertions</a></h3> <p>The idea here <a class="footnote-reference brackets" href="#id47" id="id27">[5]</a> would be to design a general purpose way for clients to make provenance assertions to verify certain properties of dependencies, each with custom syntax. Some examples:</p> <ul class="simple"> <li>The package was uploaded by a specific organization or user name e.g. <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">"azure-loganalytics</span> <span class="pre">from</span> <span class="pre">microsoft"</span></code></li> <li>The package was uploaded by an owner of a specific domain name e.g. <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">"google-cloud-compute</span> <span class="pre">from</span> <span class="pre">cloud.google.com"</span></code></li> <li>The package was uploaded by a user with a specific email address e.g. <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">"aws-cdk-lib</span> <span class="pre">from</span> <span class="pre">contact@amazon.com"</span></code></li> <li>The package matching a namespace was uploaded by an authorized party (this PEP)</li> </ul> <p>A fundamental downside is that it doesn’t play well with multiple repositories. For example, say a user wants the <code class="docutils literal notranslate"><span class="pre">azure-loganalytics</span></code> package and wants to ensure it comes from the organization named <code class="docutils literal notranslate"><span class="pre">microsoft</span></code>. If Microsoft’s organization name on PyPI is <code class="docutils literal notranslate"><span class="pre">microsoft</span></code> then a package manager that defaults to PyPI could accept <code class="docutils literal notranslate"><span class="pre">azure-loganalytics</span> <span class="pre">from</span> <span class="pre">microsoft</span></code>. However, if multiple repositories are used for dependency resolution then the user would have to specify the repository as part of the definition which is unrealistic for reasons outlined in the dedicated section on <a class="reference internal" href="#asserting-package-owner-names">asserting package owner names</a>.</p> <p>Another general weakness with this approach is that a user attempting to perform a simple <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span></code> without special syntax, which is the most common scenario, would already be vulnerable to malicious packages. In order to overcome this there would have to be some default trust mechanism, which in all cases would impose certain UX or resolver logic upon every tool.</p> <p>For example, package managers could be changed such that the first time a package is installed the user would receive a confirmation prompt displaying the provenance details. This would be very confusing and noisy, especially for new users, and would be a breaking UX change for existing users. Many methods of installation wouldn’t work for this scenario such as running in CI or installing from a requirements file where the user would potentially be getting hundreds of prompts.</p> <p>One solution to make this less disruptive for users would be to manually maintain a list of trustworthy details (organization/user names, domain names, email addresses, etc.). This could be discoverable by packages providing <a class="reference external" href="https://packaging.python.org/en/latest/specifications/entry-points/">entry points</a> which package managers could learn to detect and which corporate environments could install by default. This has the major downside of not providing automatic guarantees which would limit the usefulness for the average user who is more likely to be affected.</p> <p>There are two ideas that could be used to provide automatic protection, which could be based on <a class="pep reference internal" href="../pep-0740/" title="PEP 740 – Index support for digital attestations">PEP 740</a> attestations or a new mechanism for utilizing third-party APIs that host the metadata.</p> <p>First, each repository could offer a service that verifies the owner of a package using whatever criteria they deem appropriate. After verification, the repository would add the details to a dedicated package that would be installed by default.</p> <p>This would require dedicated maintenance which is unrealistic for most repositories, even PyPI currently. It’s unclear how community projects without the resources for something like a domain name would be supported. Critically, this solution would cause extra confusion for users in the case of multiple repositories as each might have their own verification processes, attestation criteria and default package containing the verified details. It would be challenging to get community buy-in of every package manager to be aware of each repositories’ chosen verification package and install that by default before dependency resolution.</p> <p>Should digital attestations become the chosen mechanism, a downside is that implementing this in custom package repositories would require a significant amount of work. In the case of PyPI, the prerequisite work on <a class="reference external" href="https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/#acknowledgements">Trusted Publishing</a> and then the <a class="reference external" href="https://blog.trailofbits.com/2024/10/01/securing-the-software-supply-chain-with-the-slsa-framework/">PEP 740 implementation</a> itself took the equivalent of a full-time engineer one year whose time was paid for by a corporate sponsor. Other organizations are unlikely to implement similar work because simpler mechanisms make it possible to implement reproducible builds. When everything is internally managed, attestations are also not very useful. Community projects are unlikely to undertake this effort because they would likely lack the resources to maintain the necessary infrastructure themselves and moreover there are significant downsides to <a class="reference internal" href="#dedicated-repositories">encouraging dedicated package repositories</a>.</p> <p>The other idea would be to host provenance assertions externally and push more logic client-side. A possible implementation might be to specify a provenance API that could be hosted at a designated relative path like <code class="docutils literal notranslate"><span class="pre">/provenance</span></code>. Projects on each repository could then be configured to point to a particular domain and this information would be passed on to clients during installation.</p> <p>While this distributed approach does impose less of an infrastructure burden on repositories, it has the potential to be a security risk. If an external provenance API is compromised, it could lead to malicious packages being installed. If an external API is down, it could lead to package installation failing or package managers might only emit warnings in which case there is no security benefit.</p> <p>Additionally, this disadvantages community projects that do not have the resources to maintain such an API. They could use free hosting solutions such as what many do for documentation but they do not technically own the infrastructure and they would be compromised should the generous offerings be restricted.</p> <p>Finally, while both of these theoretical approaches are not yet prescriptive, they imply assertions at the artifact level which was already a <a class="reference internal" href="#artifact-level-association">rejected idea</a>.</p> </section> <section id="asserting-package-owner-names"> <span id="id31"></span><h3><a class="toc-backref" href="#asserting-package-owner-names" role="doc-backlink">Asserting Package Owner Names</a></h3> <p>This is about asserting that the package came from a specific organization or user name. It’s quite similar to the <a class="reference internal" href="#organization-scoping">organization scoping</a> idea except that a flat namespace is the base assumption.</p> <p>This would require modifications to the <a class="pep reference internal" href="../pep-0691/" title="PEP 691 – JSON-based Simple API for Python Package Indexes">JSON API</a> of each supported repository and could be implemented by exposing extra metadata or as proper <a class="reference internal" href="#provenance-assertions">provenance assertions</a>.</p> <p>As with the organization scoping idea, a new <a class="reference external" href="https://packaging.python.org/en/latest/specifications/dependency-specifiers/">syntax</a> would be required like <code class="docutils literal notranslate"><span class="pre">microsoft::azure-loganalytics</span></code> where <code class="docutils literal notranslate"><span class="pre">microsoft</span></code> is the organization and <code class="docutils literal notranslate"><span class="pre">azure-loganalytics</span></code> is the package. Although this plays well with the existing flat namespace in comparison, it retains the critical downside of being a disruption for the community with the number of changes required.</p> <p>A unique downside is that names are an implementation detail of repositories. On PyPI, the names of organizations are separate from user names so there is potential for conflicts. In the case of multiple repositories, users might run into cases of dependency confusion similar to the one at the end of the <a class="reference internal" href="#dedicated-repositories">Encourage Dedicated Package Repositories</a> rejected idea.</p> <p>To ameliorate this, it was suggested that the syntax be expanded to also include the expected repository URL like <code class="docutils literal notranslate"><span class="pre">microsoft@pypi.org::azure-loganalytics</span></code>. This syntax or something like it is so verbose that it could lead to user confusion, and even worse, frustration should it gain increased adoption among those able to maintain dedicated infrastructure (community projects would not benefit).</p> <p>The expanded syntax is an attempt to standardize resolver behavior and configuration within dependency specifiers. Not only would this be mandating the UX of tools, it lacks precedent in package managers for language ecosystems with or without the concept of package repositories. In such cases, the resolver configuration is separate from the dependency definition.</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">Language</th> <th class="head">Tool</th> <th class="head">Resolution behavior</th> </tr> </thead> <tbody> <tr class="row-even"><td>Rust</td> <td>Cargo</td> <td>Dependency resolution can be <a class="reference external" href="https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html">modified</a> within <code class="docutils literal notranslate"><span class="pre">Cargo.toml</span></code> using the the <code class="docutils literal notranslate"><span class="pre">[patch]</span></code> table.</td> </tr> <tr class="row-odd"><td>JS</td> <td>Yarn</td> <td>Although they have the concept of <a class="reference external" href="https://yarnpkg.com/protocols">protocols</a> (which are similar to the URL schemes of our <a class="reference external" href="https://packaging.python.org/en/latest/specifications/version-specifiers/#direct-references">direct references</a>), users configure the <a class="reference external" href="https://yarnpkg.com/configuration/manifest#resolutions">resolutions</a> field in the <code class="docutils literal notranslate"><span class="pre">package.json</span></code> file.</td> </tr> <tr class="row-even"><td>JS</td> <td>npm</td> <td>Users can configure the <a class="reference external" href="https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides">overrides</a> field in the <code class="docutils literal notranslate"><span class="pre">package.json</span></code> file.</td> </tr> <tr class="row-odd"><td>Ruby</td> <td>Bundler</td> <td>The <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code> allows for specifying an <a class="reference external" href="https://bundler.io/v2.5/man/gemfile.5.html#SOURCE-PRIORITY">explicit source</a> for a gem.</td> </tr> <tr class="row-even"><td>C#</td> <td>NuGet</td> <td>It’s possible to <a class="reference external" href="https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#overriding-package-versions">override package versions</a> by configuring the <code class="docutils literal notranslate"><span class="pre">Directory.Packages.props</span></code> file.</td> </tr> <tr class="row-odd"><td>PHP</td> <td>Composer</td> <td>The <code class="docutils literal notranslate"><span class="pre">composer.json</span></code> file allows for specifying <a class="reference external" href="https://getcomposer.org/doc/articles/repository-priorities.md#filtering-packages">repository</a> sources for specific packages.</td> </tr> <tr class="row-even"><td>Go</td> <td>go</td> <td>The <code class="docutils literal notranslate"><span class="pre">go.mod</span></code> file allows for specifying a <a class="reference external" href="https://go.dev/ref/mod#go-mod-file-replace">replace</a> directive. Note that this is used for direct dependencies as well as transitive dependencies.</td> </tr> </tbody> </table> </section> <section id="use-fixed-prefixes"> <h3><a class="toc-backref" href="#use-fixed-prefixes" role="doc-backlink">Use Fixed Prefixes</a></h3> <p>The idea here would be to have one or more top-level fixed prefixes that are used for namespace reservations:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">com-</span></code>: Reserved for corporate organizations.</li> <li><code class="docutils literal notranslate"><span class="pre">org-</span></code>: Reserved for community organizations.</li> </ul> <p>Organizations would then apply for a namespace prefixed by the type of their organization.</p> <p>This would cause perpetual disruption because when projects begin it is unknown whether a user base will be large enough to warrant a namespace reservation. Whenever that happens the project would have to be renamed which would put a high maintenance burden on the project maintainers and would cause confusion for users who have to learn a new way to reference the project’s packages. The potential for this deterring projects from reserving namespaces at all is high.</p> <p>Another issue with this approach is that projects often have branding in mind (<a class="reference external" href="https://github.com/apache/airflow/discussions/41657#discussioncomment-10417439">example</a>) and would be reluctant to change their package names.</p> <p>It’s unrealistic to expect every company and project to voluntarily change their existing and future package names.</p> </section> <section id="use-dns"> <h3><a class="toc-backref" href="#use-dns" role="doc-backlink">Use DNS</a></h3> <p>The <a class="reference external" href="https://discuss.python.org/t/63455">idea</a> here is to add a new metadata field to projects in the API called <code class="docutils literal notranslate"><span class="pre">domain-authority</span></code>. Repositories would support a new endpoint for verifying the domain via HTTPS. Clients would then support options to allow certain domains.</p> <p>This does not solve the problem for the target audience who do not check where their packages are coming from and is more about checking for the integrity of uploads which is already supported in a more secure way by <a class="pep reference internal" href="../pep-0740/" title="PEP 740 – Index support for digital attestations">PEP 740</a>.</p> <p>Most projects do not have a domain and could not benefit from this, unfairly favoring organizations that have the financial means to acquire one.</p> </section> </section> <section id="open-issues"> <h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2> <p>None at this time.</p> </section> <section id="footnotes"> <h2><a class="toc-backref" href="#footnotes" role="doc-backlink">Footnotes</a></h2> <aside class="footnote-list brackets"> <aside class="footnote brackets" id="id43" role="doc-footnote"> <dt class="label" id="id43">[<a href="#id1">1</a>]</dt> <dd>Additional examples of projects with restricted namespaces:<ul class="simple"> <li><a class="reference external" href="https://github.com/python/typeshed">Typeshed</a> is a community effort to maintain type stubs for various packages. The stub packages they maintain mirror the package name they target and are prefixed by <code class="docutils literal notranslate"><span class="pre">types-</span></code>. For example, the package <code class="docutils literal notranslate"><span class="pre">requests</span></code> has a stub that users would depend on called <code class="docutils literal notranslate"><span class="pre">types-requests</span></code>. Unofficial stubs are not supposed to use the <code class="docutils literal notranslate"><span class="pre">types-</span></code> prefix and are expected to use a <code class="docutils literal notranslate"><span class="pre">-stubs</span></code> suffix instead.</li> <li><a class="reference external" href="https://www.sphinx-doc.org">Sphinx</a> is a documentation framework popular for large technical projects such as <a class="reference external" href="https://www.swift.org">Swift</a> and Python itself. They have the concept of <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/index.html">extensions</a> which are prefixed by <code class="docutils literal notranslate"><span class="pre">sphinxcontrib-</span></code>, many of which are maintained within a <a class="reference external" href="https://github.com/sphinx-contrib">dedicated organization</a>.</li> <li><a class="reference external" href="https://airflow.apache.org">Apache Airflow</a> is a platform to programmatically orchestrate tasks as directed acyclic graphs (DAGs). They have the concept of <a class="reference external" href="https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/plugins.html">plugins</a>, and also <a class="reference external" href="https://airflow.apache.org/docs/apache-airflow-providers/index.html">providers</a> which are prefixed by <code class="docutils literal notranslate"><span class="pre">apache-airflow-providers-</span></code>.</li> </ul> </aside> <aside class="footnote brackets" id="id44" role="doc-footnote"> <dt class="label" id="id44">[<a href="#id5">2</a>]</dt> <dd>Additional examples of projects with open namespaces:<ul class="simple"> <li><a class="reference external" href="https://docs.pytest.org">pytest</a> is Python’s most popular testing framework. They have the concept of <a class="reference external" href="https://docs.pytest.org/en/stable/how-to/writing_plugins.html">plugins</a> which may be developed by anyone and by convention are prefixed by <code class="docutils literal notranslate"><span class="pre">pytest-</span></code>.</li> <li><a class="reference external" href="https://www.mkdocs.org">MkDocs</a> is a documentation framework based on Markdown files. They also have the concept of <a class="reference external" href="https://www.mkdocs.org/dev-guide/plugins/">plugins</a> which may be developed by anyone and are usually prefixed by <code class="docutils literal notranslate"><span class="pre">mkdocs-</span></code>.</li> <li><a class="reference external" href="https://www.datadoghq.com">Datadog</a> offers observability as a service. The <a class="reference external" href="https://docs.datadoghq.com/agent/">Datadog Agent</a> ships out-of-the-box with <a class="reference external" href="https://github.com/DataDog/integrations-core">official integrations</a> for many products, like various databases and web servers, which are distributed as Python packages that are prefixed by <code class="docutils literal notranslate"><span class="pre">datadog-</span></code>. There is support for creating <a class="reference external" href="https://docs.datadoghq.com/developers/integrations/agent_integration/">third-party integrations</a> which customers may run.</li> </ul> </aside> <aside class="footnote brackets" id="id45" role="doc-footnote"> <dt class="label" id="id45">[<a href="#id2">3</a>]</dt> <dd>The following shows the package prefixes for the major cloud providers:<ul class="simple"> <li>Amazon: <a class="reference external" href="https://docs.aws.amazon.com/cdk/api/v2/python/">aws-cdk-</a></li> <li>Google: <a class="reference external" href="https://github.com/googleapis/google-cloud-python/tree/main/packages">google-cloud-</a> and others based on <code class="docutils literal notranslate"><span class="pre">google-</span></code></li> <li>Microsoft: <a class="reference external" href="https://github.com/Azure/azure-sdk-for-python/tree/main/sdk">azure-</a></li> </ul> </aside> <aside class="footnote brackets" id="id46" role="doc-footnote"> <dt class="label" id="id46">[<a href="#id9">4</a>]</dt> <dd>Examples of typosquatting attacks targeting Python users:<ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">django-</span></code> namespace was squatted, among other packages, leading to a <a class="reference external" href="https://mail.python.org/pipermail/security-announce/2017-September/000000.html">postmortem</a> by PyPI.</li> <li><code class="docutils literal notranslate"><span class="pre">cupy-</span></code> namespace was <a class="reference external" href="https://github.com/cupy/cupy/issues/4787">squatted</a> by a malicious actor thousands of times.</li> <li><code class="docutils literal notranslate"><span class="pre">scikit-</span></code> namespace was <a class="reference external" href="https://blog.phylum.io/a-pypi-typosquatting-campaign-post-mortem/">squatted</a>, among other packages. Notice how packages with a known prefix are much more prone to successful attacks.</li> <li><code class="docutils literal notranslate"><span class="pre">typing-</span></code> namespace was <a class="reference external" href="https://zero.checkmarx.com/malicious-pypi-user-strikes-again-with-typosquatting-starjacking-and-unpacks-tailor-made-malware-b12669cefaa5">squatted</a> and this would be useful to prevent as a <a class="reference internal" href="#hidden-grants">hidden grant</a>.</li> </ul> </aside> <aside class="footnote brackets" id="id47" role="doc-footnote"> <dt class="label" id="id47">[<a href="#id27">5</a>]</dt> <dd><a class="reference external" href="https://discuss.python.org/t/64679">Detailed write-up</a> of the potential for provenance assertions.</aside> </aside> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0752.rst">https://github.com/python/peps/blob/main/peps/pep-0752.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0752.rst">2025-03-08 07:50:09 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#terminology">Terminology</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#organizations">Organizations</a></li> <li><a class="reference internal" href="#naming">Naming</a></li> <li><a class="reference internal" href="#semantics">Semantics</a></li> <li><a class="reference internal" href="#uploads">Uploads</a></li> <li><a class="reference internal" href="#open-namespaces">Open Namespaces</a></li> <li><a class="reference internal" href="#hidden-grants">Hidden Grants</a></li> <li><a class="reference internal" href="#repository-metadata">Repository Metadata</a><ul> <li><a class="reference internal" href="#project-detail">Project Detail</a></li> <li><a class="reference internal" href="#namespace-detail">Namespace Detail</a></li> </ul> </li> <li><a class="reference internal" href="#grant-removal">Grant Removal</a></li> </ul> </li> <li><a class="reference internal" href="#community-buy-in">Community Buy-in</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#artifact-level-namespace-association">Artifact-level Namespace Association</a></li> <li><a class="reference internal" href="#organization-scoping">Organization Scoping</a></li> <li><a class="reference internal" href="#encourage-dedicated-package-repositories">Encourage Dedicated Package Repositories</a></li> <li><a class="reference internal" href="#exclusive-reliance-on-provenance-assertions">Exclusive Reliance on Provenance Assertions</a></li> <li><a class="reference internal" href="#asserting-package-owner-names">Asserting Package Owner Names</a></li> <li><a class="reference internal" href="#use-fixed-prefixes">Use Fixed Prefixes</a></li> <li><a class="reference internal" href="#use-dns">Use DNS</a></li> </ul> </li> <li><a class="reference internal" href="#open-issues">Open Issues</a></li> <li><a class="reference internal" href="#footnotes">Footnotes</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0752.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>