Skip to content

Releasing PBVex

PBVex publishes one unscoped npm package, five scoped npm packages, and standalone backend archives from the same SemVer tag:

ArtifactPurpose
pbvexCLI and server-authoring API
@pbvex/serverComplete GoReleaser backend binary matrix and pbvex-server launcher
@pbvex/protocolShared wire protocol
@pbvex/clientBrowser-neutral client
@pbvex/reactReact bindings
@pbvex/svelteSvelte bindings
GitHub release archivesSelf-contained pbvex backend for Linux, macOS, and Windows

The package is named pbvex, not @pbvex/pbvex. The @pbvex scope groups the supporting packages.

One-time npm bootstrap

npm requires a package to exist before a trusted publisher can be configured. Perform these steps once from a trusted maintainer workstation. They do not belong in CI.

  1. Create an npm account, enable account-level two-factor authentication, and create or claim the pbvex npm organization/scope. Make sure the account can publish both the unscoped pbvex package and public packages under @pbvex.

  2. Install the repository's declared pnpm version, authenticate interactively with npm login, and check that every package is still available:

    bash
    npm view pbvex
    npm view @pbvex/server
    npm view @pbvex/protocol
    npm view @pbvex/client
    npm view @pbvex/react
    npm view @pbvex/svelte

    A 404 Not Found is expected before the first publication. Stop if a name belongs to someone else.

  3. Set every publishable package.json to the same initial version, then run:

    bash
    pnpm install --frozen-lockfile
    pnpm lint
    pnpm test
    pnpm pack:smoke
    
    goreleaser build --snapshot --clean --parallelism 1
    node scripts/stage-server-binaries.mjs
    
    NPM_CONFIG_PROVENANCE=false pnpm --dir packages/protocol publish --access public --no-git-checks
    NPM_CONFIG_PROVENANCE=false pnpm --dir packages/server publish --access public --no-git-checks
    NPM_CONFIG_PROVENANCE=false pnpm --dir packages/pbvex publish --access public --no-git-checks
    NPM_CONFIG_PROVENANCE=false pnpm --dir packages/client publish --access public --no-git-checks
    NPM_CONFIG_PROVENANCE=false pnpm --dir packages/react publish --access public --no-git-checks
    NPM_CONFIG_PROVENANCE=false pnpm --dir packages/svelte publish --access public --no-git-checks

    Enter the npm one-time password when prompted. Provenance is disabled only for this local bootstrap because npm provenance is generated by supported CI providers.

  4. Open the settings for each of the six packages on npmjs.com and add the same GitHub Actions trusted publisher:

    SettingValue
    Organization or usernathabonfim59
    Repositorypbvex
    Workflow filenamenpm-publish.yaml
    Environmentnpm
    Allowed actionnpm publish

    The filename and environment are case-sensitive. Configure every package; a trusted publisher is attached to one package, not an entire scope.

  5. After one trusted tag release succeeds, set npm package access to require two-factor authentication and disallow token-based publishing. Revoke any automation token. PBVex CI does not use NPM_TOKEN.

First publication of @pbvex/server in an existing PBVex release line

If the other PBVex packages already exist on npm, claim only the new server package from a maintainer workstation. Use a disposable bootstrap prerelease; do not consume the next coordinated release version before trusted publishing is configured:

bash
npm login
BOOTSTRAP_VERSION=0.0.0-bootstrap.0
npm view "@pbvex/server@$BOOTSTRAP_VERSION"
# Continue only when npm reports that this bootstrap version does not exist.

pnpm install --frozen-lockfile
pnpm lint
pnpm test
pnpm pack:smoke

goreleaser build --snapshot --clean --parallelism 1
node scripts/stage-server-binaries.mjs
pnpm --filter @pbvex/server build

BOOTSTRAP_DIR=$(mktemp -d)
cp -R packages/server/. "$BOOTSTRAP_DIR/"
npm --prefix "$BOOTSTRAP_DIR" version "$BOOTSTRAP_VERSION" --no-git-tag-version
NPM_CONFIG_PROVENANCE=false npm publish "$BOOTSTRAP_DIR" --access public --tag bootstrap

Verify the public package from a clean temporary installation:

