Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 763 – PyPI에서의 삭제 제한

Author:
William Woodruff <william at yossarian.net>, Alexis Challande <alexis.challande at trailofbits.com>
Sponsor:
Donald Stufft <donald at stufft.io>
PEP-Delegate:
Donald Stufft <donald at stufft.io>
Discussions-To:
Discourse thread
Status:
Withdrawn
Type:
Standards Track
Topic:
Packaging
Created:
24-Oct-2024
Post-History:
09-Jul-2022, 01-Oct-2024, 28-Oct-2024
Resolution:
21-Sep-2025

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

PEP 철회

이 PEP는 2025년 9월 22일부로 철회되었습니다.

PEP에 대한 논의 과정에서 PEP가 PyPI의 삭제 정책 변경에 적합한 수단인 것은 반드시 아니라는 점이 분명해졌습니다. PyPI의 사용 정책은 현재(또는 반드시 그래야 하는 것도) PEP 절차의 일부가 아니기 때문입니다.

개요

사용자가 PyPI에서 파일, 릴리스 및 프로젝트를 삭제할 수 있는 시점을 제한할 것을 제안합니다. 프로젝트, 릴리스 또는 파일은 색인에 업로드된 시점부터 72시간 이내에만 삭제할 수 있습니다. 이 시점 이후 사용자는 PEP 592에 명시된 “yank” 메커니즘만 사용할 수 있습니다.

이 제한의 예외로 pre-release specifiers가 표시된 릴리스와 파일은 언제든 삭제할 수 있도록 합니다. PyPI 관리자는 조정 또는 보안 목적 등을 위해 언제든 파일, 릴리스 및 프로젝트를 삭제할 수 있는 권한을 유지합니다.

근거 및 동기

관련 PEP 592에서 지적했듯이, PyPI에서 사용자가 프로젝트를 삭제할 수 있으면 의존성 손상과 관련된 진퇴양난의 상황이 발생합니다:

프로젝트에서 PyPI의 특정 릴리스가 파손되었을 수 있음을 감지할 때마다, 이후 사용자가 실수로 해당 버전을 사용하지 못하도록 하려는 경우가 많습니다. 그러나 저장소에서 기존 파일을 삭제하는 명백한 해결책은 프로젝트의 특정 버전에 고정한 사용자를 파손시킵니다.

이로 인해 프로젝트는 새로운 프로젝트가 이미 문제가 알려진 이 버전을 내려받을 수 있지만, 이를 막기 위해 어떤 조치를 취하면 이미 해당 버전을 사용 중인 프로젝트를 파손시키게 되는 진퇴양난 상황에 놓입니다.

기술적 측면에서 삭제 문제는 PEP 592에 명시된 “yanking”으로 완화됩니다. 그러나 PyPI에서는 여전히 삭제가 허용되고 있으며, 그동안 Python 생태계에 여러 차례 주목할 만한 혼란을 일으켰습니다.

  • 2022년 7월: atomicwrites는 프로젝트의 “critical” 지정을 제거하려는 시도로 deleted by its maintainer되었지만, 유지 관리자는 프로젝트를 삭제하면 이전에 업로드된 모든 릴리스도 삭제된다는 사실을 알지 못했습니다.

    이 프로젝트는 이후 유지 관리자의 동의를 받아 복원되었지만, 수동으로 관리자가 조치해야 했고 pytest와 같은 프로젝트가 광범위하게 하위 단계에서 파손되는 대가를 치렀습니다. 2024년 10월 기준으로 atomicwrites는 보관 처리되었지만 여전히 PyPI에서 약 4.5 million monthly downloads from PyPI를 기록합니다.

  • 2023년 4월: codecov는 긴 지원 중단 기간 후 유지 관리자들에 의해 삭제되었습니다. 이로 인해 많은 Codecov CI/CD 사용자가 광범위하게 영향을 받았으며, CI/CD 로그에서 지원 중단 경고를 제한적으로만 확인할 수 있었기 때문에 이들은 지원 중단 기간을 알지 못했습니다.

    이 프로젝트는 이후 유지 관리자들에 의해 subsequently re-created되었고, 삭제된 릴리스(복원되지 않음)를 보완하기 위해 새 릴리스가 게시되었습니다. 따라서 버전을 고정한 설치는 계속 파손된 상태로 남았습니다. 2024년 10월 기준으로 이 단일 릴리스가 PyPI의 유일한 릴리스로 남아 있으며, 약 1.5 million monthly downloads를 기록합니다.

  • 2023년 6월: python-sonarqube-api는 2.0.2 이전에 릴리스된 모든 릴리스를 삭제했습니다.

    프로젝트의 유지 관리자는 이후 deleted conversations하고 python-sonarqube-api의 소스 저장소 태그 이력을 강제로 푸시하여, 사용자가 릴리스 간 변경 사항을 비교하려는 작업을 방해했습니다.

  • 2024년 6월: PySimpleGUI는 라이선스를 변경하고 nearly all previous releases를 삭제했습니다. 이로 인해 사용자에게 광범위한 혼란이 발생했으며, 이들은 라이선스 변경 전 PySimpleGUI를 하루에 약 25,000회 다운로드하고 있었습니다.

