수정 완료 약 7분

GitHub이 403을 줬다. 열흘간 토큰을 의심했지만, 막은 건 우리 실행 환경이었다

403이라 요청 한도인 줄 알고 열흘간 GitHub 토큰만 고쳤다. 응답 본문을 기록에 남기고 나서야, 막은 것이 GitHub이 아니라 파이프라인이 도는 클라우드 실행 환경이라는 걸 알았다.

이 글은 뉴스 요약이 아니라 이 사이트를 만들면서 있었던 일에 대한 기록입니다.

매일 아침 도구 릴리스를 모으는 수집기가 있다. 챗GPT나 클로드, 코덱스 같은 것들이 무엇을 새로 냈는지 훑어서 그날 브리핑 옆에 붙인다. 그 코덱스가 8월 25일부터 한 건도 안 들어왔다. GitHub이 403을 돌려주고 있었다.

403은 보통 요청이 너무 많다는 신호다. 그래서 나는 열흘 동안 GitHub 토큰을 붙들고 씨름했다. 토큰은 처음부터 문제가 아니었다.

처음엔 한도에 걸린 줄 알았다

인증 없이 GitHub API를 부르면 IP 하나당 시간당 60번까지다. 무인 실행 환경은 여러 작업이 같은 IP를 나눠 쓰니 이 한도가 금방 바닥난다. 토큰을 붙이면 5,000번으로 오른다. 그래서 토큰을 발급해 실행 환경에 넣었다.

다음 날에도 403이었다.

토큰을 바꿔도 안 됐다

토큰이 실행에 실렸는지부터 의심했다. 무인 실행에 환경변수가 안 실리는 함정은 전에도 겪었다. 그래서 실행할 때 토큰이 있는지 없는지만 기록에 남기게 했다. 다음 날 기록은 "있음"이었다.

그러면 토큰이 잘못된 건가. 아니었다. 잘못된 토큰은 403이 아니라 401을 받는다. 403이 왔다는 건 GitHub이 토큰을 일단 받아들였다는 뜻이다.

권한이 좁은 토큰일 수도 있었다. 그래서 public 저장소는 확실히 읽는 종류로 새로 발급해 갈아 끼웠다. 그래도 403이었다.

요청에 User-Agent가 없으면 GitHub이 403을 주기도 한다. 코드를 열어 봤다. User-Agent도 인증 헤더도 제대로 붙고 있었다.

의심한 것왜 아니었나
토큰이 안 실렸다기록에 '토큰 있음'으로 찍혔다
토큰이 잘못됐다잘못되면 401인데 403이 왔다
토큰 권한이 좁다public 읽기용으로 바꿔도 403
User-Agent가 없다코드에 정상적으로 붙어 있었다

의심을 하나씩 지웠는데 403은 그대로였다. 남은 곳은 내가 아직 안 들여다본 데였다. 실패한 요청이 정확히 무슨 답을 받았는가.

상태 코드는 같았지만 본문은 달랐다

그때까지 코드는 403이라는 숫자만 남기고 GitHub이 같이 보낸 본문은 버리고 있었다. GitHub은 왜 막았는지를 그 본문에 적어 준다. 한 줄을 고쳐 본문을 기록에 함께 남기게 했다.

다음 실행에서 답이 나왔다.

{"message": "GitHub access is not enabled for this session. An org admin must connect the Claude GitHub App for this organization."}

rate limit이 아니었다. 요청은 GitHub 서버에 닿지도 못했다. 이 파이프라인이 도는 클라우드 실행 환경이 GitHub으로 가는 요청을 가로채고 있었다. 그 환경은 세션에 연결된 저장소에만 GitHub 접근을 열어 주는데, 코덱스는 남의 저장소라 막힌 것이다.

토큰은 이 벽 앞에서 아무 힘이 없었다. 요청이 GitHub에 닿기 전에 막히니 어떤 토큰을 붙이든 답이 같았다. 열흘간 토큰을 고친 건 닫힌 문 앞에서 열쇠만 바꾼 꼴이었다.

세션에 코덱스 저장소를 함께 연결해 봤다. 저장소는 복제됐지만 API 호출은 여전히 막혔다. 접근을 여는 건 조직 관리자가 GitHub 앱을 연결해야 하는 다른 문제였고, 남의 public 저장소엔 그마저 애매했다.

게이트웨이 밖으로 나가기

가로채는 건 GitHub 도메인으로 가는 요청뿐이었다. 우리 사이트 도메인은 건드리지 않는다. 그래서 우리 사이트에 작은 함수를 하나 뒀다. 게이트웨이 밖에서 도는 이 함수가 GitHub 릴리스를 받아 그대로 넘겨준다. 수집기는 GitHub 대신 우리 주소를 부른다.

넘어오는 내용이 GitHub 원본 그대로라 읽는 코드는 손댈 게 없었다. 무인 실행에서 확인하니 코덱스가 다시 들어왔다. 열흘 만에 잡힌 정식 판의 항목 다섯 개였다.

남는 것

이 저장소에는 자매 격인 기록이 하나 있다. 죽은 피드가 성공 코드로 위장해 열나흘이 걸린 이야기다. 그 글은 이렇게 끝난다. "이번 건은 202로 왔다. 다음엔 200으로 올지도 모른다. 그래서 상태 코드 말고 내용을 보게 해뒀다."

이번엔 403으로 왔다. 그 403은 정말로 한도에 걸렸을 때의 403과 글자 하나 다르지 않았다. 둘을 가른 건 본문 한 줄이었다. 상태 코드는 무엇이 막혔는지 말해 주지만 누가 왜 막았는지는 본문에 있다. 열흘의 값은 그 본문을 안 읽은 값이었다.

← 기록 전체

이 사이트가 무엇을 어떻게 고르는지는 소개에, 매일의 수집·발행 수치는 데이터에 공개돼 있습니다.