Skip to content

ci: add CI and public-npm publish workflows - #1

Closed
olaf-cichocki wants to merge 3 commits into
mainfrom
ci/npm-publish-workflow
Closed

ci: add CI and public-npm publish workflows#1
olaf-cichocki wants to merge 3 commits into
mainfrom
ci/npm-publish-workflow

Conversation

@olaf-cichocki

Copy link
Copy Markdown
Contributor

Adds the missing release path for @cloudinary/sandbox. The repo had no .github/ at all — no CI, no publish workflow — so this is the piece needed before anything reaches npm.

Everything here targets the public npm registry (registry.npmjs.org), not an internal Nexus mirror. That's pinned in two places (publishConfig.registry and the workflow's registry-url) so a contributor whose ~/.npmrc points at Nexus can't accidentally redirect a release.

What's in it

ci.yml — build + the existing 36-test suite on Node 20/22/24 (lower bound matches engines.node). Plus a packaging job that asserts the tarball actually contains dist/index.js and the library entry points, and that the bin has a working shebang and responds to --help/--version. That job exists because files: ["dist"] + a build hook is exactly the combination that silently ships an empty package.

publish.yml — publish via a GitHub Release, or a manual run. Guards:

  • release tag must match package.json (otherwise the changelog describes a version nobody installs)
  • refuses a version already on npm, instead of failing later with an opaque 403
  • dist-tag derives from the release's prerelease flag; manual runs choose, and default to dry-run
  • gated on an npm-publish environment, so publishes wait for a required reviewer

package.json — added repository/bugs/homepage. Worth calling out: a public repository field is a hard prerequisite for provenance and it was missing entirely. Also moved the build hook prepublishOnlyprepack, because npm pack doesn't run prepublishOnly — a manual npm pack today produces a tarball with no dist/.

package-lock.json — regenerated. Its root name was still @cloudinary/cli, left over from the rename.

CONTRIBUTING.md — the release runbook.

Two things that need a decision, not code

1. Provenance needs a public repo. npm does not support provenance attestations from private or internal repositories, and this repo is internal. The workflow detects visibility and adds --provenance only when public, warning otherwise — so it works today unsigned and upgrades itself the moment the repo is flipped. Recommend flipping it before GA; a package published via npx benefits a lot from a verifiable build.

2. Trusted publishing is chicken-and-egg. npm only lets you attach a Trusted Publisher to a package that already exists, so the first publish needs a short-lived NPM_TOKEN secret. The workflow supports both: it passes NODE_AUTH_TOKEN if the secret exists, and OIDC takes over once the Trusted Publisher is configured — at which point the secret should be deleted. Steps are in CONTRIBUTING.md.

Suggestion: while the provisioning endpoint is a POC, publish under the next dist-tag (the manual-run default). npx @cloudinary/sandbox resolves latest, so tagging a version as latest before the endpoint is live hands every public caller a broken command.

Verification

Ran locally against this branch: npm ci clean, npm test 36/36 green, the packaging job's checks reproduced by hand (tarball 39 files, shebang + --help + --version OK), both workflows YAML-parse, and the publish-parameter shell logic exercised across four cases (manual/internal, release/public, prerelease, mismatched tag → correctly fails).

Separately from this PR, I left review notes on the package itself — including one confirmed bug where a drifted API response discards a provisioned sandbox's credentials. Happy to file those as issues.

🤖 Generated with Claude Code

njb90 and others added 3 commits July 28, 2026 15:11
One command to a disposable Cloudinary sandbox: `npx @cloudinary/sandbox`
provisions a claimable, TTL-bounded, IP-locked sandbox account and writes
CLOUDINARY_URL to ./.env. Zero runtime dependencies; node:test suite with
in-process HTTP stubs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the release path for @cloudinary/sandbox, targeting the public npm
registry (registry.npmjs.org) rather than an internal mirror.

- ci.yml: build + 36-test suite on Node 20/22/24, plus a packaging job that
  asserts the tarball carries dist/index.js and the library entry points and
  that the bin has a working shebang.
- publish.yml: gated publish via a GitHub Release or a manual run. Refuses a
  release tag that disagrees with package.json, refuses a version already on
  npm, derives the dist-tag from the prerelease flag, and defaults manual runs
  to dry-run. Uses OIDC (id-token: write) for trusted publishing and adds
  --provenance only when the repo is public, since attestations are
  unsupported from internal repos.
- package.json: add repository/bugs/homepage — a public repository field is a
  prerequisite for provenance and was absent. Pin publishConfig.registry so a
  Nexus-pointing ~/.npmrc cannot redirect a release. Move the build hook from
  prepublishOnly to prepack so `npm pack` cannot produce an empty tarball.
- package-lock.json: regenerate — the root name was still @cloudinary/cli
  from before the rename.
- CONTRIBUTING.md: release runbook, including the token-then-OIDC bootstrap
  and why POC versions should ship under the `next` dist-tag.
A project .npmrc outranks the user config, so this covers what the workflow's
registry-url can't: a local install or publish by someone whose ~/.npmrc points
at the internal Nexus mirror.
@olaf-cichocki
olaf-cichocki force-pushed the ci/npm-publish-workflow branch from f624846 to 5c52d67 Compare July 28, 2026 20:55
@njb90 njb90 closed this Aug 3, 2026
@njb90
njb90 deleted the ci/npm-publish-workflow branch August 3, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants