ci: add CI and public-npm publish workflows - #1
Closed
olaf-cichocki wants to merge 3 commits into
Closed
Conversation
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
force-pushed
the
ci/npm-publish-workflow
branch
from
July 28, 2026 20:55
f624846 to
5c52d67
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.registryand the workflow'sregistry-url) so a contributor whose~/.npmrcpoints 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 matchesengines.node). Plus a packaging job that asserts the tarball actually containsdist/index.jsand the library entry points, and that the bin has a working shebang and responds to--help/--version. That job exists becausefiles: ["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:package.json(otherwise the changelog describes a version nobody installs)npm-publishenvironment, so publishes wait for a required reviewerpackage.json— addedrepository/bugs/homepage. Worth calling out: a publicrepositoryfield is a hard prerequisite for provenance and it was missing entirely. Also moved the build hookprepublishOnly→prepack, becausenpm packdoesn't runprepublishOnly— a manualnpm packtoday produces a tarball with nodist/.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
--provenanceonly 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 vianpxbenefits 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_TOKENsecret. The workflow supports both: it passesNODE_AUTH_TOKENif the secret exists, and OIDC takes over once the Trusted Publisher is configured — at which point the secret should be deleted. Steps are inCONTRIBUTING.md.Suggestion: while the provisioning endpoint is a POC, publish under the
nextdist-tag (the manual-run default).npx @cloudinary/sandboxresolveslatest, so tagging a version aslatestbefore the endpoint is live hands every public caller a broken command.Verification
Ran locally against this branch:
npm ciclean,npm test36/36 green, the packaging job's checks reproduced by hand (tarball 39 files, shebang +--help+--versionOK), 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