- GitHub API를 사용하던 중 PR 코멘트 링크 생성 기능에서 ID 불일치로 링크가 작동하지 않는 문제가 발생
- 조사 결과 GitHub은 GraphQL의 node ID와 REST API의 database ID라는 두 가지 ID 체계를 병행 사용
- node ID를 base64 디코딩한 결과, 하위 32비트에 database ID가 포함되어 있음이 확인되어 간단한 비트마스크 연산으로 변환 가능
- 추가 분석을 통해 GitHub이 MessagePack 기반의 새로운 ID 포맷과 문자열 기반의 레거시 포맷을 혼용하고 있음이 드러남
- 이러한 구조는 GitHub 내부 객체 식별 체계의 이중성을 보여주며, 개발자에게 API 통합 시 주의가 필요함
GitHub의 이중 ID 체계 발견
- Greptile의 AI 코드 리뷰 도구 기능 개발 중, GitHub PR 코멘트 링크가 작동하지 않는 문제 발생
- 저장된 코멘트 ID를 URL에 연결했으나, 클릭 시 GitHub 페이지로 이동되지 않음
- GitHub 문서 확인 결과, GraphQL API의 node ID와 REST API의 database ID가 서로 다른 체계로 존재
- node ID 예시: PRRC_kwDOL4aMSs6Tkzl8
- database ID 예시: 2475899260
- node ID는 GitHub 전체에서 객체를 전역적으로 식별하기 위한 base64 인코딩 문자열, database ID는 정수형 URL 식별자로 사용
node ID와 database ID의 관계 분석
- 여러 PR 코멘트의 node ID와 database ID를 비교한 결과, 두 값이 일정한 간격으로 증가함을 확인
- node ID의 base64 부분을 디코딩하자 96비트 정수가 생성되었으며, 이 값의 하위 32비트가 database ID와 일치
- 예시: PRRC_kwDOL4aMSs6Tkzl8 → 하위 32비트 = 2475899260
- 간단한 비트마스크 연산으로 database ID를 추출 가능
-
decoded & ((1 << 32) - 1) 형태의 연산으로 변환 수행
GitHub의 레거시 ID 포맷
- 오래된 저장소(torvalds/linux)의 node ID를 디코딩하자 다른 형식의 문자열이 나타남
- 예시: MDEwOlJlcG9zaXRvcnkyMzI1Mjk4 → 010:Repository2325298
- 이 포맷은 [객체 타입 번호]:[객체 이름][Database ID] 구조로, 명시적 문자열 기반 식별자임
- 트리 객체의 경우 04:Tree2325298:7201bfb9... 형태로, 리포지토리 ID와 SHA 값을 함께 포함
- GitHub은 레거시 포맷과 새로운 포맷을 병행 사용하며, 객체 유형과 생성 시점에 따라 포맷이 달라짐
새로운 node ID 포맷의 구조
- GitHub의 GraphQL 마이그레이션 가이드는 node ID를 불투명 문자열로 취급하라고 명시하지만, 내부 구조는 존재
- base64 디코딩 후 MessagePack으로 언팩하면 배열 형태의 데이터가 나타남
- 예시: [0, 47954445, 2475899260]
- 배열의 구성
- 첫 번째 요소(0): 버전 식별자로 추정
- 두 번째 요소(47954445): 리포지토리의 database ID
- 세 번째 요소(2475899260): 객체의 database ID
- 객체 유형에 따라 배열 길이가 다르며, 커밋은 SHA를 포함, 리포지토리는 두 요소만 포함
실용적 활용과 결론
- 새로운 node ID에서 database ID를 추출하는 Python 코드 예시
import base64, msgpack
def node_id_to_database_id(node_id):
prefix, encoded = node_id.split('_')
packed = base64.b64decode(encoded)
array = msgpack.unpackb(packed)
return array[-1]
- 이 방식으로 PR 코멘트의 database ID를 직접 추출하여 URL 링크 문제 해결 가능
- GitHub은 현재 MessagePack 기반의 새로운 ID 체계와 문자열 기반의 레거시 체계를 동시에 유지
- 이러한 구조는 GitHub 내부의 전환 과정과 호환성 유지 노력을 보여주며, API를 사용하는 개발자는 ID 포맷 차이에 주의해야 함