삭제는 다운스트림에 혼란을 일으키는 것 외에도 PyPI의 지속 가능성과 생태계 전반의 보안에 해로운 영향을 미칩니다.

  • 삭제로 인해 PyPI 관리자와 중재자의 지원 업무량이 증가합니다. 사용자가 PyPI가 고장 났거나 관리자 자신이 프로젝트를 삭제했다고 잘못 생각하여 지원 요청을 제출하기 때문입니다.
  • 삭제는 외부(즉, 최종 사용자)의 사고 대응 및 분석을 저해하여, “선의의” 유지 관리자 행동과 흔적을 감추려는 악의적 행위자를 구분하기 어렵게 만듭니다.

Python 생태계는 계속 성장하고 있으므로, 향후 프로젝트 삭제는 위에서 표본으로 든 삭제보다 적어도, 더 심하지 않다면, 더 큰 혼란을 초래할 것으로 합리적으로 가정할 수 있습니다.

위의 모든 내용을 고려할 때, 이 PEP는 이제 삭제가 Python 생태계에 이익보다 더 큰 위험과 손해를 초래한다고 결론짓습니다.

이러한 기술적 주장에 더해, 다른 패키징 생태계에서도 사용자가 프로젝트와 이를 구성하는 릴리스를 삭제할 수 있는 권한을 제한하는 선례가 있습니다. 이 선례는 부록 A에 문서화되어 있습니다.

사양

삭제 가능한 객체에는 세 가지 유형이 있습니다.

  1. 파일은 개별 프로젝트 배포 패키지이며, 소스 배포 패키지나 휠 등이 이에 해당합니다.

    예: requests-2.32.3-py3-none-any.whl.

  2. 릴리스는 동일한 버전 번호를 공유하는 하나 이상의 파일을 포함합니다.

    예: requests v2.32.3.

  3. 프로젝트는 하나 이상의 릴리스를 포함합니다.

    예: requests.

삭제 자격 규칙

이 PEP는 다음과 같은 삭제 자격 규칙을 제안합니다.

  • file은 현재 시각으로부터 72시간 이내에 PyPI에 업로드되었거나, or 해당 pre-release specifier를 가진 경우에만 삭제할 수 있습니다.
  • 릴리스는 포함된 모든 파일을 삭제할 수 있는 경우에만 삭제할 수 있습니다.
  • 프로젝트는 모든 릴리스를 삭제할 수 있는 경우에만 삭제할 수 있습니다.

이러한 규칙에 따라 새 프로젝트는 전체를 삭제할 수 있고, 오래된 프로젝트도 새 파일이나 릴리스를 삭제할 수 있지만, 오래된 파일이나 릴리스를 삭제할 수는 없습니다.

구현

이 PEP의 구현은 주로 표준화되지 않았거나 표준화 대상이 아닌 PyPI의 측면, 예를 들어 웹 인터페이스와 로그인한 사용자 작업에 관한 것입니다. 따라서 이 절에서는 동작 측면에서 구현을 설명합니다.

