npm 신뢰 구성을 저장했다고 배포 준비가 끝나지 않는다: 48시간 검증 창과 만료 복구
패키지 설정에 trusted publisher를 추가해 두고 다음 정기 릴리스까지 기다렸는데, 정작 배포할 때 인증이 실패한다면 무엇부터 확인해야 할까? 저장소 이름과 워크플로 파일이 맞는지뿐 아니라 아직 검증되지 않은 신뢰 구성이 만료됐는지도 봐야 한다. 설정 화면에 항목이 남아 있다는 사실만으로 배포를 허용하는 구성이라고 판단하면 안 된다.
GitHub의 2026년 10월 2일 공식 변경 안내는 미검증 npm trusted publishing 구성이 생성 후 48시간이 지나면 만료되고 더 이상 배포를 승인하지 못한다고 발표했다. 반면 해당 구성으로 첫 배포가 성공하면 검증 상태가 되어 이 만료 대상에서 제외된다. 따라서 이번 변경의 핵심은 모든 배포 인증을 이틀마다 갱신하는 것이 아니라, 만들어 놓고 한 번도 성공적으로 사용하지 않은 신뢰 관계에 기한을 두는 데 있다.
이 글은 공식 발표와 저장된 npm 문서에 근거한 진단 제안이며, 실제 npm 설정 생성·토큰 교환·패키지 배포를 실행한 검증 보고서는 아니다.
1. 설정 저장, 첫 배포 성공, 토큰 수명을 분리한다
npm 문서의 Troubleshooting은 설정을 저장할 때 npm이 trusted publisher 구성을 검증하지 않는다고 설명한다. 잘못된 저장소나 워크플로 정보는 배포를 시도할 때 드러날 수 있다. 저장 성공은 입력이 보관됐다는 뜻이지, 그 워크플로가 실제로 인증과 배포를 완료했다는 증거가 아니다.
이번 발표에서 48시간은 미검증 구성의 생성 시점부터 적용되는 검증 창이다. 매 실행에서 쓰는 OIDC 토큰이나 레지스트리 토큰의 유효기간을 말하는 숫자가 아니다. 첫 배포가 성공한 구성이 만료에서 제외된다는 설명 역시 이후 모든 실행이 무조건 성공한다는 보증은 아니다. 워크플로 식별자와 권한, 이벤트 조건은 여전히 별도로 맞아야 한다.
48시간은 토큰 수명이 아니라 미검증 구성의 검증 창이다. 첫 배포 성공과 미검증 만료는 서로 다른 결과이며, 실제 제품 화면이 아닌 공식 정책 설명 그림이다. 출처: github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire.
운영 기록에는 설정 저장 시각만 적지 말고, 구성 생성 시각과 해당 구성으로 첫 배포가 성공했는지를 나눠 남기는 편이 좋다. 이는 편집자의 운영 제안이다. 구성 화면의 존재 여부, CI 실행 성공 여부, npm 배포 성공 여부를 한 항목으로 뭉치면 만료와 다른 인증 오류를 구분하기 어렵다.
2. 실패 지점별로 복구 방법이 다르다
아래 표는 공식 수명 정책과 문서의 인증 문제를 결합한 진단 순서다. 같은 오류 문자열만 보고 만료로 확정하지 말고, 실행이 어디까지 도달했는지와 해당 구성의 상태를 함께 확인한다.
| 관찰한 상황 | 먼저 확인할 증거 | 다음 조치 | 피할 오해 |
|---|---|---|---|
| 구성을 만들었지만 아직 첫 배포가 성공하지 않았다 | 생성 시각, 해당 구성으로 수행한 배포 결과 | 의도한 첫 릴리스가 검증 창 안에 가능한지 확인 | 저장 완료를 검증 완료로 기록하지 않는다 |
| 미검증 구성이 만료됐다 | 구성 상태와 첫 성공 배포 유무 | 구성을 다시 만들어 새로운 48시간 창을 시작 | 일반 편집만으로 기한이 연장된다고 가정하지 않는다 |
| 창 안인데 배포 인증이 실패한다 | 저장소·워크플로 식별자, 이벤트, OIDC 권한 | 실제 실행과 설정의 불일치를 먼저 수정 | 실패가 모두 만료 때문이라고 단정하지 않는다 |
| 이미 첫 배포가 성공한 구성이다 | 그 성공이 해당 구성으로 이뤄졌는지 | 이번 만료 정책보다 현재 실패의 별도 원인을 점검 | 모든 검증 완료 구성이 이틀마다 만료된다고 보지 않는다 |
| npm ci에서 private dependency 설치가 실패한다 | 실패 명령, 설치용 읽기 인증 유무 | 비공개 의존성 설치 인증을 별도 점검 | 배포용 신뢰 설정으로 설치 인증까지 해결된다고 보지 않는다 |
실패 명령과 구성 상태를 함께 보는 편집자 제안이다. 재생성이 잘못된 식별자나 허용되지 않는 이벤트까지 고치는 것은 아니다. npm 문서의 설치 인증 구분을 함께 사용했다. 출처: github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire.
설정을 다시 만드는 일은 만료 복구이지, 잘못된 워크플로 식별자나 허용되지 않는 이벤트를 고치는 방법은 아니다. 예를 들어 구성은 새로 만들었는데 워크플로가 여전히 issue_comment에서 배포를 시도하면, 새 검증 창만으로는 발표된 이벤트 거절 조건을 해결하지 못한다. 반대로 npm ci에서 멈춘 실행은 아직 배포 단계에 도달하지 않았을 수 있으므로 배포 구성의 만료를 먼저 원인으로 삼을 근거가 부족하다.
3. 만료된 항목은 남아 있고, 다른 정상 구성은 영향을 받지 않는다
발표에 따르면 만료된 구성은 trusted publisher 설정에 계속 보이지만 패키지별 구성 한도에는 포함되지 않는다. 같은 패키지의 다른 유효한 구성도 영향을 받지 않는다. 그러므로 설정 목록의 항목 수와 실제 배포를 승인할 수 있는 구성 수를 같은 것으로 읽으면 안 된다.
만료 복구는 재생성이다. 일반 편집은 기존 기한을 다시 시작하지 않는다. 저장소 또는 프로젝트 정체성이 바뀌면 새로운 신뢰 관계가 필요하고, 그 새 관계에는 새로운 48시간 검증 창이 적용된다. npm 문서도 기존 연결의 제공자와 필수 필드는 고정되며 이를 바꾸려면 삭제 후 재생성해야 한다고 설명한다. 두 설명을 합쳐 읽을 때는 기존 구성의 단순 편집과 새 연결 생성이라는 동작을 구별해야 한다.
만료 복구와 정체성 변경은 새 신뢰 구성 관점에서 처리해야 한다. 일반 편집은 자동 갱신이 아니며, 다른 정상 구성을 일괄 삭제할 근거도 아니다. 출처: github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire.
독자가 적용할 수 있는 복구 순서는 다음과 같다. 먼저 문제가 있는 구성과 실제 릴리스 워크플로를 특정한다. 만료인지, 식별자가 바뀐 것인지, 별도 인증 오류인지 확인한다. 만료 또는 정체성 변경 때문에 새 연결이 필요하다면 의도한 릴리스가 준비된 시점에 재생성을 진행하고, 그 새 구성으로 첫 배포가 성공했는지 기록한다. 다른 정상 구성을 일괄 삭제하거나 이름만 같은 저장소를 동일 주체로 간주할 이유는 없다.
48시간 안에 검증하려고 내용 없는 버전을 임의로 배포하라는 제안은 아니다. 첫 릴리스가 아직 준비되지 않았다면 생성 시점을 릴리스 계획과 맞추는 편이 더 낫다. 또한 이 글은 자동 갱신이나 만료 알림 기능이 제공된다고 주장하지 않는다. 발표가 설명한 복구는 만료된 구성을 다시 만드는 방식이다.
4. 워크플로 실행 허용과 npm 토큰 수락은 다른 관문이다
같은 발표는 npm이 GitHub Actions의 issue_comment 이벤트에서 나온 trusted publishing 토큰을 거절한다고 명시한다. 기존 pull_request_target 제한에 추가되는 내용이다. 영향을 받는 배포는 push, release, workflow_dispatch처럼 발표에서 허용 예시로 든 이벤트로 옮기라는 안내가 있다.
이것은 GitHub 전체가 해당 이벤트의 워크플로 실행을 금지한다는 뜻이 아니다. GitHub에서 작업이 시작되는 조건과, 뒤에서 npm이 배포용 토큰을 받아들이는 조건은 서로 다른 지점의 통제다. 따라서 실행 로그가 생성됐거나 테스트 작업이 성공했다는 것만으로 npm 배포 인증까지 통과했다고 판단할 수 없다.
npm의 토큰 수락 제한을 GitHub 전체의 워크플로 실행 금지로 확대하지 않는다. 발표의 허용 예시는 모든 이벤트의 완전한 목록이나 보안 보증이 아니다. 출처: github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire.
허용 예시 이벤트로 바꿨다는 사실도 워크플로 전체가 안전하다는 인증서는 아니다. 누가 실행을 시작할 수 있는지, 어떤 코드를 배포하는지, 승인이 필요한지는 별도의 보안 설계다. 이번 변경을 적용할 때는 이벤트명만 바꾸고 끝내지 말고 실제 배포 작업의 실행 경로를 확인해야 한다.
5. 실패 재시도 전에 남길 최소 증거
실패한 릴리스를 무조건 다시 실행하기보다, 해당 구성의 생성 시각·첫 성공 배포 여부·실행 이벤트·사용한 워크플로 파일·실패 명령을 한 기록에 묶어 보자. 이 조합이면 새 구성을 만들지, 연결 정보를 수정하기 위해 재생성할지, 설치 인증부터 고칠지 판단할 수 있다. 비밀 토큰 값 자체를 로그에 남길 필요는 없다.
식별자 불일치는 npm 문서의 진단 항목을 따라 확인한다. 워크플로 파일명과 필드는 정확한 대소문자로 일치해야 하고, GitHub Actions에서는 id-token: write 권한을 확인해야 한다. private dependency 설치는 배포와 다른 인증 문제다. 첫 성공 여부를 확인하는 데도 단지 계정 확인 명령의 성공을 대신 쓰지 말고, 의도한 배포 작업의 실제 결과를 사용한다.
이번 정책은 저장소나 프로젝트 이름의 소유자가 바뀌었을 때 생길 신뢰 위험을 제한하려는 조치로 설명된다. 그렇다고 공격 예방 효과를 숫자로 측정한 발표는 아니며, 이미 검증된 구성의 신뢰를 영구 보증하는 정책도 아니다. 실무에서 얻을 수 있는 가장 구체적인 변화는 설정 저장을 준비 완료로 취급하지 않고, 첫 배포 성공까지 별도 상태로 관리하는 것이다.
출처와 읽기 범위
- GitHub 공식 변경 안내: Unvalidated npm trusted publishing configurations now expire — 2026년 10월 2일 발표. 미검증 구성의 48시간 창, 첫 성공 배포의 면제, 재생성 복구, 이벤트 제한의 직접 근거다. 저장본의 수정 시각이 더 늦더라도 최초 발표일을 바꾸지 않는다.
- npm Docs: Trusted publishing for npm packages — 저장된 문서는 9월 30일 편집본으로 이번 발표보다 앞선다. 설정 저장 시 미검증, 연결 필드 변경, 인증 실패와 private dependency 설치의 범위를 보완하지만 새 만료 정책을 독립적으로 확인하는 근거로 사용하지 않았다.
함께 읽으면 구분이 쉬운 경계
- npm stage-only 토큰이 바꾸는 배포 경계: 자동화는 제출하고 사람은 승인한다 — 자동화와 최종 승인 분리를 다룬다. 이번 글의 미검증 신뢰 구성 수명과는 다른 정책이다.
- 저장소 이름은 같아도 같은 주체가 아니다: GitHub Actions OIDC의 immutable sub 전환 — 저장소 정체성을 식별하는 문제를 더 깊게 다룬다. npm 구성의 48시간 검증 창을 이 기능의 효과로 혼동하지 말자.
- GitHub Actions 실행 보호가 GA가 됐다: pull_request_target을 막기 전에 볼 세 경계 — 워크플로 시작 전 통제와 npm의 배포 토큰 수락을 비교하는 데 도움이 된다.




댓글
댓글 쓰기