Skip to content

Merge v4-beta to v4 (2026-10-19) - #218

Merged
mike-ainsel merged 15 commits into
v4from
merge-2026-10-19
Oct 19, 2026
Merged

mike-ainsel merged 15 commits into
v4from
merge-2026-10-19

Conversation

@mike-ainsel

@mike-ainsel mike-ainsel commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Merge v4-beta into v4

RetriggerView in GreptileConfidence Score: 4/5

The PR appears safe to merge, with two non-blocking improvements to avoid misleading success messages.

Fix All in Claude CodeFindings

  1. P2 Missing uploads look successful ▶
  2. P2 Setup hides registry errors ▶
Fix with agent prompt
### Issue 1
actions/node/npm-split-publish/src/publish.ts:139-142
`publishTarballs` reports success when `manifest.jsonl` is missing. A wrong `dir` or incomplete artifact therefore skips every upload without failing the release. Require the manifest to exist; an existing empty manifest can still mean there is nothing to publish.

### Issue 2
scripts/npm-trust-setup.sh:113-116
`apply` treats every failed `npm view` as proof that the package does not exist. A network error, registry outage, or expired login silently skips existing packages and still lets the command succeed. Capture the error and skip only a confirmed not-found response; stop and show other failures.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

This PR splits npm releases into two jobs:

  • npm releases are packed on the build runner and uploaded from a hosted runner.
  • Operators can find packages and set up npm trusted publishers.

Two non-blocking improvements remain: fail when the publish manifest is missing, and distinguish registry errors from missing packages during trust setup.

Important touched types:

  • ManifestEntry: One package passed between jobs. Newly records its name, version, tarball, registry, tag, and access.
  • WorkspacePackage: A package directory and its named, versioned manifest. Newly used to select and order packages.
  • PackageJson: The package fields this release code reads. Newly covers scripts, publish settings, repository details, and dependencies.
  • PackOptions: Settings for packing. Newly carries workspace paths and the optional public source repository.
  • Credentials: Upload tokens. Newly separates the GitHub Packages token from the optional npmjs fallback token.
  • PublishOptions: Upload settings. Newly combines credentials with the tarball directory, access choice, and npm config path.
  • Runner: A replaceable command runner. Newly lets tests supply command results without uploading packages.
  • RepositoryState: Whether a declared repository is missing, matches, or differs. Newly guides repository checks and temporary additions.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Build and test] --> B[Find unpublished packages]
  B --> C[Run hooks and pack]
  C --> D[Upload artifact]
  D --> E[GitHub-hosted publish job]
  E --> F[Check manifest and tarballs]
  F --> G[Publish with scripts disabled]
  G --> H[Create release tag]
Loading

Reviews (1) · Last reviewed commit: "Merge pull request #217 from milaborator..." · Reviewed by Greptile

npm trusted publishing rejects self-hosted runners, and bypass-2FA tokens
lose direct publish around January 2027.

New opt-in input `npm-trusted-publishing` on node-simple-pnpm.yaml:
- build-test-publish (gha-runner-label) runs prepublishOnly and packs every
  unpublished package in topological order (actions/node/pack-unpublished);
- new npm-publish job on ubuntu-latest uploads the tarballs via OIDC
  (actions/node/publish-tarballs) and creates the release tag.

`npm-token-fallback` (default true) keeps NPMJS_TOKEN as a fallback while
trusted publishers are configured package by package. Default behaviour is
unchanged.
…lishers

discover lists every non-private workspace package of repos whose
build.yaml calls a github-ci node workflow; apply runs npm trust github
for each, skipping configured and unpublished packages. Needs an
interactive npm login with 2FA.
- pack-unpublished.sh / publish-tarballs.sh replace the inline scripts; the
  pack script calls itself per package via pnpm exec instead of generating
  a script. The manifest format is documented in pack-unpublished.sh.
- bats suites for both scripts and for npm-trust-setup.sh apply, with
  fixtures and npm stubs; 0-test-npm-publish-split.yaml runs them with
  pnpm 9.12 and the repo's packageManager.
- npm-publish job: add packages: write for GitHub Packages uploads.
- publish-tarballs: GITHUB_TOKEN goes to npm.pkg.github.com only; any other
  non-npmjs registry fails before the first upload.
- npm-trust-setup apply: require the createPackage (npm publish) permission,
  keep npm stderr out of the JSON, stop on unreadable output, and read the
  mapping from fd 3 so npm's 2FA prompt keeps stdin.
npm attaches a token by host regardless of scheme, so an http:// registry in
the manifest would receive GITHUB_TOKEN or the npmjs token in clear text.
Review follow-up: the two composite actions now run one TS package,
actions/node/npm-split-publish, instead of shell scripts.

- ManifestEntry (src/manifest.ts) is the typed, validated contract between
  pack and publish.
- pack orders packages itself (all dependency fields, as pnpm does; cycles
  are broken and reported) and checks every package before the first
  prepublishOnly runs, so a bad package fails without side effects.
- publish parses registry URLs with URL: https only, no credentials or port
  in the URL, GITHUB_TOKEN for npm.pkg.github.com only.
