vidi's blog

npm Trusted Publishers로 GitHub Actions 자동 배포 구축하기.md

npm

들어가며

npm 패키지를 배포할 때마다 로컬에서 npm publish를 실행하는 것은 번거로운 일입니다. GitHub Actions를 통해 자동화하고 싶지만, npm 토큰을 관리하는 것도 부담스럽죠.

이 글에서는 npm의 Trusted Publishers 기능을 사용하여 토큰 없이도 안전하게 자동 배포하는 방법을 소개합니다.

Trusted Publishers란?

npm Trusted Publishers는 OpenID Connect (OIDC)를 사용하여 CI/CD 환경에서 npm에 인증하는 방식입니다.

기존 방식 (Access Token)

  • npm 토큰을 생성하고 GitHub Secrets에 저장
  • 토큰이 노출되면 보안 위험
  • 토큰 만료 시 수동 갱신 필요

Trusted Publishers

  • 토큰 없이 GitHub Actions가 직접 npm에 인증
  • GitHub의 신원 증명을 통해 배포 권한 부여
  • 더 안전하고 관리가 편함

전체 작업 흐름

  1. npm에 첫 배포 (수동)
  2. npm에서 Trusted Publishers 설정
  3. GitHub Actions 워크플로우 작성
  4. Release 생성으로 자동 배포

1단계: 패키지 준비

package.json 설정

Trusted Publishers는 provenance(출처 증명)를 검증하기 때문에 repository 필드가 정확해야 합니다.

{
  "name": "@pksung1/expo-store-signing",
  "version": "1.0.0",
  "description": "Expo config plugin for Android store signing",
  "main": "plugin/build/index.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/pksung1/expo-store-signing.git"
  },
  "homepage": "https://github.com/pksung1/expo-store-signing",
  "publishConfig": {
    "access": "public"
  },
  "scripts": {
    "build": "cd plugin && tsc",
    "prepare": "npm run build"
  },
  "files": [
    "plugin/build",
    "app.plugin.js"
  ],
  "keywords": ["expo", "expo-plugin", "android", "signing"],
  "author": "pksung1",
  "license": "MIT",
  "dependencies": {
    "@expo/config-plugins": "^9.0.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0"
  }
}

중요 포인트:

  • repository.url: 정확한 GitHub 저장소 URL
  • publishConfig.access: scoped package는 public 필수
  • files: 배포될 파일 목록 명시

Scoped Package 사용 시

@username/package-name 형태로 배포하려면 npm Organization이 필요합니다.

https://www.npmjs.com/org/create 에서 Organization을 생성하세요 (무료).

2단계: 첫 배포 (로컬)

Trusted Publishers는 이미 존재하는 패키지에만 적용되므로, 첫 배포는 수동으로 해야 합니다.

# npm 로그인
npm login

# 빌드
pnpm build

# 배포
npm publish --access public

성공하면 다음과 같이 출력됩니다:

+ @pksung1/expo-store-signing@1.0.0

3단계: npm Trusted Publishers 설정

3-1. npm 패키지 페이지 접속

배포된 패키지 페이지로 이동합니다.

https://www.npmjs.com/package/@pksung1/expo-store-signing

3-2. Trusted Publishers 추가

  1. Settings 탭 클릭
  2. Publishing access 섹션으로 스크롤
  3. Trusted publishersAdd a trusted publisher 클릭
  4. 다음 정보 입력:
    • Provider: GitHub Actions
    • GitHub organization/user: pksung1 (본인 username)
    • Repository name: expo-store-signing
    • Workflow filename: publish.yml
    • Environment (선택): 비워두거나 production
  5. Add 클릭

npm Trusted Publishers 설정 화면

4단계: GitHub Actions 워크플로우 작성

.github/workflows/publish.yml 파일을 생성합니다.

name: Publish to npm

on:
  release:
    types: [created]

jobs:
  publish:
    runs-on: ubuntu-latest
    
    # ⭐ 중요: OIDC 인증을 위한 권한
    permissions:
      contents: read
      id-token: write
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          registry-url: 'https://registry.npmjs.org'
          cache: 'pnpm'
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Build
        run: pnpm build
      
      # ⭐ 중요: --provenance 플래그 추가
      - name: Publish to npm
        run: pnpm publish --access public --no-git-checks --provenance

핵심 포인트

1. permissions 설정

permissions:
  contents: read
  id-token: write  # OIDC 토큰 발급을 위해 필수

2. —provenance 플래그

pnpm publish --provenance

이 플래그는 패키지의 출처를 증명하는 서명을 생성합니다. Sigstore를 통해 투명하게 기록됩니다.

3. NODE_AUTH_TOKEN 불필요

