github-create-secret is the simplest way to create or refresh a GitHub Actions secret.
It is especially handy for the boring maintenance task every npm publisher has:
rotating NPM_TOKEN across all the GitHub repositories that publish packages.
Instead of opening each repository settings page, encrypting the value yourself,
and replacing the secret manually, this package talks to GitHub's Actions
Secrets API for you.
Create a repository secret from the command line:
GH_TOKEN=ghp_xxx npx github-create-secret \
--owner Kikobeats \
--repo test \
--name NPM_TOKEN \
--value npm_xxx
Refresh an existing secret by enabling --upsert:
GH_TOKEN=ghp_xxx npx github-create-secret \
--owner Kikobeats \
--repo test \
--name NPM_TOKEN \
--value npm_xxx \
--upsert
Alternatively, it can be used as Node.js module:
const createSecret = require('github-create-secret')
async function main () {
await createSecret({
owner: 'Kikobeats',
repo: 'test',
token: process.env.GH_TOKEN,
name: 'NPM_TOKEN',
value: process.env.NPM_TOKEN,
upsert: true
})
}
main()The usual workflow is:
- Create a fresh npm automation token.
- Export it as
NPM_TOKEN. - Export a GitHub token as
GH_TOKEN. - Update every repository that already depends on that secret.
github-create-secret makes step 4 small enough to keep as a script:
import createSecret from 'github-create-secret'
import { Octokit } from '@octokit/rest'
const octokit = new Octokit({ auth: process.env.GH_TOKEN })
async function list (username) {
const repos = await octokit.paginate(
octokit.rest.repos.listForAuthenticatedUser,
{
username,
per_page: 100,
type: 'all'
}
)
return repos.filter(repo =>
!repo.fork &&
!repo.archived &&
repo.owner.login === username
)
}
const updateNpmToken = (repo, opts) =>
createSecret({
owner: repo.owner.login,
repo: repo.name,
token: process.env.GH_TOKEN,
name: 'NPM_TOKEN',
...opts
})
async function main () {
const { data: user } = await octokit.rest.users.getAuthenticated()
const repositories = await list(user.login)
console.log(
`${process.argv.includes('--apply') ? 'Applying' : 'Checking'} ` +
'NPM_TOKEN for ' +
`${repositories.length} repositories`
)
for (const repo of repositories) {
if (!await updateNpmToken(repo)) continue
if (process.argv.includes('--apply')) {
await updateNpmToken(repo, {
value: process.env.NPM_TOKEN,
upsert: true
})
}
console.log(
`https://github.com/${repo.full_name} ` +
`${process.argv.includes('--apply') ? 'updated' : 'would be updated'}`
)
}
}
main()Run it with:
GH_TOKEN=ghp_xxx NPM_TOKEN=npm_xxx node update-npm-token.js
GH_TOKEN=ghp_xxx NPM_TOKEN=npm_xxx node update-npm-token.js --apply
When value is omitted, github-create-secret only checks whether the secret
exists. That lets the script refresh repositories that already publish to npm
without creating NPM_TOKEN in unrelated projects. When upsert is true, the
same call replaces the encrypted secret value. The script runs as a dry run by
default; pass --apply to write the new token to GitHub.
const createSecret = require('github-create-secret')
async function main () {
await createSecret({
owner: 'Kikobeats',
repo: 'test',
token: process.env.GH_TOKEN,
name: 'NPM_TOKEN',
value: process.env.NPM_TOKEN,
upsert: true
})
}
main()owner: GitHub user or organization.repo: Repository name.token: GitHub token with permission to manage Actions secrets.name: Secret name.value: Secret value. If omitted, the call returns whether the secret exists.upsert: Replace the secret when it already exists.
github-create-secret © Kiko Beats, released under the MIT License.
Authored and maintained by Kiko Beats with help from contributors.
kikobeats.com · GitHub Kiko Beats · Twitter @kikobeats