Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
name: 'Setup Node + pnpm'
description: 'Sets up Node.js (LTS by default) with pnpm and dependency caching.'
inputs:
node-auth-token:
description: 'Optional token exposed as NODE_AUTH_TOKEN to pnpm-related steps. Defaults to github.token.'
required: false
default: ''

runs:
using: 'composite'
steps:
- name: Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # 6.0.8
env:
NODE_AUTH_TOKEN: ${{ inputs.node-auth-token || github.token }}
with:
run_install: false

- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # 6.4.0
env:
NODE_AUTH_TOKEN: ${{ inputs.node-auth-token || github.token }}
with:
node-version-file: .node-version
cache: 'pnpm'
cache-dependency-path: pnpm-lock.yaml

- name: Install dependencies
shell: bash
env:
NODE_AUTH_TOKEN: ${{ inputs.node-auth-token || github.token }}
run: pnpm install --frozen-lockfile
37 changes: 6 additions & 31 deletions .github/workflows/release-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,6 @@ name: Release (reusable)
on:
workflow_call:
inputs:
npm-scope:
description: 'npm scope to authenticate (e.g. @kin0992). Leave empty for tag-only consumers that do not publish to a registry.'
required: false
type: string
default: ''
registry-url:
description: 'npm registry to authenticate against.'
required: false
type: string
default: 'https://registry.npmjs.org'
provenance:
description: 'Publish with npm provenance (requires id-token: write and a public registry).'
required: false
Expand All @@ -25,9 +15,6 @@ on:
app_private_key:
description: 'GitHub App private key (PEM).'
required: true
npm_token:
description: 'Token for the target npm registry (e.g. an npmjs.org automation token). Required only when npm-scope is set.'
required: false

permissions:
contents: read
Expand Down Expand Up @@ -66,23 +53,12 @@ jobs:
- name: Build
run: pnpm turbo run build

- name: Configure npm scope auth
if: ${{ inputs.npm-scope != '' }}
env:
NPM_SCOPE: ${{ inputs.npm-scope }}
REGISTRY_URL: ${{ inputs.registry-url }}
run: |
set -euo pipefail
host="${REGISTRY_URL#https://}"
host="${host#http://}"
host="${host%/}"
# Write the token as an unexpanded ${NODE_AUTH_TOKEN} reference so the
# secret is never persisted to disk; npm/pnpm interpolate it from the
# environment at publish time. Runs after Build so no earlier pnpm
# invocation sees the unresolved placeholder.
echo "${NPM_SCOPE}:registry=${REGISTRY_URL}" >> .npmrc
echo "//${host}/:_authToken=\${NODE_AUTH_TOKEN}" >> .npmrc

# Publishing uses npm Trusted Publishing (OIDC): no npm token is written to
# disk or exposed in the environment. npm exchanges this workflow's id-token
# for a short-lived registry credential and signs provenance automatically.
# Each package must have a Trusted Publisher configured on npmjs.org that
# points at this repo's release.yml workflow, and npm must be >= 11.5.1
# (satisfied by the Node version in .node-version).
- name: Create release PR or publish
uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # 1.8.0
with:
Expand All @@ -92,5 +68,4 @@ jobs:
title: 'Release new artifacts'
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
NPM_CONFIG_PROVENANCE: ${{ inputs.provenance }}
4 changes: 1 addition & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ jobs:
permissions:
contents: write
pull-requests: write
id-token: write # required for npm provenance
id-token: write # required for Trusted Publishing + provenance
uses: ./.github/workflows/release-reusable.yml
with:
npm-scope: '@kin0992'
secrets: inherit
32 changes: 12 additions & 20 deletions CONSUMING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ jobs:

Consumers call the reusable workflow `release-reusable.yml`. `release.yml` in this repo is a thin local entry-point — do not reference it from another repository.

There are two modes:
Publishing uses **npm Trusted Publishing** (OIDC): the workflow exchanges the job's `id-token` for a short-lived npmjs.org credential and npm signs **provenance** automatically. No npm token is stored or passed. Each published package needs a Trusted Publisher configured on npmjs.org (see Prerequisites).

- **Publishing** — set `npm-scope` and provide the `npm_token` secret. The workflow authenticates to the registry and your `release` script publishes packages.
- **Tag-only** — omit `npm-scope` (and `npm_token`). The npm auth step is skipped entirely, so a repo whose `release` script only runs e.g. `changeset tag` needs no npm credentials.
If your `release` script only creates git tags (e.g. `changeset tag`) and never runs `npm publish`, none of the npm / Trusted-Publishing setup applies.

