npm 패키지 출시 강화은(는) 무엇을 하나요?
목표
npm 패키지를 '로컬에서 작동하는 상태'에서 '정직하고, 검사 가능하며 안전하게 출시할 수 있는 상태'로 만듭니다. 단순한 직감보다 실제 검증을 우선시합니다: 패키지 타볼 내용, 런타임 계약, CI, GitHub 설정, 의존성 업데이트 위생.
시작하기
- 정확한 저장소 확인:
pwd
git status --short --branch
git remote -v
- 패키지 표면 검사:
cat package.json
ls -la
find .github -maxdepth 3 -type f -print 2>/dev/null
- 잠금 파일로 패키지 매니저 감지:
package-lock.json-> npmpnpm-lock.yaml-> pnpmyarn.lock-> yarn
기본적으로 npm 명령어를 사용하지만, 필요 시 감지된 패키지 매니저에 맞게 변환합니다.
패키지 계약
package.json이 진실을 말하도록 만듭니다:
name: 게시 대상이 의도적이며 사용 가능함version: 현재 의도된 게시 버전description,keywords: 레지스트리 검색에 충분히 유용함license: 존재하며LICENSE와 일치함repository,homepage,bugs: 공개 저장소를 가리킴. 공개 저장소 URL이 아직 확정되지 않은 경우, 조용히 생략하지 말고 명시적으로 출시 전 TODO로 표시type,exports,main,bin: 사용자가 가져오거나 실행할 항목과 일치함files: 타볼을 게시 가능한 아티팩트로 제한함engines.node: 패키지가 실제로 지원하는 최소 런타임prepublishOnly또는 동등한 스크립트: 오래된 빌드 출력물이 게시되는 것을 방지함
CLI 패키지의 경우, bin 대상이 빌드되었고, 관련성이 있을 때 실행 가능하며, 사용자가 실행할 명령어를 통해 스모크 테스트되었는지 확인합니다.
런타임 최소 버전 규칙
Node 엔진은 약속이지 장식이 아닙니다.
engines.node가>=20이라고 명시하면, CI는 Node 20을 테스트해야 합니다.@types/node를 지원되는 최소 런타임과 동일한 메이저 라인으로 유지합니다.@types/node를 해당 런타임 라인의 최신 패치로 정확히 고정하는 것을 선호합니다.- 런타임 최소 버전을 올리지 않는 한
@types/node의 메이저 범프를 위로 병합하지 마십시오. engines.node는 권고사항입니다: npm은 사용자가engine-strict를 설정하지 않으면 설치를 강제로 막지 않고 경고만 표시하므로, CI에서 최소 버전을 테스트하는 것이 약속을 실제로 강제하는 방법입니다.
이유: Node 타입은 개발 전용이지만 TypeScript가 허용하는 것을 변경합니다. @types/node@26은 Node 20 사용자에게 실패하는 API를 사용하면서 코드가 컴파일되도록 할 수 있습니다.
검증 명령어
npm 프로젝트의 경우:
npm ci
npm run build --if-present
npm test --if-present
npm audit --omit=dev
npm pack --dry-run
pnpm/yarn의 경우, 동등한 install/build/test/audit/pack 명령어를 사용합니다. 감사 지원이 다른 경우, 있는 그대로 말하고 속이지 마십시오.
CLI의 경우, 최소한 하나의 외부 스모크 테스트도 실행합니다:
node dist/path/to/cli.js --help
npm pack --dry-run
실용적이라면, 압축된 .tgz를 임시 디렉터리에 설치하고 사용자와 똑같이 바이너리를 실행합니다.
타볼 검토
npm pack --dry-run은 레지스트리의 진실 표면입니다. 다음을 확인합니다:
- 빌드 출력물 포함
README.md및LICENSE포함- 소스 전용 쓰레기, 임시 파일, 테스트, 개인 문서, 픽스처, 로컬 데이터베이스, 비밀 정보 제외
- 패키지 크기가 합리적임
- CLI
bin경로가 타볼에 나타남
files가 없으면 추가합니다. .gitignore를 게시 정책으로 의존하지 마십시오.
GitHub 기본 설정
다음을 추가하거나 확인합니다:
.github/workflows/ci.yml.github/dependabot.yml.github/CODEOWNERS.github/pull_request_template.mdSECURITY.md
GitHub 소유 액션에 대해 현재 지원되는 메이저 버전을 사용합니다. Actions가 액션 런타임이 더 이상 사용되지 않는다고 경고하면, CI 통과 후 액션 메이저를 업데이트합니다.
CI는 일반적으로 다음을 포함해야 합니다:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@CURRENT_MAJOR
- uses: actions/setup-node@CURRENT_MAJOR
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build --if-present
- run: npm test --if-present
node-version을 패키지의 지원되는 최소 런타임으로 조정하고, 각 @CURRENT_MAJOR를 액션의 현재 메이저 태그(예: actions/checkout@v4)로 바꿉니다 — 실제 메이저로 고정하고, 플레이스홀더를 커밋하지 마십시오.
Dependabot 기본 설정
패키지 및 GitHub Actions 업데이트를 모두 구성합니다:
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
prefix: deps
include: scope
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
prefix: deps
include: scope
Dependabot이 설정 적용 직후 PR을 열면, 이는 설정이 활성화되었음을 증명하는 것으로 간주합니다. PR을 분류하고, 모든 녹색 체크를 맹목적으로 병합하지 마십시오.
Dependabot 분류
다음 경험 법칙을 사용합니다:
- 런타임 의존성 패치/마이너: 검사 통과하고 릴리스 노트가 평범하면 병합.
- 런타임 의존성 메이저: 릴리스 노트 검사 및 실제 패키지 동작 스모크 테스트.
- 개발 도구 메이저: 빌드/테스트/팩 통과하고 런타임 계약을 변경하지 않으면 병합.
- 런타임 최소 버전 이상의
@types/node: 닫거나 런타임 최소 버전으로 고정하는 것으로 대체. - GitHub Actions 메이저: CI 통과하고 지원 중단 경고를 제거하면 병합.
두 PR이 작은 설정 파일에서 충돌하는 경우, 하나를 병합하고 다른 하나를 업데이트하거나, 두 번째를 직접 적용하고 대체되었음을 명확히 주석을 답니다.
GitHub 원격 강화
저장소/계정이 지원하는 것을 적용한 다음, gh 또는 API 읽기로 실제 설정을 확인합니다.
유용한 설정:
gh repo edit OWNER/REPO \
--delete-branch-on-merge \
--enable-squash-merge \
--enable-merge-commit=false \
--enable-rebase-merge=false \
--allow-update-branch
gh api --method PUT repos/OWNER/REPO/vulnerability-alerts --silent
gh api --method PUT repos/OWNER/REPO/automated-security-fixes --silent
gh api --method PUT repos/OWNER/REPO/actions/permissions/workflow \
-f default_workflow_permissions=read \
-F can_approve_pull_request_reviews=false --silent
Actions 허용 목록의 경우, 워크플로우가 GitHub 소유 액션만 사용하는 경우에만 선호합니다. 타사 액션이 필요한 경우, 가장 작은 집합을 명시적으로 허용합니다.
공개 저장소는 일반적으로 더 많은 보안 제어를 잠금 해제합니다. 무료 요금제의 비공개 저장소는 다음을 차단할 수 있습니다:
- 브랜치 보호 또는 규칙 세트
- 코드 스캐닝
- 비밀 스캐닝
- 푸시 보호
차단된 항목을 명확히 알립니다. 사용할 수 없는 제어를 활성화된 것으로 보고하지 마십시오.
브랜치 보호
가능한 경우, 기본 브랜치를 다음으로 보호합니다:
- 병합 전 풀 리퀘스트 요구
- CI 상태 확인 요구
- 프로젝트에 맞는 경우 브랜치가 최신 상태여야 함 요구
- 대화 해결 요구
- 강제 푸시 차단
- 삭제 차단
- 스쿼시 전용 병합을 사용하는 경우 선형 기록 요구
보호 활성화 후, 사용자가 명시적으로 요청하고 우회를 이해하지 않는 한 main에 직접 푸시하는 것을 중단합니다.
게이트 PR 도구
자동화된 검토/게이트 도구를 사용하는 경우, 게이트가 PR을 생성하도록 요청하기 전에 원격에 기본/베이스 브랜치가 있는지 확인합니다. 비어 있는 새 원격 저장소는 종종 먼저 초기 main 푸시가 필요합니다. 그렇지 않으면 게이트가 기능 브랜치를 검증하고 푸시할 수 있지만, 베이스 ref가 없어 PR 생성에 실패할 수 있습니다.
게시 체크리스트
npm publish 전:
npm whoami가 의도된 계정을 표시함npm view PACKAGE_NAME name version이 이름 상태를 확인함- 게시될 커밋에서 CI가 통과함
npm pack --dry-run이 검토됨- README의 설치/사용 예제가 실제 동작과 일치함
repository,homepage,bugs가 실제 공개 저장소로 연결됨 (또는 URL이 확정되지 않은 경우 명시적으로 TODO로 표시됨)- 출시를 차단하는 Dependabot/보안 알림이 남아 있지 않음
- 버전 범프가 의도적이며, git에서 태그됨 (
git tag vX.Y.Z && git push --tags), CHANGELOG 또는 GitHub 릴리스에 반영됨 - 범위가 있는 패키지 (
@scope/name)는--access public으로 게시됨 (범위 패키지는 기본적으로 제한/비공개)
웹/패스키/2FA 인증을 사용하는 계정의 경우:
npm publish --auth-type=web
검증 가능한 공급망 링크를 위해 출처 증명(provenance)과 함께 CI에서 게시하는 것을 선호합니다. 출처 증명에는 공개 패키지, GitHub Actions와 같은 지원되는 CI, 작업에 대한 id-token: write 권한이 필요합니다:
npm publish --provenance --access public
게시 후:
npm view PACKAGE_NAME version
npm view PACKAGE_NAME bin files engines repository --json
npx -y PACKAGE_NAME --help
출처 증명과 함께 게시된 경우, 레지스트리가 패키지 페이지에 출처 증명 / 'Built and signed' 증명을 표시하는지 확인합니다.
최종 응답
실제로 검증된 것만 보고합니다:
- 실행된 패키지 검사
- 타볼 결과
- 의존성 PR 결정
- 생성되거나 병합된 커밋/PR
- 확인된 GitHub 설정
- 요금제/가시성에 의해 차단된 제어
- 게시된 경우 릴리스 태그 및 출처 증명 상태
- 여전히 사용자 소유인 경우 게시 명령어 또는 게시 후 검증