Publishing CineplanetCLI to npm
This runbook explains the one-time setup and the recurring release process for
publishing the Rust CLI to the public npm registry. It is written for the
maintainer who owns both the npm package and the GitHub repository.
Status: npm publishing is not configured in this repository yet. Follow the
one-time setup before attempting a release. Do not run npm publish from the
repository root: this is a Rust project and currently has no npm package to
publish.
Release model
Use dist to build native Rust
binaries, upload them to a GitHub Release, generate a small npm installer
package, and publish that installer to npm.
The npm package does not compile Rust on the user's machine. At installation
time it downloads the correct prebuilt binary from the matching GitHub Release
and exposes it as the cineplanet-cli command. This supports both:
npm install --global cineplanet-cli
cineplanet-cli
and:
The Cargo package version, Git tag, GitHub Release, and npm package version must
always match. For example, version 0.2.0 uses tag v0.2.0 and npm version
0.2.0.
This differs from the crafter.run release flow. Crafter publishes JavaScript
built from its monorepo and uses Changesets to create a release PR. This project
publishes generated npm installer metadata plus native binaries, so dist and
version tags are the source of the release workflow. The useful practices kept
from Crafter are CI-only publishing, explicit verification, provenance, release
serialization, and a documented recovery process.
One-time npm account setup
1. Create and verify the account
- Open https://www.npmjs.com/signup.
- Choose a lowercase username, provide an email address, and use a unique
password stored in a password manager.
- Accept npm's terms and create the account.
- Open npm's verification email and verify the email address. npm does not
allow an unverified account to publish.
- Install a current Node.js release and confirm npm login locally:
npm whoami must print the expected maintainer account. Never place the npm
password in GitHub Actions.
2. Enable two-factor authentication
Publishing requires strong authentication. In npmjs.com, open the profile menu,
select Account, and enable Two-Factor Authentication. Prefer a WebAuthn
security key such as Touch ID or a hardware key.
Store the recovery codes in a password manager, separately from the security
key. Add a second security key when possible, and link the maintainer's GitHub
account under npm's recovery options.
3. Choose the package owner and name
There are two reasonable naming models:
cineplanet-cli: unscoped, public, and simplest for npx cineplanet-cli.
@OWNER/cineplanet-cli: public package owned by an npm user or organization.
Users run npx @OWNER/cineplanet-cli.
An npm organization is optional for public packages. Use one when multiple
maintainers need durable team ownership instead of tying releases to one
person. Create it from Profile > Add an Organization, select the free public
package plan, and invite at least one backup maintainer. After the first publish,
grant and verify package access as well as organization membership. For an
unscoped package:
npm owner add BACKUP_NPM_USERNAME cineplanet-cli
npm owner ls cineplanet-cli
For a scoped organization package, grant an npm team read/write access to the
package and verify it in the package's Access settings.
Check the proposed name immediately before configuration:
npm view cineplanet-cli name version
An E404 currently indicates that the name is not published, but availability
can change and does not establish trademark permission. The maintainer must
confirm that the project name and package metadata comply with npm policy and
any applicable Cineplanet trademark requirements before publishing.
One-time repository setup
The following work should be implemented and reviewed in a normal pull request.
1. Complete the Cargo package metadata
Add at least these fields under [package] in Cargo.toml:
[package]
name = "cineplanet-cli"
version = "0.1.0"
description = "Find Cineplanet showtimes with good contiguous seats"
repository = "https://github.com/asther0/cineplanet-cli"
homepage = "https://github.com/asther0/cineplanet-cli"
readme = "README.md"
license = "LICENSE-IDENTIFIER"
Replace LICENSE-IDENTIFIER only after the project has an actual license file
and the owner has selected its SPDX identifier. Do not invent a license during
release setup.
2. Install and initialize dist
Install dist using its current official installation instructions, then run:
During setup:
- Enable GitHub Releases.
- Enable the
npm installer.
- Select the npm scope only if using a scoped package.
- Select the initially supported targets. Do not advertise an operating system
until its binary has been exercised there.
- Enable the npm publish job.
- Enable GitHub artifact attestations (
github-attestations = true) so the
native archives receive attestations separate from the npm installer.
The resulting dist configuration should include the npm installer and publish
job. Depending on the installed dist version, it may appear in Cargo.toml or
dist-workspace.toml and resemble:
[workspace.metadata.dist]
installers = ["npm"]
publish-jobs = ["npm"]
# npm-scope = "@OWNER" # Only for a scoped package.
dist init also generates .github/workflows/release.yml. Treat that file as
generated: change dist settings and rerun dist init instead of hand-editing
the workflow unless the configuration explicitly opts into custom CI.
Validate the generated release plan:
dist plan
dist build
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
Inspect the generated npm package and confirm it exposes exactly one command,
cineplanet-cli, and points to release artifacts from
asther0/cineplanet-cli.
3. Review the generated GitHub workflow
As of August 2026, released dist 0.32.0 does not generate an npm trusted
publishing job. Its built-in npm publisher uses Node 20 and NPM_TOKEN; upstream
OIDC support is still pending. Do not assume that adding id-token: write to the
generated workflow is sufficient.
The supported initial implementation for this repository is therefore:
- Use dist's generated npm publish job.
- Store a short-lived, granular
NPM_TOKEN as a repository secret.
- Migrate to OIDC only when the installed dist release supports it, or replace
the built-in publisher with a reviewed custom publish workflow.
The release workflow must:
- Trigger releases only for version tags such as
v0.2.0. Use GitHub's Rerun
failed jobs operation for recovery; dist's dispatch mode is an alternative
release mode, not an additional trigger.
- Grant only the permissions each job requires.
- Configure
https://registry.npmjs.org as the npm registry.
- Build all advertised target archives before publishing.
- Depend on required branch CI for formatting, tests, and Clippy. The generated
dist workflow builds release binaries but does not replace those checks.
- Use immutable full commit SHAs for release actions where practical. dist can
manage these through github-action-commits; mutable major-version action
tags carry additional supply-chain risk.
The built-in publish job will consume the repository secret as
NODE_AUTH_TOKEN or NPM_TOKEN. Confirm this in the generated file after every
dist upgrade. Do not hand-edit generated CI: dist rejects drift unless
allow-dirty = ["ci"] is deliberately enabled, which also makes future dist
upgrades manual.
When dist gains trusted publishing support, or a custom reusable publish job is
adopted, the publish job needs the equivalent of:
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "24"
registry-url: https://registry.npmjs.org
package-manager-cache: false
- run: npm publish --access public
Node must be at least 22.14.0 and npm at least 11.5.1 for npm OIDC. The
complete dist workflow contains additional planning, native build, artifact
upload, and GitHub Release jobs. Do not replace those jobs with this fragment.
If the publish step lives in a reusable workflow, npm may validate the calling
workflow rather than the called workflow. Configure the exact filename npm
observes, and grant id-token: write in both caller and called workflows.
4. Decide whether to add a protected GitHub environment
The current built-in dist npm job does not declare a GitHub environment. Its
NPM_TOKEN must therefore be a repository secret, not an environment secret.
If the project later adopts a custom publish job, create an environment named
npm under Repository Settings > Environments. Add required reviewers and
prevent self-review if the repository's GitHub plan supports those controls.
Set that custom npm publish job to:
Using an environment is recommended because a tag alone should not silently
publish a permanent registry version. This requires a custom dist publish job
or deliberately maintained custom CI; adding the environment only in GitHub's
settings does not affect the built-in job. If the environment name is included
in npm's trusted publisher configuration, the workflow must use the exact same
case-sensitive name.
Bootstrap the first npm version
npm can attach a trusted publisher only after the package exists. The first
version is therefore a controlled release using the temporary granular token.
- Finish and merge the dist setup PR.
- Confirm the intended package name is still available.
- Create the temporary token and repository secret described in
Configure the npm token.
- Before tagging, run
dist build and find the generated npm package path in
its output. Inspect that exact package rather than running npm commands from
the Rust repository root. For a generated .tar.gz package:
tar -tzf target/distrib/GENERATED-NPM-PACKAGE.tar.gz
tar -xOf target/distrib/GENERATED-NPM-PACKAGE.tar.gz package/package.json
- Push the first release tag and let the reviewed dist workflow publish it.
- Verify the first version as described in Verify a release.
- Restrict the token to only the new package if All Packages was required
for bootstrap, or replace it with a package-scoped token.
Do not run npm publish from this repository root. A manual emergency publish
must target the exact generated tarball, for example
npm publish target/distrib/GENERATED-NPM-PACKAGE.tar.gz --access public, and
should not be used for a normal release.
Never publish an empty placeholder package merely to reserve the name. The
first published package must install and run.
Configure trusted publishing with GitHub OIDC
Trusted publishing is the security target because GitHub issues a short-lived
identity token for one workflow run and no reusable npm credential is stored in
GitHub. It is not supported by dist's built-in npm job in released dist 0.32.0.
Follow this section only after upgrading to a dist version that explicitly
supports npm OIDC, or after implementing and reviewing a custom publish job.
npm configuration
- Open the package on npmjs.com.
- Open Settings > Trusted Publisher.
- Select GitHub Actions.
- Set Organization or user to
asther0.
- Set Repository to
cineplanet-cli.
- Set Workflow filename to the generated release workflow filename, for
example release.yml. Enter the filename only, not .github/workflows/.
- Set Environment name to
npm if the publish job uses that environment.
- Allow
npm publish. For stricter human approval, allow only
npm stage publish and adopt npm staged publishing instead.
- Save and re-check every case-sensitive value. npm does not validate this
configuration until a publish is attempted.
Each npm package can have only one trusted publisher configuration.
GitHub configuration
The publish job must have:
permissions:
contents: read
id-token: write
Do not set NPM_TOKEN or NODE_AUTH_TOKEN on the OIDC publish step. npm
automatically detects GitHub OIDC and exchanges it for a short-lived publish
credential. npm whoami cannot test OIDC because the exchange occurs only for
npm publish or npm stage publish.
After the first successful OIDC release:
- Open Package Settings > Publishing access on npm.
- Select Require two-factor authentication and disallow tokens.
- Revoke any old write tokens.
This setting blocks traditional token publishing but continues to allow the
configured trusted publisher.
For a public npm package built from this public GitHub repository, trusted
publishing automatically includes npm provenance. It attests the small npm
installer package and links it to its source commit and workflow. It does not by
itself attest the native Rust archive downloaded later from GitHub Releases.
Keep dist's GitHub artifact attestations enabled for those archives and verify a
downloaded archive with gh attestation verify PATH --repo asther0/cineplanet-cli.
Configure the npm token (current dist path)
This is the working authentication path for dist 0.32.0. Keep the token
short-lived and migrate to OIDC when the installed dist release supports it.
npm supports granular access tokens; legacy tokens have been removed.
Create the token
- Sign in to npmjs.com.
- Open Profile > Access Tokens > Generate New Token.
- Name it
cineplanet-cli GitHub Actions and document why it exists.
- Enable Bypass two-factor authentication. Non-interactive direct
publishing cannot answer a 2FA prompt.
- Set Packages and scopes to Read and write.
- Select only
cineplanet-cli after the package exists. For the first publish,
npm may require All Packages because the package cannot yet be selected.
- Set Organizations to No access. Organization administration access
does not grant package publishing access.
- Do not set an IP allowlist for GitHub-hosted runners because their outbound
addresses are not stable enough for a practical narrow allowlist.
- Choose the shortest expiration that covers the bootstrap or recovery window.
- Generate and copy the token immediately. npm will not display it again.
Store the token in GitHub
The built-in dist publisher requires a repository secret:
gh secret set NPM_TOKEN --repo asther0/cineplanet-cli
Paste the token when prompted. Do not place it on the command line, in a file,
in .npmrc, or in shell history. Confirm only the secret name is visible:
gh secret list --repo asther0/cineplanet-cli
The equivalent web path is Repository Settings > Secrets and variables >
Actions > New repository secret. Name it NPM_TOKEN. If a future custom
publish job declares environment: npm, move the token to that environment
instead.
Use the token in the workflow
actions/setup-node writes a temporary runner .npmrc that reads
NODE_AUTH_TOKEN. Expose the GitHub secret only to the publish step:
- name: Publish npm installer
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Some release tools expect NPM_TOKEN directly. If dist requires it, pass both
names from the same secret only to that job:
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Never print either environment variable. GitHub masking reduces accidental
exposure but does not make logging a secret safe. Token authentication does not
automatically produce npm provenance. Adding --provenance also requires an
OIDC-capable GitHub-hosted job with id-token: write; do not add the flag to the
generated dist job without implementing and reviewing that complete setup.
Rotate or revoke the token
Tokens expire and are tied to the creating user's package permissions. Before
expiration, create a replacement with the same restricted permissions, replace
the GitHub secret, verify one publish, and revoke the old token under npm
Access Tokens. If exposure is suspected, revoke first and investigate
before releasing again.
After OIDC succeeds, remove the GitHub NPM_TOKEN secret and revoke the token.
Normal release process
Do not manually publish normal releases. The maintainer prepares a version; the
tag causes GitHub Actions to build and publish that exact source revision.
1. Select the version
Use the smallest SemVer increment that describes the user-visible change:
patch: compatible bug fix or internal improvement.
minor: backward-compatible capability or command behavior.
major: breaking CLI, output, configuration, installation, or platform
support change.
Before 1.0.0, document how the project interprets breaking 0.x releases and
apply that rule consistently.
Do not publish prerelease versions such as 0.2.0-beta.1 until a separate
prerelease policy is implemented and tested. A prerelease must use a non-stable
npm dist-tag such as next or beta; it must never move latest. dist's
publish-prereleases behavior and generated npm command must be reviewed before
enabling it.
2. Prepare and test the release PR
- Update
version in Cargo.toml.
- Run Cargo once so
Cargo.lock records the same package version.
- Update release notes or a changelog if the project adopts one.
- Run:
cargo fmt --check
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
dist plan
- Confirm the dist plan includes the intended npm package, target binaries,
checksums, and GitHub Release.
- Merge the reviewed PR to
main.
3. Create and push the release tag
Start from the exact merged commit on main:
git switch main
git pull --ff-only origin main
git status --short
grep '^version' Cargo.toml | head -1
git tag -a v0.2.0 -m "Release v0.2.0"
git push origin v0.2.0
Replace 0.2.0 everywhere with the prepared version. Before pushing, confirm
the working tree is clean and the tag version equals Cargo.toml. A published
npm version is immutable, so do not reuse a tag or version.
Wait for the release workflow to finish before pushing another release tag.
The generated dist workflow does not serialize separate tag runs by default.
4. Supervise GitHub Actions
gh run list --workflow release.yml --limit 5
gh run watch
If a custom publisher uses the protected npm environment, approve its
deployment after checking the version, source commit, planned artifacts, and
completed tests. The built-in dist publisher has no environment approval. In
either case, confirm that npm publishing starts only after all required binary
builds succeed.
Verify a release
Do not treat a green workflow as sufficient. Verify the registry and a real
installation:
npm view cineplanet-cli version dist-tags repository --json
npm view cineplanet-cli@0.2.0 dist.integrity dist.tarball --json
npx --yes cineplanet-cli@0.2.0
Also verify:
latest points to the intended stable version.
- The npm page links to
https://github.com/asther0/cineplanet-cli.
- If OIDC trusted publishing is configured, npm displays provenance and links
it to the correct workflow run and commit.
- The corresponding GitHub Release exists and contains all expected archives
and checksums.
- Each native archive has a GitHub attestation that verifies with
gh attestation verify.
- A clean global install exposes the expected executable:
npm install --global cineplanet-cli@0.2.0
command -v cineplanet-cli
cineplanet-cli
npm uninstall --global cineplanet-cli
Test at least every supported OS/architecture before calling a release fully
verified. The TUI is interactive, so verification must confirm that it starts,
renders, accepts input, and exits cleanly, not merely that installation exits
with status zero.
Failed releases and recovery
First determine which irreversible steps completed:
npm view cineplanet-cli@0.2.0 version --json
gh release view v0.2.0
gh run list --workflow release.yml --limit 5
Nothing was published
Fix the workflow or code in a normal PR. If the tagged source itself is valid
and the failure was transient, rerun the failed workflow. Do not move the tag to
a different commit.
GitHub Release exists but npm does not
Fix authentication or the npm publish job, then rerun only if the generated npm
package still references the same immutable tag and artifacts.
npm already contains the version
Do not retry, overwrite, or reuse that version; npm versions are immutable. If
the package is correct but later automation failed, repair the GitHub metadata
without republishing npm. If the package is defective, prepare a new patch
version.
For a harmful release, deprecate the bad version with a clear replacement:
npm deprecate cineplanet-cli@0.2.0 "Broken release; use 0.2.1"
Use npm unpublish only for a security incident or other exceptional case and
only after reviewing npm's current unpublish policy. Deletion can break users
and does not permit casually reusing package names or versions.
Authentication errors
For ENEEDAUTH or OIDC failures, check:
- The npm trusted publisher owner, repository, workflow filename, and
environment exactly match GitHub, including case and .yml/.yaml.
- The job has
id-token: write.
- The publisher is running on a GitHub-hosted runner.
- Node is at least
22.14.0 and npm is at least 11.5.1.
repository metadata points to the same GitHub repository.
- A reusable workflow has OIDC permission in both caller and called workflow.
- No stale
NODE_AUTH_TOKEN is forcing an unintended token fallback.
For token publishing, check the token has not expired, has read/write package
access, has bypass 2FA enabled, and belongs to a user who still has permission
to publish the package.
Installation errors
If npm publishes successfully but installation fails, inspect the generated
package, GitHub archive names, checksums, target mapping, and release visibility.
The npm installer fetches GitHub Release artifacts, so deleting or renaming
those artifacts breaks installation of an otherwise valid npm version.
Maintainer checklist
One-time setup:
Every release:
References
Review npm and dist documentation when implementing the workflow or rotating
credentials. Registry security requirements and generated workflow details can
change independently of this repository.
Publishing CineplanetCLI to npm
This runbook explains the one-time setup and the recurring release process for
publishing the Rust CLI to the public npm registry. It is written for the
maintainer who owns both the npm package and the GitHub repository.
Release model
Use
distto build native Rustbinaries, upload them to a GitHub Release, generate a small npm installer
package, and publish that installer to npm.
The npm package does not compile Rust on the user's machine. At installation
time it downloads the correct prebuilt binary from the matching GitHub Release
and exposes it as the
cineplanet-clicommand. This supports both:and:
The Cargo package version, Git tag, GitHub Release, and npm package version must
always match. For example, version
0.2.0uses tagv0.2.0and npm version0.2.0.This differs from the
crafter.runrelease flow. Crafter publishes JavaScriptbuilt from its monorepo and uses Changesets to create a release PR. This project
publishes generated npm installer metadata plus native binaries, so
distandversion tags are the source of the release workflow. The useful practices kept
from Crafter are CI-only publishing, explicit verification, provenance, release
serialization, and a documented recovery process.
One-time npm account setup
1. Create and verify the account
password stored in a password manager.
allow an unverified account to publish.
npm whoamimust print the expected maintainer account. Never place the npmpassword in GitHub Actions.
2. Enable two-factor authentication
Publishing requires strong authentication. In npmjs.com, open the profile menu,
select Account, and enable Two-Factor Authentication. Prefer a WebAuthn
security key such as Touch ID or a hardware key.
Store the recovery codes in a password manager, separately from the security
key. Add a second security key when possible, and link the maintainer's GitHub
account under npm's recovery options.
3. Choose the package owner and name
There are two reasonable naming models:
cineplanet-cli: unscoped, public, and simplest fornpx cineplanet-cli.@OWNER/cineplanet-cli: public package owned by an npm user or organization.Users run
npx @OWNER/cineplanet-cli.An npm organization is optional for public packages. Use one when multiple
maintainers need durable team ownership instead of tying releases to one
person. Create it from Profile > Add an Organization, select the free public
package plan, and invite at least one backup maintainer. After the first publish,
grant and verify package access as well as organization membership. For an
unscoped package:
For a scoped organization package, grant an npm team read/write access to the
package and verify it in the package's Access settings.
Check the proposed name immediately before configuration:
An
E404currently indicates that the name is not published, but availabilitycan change and does not establish trademark permission. The maintainer must
confirm that the project name and package metadata comply with npm policy and
any applicable Cineplanet trademark requirements before publishing.
One-time repository setup
The following work should be implemented and reviewed in a normal pull request.
1. Complete the Cargo package metadata
Add at least these fields under
[package]inCargo.toml:Replace
LICENSE-IDENTIFIERonly after the project has an actual license fileand the owner has selected its SPDX identifier. Do not invent a license during
release setup.
2. Install and initialize dist
Install
distusing its current official installation instructions, then run:During setup:
npminstaller.until its binary has been exercised there.
github-attestations = true) so thenative archives receive attestations separate from the npm installer.
The resulting dist configuration should include the npm installer and publish
job. Depending on the installed dist version, it may appear in
Cargo.tomlordist-workspace.tomland resemble:dist initalso generates.github/workflows/release.yml. Treat that file asgenerated: change dist settings and rerun
dist initinstead of hand-editingthe workflow unless the configuration explicitly opts into custom CI.
Validate the generated release plan:
dist plan dist build cargo test --locked cargo clippy --locked --all-targets -- -D warningsInspect the generated npm package and confirm it exposes exactly one command,
cineplanet-cli, and points to release artifacts fromasther0/cineplanet-cli.3. Review the generated GitHub workflow
As of August 2026, released dist
0.32.0does not generate an npm trustedpublishing job. Its built-in npm publisher uses Node 20 and
NPM_TOKEN; upstreamOIDC support is still pending. Do not assume that adding
id-token: writeto thegenerated workflow is sufficient.
The supported initial implementation for this repository is therefore:
NPM_TOKENas a repository secret.the built-in publisher with a reviewed custom publish workflow.
The release workflow must:
v0.2.0. Use GitHub's Rerunfailed jobs operation for recovery; dist's dispatch mode is an alternative
release mode, not an additional trigger.
https://registry.npmjs.orgas the npm registry.dist workflow builds release binaries but does not replace those checks.
manage these through
github-action-commits; mutable major-version actiontags carry additional supply-chain risk.
The built-in publish job will consume the repository secret as
NODE_AUTH_TOKENorNPM_TOKEN. Confirm this in the generated file after everydist upgrade. Do not hand-edit generated CI: dist rejects drift unless
allow-dirty = ["ci"]is deliberately enabled, which also makes future distupgrades manual.
When dist gains trusted publishing support, or a custom reusable publish job is
adopted, the publish job needs the equivalent of:
Node must be at least
22.14.0and npm at least11.5.1for npm OIDC. Thecomplete dist workflow contains additional planning, native build, artifact
upload, and GitHub Release jobs. Do not replace those jobs with this fragment.
If the publish step lives in a reusable workflow, npm may validate the calling
workflow rather than the called workflow. Configure the exact filename npm
observes, and grant
id-token: writein both caller and called workflows.4. Decide whether to add a protected GitHub environment
The current built-in dist npm job does not declare a GitHub environment. Its
NPM_TOKENmust therefore be a repository secret, not an environment secret.If the project later adopts a custom publish job, create an environment named
npmunder Repository Settings > Environments. Add required reviewers andprevent self-review if the repository's GitHub plan supports those controls.
Set that custom npm publish job to:
Using an environment is recommended because a tag alone should not silently
publish a permanent registry version. This requires a custom dist publish job
or deliberately maintained custom CI; adding the environment only in GitHub's
settings does not affect the built-in job. If the environment name is included
in npm's trusted publisher configuration, the workflow must use the exact same
case-sensitive name.
Bootstrap the first npm version
npm can attach a trusted publisher only after the package exists. The first
version is therefore a controlled release using the temporary granular token.
Configure the npm token.
dist buildand find the generated npm package path inits output. Inspect that exact package rather than running npm commands from
the Rust repository root. For a generated
.tar.gzpackage:for bootstrap, or replace it with a package-scoped token.
Do not run
npm publishfrom this repository root. A manual emergency publishmust target the exact generated tarball, for example
npm publish target/distrib/GENERATED-NPM-PACKAGE.tar.gz --access public, andshould not be used for a normal release.
Never publish an empty placeholder package merely to reserve the name. The
first published package must install and run.
Configure trusted publishing with GitHub OIDC
Trusted publishing is the security target because GitHub issues a short-lived
identity token for one workflow run and no reusable npm credential is stored in
GitHub. It is not supported by dist's built-in npm job in released dist
0.32.0.Follow this section only after upgrading to a dist version that explicitly
supports npm OIDC, or after implementing and reviewing a custom publish job.
npm configuration
asther0.cineplanet-cli.example
release.yml. Enter the filename only, not.github/workflows/.npmif the publish job uses that environment.npm publish. For stricter human approval, allow onlynpm stage publishand adopt npm staged publishing instead.configuration until a publish is attempted.
Each npm package can have only one trusted publisher configuration.
GitHub configuration
The publish job must have:
Do not set
NPM_TOKENorNODE_AUTH_TOKENon the OIDC publish step. npmautomatically detects GitHub OIDC and exchanges it for a short-lived publish
credential.
npm whoamicannot test OIDC because the exchange occurs only fornpm publishornpm stage publish.After the first successful OIDC release:
This setting blocks traditional token publishing but continues to allow the
configured trusted publisher.
For a public npm package built from this public GitHub repository, trusted
publishing automatically includes npm provenance. It attests the small npm
installer package and links it to its source commit and workflow. It does not by
itself attest the native Rust archive downloaded later from GitHub Releases.
Keep dist's GitHub artifact attestations enabled for those archives and verify a
downloaded archive with
gh attestation verify PATH --repo asther0/cineplanet-cli.Configure the npm token (current dist path)
This is the working authentication path for dist
0.32.0. Keep the tokenshort-lived and migrate to OIDC when the installed dist release supports it.
npm supports granular access tokens; legacy tokens have been removed.
Create the token
cineplanet-cli GitHub Actionsand document why it exists.publishing cannot answer a 2FA prompt.
cineplanet-cliafter the package exists. For the first publish,npm may require All Packages because the package cannot yet be selected.
does not grant package publishing access.
addresses are not stable enough for a practical narrow allowlist.
Store the token in GitHub
The built-in dist publisher requires a repository secret:
gh secret set NPM_TOKEN --repo asther0/cineplanet-cliPaste the token when prompted. Do not place it on the command line, in a file,
in
.npmrc, or in shell history. Confirm only the secret name is visible:The equivalent web path is Repository Settings > Secrets and variables >
Actions > New repository secret. Name it
NPM_TOKEN. If a future custompublish job declares
environment: npm, move the token to that environmentinstead.
Use the token in the workflow
actions/setup-nodewrites a temporary runner.npmrcthat readsNODE_AUTH_TOKEN. Expose the GitHub secret only to the publish step:Some release tools expect
NPM_TOKENdirectly. If dist requires it, pass bothnames from the same secret only to that job:
Never print either environment variable. GitHub masking reduces accidental
exposure but does not make logging a secret safe. Token authentication does not
automatically produce npm provenance. Adding
--provenancealso requires anOIDC-capable GitHub-hosted job with
id-token: write; do not add the flag to thegenerated dist job without implementing and reviewing that complete setup.
Rotate or revoke the token
Tokens expire and are tied to the creating user's package permissions. Before
expiration, create a replacement with the same restricted permissions, replace
the GitHub secret, verify one publish, and revoke the old token under npm
Access Tokens. If exposure is suspected, revoke first and investigate
before releasing again.
After OIDC succeeds, remove the GitHub
NPM_TOKENsecret and revoke the token.Normal release process
Do not manually publish normal releases. The maintainer prepares a version; the
tag causes GitHub Actions to build and publish that exact source revision.
1. Select the version
Use the smallest SemVer increment that describes the user-visible change:
patch: compatible bug fix or internal improvement.minor: backward-compatible capability or command behavior.major: breaking CLI, output, configuration, installation, or platformsupport change.
Before
1.0.0, document how the project interprets breaking0.xreleases andapply that rule consistently.
Do not publish prerelease versions such as
0.2.0-beta.1until a separateprerelease policy is implemented and tested. A prerelease must use a non-stable
npm dist-tag such as
nextorbeta; it must never movelatest. dist'spublish-prereleasesbehavior and generated npm command must be reviewed beforeenabling it.
2. Prepare and test the release PR
versioninCargo.toml.Cargo.lockrecords the same package version.cargo fmt --check cargo test --locked cargo clippy --locked --all-targets -- -D warnings dist planchecksums, and GitHub Release.
main.3. Create and push the release tag
Start from the exact merged commit on
main:Replace
0.2.0everywhere with the prepared version. Before pushing, confirmthe working tree is clean and the tag version equals
Cargo.toml. A publishednpm version is immutable, so do not reuse a tag or version.
Wait for the release workflow to finish before pushing another release tag.
The generated dist workflow does not serialize separate tag runs by default.
4. Supervise GitHub Actions
If a custom publisher uses the protected
npmenvironment, approve itsdeployment after checking the version, source commit, planned artifacts, and
completed tests. The built-in dist publisher has no environment approval. In
either case, confirm that npm publishing starts only after all required binary
builds succeed.
Verify a release
Do not treat a green workflow as sufficient. Verify the registry and a real
installation:
Also verify:
latestpoints to the intended stable version.https://github.com/asther0/cineplanet-cli.it to the correct workflow run and commit.
and checksums.
gh attestation verify.npm install --global cineplanet-cli@0.2.0 command -v cineplanet-cli cineplanet-cli npm uninstall --global cineplanet-cliTest at least every supported OS/architecture before calling a release fully
verified. The TUI is interactive, so verification must confirm that it starts,
renders, accepts input, and exits cleanly, not merely that installation exits
with status zero.
Failed releases and recovery
First determine which irreversible steps completed:
Nothing was published
Fix the workflow or code in a normal PR. If the tagged source itself is valid
and the failure was transient, rerun the failed workflow. Do not move the tag to
a different commit.
GitHub Release exists but npm does not
Fix authentication or the npm publish job, then rerun only if the generated npm
package still references the same immutable tag and artifacts.
npm already contains the version
Do not retry, overwrite, or reuse that version; npm versions are immutable. If
the package is correct but later automation failed, repair the GitHub metadata
without republishing npm. If the package is defective, prepare a new patch
version.
For a harmful release, deprecate the bad version with a clear replacement:
npm deprecate cineplanet-cli@0.2.0 "Broken release; use 0.2.1"Use
npm unpublishonly for a security incident or other exceptional case andonly after reviewing npm's current unpublish policy. Deletion can break users
and does not permit casually reusing package names or versions.
Authentication errors
For
ENEEDAUTHor OIDC failures, check:environment exactly match GitHub, including case and
.yml/.yaml.id-token: write.22.14.0and npm is at least11.5.1.repositorymetadata points to the same GitHub repository.NODE_AUTH_TOKENis forcing an unintended token fallback.For token publishing, check the token has not expired, has read/write package
access, has bypass 2FA enabled, and belongs to a user who still has permission
to publish the package.
Installation errors
If npm publishes successfully but installation fails, inspect the generated
package, GitHub archive names, checksums, target mapping, and release visibility.
The npm installer fetches GitHub Release artifacts, so deleting or renaming
those artifacts breaks installation of an otherwise valid npm version.
Maintainer checklist
One-time setup:
dist plan.NPM_TOKENstored as a repository secret.Every release:
Cargo.tomlandCargo.lock.dist planpass.main.vX.Y.Ztag points to the merged release commit.latest, GitHub Release, attestations, and clean install verified.References
Review npm and dist documentation when implementing the workflow or rotating
credentials. Registry security requirements and generated workflow details can
change independently of this repository.