Skip to content

feat: Add create-package-releases and upload-package-sboms- and verify-package#63

Merged
David Elner (delner) merged 12 commits into
mainfrom
lforst/js-changes
Jul 17, 2026
Merged

feat: Add create-package-releases and upload-package-sboms- and verify-package#63
David Elner (delner) merged 12 commits into
mainfrom
lforst/js-changes

Conversation

@lforst

Copy link
Copy Markdown
Member

Adds smaller units of work that are usable in the js repo.

Flow for the JS repo would be:

  • Start publish workflow with specific commit SHA as input
  • The sha is checked out
  • An unprivileged job: Finds package versions not on npm yet, writes a manifest with those packages and versions, packs the packages productin .tgz files alongside SBOMs and uploads those as artifacts.
  • The release/packages are posted to Slack and we wait for release gate approval
  • After approval, the publish job downloads the pre-built artifacts, verifies attestations (so that we know they have not been tampered with), publishes the .tgz files to npm, pushes package tags based on changesets, creates a github release per package tag, attaches the SBOMs to the github releases, comments on issues closed by the releases

The JS SDK side of things is tracked in this PR: braintrustdata/braintrust-sdk-javascript#2216

Base automatically changed from release_custom_build_actions to main July 13, 2026 17:44

@delner David Elner (delner) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think adding some of these actions are fine, but I recommend we make some structural changes to them before adopting them as a part of the "public API" of our action library.

Comment thread templates/actions/release/verify-package.yml.erb
Comment thread templates/actions/release/lang/js/publish-npm-tarballs.yml.erb Outdated
Comment thread templates/actions/release/lang/js/publish-npm-tarballs.yml.erb

<%= render_step('slack/send', text: "${{ steps.message-published.outputs.text }}") %>

- name: Build failure Slack message

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why not reuse steps/release/lang/js/on-failure for this?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

steps/release/lang/js/on-failure combines two things: lang/js/env-dump and release/notify-failure

  • env-dump is a bit pointless in a monorepo, and a bit pointless in general I think. The information it prints is irrelevant to publishing.
  • release/notify-failure is problematic for a few reasons:
    • In the flow I came up with, GH releases and tags are done after publishing the tarballs. release/notify-failure wants a tag.
    • release/notify-failure wants one tag while in the monorepo we have multiple tags.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The purpose of env-dump is to help with debugging failed releases: sometimes there's problems with release tooling (version mismatches, runtime issues, etc.) Granted, I didn't refine this for Node, but it has been useful when the build has broken a few other times.

If you feel like this is bespoke enough to warrant its own failure handling, I can live with that though.

Comment thread templates/steps/release/upload-package-sboms.yml.erb Outdated
Comment thread templates/actions/release/upload-package-sboms.yml.erb Outdated
artifact_base="${name#@}"
artifact_base="${artifact_base//\//-}"
artifact_base="${artifact_base//@/-}"
expected="${sbom_asset:-$artifact_base-$version.sbom.json}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think it'd be better if we explicitly required an SBOM asset here instead of guess at a derivation. The convention is hidden and looks npm-ish which doesn't fit well with making this a language agnostic behavior.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yup agree! I made it so that we make the sbom path part of the artifacts manifest a) so that it's not duplicated b) so that we don't have js-isms in a generic thing

Also, I renamed publish-tarballs -> publish-npm-tarballs and create-package-releases -> create-npm-package-github-releases.

@delner David Elner (delner) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Few more things that stood out, but it's moving in the right direction.

@@ -0,0 +1,128 @@
name: Create npm Package GitHub Releases

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't look npm specific? If it isn't we should rename (drop npm). If it is, I think we should move it to release/lang/js.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I renamed it!

if [ -z "$sbom_asset" ]; then
echo "::error title=SBOM asset missing::manifest package $name@$version must set sbom_asset."
rm -f "$notes_file"
exit 1

@delner David Elner (delner) Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If I'm reading this correctly, this means we could fail mid-way through releasing multiple packages? What's the recovery path when that happens?

I think we could mitigate this somewhat at the "validate" stage (pre-approval) but at a minimum we should have a means of healing, ideally self-healing.

(This was one of the advantages a "job per package" or "package per workflow" scheme offers as you can isolate/restart individual jobs. Here I'm not so sure how that works.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's not that bad I think.

We have two failure modes:

  • Something goes wrong at the "publish npm tarball" step
  • Something goes wrong at the "create github releases" step

If we make both """idempotent""", meaning that re-running the action will not re-publish either a tarball, or a github release, I think we are perfectly fine right? I tried to implement this now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes, idempotency is the answer. I also applied this to other workflows in another branch.

channel="$(jq -r '.channel // empty' <<< "$package_json")"
provenance="$(jq -r '.provenance // empty' <<< "$package_json")"

[ -n "$expected_tarball" ] || expected_tarball="$(artifact_base "$name" "$version").tgz"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like this is also deriving (guessing) rather than using an explicit input? (Same as the SBOM comment before.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Made it so that publish-npm-tarballs wants a tarball_asset, requires it to be an exact match, and verifies exactly one downloaded tarball matches.

@delner
David Elner (delner) merged commit cce742f into main Jul 17, 2026
44 checks passed
@delner
David Elner (delner) deleted the lforst/js-changes branch July 17, 2026 17:11
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