변경 사항

  • 위의 자격 규칙에 따라 PyPI는 해당 객체가 삭제 자격을 갖추지 못한 경우 파일, 릴리스 또는 프로젝트 삭제를 위한 웹 인터페이스 요청을 적절한 HTTP 응답 코드로 거부합니다.
  • PyPI는 파일/릴리스/프로젝트를 삭제할 수 없음을 나타내도록 웹 인터페이스를 수정합니다. 예를 들어 관련 UI 요소의 스타일을 “inactive”로 지정하고 관련 버튼/양식을 클릭할 수 없게 만듭니다.

보안 영향

이 PEP는 제안된 접근 방식과 관련된 부정적인 보안 영향을 식별하지 않습니다.

이 PEP는 한 가지 사소하지만 긍정적인 보안 영향을 식별합니다. 사용자 제어 삭제를 제한함으로써 악의적인 행위자가 색인에서 악성 코드를 삭제하여 흔적을 감추기 어렵게 만들기 때문입니다. 이는 특히 외부 당사자, 즉 PyPI 관리자가 아닌 당사자가 수행하는 분류 및 사고 대응에 유용합니다. 이러한 경우 방어하는 측은 침해 지표를 개발하기 위해 악성 코드 샘플에 쉽게 접근할 수 있어야 합니다.

이를 가르치는 방법

이 PEP는 더 광범위한 Python 패키징 커뮤니티와 그 하위 소비자가 변경 사항을 이해하는 데 도움이 되도록, 대외 공개 자료를 최소 두 가지 제안합니다.

  • PEP의 성격과 동기, PyPI에 미치는 동작상의 영향을 설명하는 PyPI 블로그에 게시할 공지 글입니다.
  • 앞서 언급한 글로 연결되는 PyPI 자체의 공지 배너입니다.
  • 삭제와 얀킹의 차이 및 패키지 소유자가 전자를 여전히 시작할 수 있는 제한된 조건을 설명하는 PyPI 사용자 문서의 업데이트입니다.

거부된 아이디어

의존 관계에 따른 삭제 조건 설정

시간 기반 삭제 기간의 대안은 하위 의존자에 기반하여 삭제 가능 여부를 결정하는 것입니다. 예를 들어, 릴리스가 PyPI에 하위 의존자를 N개 미만으로 보유한 경우에만 삭제할 수 있는 것으로 간주할 수 있으며, 여기서 N은 1까지 낮출 수 있습니다.

이 아이디어는 삭제 가능 여부를 직접적으로 파급 효과와 연결하므로 매력적입니다. npm는 이를 사용하며, 패키지 색인에 알려진 하위 의존성이 전혀 없는 경우에만 프로젝트 제거를 허용합니다.

이러한 매력에도 불구하고, 이 PEP는 의존성에 따른 삭제를 PyPI에 적용하기 어렵게 만드는 몇 가지 단점과 기술적 한계를 확인합니다.

  1. PyPI는 의존 관계를 인식하지 못합니다. Python 패키징에서는 프로젝트 빌드 메타데이터 생성이 임의의 프로젝트 지정 코드를 포함하는 동적 작업인 경우가 많습니다. 이는 setup.py 스크립트를 포함하는 소스 배포판에서 잘 드러나며, 여기서는 setup.py 실행이 프로젝트 메타데이터에 인코딩된 의존성 집합을 계산합니다.

    이는 npm 및 Rust의 crates와 같은 생태계와 현저히 대조됩니다. 이러한 생태계에서는 프로젝트 빌드가 동적일 수 있지만 프로젝트의 메타데이터 자체는 정적입니다.

    그 결과 PyPI는 프로젝트의 의존성을 알지 못하며, 임의의 코드를 실행하거나(중대한 보안 위험) setup.py 기반 빌드를 PEP 517PEP 621 방식의 정적 메타데이터로 대체하는 장기간의 사용 중단 절차를 수행하지 않는 한 이를 알 수 없는 구조입니다.

  2. 직관적이지 않은 권한 모델을 초래합니다. 의존성에 따른 삭제는 “역전된” 권력 관계를 초래하며, 프로젝트에 대한 의존성을 추가한 누구나 해당 프로젝트의 삭제를 막을 수 있습니다.

    이는 표면적으로는 합리적이지만, 예상하지 못한 바람직하지 않은 결과를 만들도록 악용될 수 있습니다(일부 삭제를 허용한다는 맥락에서). 대표적인 예로 npm의 everything package가 있으며, 이 패키지는 npm의 모든 공개 패키지(2023년 12월 30일 기준)에 의존하므로 해당 패키지들의 삭제를 막습니다.