- vitest: unit tests with a fake command runner, integration tests with real
  pnpm on the fixture workspace (CI: pnpm 9.12 and the repo's pnpm).
- lib/ is committed like the other TS actions; the test workflow fails when
  it does not match a fresh build.

npm-trust-setup.sh stays bash with its bats suite.
…d job

The manifest and tarballs reach the GitHub-hosted job as an artifact.
- Validate every value (package name, semver version, .tgz basename, https
  registry, dist-tag, access) so none can be read by npm as an option; the
  pack side validates on write, so bad values fail in the build job.
- Pass values as --flag=value.
- Run npm from an empty temp directory: npm reads a project .npmrc from its
  working directory, and the artifact directory could carry one.
- Provenance: under trusted publishing npm turns provenance on for public
  packages and the registry rejects (E422) a package.json whose
  repository.url does not name the building repository; most of ours have
  none. pack fills a missing `repository` into the packed copy and fails
  early on a different repository. Reproduced on the canary (0.0.5).
- Dist-tag: always pass --tag (publishConfig.tag, else latest). npm 11
  refuses prereleases and versions below the highest one without it; npm 10
  on the old path tagged them latest. Covered by a real-npm dry-run test.
- Private packages without a version no longer fail pack.
- The upload job checks each tarball's package.json against its manifest
  entry before the first upload.
- The upload job no longer loads all caller secrets (actions/env); it gets
  NPMJS_TOKEN only, and only with npm-token-fallback.
- Artifact named per call (app-name-slug); npm pinned to 11.21.0; pack step
  gets GITHUB_TOKEN as the old publish step did.
- README: provenance, tag policy, artifact trust, partial-release recovery.
- Fallback token: extracted from the caller's env secret in its own step and
  masked (::add-mask::) before any step gets it as an input; GitHub masks the
  JSON secret as a whole, not values taken out of it.
- Run `prepublish` after `prepublishOnly`, as pnpm publish does.
- Checks (unsupported scripts, repository) run only on packages this release
  uploads; repository handling applies only to npmjs targets from public
  repositories, and the packed tarball is checked to carry it.
- Tarball check: reject entries outside package/ and duplicate
  package.json (npm strips the top directory; last one wins), handle pax and
  long-name headers.
- Refuse packed publishConfig keys that npm would apply for auth, proxy or
  scope registries, and a registry other than the entry's; correct the
  manifest comment that said npm ignores the tarball's publishConfig.
- Re-run of a restricted package without a token: treat npm's duplicate
  refusal as already published.
- Test workflow also runs on node-simple-pnpm.yaml changes; README documents
  the latest-tag trade-off.
…d unusual headers

npm's unpacker normalizes paths (package/./package.json is
package/package.json), so a second manifest spelled differently could pass
the identity check. Paths are normalized before comparison; '..', links and
other special entries, pax size records and non-octal sizes are refused.
Replace the hand-written tar reader with node-tar 7.5.22 extraction using
pacote's options (strip 1, no links), as npm 11.21 reads a tarball before
publishing. A custom parser can always disagree with npm on some edge case;
tests now compare our result with npm's own (npm pack --dry-run --json) for
duplicate manifests, odd path spellings, '..', links and missing manifests.
npm no longer accepts 2FA-bypass tokens for direct publish, so the
token-based path (changesets/action + pnpm -r publish on the build runner)
cannot publish anymore and an opt-in flag has no use. Remove the
`npm-trusted-publishing` input and the old publish and tag steps: every
node-simple-pnpm caller now packs on its runner and uploads from the
GitHub-hosted `npm-publish` job with trusted publishing.

`npm-token-fallback` stays (default true): npm tries OIDC first, so the
token only matters while it can still publish.
…ishing

MILAB-7081: npm trusted publishing (OIDC) for node-simple-pnpm
Comment on lines +139 to +142
const entries = readManifest(dir);
if (entries.length === 0) {
log('Nothing to publish.');
return [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing uploads look successful

publishTarballs reports success when manifest.jsonl is missing. A wrong dir or incomplete artifact therefore skips every upload without failing the release. Require the manifest to exist; an existing empty manifest can still mean there is nothing to publish.

Prompt To Fix With AI
This is a comment left during a code review.
Path: actions/node/npm-split-publish/src/publish.ts
Line: 139-142

Comment:
**Missing uploads look successful**

`publishTarballs` reports success when `manifest.jsonl` is missing. A wrong `dir` or incomplete artifact therefore skips every upload without failing the release. Require the manifest to exist; an existing empty manifest can still mean there is nothing to publish.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

Comment on lines +113 to +116
if ! npm view "${pkg}" name >/dev/null 2>&1; then
echo "SKIP ${pkg}: not on the registry yet (publish once, then configure)"
skipped=$((skipped + 1))
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Setup hides registry errors

apply treats every failed npm view as proof that the package does not exist. A network error, registry outage, or expired login silently skips existing packages and still lets the command succeed. Capture the error and skip only a confirmed not-found response; stop and show other failures.

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/npm-trust-setup.sh
Line: 113-116

Comment:
**Setup hides registry errors**

`apply` treats every failed `npm view` as proof that the package does not exist. A network error, registry outage, or expired login silently skips existing packages and still lets the command succeed. Capture the error and skip only a confirmed not-found response; stop and show other failures.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

@mike-ainsel
mike-ainsel merged commit 884ce28 into v4 Oct 19, 2026
2 checks passed
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.

1 participant