Skip to content

ci: reduce workflow-level permissions to least privilege (#1033) #3

ci: reduce workflow-level permissions to least privilege (#1033)

ci: reduce workflow-level permissions to least privilege (#1033) #3

name: Package Release
on:
push:
branches:
- main
env:
GH_PACKAGES_TOKEN: ${{ secrets.GH_PACKAGES_TOKEN }}
permissions:
# Enable the use of OIDC for trusted publishing and npm provenance
id-token: write
# Enable the use of GitHub Packages registry
packages: write
# Enable the CI validation workflow to checkout the repository
contents: read
# The release workflow involves many crucial steps that once triggered shouldn't be cancelled until
# finished, otherwise we might end up in an inconsistent state (e.g., published to GitHub Packages
# but not npm), so new workflow runs are queued until the previous one has completely finished.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
ci-validation:
name: CI Validation
uses: ./.github/workflows/check-ci-validation.yml
release-and-publish:
name: Release & Publish
runs-on: ubuntu-latest
timeout-minutes: 30
needs: ci-validation
steps:
- name: Generate release bot token
id: release-bot
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.DOIST_RELEASE_BOT_ID }}
private-key: ${{ secrets.DOIST_RELEASE_BOT_PRIVATE_KEY }}
permission-contents: write
permission-issues: write
permission-pull-requests: write
- name: Checkout repository
uses: actions/checkout@v6
with:
token: ${{ steps.release-bot.outputs.token }}
fetch-depth: 0
- name: Prepare Node.js environment
uses: actions/setup-node@v6
with:
cache: npm
node-version-file: .node-version
- name: Cache project 'node_modules' directory
id: node-modules-cache
uses: actions/cache@v5
with:
key: node-modules-cache-${{ hashFiles('**/package-lock.json', '**/.node-version', 'patches/**') }}
path: node_modules/
- name: Install project npm dependencies
if: ${{ steps.node-modules-cache.outputs.cache-hit != 'true' }}
run: |
npm ci
- name: Build package
run: |
npm run build
# The Node.js environment is prepared based on the `.npmrc` file in the repo, which
# configures Doist scoped packages to use the public npm registry with OIDC
# authentication for the initial `semantic-release` publish, after which we remove the
# Doist registry configuration, and prepare the Node.js environment for the GitHub
# Packages registry, providing a predictable release workflow for both registries.
- name: Publish package to public npm registry
id: semantic-release
run: |
npx semantic-release
env:
GITHUB_TOKEN: ${{ steps.release-bot.outputs.token }}
GIT_AUTHOR_EMAIL: [email protected]
GIT_AUTHOR_NAME: Doist Bot
GIT_COMMITTER_EMAIL: [email protected]
GIT_COMMITTER_NAME: Doist Bot
- name: Remove Doist registry configuration from `.npmrc`
if: ${{ steps.semantic-release.outputs.package-published == 'true' }}
run: |
npm config delete @doist:registry --location=project
- name: Prepare Node.js environment for GitHub Packages registry
if: ${{ steps.semantic-release.outputs.package-published == 'true' }}
uses: actions/setup-node@v6
with:
cache: npm
node-version-file: .node-version
registry-url: https://npm.pkg.github.com/
scope: '@doist'
- name: Publish package to private GitHub Packages registry
if: ${{ steps.semantic-release.outputs.package-published == 'true' }}
run: |
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GH_PACKAGES_TOKEN }}