Release process
Prepare, verify, publish, prove, and roll back Ownfold package releases without enabling CI on ordinary pushes.
Ownfold separates a reviewed version commit from the irreversible npm publish. Ordinary pushes do
not run CI. Pull requests run the verification workflow; publishing is a separate manual workflow
dispatch protected by the GitHub npm environment.
One-time registry setup
Before the first public beta:
- Make the source repository public. npm provenance is not generated from a private repository.
- Reserve the
@ownfoldnpm organization and require two-factor authentication for maintainers. - For every public package, configure npm trusted publishing for
DeepanshuMishraa/ownfold, workflowrelease.yml, and GitHub environmentnpm. - Protect the GitHub
npmenvironment with required reviewers. Do not add a long-lived npm token. - Protect
main, require review for the version pull request, and require signed release commits and tags where the repository policy supports them.
The workflow uses Node 24 and npm 11.6.2 because npm trusted publishing requires npm 11.5.1 or
newer and Node 22.14 or newer. It requests id-token: write; npm exchanges that short-lived OIDC
identity and emits provenance for public packages.
Prepare the version commit
- Start from a clean branch based on
main. - Run
pnpm changeset statusand review every intended package bump. - Run
pnpm release:checkwith the disposable PostgreSQL test database. - Run
pnpm release:version. This applies Changesets and refreshes the lockfile. - Review every version, changelog, internal dependency range, persisted-format note, and database
migration instruction. Run
pnpm install --frozen-lockfileandpnpm release:checkagain. - Merge the version commit through a substantial, reviewed pull request.
Do not combine unrelated source changes with the version commit. A release commit must contain no
pending .changeset/*.md files; pnpm release:assert-publishable enforces this.
The aggregate gate runs pnpm security:audit, which rejects known moderate, high, or critical
advisories across the complete dependency graph, including build and documentation tooling. Do not
suppress an advisory merely because it is transitive or development-only. Upgrade the owning
dependency, verify the resolved graph, and rerun the complete gate; if no compatible fix exists,
the release remains blocked until the risk receives explicit security review and documented
release-owner acceptance.
The root override pins @vercel/routing-utils to path-to-regexp@6.3.0. Its declared 6.1.0
dependency is affected by GHSA-9wv6-86v2-598j; 6.3.0 is the compatible patched release. Remove the
override only after the upstream dependency no longer resolves a vulnerable version.
Blume’s current graph declares two stale peer ranges while building successfully against its own
resolved dependencies. pnpm accepts only @pierre/theming with @pierre/theme@2 and
@scalar/astro with astro@7; the scoped rules do not suppress peer mismatches elsewhere.
The workspace pins pnpm 11, rejects exotic transitive dependency sources, fails on unreviewed dependency build scripts, and quarantines newly published package versions for at least three days. An urgent security release may be excluded from the age gate only by an exact package-and-version entry reviewed in the same pull request; never add a broad package-name exception.
The checked-in exceptions are limited to direct versions reviewed during the 2026-08-03 audit:
@types/pg@8.20.3, better-result@3.0.0, and blume@1.3.1. Blume removes vulnerable transitive
build tooling; the other two were already required direct versions with no older release satisfying
their declared major range.
Lifecycle scripts are allowlisted only for @prisma/engines, prisma, and esbuild, whose install
steps supply the binaries used by the checked-in database generation and build workflows. A new
package requesting a lifecycle script fails installation until its script and provenance are
reviewed.
Publish
From GitHub Actions, manually run Publish packages on main and enter publish exactly. The
workflow refuses another branch, private repository provenance, pending Changesets, placeholder
versions, or non-public package configuration. It runs the complete release gate before
changeset publish, then pushes the package tags generated by Changesets.
For an explicitly approved prerelease from a private repository, the named release owner may publish locally with npm write 2FA after the same versioned release gate passes. This path does not produce npm provenance and must be recorded as an exception; it is not equivalent to the protected trusted-publisher workflow.
After publishing, verify each npm page, version, integrity, provenance statement, export map, README, license, and installation in a clean consumer project. Record the workflow run, source commit, package versions, database migration range, and compatibility manifest in the release evidence. Never retry a partially failed publish blindly: first compare npm versions and local tags package by package because npm versions are immutable.
Run pnpm release:smoke-registry only after every package version is visible from the public npm
registry. It installs the exact workspace versions into a temporary project, type-checks every
public package root and supported subpath, imports them at runtime, and removes the project.
The package dry-run gate requires every tarball to contain its own README and an exact copy of the repository license. Package READMEs must identify the infrastructure-independent security boundary, link the threat model, and route vulnerability reports to the private security process.
Rollback and revocation
npm packages cannot be safely overwritten. For a bad release, stop further publishing, assess whether any persisted writer format or migration ran, deprecate affected versions with an explicit message, publish a forward fix, and follow Versioning and upgrades. Do not delete encrypted data, rewrite authenticated envelopes, or restore the coordination database independently of application ciphertext. A compromised release also follows the incident-response runbook.