package-lock의 resolved가 옛 레지스트리를 가리킴 — npm ci 인증 실패
비공개 npm 패키지를 그동안 GitHub Packages 에 올려 두고 받아 썼고, 사설 레지스트리를 Nexus 로
모으면서 이 패키지들도 같이 옮기게 됐습니다. 패키지를 Nexus 에 올리고 각 프로젝트의 .npmrc 가
새 주소를 보게 바꾸면 끝날 일로 봤습니다.
.npmrc 를 바꾸고 로컬에서 설치해 보니 잘 됐습니다. 그런데 CI 에서 npm ci 가 일부 패키지에서
401 과 403 으로 계속 실패했습니다.
프로젝트마다 package-lock.json 을 커밋해 두고 CI 는 npm install 이 아니라 npm ci 로
설치하고, lock 에 적힌 버전 그대로만 받아서 로컬과 CI 가 같은 트리를 쓰게 하려던 것이었습니다.
증상 — .npmrc는 바꿨는데 옛 주소로
.npmrc 는 분명히 새 레지스트리를 가리키지만, 에러에 찍힌 요청 주소는 옛 GitHub Packages
였습니다.
npm error 401 Unauthorized - GET https://npm.pkg.github.com/@scope%2f...
GitHub 토큰이 없는 새 환경이라 401 이 나는 건데, 애초에 왜 아직도 GitHub Packages 로 가느냐가 문제였습니다.
원인 — 옛 URL로 고정된 lockfile resolved
package-lock.json 은 의존성마다 어디서 받아왔는지를 resolved URL 로 박아 둡니다. 이 lock 이
GitHub Packages 를 쓰던 시절에 만들어졌다 보니 그 URL 들이 전부 npm.pkg.github.com 을 가리키고
있었습니다.
"node_modules/@scope/pkg": {
"resolved": "https://npm.pkg.github.com/@scope/pkg/-/pkg-1.2.3.tgz",
...
}
여기에 npm ci 의 동작이 겹칩니다. lockfile 을 신뢰하고 그대로 재현하는 명령이라 .npmrc
의 레지스트리보다 lock 의 resolved URL 을 우선해서 그 주소로 직접 받으러 갔습니다. .npmrc 를
아무리 바꿔도 lock 안의 옛 GitHub 주소로 가서 토큰이 없어 401 이 났던 것이었습니다. (npm install 은 필요하면 lock 을 갱신하니 로컬에선 문제가 안 보였고, lock 을 고정하는 CI 의 npm ci
에서만 터졌습니다.)
해결 — 새 레지스트리 기준으로 lockfile 재생성
.npmrc 만 바꾸는 걸로는 부족하고 lock 의 resolved 도 새 레지스트리로 옮겨야 하니, lock
을 재생성하면 됩니다.
rm package-lock.json
npm install # 새 .npmrc 기준으로 resolved가 다시 써짐
이후 package-lock.json 의 resolved 가 내부 레지스트리 주소로 바뀐 걸 확인하고 커밋했습니다.
스코프 패키지는 .npmrc 에 스코프별 레지스트리도 명시해 둡니다.
@scope:registry=https://<내부-레지스트리>/repository/npm-group/
스코프별로 다른 레지스트리를 쓸 거면 이 줄이 있어야 합니다.
lockfile의 resolved와 npm ci의 lock 고정
레지스트리를 옮길 때는 .npmrc 만 바꾸면 끝난 것 같지만 lockfile 에도 레지스트리 주소가
resolved 로 박혀 있고, npm ci 는 그 lock 을 그대로 따라가서 재생성하지 않으면 옛 주소로 계속
가게 됩니다.
로컬 npm install 은 되면서 CI npm ci 만 실패한다는 증상 자체가 이 둘의 동작 차이를
가리킵니다. 앞은 필요하면 lock 을 갱신하고 뒤는 lock 을 고정하니, 이 조합이 보이면 .npmrc 말고
package-lock.json 의 resolved 부터 열어 보면 됩니다.
댓글 0