bash
VERIFY_DIR=$(mktemp -d)
npm install --prefix "$VERIFY_DIR" "@pbvex/server@$BOOTSTRAP_VERSION"
"$VERIFY_DIR/node_modules/.bin/pbvex-server" serve --help
npm view "@pbvex/server@$BOOTSTRAP_VERSION" dist.integrity

After the bootstrap package exists, configure its trusted publisher using the settings above. The normal signed-tag release can then publish the next real version of all six packages together, including the exact @pbvex/server version required by pbvex. Do not publish that coordinated version manually and do not attempt to republish an existing pbvex version merely to add the dependency.

One-time GitHub hardening

Repository settings cannot be fully expressed by workflow files. Configure these controls in GitHub before creating a release tag:

  1. Under Settings > Actions > General, set the default GITHUB_TOKEN permission to read-only, require approval for workflows from fork pull requests, and enable the policy that requires actions to be pinned to a full-length commit SHA.
  2. Create an environment named npm. Allow only tags matching v*.*.*, add a required maintainer reviewer, prevent self-review when the plan supports it, and disable administrator bypass where practical. Do not add npm secrets.
  3. Create a github-release environment with the same tag and reviewer rules. It also needs no stored secret; GoReleaser uses the short-lived repository GITHUB_TOKEN.
  4. Add an active tag ruleset for v*.*.*. Restrict tag creation, updates, and deletion to release maintainers and require signed tags if every authorized maintainer can satisfy that policy.
  5. Protect master: require pull requests, CODEOWNER review for workflow and release files, resolved conversations, and the CI checks. Enable immutable GitHub Releases if the repository setting is available.
  6. Keep private vulnerability reporting and secret scanning/push protection enabled. Review Dependabot pull requests like any other dependency change; a passing build is not proof that an update is trustworthy.

The workflows deliberately do not use pull_request_target. Fork pull requests run .github/workflows/ci.yaml with read-only access and no secrets. The npm publish job does not check out or build repository code: it receives the tarballs produced by its unprivileged validation job, verifies their checksums, and only then receives an OIDC identity through the protected npm environment.

Prepare a release

  1. Update the version in all six publishable package manifests. The root workspace is private and its version is not published.

  2. Update the PBVex section of CHANGELOG.md.

  3. Run the complete local gates:

    bash
    pnpm install --frozen-lockfile
    pnpm lint
    pnpm build
    pnpm test
    pnpm pack:smoke
    
    cd backend
    test -z "$(gofmt -l .)"
    go vet ./...
    go test -count=1 ./...
    CGO_ENABLED=1 go test -race -count=1 ./...
    cd ..
    
    goreleaser check
    ./scripts/release-validate.sh
    goreleaser release --snapshot --clean
    node scripts/stage-server-binaries.mjs
    VALIDATE_TAG_TEST=1 ./scripts/validate-tag.sh
  4. Merge the release commit to master. Create a signed annotated tag whose version exactly matches every package manifest, then push only that tag:

    bash
    git tag -s v0.1.0 -m 'PBVex v0.1.0'
    git push origin v0.1.0

The tag starts both publishing workflows. Stable versions use npm's latest distribution tag; SemVer prereleases use next. GoReleaser publishes archives for supported Linux, macOS, and Windows targets plus checksums.txt. GitHub also records build-provenance attestations for the archives, while npm trusted publishing automatically records npm provenance. The npm workflow builds the same GoReleaser target matrix, stages it into @pbvex/server, publishes that package before pbvex, and then publishes the client integrations.

Do not move or reuse a release tag. If publication partially fails, determine which immutable package versions already exist, fix the cause, and release a new patch version. npm versions and immutable GitHub releases cannot safely be overwritten.

Verify a release

Download an archive and checksums.txt from the GitHub release, then verify both its checksum and GitHub attestation:

bash
sha256sum --check --ignore-missing checksums.txt
gh attestation verify pbvex_0.1.0_linux_amd64.tar.gz --repo nathabonfim59/pbvex

Confirm each npm page shows the expected version and provenance, then test the CLI from a clean directory:

bash
npx --yes pbvex@0.1.0 --help

Generated API reference. Source of truth is the codebase.