```yaml
name: Release
Expand All @@ -85,33 +84,26 @@ jobs:
permissions:
contents: write
pull-requests: write
id-token: write # required for npm provenance
id-token: write # required for Trusted Publishing + provenance
uses: kin0992/dev-toolkit/.github/workflows/release-reusable.yml@main
with:
npm-scope: '@yourscope'
# registry-url defaults to https://registry.npmjs.org
# provenance defaults to true (needs id-token: write and a public registry)
# provenance defaults to true; pass `provenance: false` to opt out
secrets:
app_id: ${{ secrets.APP_ID }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
npm_token: ${{ secrets.NPM_TOKEN }}
```

**Inputs:**

| Input | Required | Default | Description |
| -------------- | -------- | ---------------------------- | ---------------------------------------------------------------- |
| `npm-scope` | no | `''` | npm scope to authenticate (e.g. `@yourscope`). Empty = tag-only. |
| `registry-url` | no | `https://registry.npmjs.org` | Registry the scope is authenticated against. |
| `provenance` | no | `true` | Publish with npm provenance (needs `id-token: write`). |
| Input | Required | Default | Description |
| ------------ | -------- | ------- | ------------------------------------------------------ |
| `provenance` | no | `true` | Publish with npm provenance (needs `id-token: write`). |

**Secrets:**

| Secret | Required | Description |
| ----------------- | -------- | --------------------------------------------------------------------- |
| `app_id` | yes | GitHub App client ID used to mint a token for git ops. |
| `app_private_key` | yes | GitHub App private key (PEM). |
| `npm_token` | no | Token for the target registry. Required only when `npm-scope` is set. |
| Secret | Required | Description |
| ----------------- | -------- | ------------------------------------------------------ |
| `app_id` | yes | GitHub App client ID used to mint a token for git ops. |
| `app_private_key` | yes | GitHub App private key (PEM). |

**Prerequisites:**

Expand All @@ -120,7 +112,7 @@ jobs:
- Create a GitHub App with `contents: write` and `pull-requests: write` permissions on your repository.
- Add `APP_ID` (the numeric App ID — used as `client-id`) and `APP_PRIVATE_KEY` (the PEM private key) as repository secrets.
- Install the GitHub App on the repository.
- For publishing to npmjs.org, generate an **Automation** access token for an account that owns (or is a member of) the target scope and add it as the `NPM_TOKEN` repository secret.
- For publishing to npmjs.org, configure **Trusted Publishing** once per package: on npmjs.org open the package → **Settings → Trusted Publisher → GitHub Actions**, and set the owner/repo to your consumer repo and the workflow filename to your release workflow (e.g. `release.yml`). No npm token is needed. (A brand-new package may need an initial token-based publish before a trusted publisher can be attached — see npm's docs.)
- Provenance requires the repository to be **public** and the job to grant `id-token: write`. Each published package should set `"publishConfig": { "access": "public", "provenance": true }`.

### Security analysis (CodeQL + secret scan + pnpm audit)
Expand Down
2 changes: 0 additions & 2 deletions infra/Pulumi.prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@ config:
devToolkit:repoName: dev-toolkit
devToolkit:defaultBranch: main
github:owner: kin0992
devToolkit:npmToken:
secure: AAABAJBpCXqVz2KYKQtgTPB4oEUkgDOLc1AhEHGhogxUi8vnCc6VjyIyIR0ilZhWdozxWL2eByCJ+w8dW9o/YyJ8o2j/XADZ
devToolkit:pulumiAccessToken:
secure: AAABAFzzntAVe+s+2gBaaraLf9IrltK0s4ReAMCJ/FTm3/37kuSOyzOeZQPZR0GetzDO9Oj1A+i6qaJn53h6A0ct9lEmbIitL7Ap5Q==
9 changes: 0 additions & 9 deletions infra/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import * as github from '@pulumi/github';

const cfg = new pulumi.Config('devToolkit');
const repoName = cfg.get('repoName') ?? 'dev-toolkit';
// npmjs.org Automation token consumed by the release workflow to publish
// @kin0992/* packages with provenance.
const npmToken = cfg.requireSecret('npmToken');
// Pulumi Cloud access token consumed by the IaC drift/deploy workflows to
// authenticate the Pulumi CLI in non-interactive CI runs.
const pulumiAccessToken = cfg.requireSecret('pulumiAccessToken');
Expand Down Expand Up @@ -82,12 +79,6 @@ new github.RepositoryDependabotSecurityUpdates('dependabot-updates', {
enabled: true,
});

new github.ActionsSecret('npm-token', {
repository: repo.name,
secretName: 'NPM_TOKEN',
value: npmToken,
});

new github.ActionsSecret('pulumi-access-token', {
repository: repo.name,
secretName: 'PULUMI_ACCESS_TOKEN',
Expand Down
Loading