npm 자동 배포에 사람 승인을 넣으려면 토큰 이름만 바꾸는 것으로는 부족합니다. CLI 버전, 명령, 2FA, 패키지 권한을 함께 전환해야 합니다.
검증 기준일: 2026년 9월 29일. GitHub의 stage-only npm 토큰 발표와 npm의 staged publishing 공식 문서를 기준으로 요구조건을 대조했습니다. 실제 npm 패키지를 게시하거나 토큰을 만들지는 않았고, 계정 정보가 없는 로컬 점검기에서 위험한 초기 조건과 전환 완료 조건을 직접 입력해 결과 변화를 확인했습니다.
stage-only 토큰이 바꾸는 것은 공개 권한이다
일반적인 자동 배포는 CI가 빌드와 테스트를 마친 뒤 npm publish까지 실행합니다. 장점은 빠른 공개지만, 장기 토큰이나 워크플로가 탈취되면 검토할 틈 없이 새 버전이 레지스트리에 올라갈 수 있습니다. 사람의 확인이 GitHub Actions 승인 단계에 있더라도 npm 권한 자체가 직접 게시를 허용하면 우회 경로가 남습니다.
stage-only 토큰은 새 버전을 즉시 공개하지 못하게 하고 npm stage publish로 검토 대기 상태만 만들게 합니다. 그다음 관리자가 대기 버전을 확인하고 2FA를 거쳐 승인해야 공개됩니다. 여기서 핵심은 “CI가 패키지를 전송한다”와 “새 버전이 공개된다”를 분리하는 것입니다. 자동화는 반복 작업을 맡고, 최종 공개는 별도의 사람 인증 경계에서 결정합니다.
다만 이 권한은 토큰을 읽기 전용으로 만드는 기능이 아닙니다. npm 공식 문서에 따르면 stage-only 토큰도 dist-tag 이동과 기존 버전 폐기 같은 쓰기 작업을 할 수 있습니다. 따라서 유출돼도 아무 피해가 없다는 뜻이 아니며, 대상 패키지 제한·짧은 만료 기간·IP 제한·비밀 저장소 보호가 계속 필요합니다.
전환 전에 확인할 7개 필수 조건
staged publishing은 모든 npm 프로젝트에 바로 적용되는 기능이 아닙니다. 다음 조건 가운데 하나라도 빠지면 CI 파일을 먼저 바꾸기보다 환경과 권한을 정리해야 합니다.
- Node.js 22.14.0 이상: npm 공식 요구조건의 최소 런타임을 충족해야 합니다.
- npm CLI 11.15.0 이상: 이 버전부터
npm stage명령을 사용할 수 있습니다. - 기존 npm 패키지: 아직 레지스트리에 없는 새 패키지는 staged publishing 대상으로 시작할 수 없습니다.
- 패키지 쓰기 권한: 토큰이나 OIDC 주체가 해당 패키지에 stage를 만들 권한이 있어야 합니다.
- 관리자 계정 2FA: 대기 버전을 승인하거나 거절할 때 사람 인증이 필요합니다.
- 직접 게시 차단: granular access token은 Read and write (stage only), OIDC는 stage-only 권한으로 제한합니다.
- CI 명령 변경: 워크플로의
npm publish를npm stage publish로 바꿉니다.
이 목록은 독립적인 선택 항목이 아닙니다. npm만 올리고 명령을 그대로 두면 stage-only 토큰에서 E_STAGE_REQUIRED가 발생합니다. 반대로 명령만 바꾸고 관리자의 2FA를 준비하지 않으면 대기 버전은 만들 수 있어도 승인 단계에서 멈춥니다. 버전, 인증, 명령, 사람 역할을 하나의 변경 단위로 다뤄야 합니다.
직접 실행: 위험한 초기값에서 승인 경계까지
검증일: 2026년 9월 29일. 환경: Windows Chromium, 1200×675, 로컬 정적 HTML. 초기 입력: Node.js 22.13.1, npm 11.14.0, 기존 패키지 없음, 쓰기 권한 없음, 2FA 비활성, 직접 게시 가능한 토큰, npm publish. 변경 입력: Node.js 22.14.0, npm 11.15.0, 기존 패키지와 쓰기 권한 있음, 2FA 활성, stage-only 토큰, npm stage publish.
첫 화면은 실제 장애를 만들기 위한 레지스트리 호출이 아니라, 변경 전 구성을 명시적으로 기록한 기준선입니다. 자동화 토큰을 화면에 넣지 않았고 실제 조직·패키지 이름도 사용하지 않았습니다. “CI → 직접 공개 가능 · 사람 승인 없음”이라는 흐름이 보여 주듯, 실패의 핵심은 개별 값보다 공개 경계가 자동화 안에 남아 있다는 점입니다.
관찰 결과: 일곱 항목을 모두 충족했을 때 통과 점수는 7/7, 판정은 “단계 전환 준비”, 흐름은 “CI stage → 보류 상태 → 관리자 검토 → 2FA 승인 → 공개”로 바뀌었습니다. 화면과 영상은 같은 실행 세션에서 기록했고 서로 다른 프레임 변화를 포함합니다. 이 결과는 공식 요구조건을 입력한 로컬 사전점검의 성공이며, npm 레지스트리에서 실제 패키지가 게시됐다는 증거는 아닙니다.
GitHub Actions 워크플로를 바꾸는 순서
운영 중인 워크플로에서는 한 번에 토큰과 명령을 교체하지 말고, 되돌릴 지점을 남긴 순서로 진행하는 편이 안전합니다. 먼저 현재 게시 작업의 트리거, 대상 브랜치, 환경 승인, 패키지 이름, provenance 설정을 기록합니다. 다음으로 Node.js와 npm 버전을 최소 요구조건 이상으로 고정하고, 테스트·패키징까지만 수행하는 실행이 성공하는지 확인합니다.
# 개념 예시: 실제 저장소의 action 버전과 권한은 별도 검토
- run: npm publish
+ run: npm stage publish
그다음 npm 설정에서 대상 패키지에만 접근하는 stage-only 인증을 준비합니다. 장기 토큰을 쓰는 경우 GitHub Actions secret을 새 값으로 교체하되 로그·캐시·artifact에 토큰이 남지 않는지 확인합니다. 가능하면 장기 토큰 대신 OIDC 기반 trusted publishing을 먼저 검토하고, 그 구성도 직접 게시를 허용하지 않는 stage-only로 제한합니다.
마지막으로 CI가 stage를 만들면 관리자에게 stage ID와 검사 대상 tarball 정보를 전달합니다. 관리자는 npm stage list, npm stage view, npm stage download로 버전과 파일을 살핀 뒤 승인하거나 거절합니다. 승인에는 2FA가 필요하고, 이 시점에야 버전이 공개됩니다. 자동 배포의 책임 경계를 분명히 하려면 CI 작업자와 승인자를 분리하고 승인 근거를 릴리스 기록에 남기는 것이 좋습니다.
검토 단계에서 실제로 볼 항목
사람 승인을 추가했다고 해서 검토 품질이 자동으로 좋아지는 것은 아닙니다. 관리자가 stage ID만 보고 승인하면 새로운 단계가 형식적인 버튼으로 바뀝니다. 최소한 패키지 버전, dist-tag, tarball 파일 목록, 빌드 산출물, 의존성 잠금 변경, provenance, changelog, 테스트 결과를 함께 봐야 합니다.
- 버전 충돌: staged 버전도 공개 버전과 같은 semver 고유성을 사용하므로 이미 대기 중인 버전을 다시 만들 수 있는지 확인합니다.
- 민감 파일:
npm pack --dry-run또는 stage download 결과에서 환경 파일·내부 문서·소스맵 포함 여부를 봅니다. - tag: prerelease를 latest로 잘못 올리지 않도록
--tag값을 검토합니다. - 승인자: 배포를 시작한 사람과 같은 사람이 무조건 승인하지 않도록 소유권과 비상 대체자를 정합니다.
- 시간 제한: 오래 방치된 stage는 코드와 의존성이 달라질 수 있으므로 재검토 또는 거절 기준을 둡니다.
기존 자동화 변경을 작은 단위로 검증하는 방법은 AI 프롬프트 회귀 테스트 글의 기준선·결과 비교 방식과 같습니다. 배포 전에 비밀값과 실행 권한을 별도로 확인하려면 AI 코딩 보안 점검도 함께 참고할 수 있습니다.
실패 조건과 되돌리기 계획
첫 번째 실패 조건은 CI에서 E_STAGE_REQUIRED가 발생하는 경우입니다. stage-only 토큰을 연결했지만 명령이 여전히 npm publish인 상태일 가능성이 큽니다. 실패를 직접 게시 가능한 토큰으로 우회하지 말고 명령과 CLI 버전을 다시 확인합니다.
두 번째는 npm stage 명령을 찾지 못하는 경우입니다. 로컬 개발자 환경만 올리고 CI 러너의 npm이 낮을 수 있습니다. 워크플로 로그에서 node --version과 npm --version을 비밀값 없이 출력해 실제 실행기를 확인합니다. 프로젝트의 engines 범위와 런타임 호환성도 함께 검토해야 합니다.
세 번째는 stage는 만들어졌지만 승인이 불가능한 경우입니다. 기존 패키지 여부, 쓰기 권한, 승인자 2FA, malware scan 완료 상태, stage 소유권을 확인합니다. 오류 원인을 모르는 상태에서 같은 버전을 반복 제출하면 대기열만 복잡해질 수 있으므로 기존 stage를 먼저 조회합니다.
되돌리기는 “다시 직접 게시”를 기본값으로 삼지 않습니다. 새 워크플로를 중지하고 기존 공개 버전을 유지한 채, 실패한 stage를 거절하거나 만료 정책에 따라 정리합니다. 꼭 긴급 배포가 필요하다면 누가 어떤 위험을 승인했는지 기록하고 별도 비상 절차를 적용해야 합니다.
한계와 주의사항: stage-only도 쓰기 토큰이다
이번 직접 실행은 실제 npm 계정·패키지·토큰 없이 공식 요구조건을 로컬 점검기에 입력한 사전 검증입니다. 따라서 계정별 권한, 조직 정책, 레지스트리 응답, malware scan, 실제 2FA 승인 화면을 확인하지 않았습니다. 독자는 자신의 테스트 패키지와 별도 환경에서 stage 생성부터 승인 전까지 확인해야 합니다.
또한 stage-only 토큰은 새 버전 직접 게시만 제한합니다. dist-tag 이동이나 버전 폐기 권한이 남을 수 있으므로 패키지 범위를 최소화하고 만료일·IP 제한·감사 로그를 운영해야 합니다. 장기 토큰을 제거할 수 있는 환경이라면 OIDC trusted publishing과 stage-only 권한의 조합이 더 나은 선택일 수 있지만, 이 경우에도 저장소·워크플로·환경 매핑이 과도하게 넓지 않은지 검토해야 합니다.
결론적으로 안전한 전환은 “토큰 교체”가 아니라 네 요소의 동시 변경입니다. CI는 공개 대신 stage까지만 수행하고, 관리자는 tarball과 버전을 검토하며, 2FA가 최종 공개를 승인하고, 토큰의 남은 쓰기 권한은 별도로 제한합니다. 이 경계를 실제 배포 기록에 남겨야 자동화 속도와 사람 검토가 함께 작동합니다.