547 lines
24 KiB
ReStructuredText
547 lines
24 KiB
ReStructuredText
PEP: 752
|
|
Title: Implicit namespaces for package repositories
|
|
Author: Ofek Lev <ofekmeister@gmail.com>
|
|
Sponsor: Barry Warsaw <barry@python.org>
|
|
PEP-Delegate: Dustin Ingram <di@python.org>
|
|
Discussions-To: https://discuss.python.org/t/63192
|
|
Status: Draft
|
|
Type: Standards Track
|
|
Topic: Packaging
|
|
Created: 13-Aug-2024
|
|
Post-History: `18-Aug-2024 <https://discuss.python.org/t/61227>`__,
|
|
`07-Sep-2024 <https://discuss.python.org/t/63192>`__,
|
|
|
|
Abstract
|
|
========
|
|
|
|
This PEP specifies a way for organizations to reserve package name prefixes
|
|
for future uploads.
|
|
|
|
"Namespaces are one honking great idea -- let's do more of
|
|
those!" - :pep:`20`
|
|
|
|
Motivation
|
|
==========
|
|
|
|
The current ecosystem lacks a way for projects with many packages to signal a
|
|
verified pattern of ownership. Such projects fall into two categories.
|
|
|
|
The first category is projects [1]_ that want complete control over their
|
|
namespace. A few examples:
|
|
|
|
* Major cloud providers like Amazon, Google and Microsoft have a common prefix
|
|
for each feature's corresponding package [3]_. For example, most of Google's
|
|
packages are prefixed by ``google-cloud-`` e.g. ``google-cloud-compute`` for
|
|
`using virtual machines <https://cloud.google.com/products/compute>`__.
|
|
* `OpenTelemetry <https://opentelemetry.io>`__ is an open standard for
|
|
observability with `official packages`__ for the core APIs and SDK with
|
|
`contrib packages`__ to collect data from various sources. All packages
|
|
are prefixed by ``opentelemetry-`` with child prefixes in the form
|
|
``opentelemetry-<component>-<name>-``. The contrib packages live in a
|
|
central repository and they are the only ones with the ability to publish.
|
|
|
|
__ https://github.com/open-telemetry/opentelemetry-python
|
|
__ https://github.com/open-telemetry/opentelemetry-python-contrib
|
|
|
|
The second category is projects [2]_ 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:
|
|
|
|
* `Project Jupyter <https://jupyter.org>`__ is devoted to the development of
|
|
tooling for sharing interactive documents. They support `extensions`__
|
|
which in most cases (and in all cases for officially maintained
|
|
extensions) are prefixed by ``jupyter-``.
|
|
* `Django <https://www.djangoproject.com>`__ is one of the most widely used web
|
|
frameworks in existence. They have the concept of `reusable apps`__, which
|
|
are commonly installed via
|
|
`third-party packages <https://djangopackages.org>`__ that implement a subset
|
|
of functionality to extend Django-based websites. These packages are by
|
|
convention prefixed by ``django-`` or ``dj-``.
|
|
|
|
__ https://jupyterlab.readthedocs.io/en/stable/user/extensions.html
|
|
__ https://docs.djangoproject.com/en/5.1/intro/reusable-apps/
|
|
|
|
Such projects are uniquely vulnerable to name-squatting attacks
|
|
which can ultimately result in `dependency confusion`__.
|
|
|
|
__ https://www.activestate.com/resources/quick-reads/dependency-confusion/
|
|
|
|
For example, say a new product is released for which monitoring would be
|
|
valuable. It would be reasonable to assume that
|
|
`Datadog <https://www.datadoghq.com>`__ 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.
|
|
|
|
Although :pep:`708` 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.
|
|
|
|
Namespacing also would drastically reduce the incidence of
|
|
`typosquatting <https://en.wikipedia.org/wiki/Typosquatting>`__
|
|
because typos would have to be in the prefix itself which is
|
|
`normalized <naming_>`_ and likely to be a short, well-known identifier like
|
|
``aws-``. In recent years, typosquatting has become a popular attack vector
|
|
[4]_.
|
|
|
|
The `current protection`__ against typosquatting used by PyPI is to normalize
|
|
similar characters but that is insufficient for these use cases.
|
|
|
|
__ https://github.com/pypi/warehouse/blob/8615326918a180eb2652753743eac8e74f96a90b/warehouse/migrations/versions/d18d443f89f0_ultranormalize_name_function.py#L29-L42
|
|
|
|
Rationale
|
|
=========
|
|
|
|
Other package ecosystems have generally solved this problem by taking one of
|
|
two approaches: either minimizing or maximizing backwards compatibility.
|
|
|
|
* `NPM <https://www.npmjs.com>`__ has the concept of
|
|
`scoped packages <https://docs.npmjs.com/about-scopes>`__ which were
|
|
`introduced`__ 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
|
|
`package <https://www.npmjs.com/package/@google-cloud/storage>`__ for using
|
|
Google Cloud Storage is ``@google-cloud/storage`` where ``@google-cloud/`` is
|
|
the scope. Regular user accounts (non-organization) may publish `unscoped`__
|
|
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.
|
|
* `NuGet <https://www.nuget.org>`__ has the concept of
|
|
`package ID prefix reservation`__ which was
|
|
`introduced`__ 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
|
|
`on its page <https://www.nuget.org/packages/Google.Cloud.Storage.V1>`__ 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.
|
|
|
|
__ https://blog.npmjs.org/post/116936804365/solving-npms-hard-problem-naming-packages
|
|
__ https://docs.npmjs.com/package-scope-access-level-and-visibility
|
|
__ https://learn.microsoft.com/en-us/nuget/nuget-org/id-prefix-reservation
|
|
__ https://devblogs.microsoft.com/nuget/Package-identity-and-trust/
|
|
|
|
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.
|
|
|
|
Although existing packages matching a reserved namespace would be untouched,
|
|
preventing future unauthorized uploads and strategically applying :pep:`541`
|
|
takedown requests for malicious cases would reduce risks to users to a
|
|
negligible level.
|
|
|
|
Terminology
|
|
===========
|
|
|
|
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 :rfc:`2119`.
|
|
|
|
Organization
|
|
`Organizations <orgs_>`_ are entities that own projects and have various
|
|
users associated with them.
|
|
Grant
|
|
A grant is a reservation of a namespace for a package repository.
|
|
Open Namespace
|
|
An `open <open-namespaces_>`_ namespace allows for uploads from any project
|
|
owner.
|
|
Restricted Namespace
|
|
A restricted namespace only allows uploads from an owner of the namespace.
|
|
Parent Namespace
|
|
A namespace's parent refers to the namespace without the trailing
|
|
hyphenated component e.g. the parent of ``foo-bar`` is ``foo``.
|
|
Child Namespace
|
|
A namespace's child refers to the namespace with additional trailing
|
|
hyphenated components e.g. ``foo-bar`` is a valid child of ``foo`` as is
|
|
``foo-bar-baz``.
|
|
|
|
Specification
|
|
=============
|
|
|
|
.. _orgs:
|
|
|
|
Organizations
|
|
-------------
|
|
|
|
Any package repository that allows for the creation of projects (e.g.
|
|
non-mirrors) MAY offer the concept of `organizations`__. Organizations
|
|
are entities that own projects and have various users associated with them.
|
|
|
|
__ https://blog.pypi.org/posts/2023-04-23-introducing-pypi-organizations/
|
|
|
|
Organizations MAY reserve one or more namespaces. Such reservations neither
|
|
confer ownership nor grant special privileges to existing projects.
|
|
|
|
.. _naming:
|
|
|
|
Naming
|
|
------
|
|
|
|
A namespace MUST be a `valid`__ project name and `normalized`__ internally e.g.
|
|
``foo.bar`` would become ``foo-bar``.
|
|
|
|
__ https://packaging.python.org/en/latest/specifications/name-normalization/#name-format
|
|
__ https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization
|
|
|
|
Semantics
|
|
---------
|
|
|
|
A namespace grant bestows ownership over the following:
|
|
|
|
1. A project matching the namespace itself such as the placeholder package
|
|
`microsoft <https://pypi.org/project/microsoft/>`__.
|
|
2. Projects that start with the namespace followed by a hyphen. For example,
|
|
the namespace ``foo`` would match the normalized project name ``foo-bar``
|
|
but not the project name ``foobar``.
|
|
|
|
Package name matching acts upon the `normalized <naming_>`_ namespace.
|
|
|
|
Namespaces are per-package repository and SHALL NOT be shared between
|
|
repositories. For example, if PyPI has a namespace ``microsoft`` that is owned
|
|
by the company Microsoft, packages starting with ``microsoft-`` that come from
|
|
other non-PyPI mirror repositories do not confer the same level of trust.
|
|
|
|
Grants MUST NOT overlap. For example, if there is an existing grant
|
|
for ``foo-bar`` then a new grant for ``foo`` would be forbidden. An overlap is
|
|
determined by comparing the `normalized <naming_>`_ 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.
|
|
|
|
.. _uploads:
|
|
|
|
Uploads
|
|
-------
|
|
|
|
If the following criteria are all true for a given upload:
|
|
|
|
1. The project does not yet exist.
|
|
2. The name matches a reserved namespace.
|
|
3. The project is not owned by an organization with an active grant for the
|
|
namespace.
|
|
|
|
Then the upload MUST fail with a 403 HTTP status code.
|
|
|
|
.. _open-namespaces:
|
|
|
|
Open Namespaces
|
|
-----------------
|
|
|
|
The owner of a grant may choose to allow others the ability to release new
|
|
projects with the associated namespace. Doing so MUST allow
|
|
`uploads <uploads_>`_ for new projects matching the namespace from any user.
|
|
|
|
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.
|
|
|
|
.. _hidden-grants:
|
|
|
|
Hidden Grants
|
|
-------------
|
|
|
|
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
|
|
`open <open-namespaces_>`_ and SHOULD NOT be exposed in the
|
|
`API <repository-metadata_>`_.
|
|
|
|
Hidden grants are useful for repositories that wish to enforce upload
|
|
restrictions without the need to expose the namespace to the public.
|
|
|
|
.. _repository-metadata:
|
|
|
|
Repository Metadata
|
|
-------------------
|
|
|
|
The :pep:`JSON API <691>` version will be incremented from ``1.2`` to ``1.3``.
|
|
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.
|
|
|
|
.. _project-detail:
|
|
|
|
Project Detail
|
|
''''''''''''''
|
|
|
|
The :pep:`project detail <691#project-detail>` response will be modified as
|
|
follows.
|
|
|
|
The ``namespace`` key MUST be ``null`` 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:
|
|
|
|
* ``prefix``: This is the associated `normalized <naming_>`_ namespace e.g.
|
|
``foo-bar``. 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 ``foo-bar`` and ``foo-bar-baz`` then this
|
|
key would be the latter.
|
|
* ``authorized``: 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.
|
|
* ``open``: This is a boolean indicating whether the namespace is
|
|
`open <open-namespaces_>`_.
|
|
|
|
Namespace Detail
|
|
''''''''''''''''
|
|
|
|
The format of this URL is ``/namespace/<namespace>`` where ``<namespace>`` is
|
|
the `normalized <naming_>`_ namespace. For example, the URL for the namespace
|
|
``foo.bar`` would be ``/namespace/foo-bar``.
|
|
|
|
The response will be a mapping with the following keys:
|
|
|
|
* ``prefix``: This is the `normalized <naming_>`_ version of the namespace e.g.
|
|
``foo-bar``.
|
|
* ``owner``: This is the organization that is responsible for the namespace.
|
|
* ``open``: This is a boolean indicating whether the namespace is
|
|
`open <open-namespaces_>`_.
|
|
* ``parent``: This is the parent namespace if it exists. For example, if the
|
|
namespace is ``foo-bar`` and there is an active grant for ``foo``, then this
|
|
would be ``"foo"``. If there is no parent then this key will be ``null``.
|
|
* ``children``: This is an array of any child namespaces. For example, if the
|
|
namespace is ``foo`` and there are active grants for ``foo-bar`` and
|
|
``foo-bar-baz`` then this would be ``["foo-bar", "foo-bar-baz"]``.
|
|
|
|
Grant Removal
|
|
-------------
|
|
|
|
When a reserved namespace becomes unclaimed, repositories MUST set the
|
|
``namespace`` key to ``null`` in the `API <project-detail_>`_.
|
|
|
|
Namespaces that were previously claimed but are now not SHOULD be eligible for
|
|
claiming again by any organization.
|
|
|
|
Community Buy-in
|
|
================
|
|
|
|
Representatives from the following organizations have expressed support for
|
|
this PEP (with a link to the discussion):
|
|
|
|
* `Apache Airflow <https://github.com/apache/airflow/discussions/41657#discussioncomment-10412999>`__
|
|
* `Typeshed <https://discuss.python.org/t/1609/37>`__
|
|
* `Project Jupyter <https://discuss.python.org/t/61227/16>`__
|
|
(`expanded <https://discuss.python.org/t/61227/48>`__)
|
|
* `Microsoft <https://discuss.python.org/t/63191/40>`__
|
|
* `DataDog <https://discuss.python.org/t/63191/53>`__
|
|
|
|
Backwards Compatibility
|
|
=======================
|
|
|
|
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 `typeshed has done`__.
|
|
|
|
__ https://github.com/python/typeshed/issues/2491#issuecomment-578456045
|
|
|
|
Security Implications
|
|
=====================
|
|
|
|
* There is an opportunity to build on top of :pep:`740` and :pep:`480` 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.
|
|
|
|
How to Teach This
|
|
=================
|
|
|
|
For consumers of packages we will document how metadata is exposed in the
|
|
`API <repository-metadata_>`_ and potentially in future note tooling that
|
|
supports utilizing namespaces to provide extra security guarantees during
|
|
installation.
|
|
|
|
Reference Implementation
|
|
========================
|
|
|
|
None at this time.
|
|
|
|
Rejected Ideas
|
|
==============
|
|
|
|
Organization Scoping
|
|
--------------------
|
|
|
|
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 ``bar`` in the
|
|
namespace ``foo`` then the user must be careful to install ``@foo/bar`` and not
|
|
``foo-bar``, 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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Encourage Dedicated Package Repositories
|
|
----------------------------------------
|
|
|
|
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.
|
|
|
|
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 ``pip install``
|
|
would already be vulnerable to malicious packages.
|
|
|
|
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.
|
|
|
|
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 ``X``
|
|
and ``Y``. If each repository has both packages but one is malicious on ``X``
|
|
and the other is malicious on ``Y`` then the user would be unable to satisfy
|
|
their requirements without encountering a malicious package.
|
|
|
|
Use Fixed Prefixes
|
|
------------------
|
|
|
|
The idea here would be to have one or more top-level fixed prefixes that are
|
|
used for namespace reservations:
|
|
|
|
* ``com-``: Reserved for corporate organizations.
|
|
* ``org-``: Reserved for community organizations.
|
|
|
|
Organizations would then apply for a namespace prefixed by the type of their
|
|
organization.
|
|
|
|
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.
|
|
|
|
Another issue with this approach is that projects often have branding in mind
|
|
(`example`__) and would be reluctant to change their package names.
|
|
|
|
__ https://github.com/apache/airflow/discussions/41657#discussioncomment-10417439
|
|
|
|
It's unrealistic to expect every company and project to voluntarily change
|
|
their existing and future package names.
|
|
|
|
Use DNS
|
|
-------
|
|
|
|
The `idea <https://discuss.python.org/t/63455>`__ here is to add a new
|
|
metadata field to projects in the API called ``domain-authority``. Repositories
|
|
would support a new endpoint for verifying the domain via HTTPS. Clients would
|
|
then support options to allow certain domains.
|
|
|
|
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 :pep:`740`.
|
|
|
|
Most projects do not have a domain and could not benefit from this, unfairly
|
|
favoring organizations that have the financial means to acquire one.
|
|
|
|
Open Issues
|
|
===========
|
|
|
|
None at this time.
|
|
|
|
Footnotes
|
|
=========
|
|
|
|
.. [1] Additional examples of projects with restricted namespaces:
|
|
|
|
- `Typeshed <https://github.com/python/typeshed>`__ 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 ``types-``. For
|
|
example, the package ``requests`` has a stub that users would depend on
|
|
called ``types-requests``. Unofficial stubs are not supposed to use the
|
|
``types-`` prefix and are expected to use a ``-stubs`` suffix instead.
|
|
- `Sphinx <https://www.sphinx-doc.org>`__ is a documentation framework
|
|
popular for large technical projects such as
|
|
`Swift <https://www.swift.org>`__ and Python itself. They have
|
|
the concept of `extensions`__ which are prefixed by ``sphinxcontrib-``,
|
|
many of which are maintained within a
|
|
`dedicated organization <https://github.com/sphinx-contrib>`__.
|
|
- `Apache Airflow <https://airflow.apache.org>`__ is a platform to
|
|
programmatically orchestrate tasks as directed acyclic graphs (DAGs).
|
|
They have the concept of `plugins`__, and also `providers`__ which are
|
|
prefixed by ``apache-airflow-providers-``.
|
|
|
|
.. [2] Additional examples of projects with open namespaces:
|
|
|
|
- `pytest <https://docs.pytest.org>`__ is Python's most popular testing
|
|
framework. They have the concept of `plugins`__ which may be developed by
|
|
anyone and by convention are prefixed by ``pytest-``.
|
|
- `MkDocs <https://www.mkdocs.org>`__ is a documentation framework based on
|
|
Markdown files. They also have the concept of
|
|
`plugins <https://www.mkdocs.org/dev-guide/plugins/>`__ which may be
|
|
developed by anyone and are usually prefixed by ``mkdocs-``.
|
|
- `Datadog <https://www.datadoghq.com>`__ offers observability as a service
|
|
for organizations at any scale. The
|
|
`Datadog Agent <https://docs.datadoghq.com/agent/>`__ ships out-of-the-box
|
|
with
|
|
`official integrations <https://github.com/DataDog/integrations-core>`__
|
|
for many products, like various databases and web servers, which are
|
|
distributed as Python packages that are prefixed by ``datadog-``. There is
|
|
support for creating `third-party integrations`__ which customers may run.
|
|
|
|
.. [3] The following shows the package prefixes for the major cloud providers:
|
|
|
|
- Amazon: `aws-cdk- <https://docs.aws.amazon.com/cdk/api/v2/python/>`__
|
|
- Google: `google-cloud- <https://github.com/googleapis/google-cloud-python/tree/main/packages>`__
|
|
and others based on ``google-``
|
|
- Microsoft: `azure- <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk>`__
|
|
|
|
.. [4] Examples of typosquatting attacks targeting Python users:
|
|
|
|
- ``django-`` namespace was squatted, among other packages, leading to
|
|
a `postmortem <https://mail.python.org/pipermail/security-announce/2017-September/000000.html>`__
|
|
by PyPI.
|
|
- ``cupy-`` namespace was
|
|
`squatted <https://github.com/cupy/cupy/issues/4787>`__ by a malicious
|
|
actor thousands of times.
|
|
- ``scikit-`` namespace was
|
|
`squatted <https://blog.phylum.io/a-pypi-typosquatting-campaign-post-mortem/>`__,
|
|
among other packages. Notice how packages with a known prefix are much
|
|
more prone to successful attacks.
|
|
- ``typing-`` namespace was
|
|
`squatted <https://zero.checkmarx.com/malicious-pypi-user-strikes-again-with-typosquatting-starjacking-and-unpacks-tailor-made-malware-b12669cefaa5>`__
|
|
and this would be useful to prevent as a `hidden grant <hidden-grants_>`__.
|
|
|
|
__ https://www.sphinx-doc.org/en/master/usage/extensions/index.html
|
|
__ https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/plugins.html
|
|
__ https://airflow.apache.org/docs/apache-airflow-providers/index.html
|
|
__ https://docs.pytest.org/en/stable/how-to/writing_plugins.html
|
|
__ https://docs.datadoghq.com/developers/integrations/agent_integration/
|
|
|
|
Copyright
|
|
=========
|
|
|
|
This document is placed in the public domain or under the
|
|
CC0-1.0-Universal license, whichever is more permissive.
|