Skip to content

Phase 1 research: npm workspaces support#211

Merged
TomHennen merged 3 commits into
mainfrom
research/npm-workspaces-phase-1
May 14, 2026
Merged

Phase 1 research: npm workspaces support#211
TomHennen merged 3 commits into
mainfrom
research/npm-workspaces-phase-1

Conversation

@TomHennen
Copy link
Copy Markdown
Owner

Summary

Phase 1 research for #208 — extending the existing npm build type to support package.json with a workspaces field. Research only; no code changes. Implementation follows in a separate PR after this doc is reviewed.

Models on #178's npm Phase 1 (which became SPEC.md when v0.1 landed). The new file is a sibling research doc at build/actions/npm/WORKSPACES_PHASE_1.md; once the implementation PR lands, the relevant content folds into SPEC.md.

Answers to the 8 design questions

# Question Answer
1 Artifact model — where does the "exactly 1 tarball" assertion propagate? Replaced by "exactly N tarballs" driven by enumerated workspace members. Single-package path stays as-is.
2 SLSA generator subject list semantics One bundle, N subjects via the generic generator's existing multi-subject support. Same shape python uses for wheel+sdist.
3 slsa-verifier verify-artifact with multi-subject bundles Verifies single artifact by hash match against subjects[]. Verify step loops per-tarball.
4 Publish step shape Adopter's caller workflow iterates dist/*.tgz. --access public harmless on subsequent publishes.
5 SBOM granularity Per-workspace-member, not repo-wide. Reflects what consumers actually install.
6 Versioning coordination Wrangle stays tool-agnostic; example workflow demonstrates the canonical changesets pattern.
7 Mixed-scope handling Adopter-side concern (per-package Trusted Publisher registration on npmjs.com); no wrangle code changes.
8 Failure semantics Atomic. Partial publish recovered by re-running the workflow.

Key design decisions worth flagging for review

  • Backcompat: action.yml's existing tarball output (string) stays populated (with the first tarball when workspaces is active) so v0.1 adopter workflows don't break. New tarballs output (list) for callers that need the full set.
  • private: true workspaces are skipped by pack invocation AND skipped in the expected-count check — adopters with private examples / fixtures aren't surprised by failed counts.
  • workspace:* protocol resolution is handled by the package managers' pack commands automatically; the doc flags it as something to verify in a structural test rather than as wrangle work.
  • Yarn Berry support is explicitly deferred to a follow-up — detection works the same, but yarn's CLI differs enough to warrant its own validation pass.

Open questions left for the implementation PR

  • Yarn workspace pack behavior (mostly a "later" concern).
  • Whether to ship a versioning prep helper (leaning no — document changesets pattern instead).
  • SLSA generator subject-count cap (probably none, worth confirming).
  • Single-package fallback test coverage (structural test on the implementation PR).

Test plan

  • No tests intended — research-only doc.
  • Reviewer: confirm the multi-subject SLSA generator claim against current generator docs (generator_generic_slsa3.yml@v2.1.0).
  • Reviewer: confirm slsa-verifier verify-artifact semantics with multi-subject bundles — the verify-step-as-loop pattern depends on this.
  • Reviewer: gut-check the changesets pattern recommendation against your own preferences for adopter examples.

Related

https://claude.ai/code/session_01AqkojrFQsx5CgHGndN96E2


Generated by Claude Code

Drafts the design for extending the existing npm build type to handle
package.json with a workspaces field — the N-tarballs-per-build case
that v0.1 currently rejects in validate_inputs.sh.

Models on the existing npm Phase 1 research (which became SPEC.md when
v0.1 landed). Answers the 8 design questions from #208:

1. Artifact model — exactly-one-tarball assertion is replaced by an
   exactly-N-tarball assertion driven by enumerated workspace members.
2. Subject list semantics — single bundle with N subjects via the
   generic SLSA generator's existing multi-subject support. No per-
   package bundle.
3. slsa-verifier behavior — confirmed verifies single artifact against
   multi-subject bundle by hash match; verify step loops per-tarball.
4. Publish step shape — adopter's caller workflow iterates over
   dist/*.tgz; --access public is harmless on subsequent publishes.
5. SBOM granularity — per-member, not repo-wide. Reflects what
   consumers actually install.
6. Versioning coordination — wrangle stays tool-agnostic; example
   workflow shows changesets pattern.
7. Mixed-scope handling — adopter-side concern (Trusted Publisher
   registration per package); no wrangle changes needed.
8. Failure semantics — atomic; partial-publish caught by adopter
   re-running the workflow.

Plus implementation notes for the eventual PR (action.yml output shape
keeps backcompat with existing 'tarball' output; new 'tarballs' output
for callers that need the full list).

No code changes. Implementation tracked in #208's implementation PR.
…rections

- pnpm pack recursive form: `pnpm -r exec pnpm pack ...` (not `pnpm -r pack`
  which isn't a real command).
- Verify step: single `slsa-verifier verify-artifact ... dist/*` call,
  mirroring python's wheel+sdist pattern (not an N-call loop).
- Fix `--skip-existing` inaccuracy: npm publish has no such flag; recovery
  goes through `npm view <pkg>@<version>` gating in the adopter loop.
- Drop the `tarball` "first one" silent-pitfall: leave it empty on the
  workspaces path so single-package-shaped callers fail loudly instead of
  under-publishing 1 of N.
- Elevate `workspace:` protocol resolution from Awkward cases to a
  Recommended default with a mandatory structural test.
- Clarify per-member SBOM filename is path-derived (`<member-shortname>`),
  not name-derived.
- Mark the SLSA generator subject cap as design-blocking pre-implementation
  verification, not an open question.
- Add the two-layer (L2 per-package-publish / L3 shared-build) attestation
  model as an intentional design point in the Provenance bundle section.
- Note the hash-step sort divergence from python's bare-glob pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@TomHennen TomHennen temporarily deployed to integration-test May 14, 2026 01:13 — with GitHub Actions Inactive
…t, redesign paths, UX hint

- Per-workspace member validation: spell out that `private: true` filtering
  is mandatory at the expected-N step, not just at pack time, with a
  concrete jq fragment. Otherwise the count check fails for every adopter
  with private fixtures.
- Hash step: force LC_ALL=C on the filename sort so character collation
  doesn't drift across CI runner locales. Note that python's hash step
  could use the same hardening (invisible at N=2, but the principle
  generalizes).
- Subject-cap open question: pre-document the two redesign paths
  (chunked bundles vs per-namespace bundles) with shape guidance so the
  implementer isn't inventing under pressure if the cap-check fails.
- tarball-empty UX hint: add a job-summary line and README migration
  section instead of a sentinel string. Sentinel approach was rejected
  because it passes defensive `[[ -n ... ]]` checks then proceeds with a
  broken value — worse than failing the check loudly. Optional additive
  `tarball-unavailable-reason` output flagged for later if the summary
  isn't enough.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@TomHennen TomHennen temporarily deployed to integration-test May 14, 2026 01:21 — with GitHub Actions Inactive
@TomHennen TomHennen merged commit 392d92a into main May 14, 2026
6 checks passed
@TomHennen TomHennen deleted the research/npm-workspaces-phase-1 branch May 14, 2026 01:24
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