-
Notifications
You must be signed in to change notification settings - Fork 0
chore: add automated npm release tooling #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| name: Publish to npm | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - 'v*' | ||
|
|
||
| jobs: | ||
| publish: | ||
| runs-on: ubuntu-latest | ||
| # 環境保護: production環境を使用(要手動承認設定) | ||
| environment: | ||
| name: npm-publish | ||
| url: https://www.npmjs.com/package/react-github-ribbons | ||
|
|
||
| # 最小権限原則 | ||
| permissions: | ||
| contents: read | ||
| id-token: write # provenance署名用 | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||
| with: | ||
| # タグの完全な履歴を取得 | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Verify tag format | ||
| run: | | ||
| TAG_NAME="${GITHUB_REF#refs/tags/}" | ||
| if ! [[ "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | ||
| echo "Error: Invalid tag format. Expected vX.Y.Z or vX.Y.Z-prerelease" | ||
| exit 1 | ||
| fi | ||
| echo "Tag format verified: $TAG_NAME" | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@60edb5dd545a775178f52524783378180ac39da4 # v4.0.2 | ||
| with: | ||
| node-version: '20.x' | ||
| registry-url: 'https://registry.npmjs.org' | ||
| cache: 'npm' | ||
|
|
||
| - name: Verify package-lock.json integrity | ||
| run: | | ||
| if ! npm ci --dry-run; then | ||
| echo "Error: package-lock.json integrity check failed" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci --audit=true | ||
|
|
||
| - name: Audit dependencies | ||
| run: | | ||
| npm audit --audit-level=high || { | ||
| echo "Warning: High severity vulnerabilities detected" | ||
| # 本番環境では exit 1 を検討 | ||
| } | ||
|
|
||
| - name: Lint | ||
| run: npm run lint | ||
|
|
||
| - name: Build | ||
| run: npm run build | ||
|
|
||
| - name: Test | ||
| run: npm test | ||
|
|
||
| - name: Verify package contents | ||
| run: | | ||
| # distディレクトリが存在し、空でないことを確認 | ||
| if [ ! -d "dist" ] || [ -z "$(ls -A dist)" ]; then | ||
| echo "Error: dist directory is missing or empty" | ||
| exit 1 | ||
| fi | ||
| # 必須ファイルの存在確認 | ||
| if [ ! -f "dist/index.js" ] || [ ! -f "dist/index.cjs" ] || [ ! -f "dist/index.d.ts" ]; then | ||
| echo "Error: Required build artifacts are missing" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Verify package version matches tag | ||
| run: | | ||
| TAG_VERSION="${GITHUB_REF#refs/tags/v}" | ||
| PACKAGE_VERSION=$(node -p "require('./package.json').version") | ||
| if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then | ||
| echo "Error: Tag version ($TAG_VERSION) does not match package.json version ($PACKAGE_VERSION)" | ||
| exit 1 | ||
| fi | ||
| echo "Version verified: $PACKAGE_VERSION" | ||
|
|
||
| - name: Publish to npm | ||
| run: npm publish --provenance --access public | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
|
|
||
| - name: Create GitHub Release | ||
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | ||
| with: | ||
| script: | | ||
| const tagName = context.ref.replace('refs/tags/', ''); | ||
| await github.rest.repos.createRelease({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| tag_name: tagName, | ||
| name: tagName, | ||
| generate_release_notes: true, | ||
| }); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,7 @@ | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| "yarn": false, | ||||||||||||||||||||||||||||||
| "anyBranch": false, | ||||||||||||||||||||||||||||||
| "2fa": false, | ||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disabling two-factor authentication (2FA) for publishing ( |
||||||||||||||||||||||||||||||
| "contents": ".", | ||||||||||||||||||||||||||||||
| "cleanup": true | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disable 2FA requirement in .nprc introduces security risk. The setting Enable 2FA verification to strengthen package security: {
"yarn": false,
"anyBranch": false,
- "2fa": false,
+ "2fa": true,
"contents": ".",
"cleanup": true
}If there are operational reasons for disabling 2FA here, consider implementing compensating controls such as:
📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| # Security Policy | ||
|
|
||
| ## Release Security | ||
|
|
||
| このプロジェクトでは、サプライチェーン攻撃を防ぐため、以下のセキュリティ対策を実施しています。 | ||
|
|
||
| ### 🔒 実装済みの対策 | ||
|
|
||
| #### 1. GitHub Environment Protection | ||
| - **環境名**: `npm-publish` | ||
| - **保護レベル**: 要手動承認(推奨設定) | ||
| - リリース時に信頼できる管理者の承認が必須 | ||
|
|
||
| #### 2. タグとバージョンの検証 | ||
| - セマンティックバージョニング形式の強制 (`vX.Y.Z`) | ||
| - package.jsonのバージョンとGitタグの一致確認 | ||
| - 不正なタグによる公開を防止 | ||
|
|
||
| #### 3. 依存関係の整合性チェック | ||
| - `package-lock.json`の整合性検証 | ||
| - `npm audit`による脆弱性スキャン | ||
| - 高リスクの依存関係を検出 | ||
|
|
||
| #### 4. ビルド成果物の検証 | ||
| - 必須ファイルの存在確認 | ||
| - 空ディレクトリの検出 | ||
| - 改ざん防止 | ||
|
|
||
| #### 5. GitHub Actions セキュリティ | ||
| - アクションをSHA256ハッシュで固定(タグ改ざん対策) | ||
| - 最小権限の原則(`permissions`で制限) | ||
| - Provenance署名によるパッケージの証明 | ||
|
|
||
| #### 6. NPM Provenance | ||
| - `--provenance`フラグで公開 | ||
| - 署名付きビルド証明書を生成 | ||
| - サプライチェーンの透明性を確保 | ||
|
|
||
| ### 🛡️ 推奨する追加設定 | ||
|
|
||
| #### GitHubリポジトリ設定 | ||
|
|
||
| 1. **ブランチ保護ルール** (`main`/`master`) | ||
| ``` | ||
| Settings → Branches → Add rule | ||
| - Require pull request reviews before merging | ||
| - Require status checks to pass | ||
| - Require signed commits (推奨) | ||
| - Do not allow bypassing the above settings | ||
| ``` | ||
|
|
||
| 2. **タグ保護ルール** | ||
| ``` | ||
| Settings → Tags → Add rule | ||
| - Tag name pattern: v* | ||
| - Require signed commits | ||
| - 管理者のみタグ作成可能に設定 | ||
| ``` | ||
|
|
||
| 3. **Environment Protection** (`npm-publish`) | ||
| ``` | ||
| Settings → Environments → npm-publish | ||
| - Required reviewers: 信頼できる管理者を追加 | ||
| - Wait timer: 5分(誤操作防止) | ||
| - Deployment branches: タグのみ許可 | ||
| ``` | ||
|
|
||
| 4. **Workflow保護** | ||
| ``` | ||
| Settings → Actions → General | ||
| - Require approval for all outside collaborators | ||
| - Fork pull request workflows: Require approval for first-time contributors | ||
| ``` | ||
|
|
||
| #### NPM設定 | ||
|
|
||
| 1. **2要素認証 (2FA) を有効化** | ||
| ```bash | ||
| npm profile enable-2fa auth-and-writes | ||
| ``` | ||
|
|
||
| 2. **NPM Token スコープを限定** | ||
| - Automation token (推奨) | ||
| - 公開のみ許可(読み取り・削除権限なし) | ||
| - トークンの定期更新 | ||
|
|
||
| 3. **パッケージ設定** | ||
| ```bash | ||
| # npmウェブサイトで設定 | ||
| - Require 2FA for package publishing | ||
| - Enable package provenance | ||
| ``` | ||
|
|
||
| ### 🚨 セキュリティインシデント対応 | ||
|
|
||
| #### NPM Tokenが漏洩した場合 | ||
|
|
||
| 1. **即座にトークンを無効化** | ||
| ```bash | ||
| # npmウェブサイト → Access Tokens → Revoke | ||
| ``` | ||
|
|
||
| 2. **GitHub Secretsを更新** | ||
| ``` | ||
| Settings → Secrets and variables → Actions → NPM_TOKEN | ||
| ``` | ||
|
|
||
| 3. **最近のリリースを確認** | ||
| ```bash | ||
| npm view react-github-ribbons versions --json | ||
| ``` | ||
|
|
||
| 4. **不正なバージョンがあれば削除** | ||
| ```bash | ||
| npm unpublish react-github-ribbons@x.x.x | ||
| ``` | ||
|
|
||
| #### 不審なタグが作成された場合 | ||
|
|
||
| 1. **タグを削除** | ||
| ```bash | ||
| git tag -d v1.2.3 | ||
| git push --delete origin v1.2.3 | ||
| ``` | ||
|
|
||
| 2. **GitHub Actionsログを確認** | ||
| ``` | ||
| Actions → Publish to npm → 該当ワークフローの確認 | ||
| ``` | ||
|
|
||
| 3. **環境保護で承認前なら拒否** | ||
|
|
||
| ### 📋 リリースチェックリスト | ||
|
|
||
| リリース担当者は以下を確認してください: | ||
|
|
||
| - [ ] `package.json`のバージョンが正しい | ||
| - [ ] `CHANGELOG.md`が更新されている | ||
| - [ ] すべてのテストが通過 | ||
| - [ ] `npm audit`で高リスクの脆弱性がない | ||
| - [ ] タグ名がセマンティックバージョニングに準拠 | ||
| - [ ] コミットが署名されている(推奨) | ||
| - [ ] 信頼できるブランチからのリリース | ||
|
|
||
| ### 🔗 参考資料 | ||
|
|
||
| - [npm Provenance](https://docs.npmjs.com/generating-provenance-statements) | ||
| - [GitHub Actions Security](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions) | ||
| - [Supply Chain Security Best Practices](https://slsa.dev/) | ||
|
|
||
| ### 報告 | ||
|
|
||
| セキュリティ上の懸念や脆弱性を発見した場合は、公開のIssueではなく、 | ||
| リポジトリ管理者に直接連絡してください。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Missing NPM_CONFIG_PROVENANCE environment variable for provenance signing.
npm provenance requires the NPM_CONFIG_PROVENANCE environment variable set to true in the GitHub Actions workflow, in addition to the
--provenanceflag. Without this environment variable, provenance signing may not be properly configured.Add the missing environment variable:
- name: Publish to npm run: npm publish --provenance --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: trueAdditionally, npm classic token creation is now disabled as of November 19, 2025, and you should migrate to trusted publishing or granular access tokens to avoid disruption. Consider migrating from long-lived tokens to trusted publishers which use short-lived, scoped credentials that eliminate the need for long-lived tokens and reduce security risks.
🤖 Prompt for AI Agents