다운로드 수에 따른 삭제 조건 설정

시간 기반 삭제 기간의 또 다른 대안은 다운로드 수를 기준으로 삭제하는 것입니다. 예를 들어, 릴리스가 최근 기간 동안 N회 미만 다운로드된 경우에만 삭제할 수 있는 것으로 간주할 수 있습니다.

이 PEP는 프로젝트 사용량과 삭제 가능성을 연결함으로써 장점을 제시하면서도 이 접근 방식의 몇 가지 한계를 확인합니다.

  1. 생태계의 다양성. Python 생태계에는 사용 패턴이 매우 다양한 프로젝트가 포함되어 있습니다. 고정된 다운로드 임계값은 자연스럽게 다운로드 수가 낮은 틈새 프로젝트이지만 중요한 프로젝트를 적절히 고려하지 못합니다.
  2. 시간 민감성. 다운로드 수가 프로젝트의 현재 상태나 중요도를 반드시 반영하는 것은 아닙니다. 이전에 인기가 높았던 프로젝트가 최근 다운로드 수는 낮더라도 구형 시스템을 유지하는 데 여전히 중요할 수 있습니다.
  3. 기술적 복잡성. PyPI 내에서 프로젝트의 다운로드 수에 접근하는 일은 간단하지 않으며, 미러나 다른 배포 시스템에서 프로젝트의 다운로드 통계를 수집할 가능성도 제한적입니다.

부록 A: 다른 생태계의 선례

다음은 서로 다른 패키징 생태계에서 삭제를 지원하는 현황을 나타낸 표입니다. 생태계가 이 PEP와 유사한 방식으로 사용자의 삭제 수행 능력을 제한한다면 해당 생태계는 삭제를 지원하지 않는 것으로 간주합니다.

삭제만을 표시한 이 표의 이전 버전은 Python 토론 포럼에서 Donald Stufft와 다른 사람들이 2022년 7월에 작성했습니다.

Ecosystem (Index) Deletion Yanking Notes
Python (PyPI) [1] [2] Deletion currently completely unrestricted.
Rust (crates.io) [3] Deletion by users not allowed at all.
JavaScript (npm) [4] [5] Deletion is limited by criteria similar to this PEP.
Ruby (RubyGems) [6] RubyGems calls deletion “yanking.” Yanking in PyPI’s terms is not supported at all.
Java (Maven Central) [7] Deletion by users not allowed at all.
PHP (Packagist) [8] Deletion restricted after an undocumented number of installs.
.NET (NuGet) [9] [10] NuGet calls yanking “unlisting.”
Elixir (Hex) [11] [11] Hex calls yanking “retiring.”
R (CRAN) [12] [12] Deletion is limited to within 24 hours of initial release or 60 minutes for subsequent versions. CRAN calls yanking “archiving.”
Perl (CPAN) Yanking is not supported at all. Deletion seemingly encouraged, at least as of 2021 [13].
Lua (LuaRocks) [14] [14] LuaRocks calls yanking “archiving.”
Haskell (Hackage) [15] [16] Hackage calls yanking “deprecating.”
OCaml (OPAM) [17] [17] Deletion is allowed if it occurs “reasonably soon” after inclusion. Yanking is de facto supported by the available: false marker, which effectively disables resolution.

다음과 같은 경향이 나타납니다.

  • 색인의 압도적 다수가 삭제를 지원하지 않습니다(9 대 4).
  • 색인의 압도적 다수가 인출을 지원합니다(9 대 4).
  • 압도적 다수의 패키지 색인은 둘 중 하나만 지원하거나 어느 쪽도 지원하지 않지만, 둘 다 지원하지는 않습니다 (11 대 2).
    • PyPI와 LuaRocks는 삭제와 인출을 모두 지원하는 주목할 만한 예외입니다.

각주