PEP 778 – 휠에서 심볼릭 링크 지원하기
- Author:
- Emma Harper Smith <emma at python.org>
- Sponsor:
- Barry Warsaw <barry at python.org>
- PEP-Delegate:
- Paul Moore <p.f.moore at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Deferred
- Type:
- Standards Track
- Topic:
- Packaging
- Requires:
- 777
- Created:
- 18-May-2024
- Post-History:
- 10-Oct-2024
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
현재 휠은 심볼릭 링크를 제대로 처리하지 못하며, 설치할 때 심볼릭 링크를 만드는 대신 내용을 복사합니다. 휠로 라이브러리를 올바르게 배포할 수 있도록, 플랫폼 이식성 있는 방식으로 심볼릭 링크를 처리하는 새로운 LINKS 메타데이터 파일을 제안합니다. 이 명세에는 PEP 777에서 논의하는 새로운 휠 메이저 버전이 필요합니다.
PEP 보류
휠 형식의 주요 변경에 대한 더 나은 호환성 방안이 마련될 때까지 이 PEP는 보류되었습니다. 하위 호환되지 않는 동작을 거슬리지 않는 방식으로 허용하는 휠 호환성 방안이 마련되면, 이 PEP에서 다음 사항을 다루어야 합니다:
- 이 주제를 POSIX 플랫폼의 공유 라이브러리용 심볼릭 링크로만 좁히고, 어쩌면 플랫폼 태그와 연계해야 합니까?
- 심볼릭 링크를 아카이브의 파일 속성으로 구현해야 합니까, 아니면
LINKS파일로 구현해야 합니까? 이를RECORD에 인코딩할 수 있습니까? - 이 PEP는 더 이상 크로스 플랫폼이 아니게 되므로 PEP 660 편집 가능 설치에 유용하게 쓰이기에는 불충분하다는 점을 명확히 하십시오.
- POSIX 플랫폼에서 심볼릭 링크를 사용할 수 없는 경우의 대체 동작을 기술하십시오.
동기
현재 휠 안의 심볼릭 링크는 파일 복사본으로 생성되는데, 이는 보안상의 이유로 CPython의 zipfile 모듈이 심볼릭 링크를 그 자리에서 처리하는 것을 지원하지 않기 때문입니다.
이는 대용량 컴파일 라이브러리를 휠로 배포하려는 프로젝트에 문제가 됩니다. 이러한 프로젝트는 디스크상의 프로젝트 설치 크기를 크게 늘리거나, 심볼릭 링크를 생략하여 일부 다운스트림 사용 사례를 망가뜨릴 위험을 감수하는 것 중 하나를 선택해야 하기 때문입니다.
POSIX에서 런타임 사용을 위해 올바르게 로드되거나 빌드 시점에 링크될 수 있는 라이브러리를 배포하려면, 라이브러리는 POSIX 방식의 로더 및 링커 검색 규칙을 따라야 합니다. 로더가 사용하는 두 가지 주요 파일 이름은 “soname”과 “real name”입니다. “soname”은 libfoo.so.3과 같은 파일이며, 여기서 3은 라이브러리의 인터페이스가 변경될 때 증가하는 숫자입니다. “real name”은 libfoo.so.3.1.4와 같은 이름의 파일로, 추가 버전 정보를 통해 로더가 특정 버전의 라이브러리를 찾을 수 있습니다. 마지막으로, 라이브러리에 링크하도록 코드를 컴파일할 때 링커는 libfoo.so와 같은 이름의 “linker name”을 검색합니다. 더 자세한 설명은 공유 라이브러리에 관한 이 리눅스 문서에서 볼 수 있습니다. 모든 런타임 및 빌드 시점 사용 사례를 완전히 지원하려면, 프로젝트는 3개 파일을 모두 배포해야 합니다. 일반적으로 POSIX 플랫폼에서는 심볼릭 링크를 사용하여 이를 처리하므로, 라이브러리가 디스크에 3번 중복되지 않습니다.
Python 패키징으로 돌아가 보면, numpy, scipy, pyarrow처럼 바이너리 라이브러리를 함께 배포하는 인기 프로젝트가 많습니다. pytorch와 jax 같은 다른 site-packages 패키지는 다른 휠에 있는 라이브러리를 dlopen으로 불러옵니다. 이러한 프로젝트는 현재 휠 안의 단일 라이브러리에 의존하지만, “real name” 라이브러리 버전을 가진 시스템 라이브러리가 있으면 링커가 잘못된 라이브러리를 찾을 수 있습니다.
또한 휠의 심볼릭 링크를 사용하면 사용자의 site-packages 디렉터리에 심볼릭 링크를 두는 것만으로 더 간단하게 편집 가능 설치를 할 수 있다는 잠재적 이점도 있지만, 이 PEP는 이를 향후 PEP에서 탐구할 열린 질문으로 남겨 둡니다.
근거
POSIX에서 로딩과 라이브러리 링킹에 사용되는 라이브러리의 세 가지 주요 이름 형식을 지원하기 위해, Python wheel에 심볼릭 링크 지원을 추가할 것을 제안합니다. 생성된 심볼릭 링크를 추적할 수 있도록 하고, POSIX 심볼릭 링크를 직접 지원하지 않을 수 있는 다른 플랫폼도 지원할 수 있도록, 새로운 휠 메타데이터 파일 LINKS의 사용을 제안합니다. 이 파일은 .dist-info 디렉터리에 METADATA, RECORD 및 기타 메타데이터 파일과 함께 위치합니다.
LINKS 파일을 사용하면 심볼릭 링크와 비슷한 방식을 여러 플랫폼에서 더 폭넓게 사용할 수 있습니다. Windows에서 심볼릭 링크를 만들려면 사용자가 심볼릭 링크를 만들 수 있도록 허용하는 그룹 정책(예: 개발자 모드 활성화)이나 관리자 권한이 필요합니다. 따라서 일부 사용자 시스템에서는 심볼릭 링크가 지원되지 않을 수도 있습니다. LINKS 파일을 사용하면 설치 프로그램이 Windows의 정션처럼 심볼릭 링크를 처리하는 다른 방법을 사용할 수 있게 됩니다. 이런 파일이 없다면 이 경우 설치 프로그램은 실패할 수밖에 없습니다.
이 PEP는 업데이트된 휠을 설치할 때 설치 프로그램이 수행해야 하는 검사도 설명합니다. 이러한 검사는 휠이 심볼릭 링크를 설치하도록 허용할 때 생기는 보안 위험에 대처하기 위해 존재합니다. 이러한 검사가 왜 중요한지에 대한 자세한 내용은 Security Implications를 참조하십시오.
명세
Wheel 메이저 버전 상향
이 PEP는 wheel 메이저 버전 상향을 요구합니다. 따라서 이전 설치 프로그램이 심볼릭 링크 설치에 조용히 실패하여 사용자 환경을 망가뜨리는 일이 없도록, LINKS를 포함하여 생성된 wheel의 Wheel-Version은 반드시 2.0 이상이어야 합니다. 자세한 내용은 PEP 777을 참조하십시오.
새로운 LINKS 메타데이터 파일
여러 플랫폼에서 심볼릭 링크를 쓸 수 있도록 이 PEP는 새로운 휠 메타데이터 파일인 LINKS를 도입합니다. 다음은 LINKS 파일의 예입니다:
my_package/libfoo.so.3.1.4,my_package/libfoo.so.3
my_package/libfoo.so.3,my_package/libfoo.so
위에서 볼 수 있듯이 LINKS의 형식은 source_path,target_path입니다. 여기서 source_path는 휠에 있는 네임스페이스 루트나 패키지 루트를 기준으로 한 상대 경로입니다. target_path는 휠에 있는 패키지의 패키지 또는 네임스페이스 안에 있는 댕글링되지 않은 경로(즉, 휠의 내용을 추출한 후 파일 시스템에 존재하는 경로)입니다. 따라서 휠에 여러 패키지가 들어 있다면 휠 안의 모든 패키지에 있는 경로를 사용할 수 있습니다.
설치 프로그램 동작 명세
설치 프로그램은 source_path 또는 target_path가 유효한지 판단하기 전에 LINKS 파일에 포함된 모든 링크의 경로를 반드시 해석해야 합니다. 설치 프로그램은 source_path와 target_path가 휠에서 온 네임스페이스나 패키지 안에 있는지 반드시 확인해야 합니다. 설치 프로그램은 휠에 있는 순환 심볼릭 링크를 반드시 거부해야 합니다. 심볼릭 링크 체인(심볼릭 링크를 가리키는 심볼릭 링크가 여러 번 반복되는 것)이 설치 프로그램에서 정한 한도를 넘을 만큼 길면 설치 프로그램은 오류를 발생시켜도 됩니다.
심볼릭 링크가 포함된 휠을 처리할 때 설치 프로그램은 반드시 다음 단계를 따라야 합니다:
.dist-info에LINKS파일이 있는지 확인합니다. 파일이 없으면 더 이상 수행할 단계가 없습니다.- 휠 1.x에서와 마찬가지로 휠의 패키지와 데이터 디렉터리에 있는 모든 파일을 추출합니다.
- 각
source_path와target_path쌍마다target_path가 방금 추출한 패키지 네임스페이스 중 하나에 있는지 확인합니다. - 다음으로, 설치 프로그램이 사이트 디렉터리에서 각 쌍에 대해 어떤 종류든 링크를 만들 수 있는지 확인합니다. 설치 프로그램이 현재 플랫폼에서 파일/폴더
target_path에 대한 링크를 만들 수 없으면 반드시 오류를 발생시켜야 합니다. 실패 사례로는 파일을 대상으로 하는 POSIX 심볼릭 링크를 들 수 있습니다. 설치 프로그램이 Windows에서 실행되고 있고 심볼릭 링크는 만들 수 없지만 정션은 만들 수 있는 경우입니다. 이 경우 설치 프로그램은 링크를 처리할 수 없으므로 반드시 오류를 발생시켜야 합니다. - 마지막으로, 설치 프로그램은
source_path와target_path사이에 플랫폼에 맞는 링크를 반드시 추가해야 합니다.
설치 프로그램은 심볼릭 링크를 처리할 때 기본 동작으로 심볼릭 링크를 생성하는 대신 파일을 복사해서는 안 됩니다. 설치 프로그램은 별도의 설정이나 명령줄 플래그를 통해 그러한 동작을 제공할 수 있습니다.
빌드 백엔드 명세
휠을 생성할 때, 빌드 백엔드는 심볼릭 링크를 휠에 포함할지 결정하면서 심볼릭 링크를 그 대상과 동일한 방식으로 다루어야 합니다. 빌드 백엔드는 LINKS 파일에 끊어진 심볼릭 링크가 없는지 반드시 검증해야 합니다. 빌드 백엔드는 빌드에 포함될 플랫폼 관련 심볼릭 링크를 인식하는 것이 좋습니다. POSIX 시스템에서는 일반적으로 심볼릭 링크가 이에 해당하며, Windows에서는 심볼릭 링크와 정션이 포함됩니다.
하위 호환성
심볼릭 링크를 도입하려면 wheel 형식의 메이저 버전을 올려야 합니다. 이는 wheel 명세에 따라, 새 wheel 형식을 사용하는 새 wheel이 이전 설치 프로그램 도구에서 오류를 발생시킨다는 것을 의미합니다.
“Wheel 2.0”에 관해서는 PEP 777을 참조하십시오.
보안 영향
심볼릭 링크는 주의 깊게 처리하지 않으면 상당히 위험할 수 있습니다. 간단한 예로, 사용자가 sudo pip install malicious를 실행하는데 아무런 보호 장치가 없다면, 악성 패키지가 /etc/shadow를 덮어써서 시스템의 비밀번호 해시를 교체하고 악의적인 로그인을 가능하게 할 수 있습니다.
이 PEP는 앞서 설명한 것과 같은 공격이 일어날 수 없도록, 설치 프로그램이 wheel 내 심볼릭 링크에 대해 수행해야 하는 검사에 관한 여러 요구 사항을 나열합니다. 따라서 설치 프로그램이 이러한 보안 장치를 신중하게 구현하여 패키지 설치 시 악의적인 사용을 방지하는 것이 매우 중요합니다.
특히 설치 프로그램은 다음 검사를 반드시 수행해야 합니다:
- 심볼릭 링크가 휠에서 제공되는 어떠한 패키지나 네임스페이스의 바깥도 가리키지 않는지
- 심볼릭 링크가 끊어지지 않았는지(설치 시점에 대상이 존재하는지)
- 심볼릭 링크가 순환하지 않는지(서비스 거부 요청을 피하기 위해 일정 깊이까지 검사한 후 중단)
제거할 때 심볼릭 링크를 따라가지 마십시오.
교육 방법
최종 사용자는 변경 사항이 생태계 전반에 전파되고 나면 휠의 심볼릭 링크가 주는 이점을 투명하게 누릴 수 있어야 합니다. 플랫폼에서 심볼릭 링크를 지원하지 않는 경우, 설치 프로그램은 명확한 오류 메시지를 제공하고 설치가 실패한 이유를 설명하는 것이 중요합니다.
라이브러리를 빌드하는 사람들을 위해, packaging.python.org의 문서에서 휠의 심볼릭 링크에 대한 사용 사례와 주의 사항(특히 플랫폼 지원)을 설명해야 합니다. 그 밖의 경우에는 빌드 백엔드가 일반 파일을 처리하는 것과 동일한 방식으로 이를 투명하게 처리해야 합니다.
참조 구현
TODO
기각된 아이디어
모든 곳에서 POSIX 심볼릭 링크만 사용하기
이 PEP는 향후 도입될 수 있는 PEP 660 편집 가능 설치에 LINKS를 사용할 수 있도록 허용하고자 합니다. 이 향후 PEP는 Windows를 지원해야 하므로, 정션을 사용해야 할 수도 있습니다.
LINKS에 정션을 사용하지 않기
정션은 Windows에서 폴더 간 심볼릭 링크를 지원하는 제한적인 방법입니다. 정션은 파일을 지원하지 않습니다. 사용자가 폴더만 다른 위치로 링크하고 싶을 수 있고, 향후 PEP 660 구현이 이 기능에 의존해야 할 수도 있으므로 이 PEP는 정션을 허용합니다.
심볼릭 링크를 RECORD 메타데이터 파일에 넣기
이렇게 할 수는 있지만, RECORD 파일이 어수선해집니다. 게다가 가장 간단한 구현에서는 대상을 레코드 끝에 두게 됩니다. 그러면 줄을 훑어보며 휠에 어떤 심볼릭 링크가 있는지 눈으로 확인하기가 더 어려워집니다.
라이브러리 유지 관리자는 Python을 사용하여 라이브러리를 찾아야 합니다
Python을 사용해 라이브러리를 찾는 편이 훨씬 쉬울 것입니다. 하지만 libtorch 같은 일부 라이브러리는 확장 모듈에서 사용되며, 그 자체로도 의존성을 로드해야 합니다. 일부 컴파일된 라이브러리는 Python을 사용해 로더 의존성을 찾을 수 없습니다.
하드 링크 지원 포함하기
이 PEP는 하드 링크에 관한 어떠한 동작도 명시하지 않습니다. 이는 의도된 것입니다. 이는 향후 PEP의 확장으로 남겨 둡니다.
미해결 문제
PEP 660과 편집 가능 설치 지원의 연기
이 PEP는 PEP 660 편집 가능 설치 메커니즘의 명세와 구현을 이후 PEP에서 다룰 미해결 사항으로 남겨 둡니다. 이를 이 PEP에서 명시해야 합니까?
보안
이 PEP가 새로운 보안 취약점을 허용하지 않는지 확인하기 위해 검토가 필요합니다. 사용자를 보호하기 위해 심볼릭 링크의 원본이나 대상에 추가로 두어야 할 제한이 있습니까?
패키지 간 심볼릭 링크 허용하기
이는 대형 라이브러리 같은 의존성을 여러 휠에 나누어 두되 주 상위 휠에서 사용할 수 있게 하려는 프로젝트에 유용할 수 있습니다.
LINKS의 형식
현재 형식은 RECORD에서 파생되었지만, 더 나은 형식이 있을 수도 있습니다.
이전 논의
https://discuss.python.org/t/symbolic-links-in-wheels/1945/25
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.