기존 방식과 달리 환경변수로 토큰을 전달할 필요가 없습니다. GitHub Actions의 OIDC 토큰이 자동으로 사용됩니다.

5단계: 배포 테스트

버전 업데이트

# 버전 업데이트
npm version patch  # 1.0.0 → 1.0.1

# 커밋 & 태그 푸시
git push --follow-tags

GitHub Release 생성

  1. GitHub 저장소 → Releases
  2. Create a new release 클릭
  3. 태그 선택 (예: v1.0.1)
  4. Release 제목 입력
  5. Publish release 클릭

그러면 자동으로:

  • GitHub Actions 워크플로우 실행
  • 패키지 빌드
  • npm에 자동 배포
  • Provenance 서명 생성

Actions 로그 확인

Actions 탭에서 워크플로우 실행 로그를 확인할 수 있습니다.

성공하면 다음과 같은 로그를 볼 수 있습니다:

npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
npm notice Signed provenance statement with source and build information from GitHub Actions
npm notice Provenance statement published to transparency log
+ @pksung1/expo-store-signing@1.0.1

트러블슈팅

1. 404 Not Found 에러

npm error 404 Not Found - PUT https://registry.npmjs.org/@pksung1%2fexpo-store-signing

원인: 패키지가 아직 존재하지 않음

해결: 로컬에서 첫 배포를 먼저 해야 합니다.

npm publish --access public

2. Provenance 검증 실패

Error verifying sigstore provenance bundle: 
Failed to validate repository information: 
package.json: "repository.url" is "", expected to match "https://github.com/..."

원인: package.jsonrepository.url이 비어있거나 잘못됨

해결: repository.url을 정확히 입력

{
  "repository": {
    "type": "git",
    "url": "https://github.com/username/repo.git"
  }
}

3. Git Unclean 에러

ERR_PNPM_GIT_UNCLEAN Unclean working tree. Commit or stash changes first.

원인: 빌드 과정에서 생성된 파일이 Git 상태를 변경함

해결: --no-git-checks 플래그 추가

pnpm publish --no-git-checks

4. Permissions 에러

Error: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable

원인: id-token: write 권한 누락

해결: 워크플로우에 permissions 추가

permissions:
  contents: read
  id-token: write

모노레포에서 특정 패키지만 배포

pnpm workspace를 사용하는 모노레포라면:

name: Publish Package

on:
  push:
    tags:
      - 'package-name-v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: pnpm/action-setup@v2
        with:
          version: 8
      
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          registry-url: 'https://registry.npmjs.org'
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      
      # 특정 패키지만 빌드
      - name: Build package
        run: pnpm --filter @pksung1/expo-store-signing build
      
      # 해당 디렉토리에서 배포
      - name: Publish to npm
        working-directory: packages/expo-store-signing
        run: pnpm publish --access public --no-git-checks --provenance

보안 강화: Environment 사용

더 안전한 배포를 위해 GitHub Environment를 설정할 수 있습니다.

Environment 생성

  1. GitHub 저장소 → SettingsEnvironments
  2. New environment → 이름: production
  3. Protection rules 설정:
    • Required reviewers: 특정 사용자 승인 필요
    • Wait timer: 배포 전 대기 시간
    • Deployment branches: main 브랜치만 허용

워크플로우에 적용

jobs:
  publish:
    runs-on: ubuntu-latest
    environment: production  # Environment 지정
    permissions:
      contents: read
      id-token: write
    steps:
      # ...

npm Trusted Publishers에도 추가

npm의 Trusted Publishers 설정에서 Environment 필드에 production 입력

이제 배포 시 승인 과정을 거치게 됩니다.

Provenance의 장점

--provenance 플래그를 사용하면 패키지에 다음 정보가 서명되어 기록됩니다:

  • 소스 코드 저장소
  • 빌드 환경 (GitHub Actions)
  • 빌드 시점
  • 커밋 해시

사용자는 이를 통해 패키지의 출처를 검증할 수 있습니다:

npm view @pksung1/expo-store-signing --json | jq .dist.integrity

Sigstore 투명성 로그에서도 확인 가능: https://search.sigstore.dev/

기존 토큰 방식과 비교

항목Access TokenTrusted Publishers
설정 복잡도간단중간
보안토큰 노출 위험더 안전
토큰 관리수동 갱신 필요불필요
Provenance선택사항자동 포함
첫 배포CI에서 가능수동 필요

결론

npm Trusted Publishers를 사용하면:

✅ 토큰 관리 부담 없음
✅ 더 안전한 배포
✅ 자동 provenance 서명
✅ GitHub Release로 간편한 배포

초기 설정은 약간 복잡하지만, 한 번 설정하면 훨씬 편리하고 안전하게 패키지를 관리할 수 있습니다.

참고 자료