Skip to content

feat(release): SBOMs for the WebAssembly modules, the npm tarballs and the Windows installer - #1596

Merged
HuiJun merged 6 commits into
developfrom
feature/release-sbom-remaining
Oct 28, 2026
Merged

HuiJun merged 6 commits into
developfrom
feature/release-sbom-remaining

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What and why

PR #1592 (feature/release-sbom) publishes an SPDX 2.3 SBOM per archive, wheel, sdist and raw binary, listed in SHA256SUMS.txt so the cosign signature and the provenance cover them, and deferred three asset classes. This PR covers them, with the same scripts/release-sbom.py, naming (<asset>.spdx.json) and pinned syft 1.55.0.

Builds on #1592, now on develop; this PR targets develop and carries develop merged in.

  • WebAssembly modules (sysml-wasm.wasm, sysml-prod.wasm.gz). Go embeds the module information in a wasm module, but go version -m sysml-wasm.wasm answers could not read Go build info … unrecognized file format and syft writes a document naming nothing (both reproduced locally on a fresh GOOS=js GOARCH=wasm build — the 32-byte \xff Go buildinf: header is absent from the wasm, only the sentinel-wrapped module list is there). release-sbom.py now reads that list between debug/buildinfo's infoStart/infoEnd markers and the runtime's unique go1.x.y string (refusing a module with none or several), and writes the SPDX document itself with the packages syft would record (main module, every dependency at its built version, stdlib). The same build-info check applies. No go list -deps fallback was needed.
  • npm tarballs. Packing moves before the manifest: a new build-npm-package job (node executor, beside build-python-package) checks the tag against client/node/package.json, stamps the service digests, builds and packs the client (asserting its pins, as before), packs @openmbee/sysml-mcp and the generator-derived @openmbee/opensysml-mcp, and persists dist/npm. build-release writes one SBOM per tarball — the packed package/package.json (exact packed version, the tarball's SHA-256) as the described package, dependencies catalogued by syft from the lockfile (client/node/package-lock.json; packaging/npm/sysml-mcp/package-lock.json for the runner and its alias, which has no lockfile and pins the same five platform packages) — refusing a dependency the lock does not resolve or an exact pin at another version — except the release's own platform packages (@openmbee/ optional dependencies pinned at the tarball's version), which cannot be in the lockfile before the release publishes them and are declared from the manifest's pin with a sourceInfo saying so — and lists tarballs and SBOMs in SHA256SUMS.txt. publish-github-release uploads the tarballs; publish-npm no longer packs anything: it verifies the three tarballs against the signed manifest (sha256sum --check --strict) and publishes those bytes. Dev dependencies are not catalogued (syft default); peer dependencies are the installer's and are not required.
  • Windows MSI. release-windows.yml's Linux build job installs the same pinned syft, downloads the Z3 zip packaging/msi/z3.pin names and refuses a digest other than the pin's (as build-msi.sh does), and runs release-sbom.py --msi-inputs dist/unsigned --z3-pin … --z3-zip …: syft over the four Go executables (checked with go version -m) plus a declared z3 package (version, zip URL, pinned SHA-256, purl pkg:github/z3prover/z3@z3-5.1.0) with the five files the installer takes from the zip and their SHA-256s. The document is uploaded as an artifact; the msi job requires it to be named after the MSI it built and lists both in SHA256SUMS-windows-msi.txt. The sign job writes the -signed.msi.spdx.json the same way from the SignPath-returned executables in dist/signed (--msi-signed), so its file digests are the signed bytes'; publish-signed lists it in SHA256SUMS-windows-signed.txt. Documented as input-derived.
  • Tests: scripts/release-sbom-test.py (47 tests: wasm module-info reading incl. gz and the toolchain ambiguity refusal, authored document shape and reproducibility apart from created, npm manifest/name/dependency checks incl. the alias and the unpublished-platform-package case (a missing third-party optional dependency is still refused), Z3 pin/zip/digest/files, MSI naming as build-msi.sh derives it); scripts/release-provenance-test.py asserts a tarball and the wasm/npm SBOMs become subjects; tests/hygiene: TestNodePackageIsStampedWithItsReleaseDigests and TestNpmRunnerIsPublishedWithTheClient now hold build-npm-package/publish-npm to the new contract, TestReleaseSBOMsAreSignedWithTheManifest requires the wasm and npm SBOMs before the manifest and the tarballs listed before the SBOMs, new TestWindowsInstallerSBOMIsDerivedFromItsInputs (same syft pin in both CI files, SBOM named after the MSI before it is listed), TestMCPServerShipsAsItsOwnArchive admits build-npm-package reading dist/mcp.
  • Docs: docs/project/releasing.md (asset inventory, SBOM section with the three routes, Windows installer section, npm job order), docs/downloads.md § Verify, README. Changelog fragment changes/unreleased/release-sbom-remaining.added.md. (docs(security): publish the security policy on the site with security.txt and release verification #1591 also edits docs/downloads.md § Verify — expect a trivial conflict with whichever lands second.)

How it was verified

Local rehearsal with syft 1.55.0 (pinned download, digest checked) and go1.25.11:

class asset result
wasm sysml-wasm.wasm (fresh GOOS=js GOARCH=wasm build of cmd/sysml-wasm), sysml-prod.wasm.gz (gzip of it) 4 components each (OpenSysML, goldmark, x/text, stdlib go1.25.11); go version -m on the same file: unrecognized file format; syft: 1 package (the file)
npm openmbee-opensysml-0.11.0.tgz (npm pack of client/node after npm run build) 58 components (the lock's runtime closure, dev excluded; the client at the packed version with the tarball's digest)
npm openmbee-sysml-mcp-0.11.0.tgz, openmbee-opensysml-mcp-0.11.0.tgz (alias from build-platform-packages.mjs --mcp) 6 components each (the package + its five platform packages at 0.11.0)
MSI --msi-inputs over GOOS=windows builds of cmd/sysml and cmd/sysml-mcp with the real z3-5.1.0-x64-win.zip (6ff368ea…), tag v0.12.0-rc1 opensysml-0.12.0-windows-amd64.msi.spdx.json (and …-signed.msi.spdx.json with --msi-signed): 41 Go module components + Z3 5.1.0 with its five files' digests

Gates: go build ./..., go vet ./..., gofmt -l . (empty), go test ./tests/hygiene (ok), python3 scripts/release-sbom-test.py (43 OK), python3 scripts/release-provenance-test.py (15 OK), circleci config validate (valid), actionlint .github/workflows/release-windows.yml (clean), scripts/check-doc-links.py (0 broken), scripts/changelog.py check. Full go test ./... before un-drafting.

Not rehearsed end to end: the CircleCI release pipeline and the Windows runner path (release_rehearsal=true on the next merge to main exercises build-npm-package and the new build-release steps; workflow_dispatch of release-windows.yml with a dry-run version exercises the MSI SBOM).

Checklist

  • make test and make lint pass locally
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (compliance rows need nothing: the census is counted at docs build)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/4ef7130ad284408b9dc99863b96b72b5
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/4ef7130ad284408b9dc99863b96b72b5?variant=devin
Requested by: @HuiJun

…d the Windows installer

The wasm modules are described from the module information Go embeds in
them, which go version -m and syft cannot read from this format. The npm
tarballs are packed by a new build-npm-package job before the manifest, so
tarballs and SBOMs are lines of SHA256SUMS.txt and publish-npm publishes
the bytes the signed manifest lists; each SBOM describes the packed
manifest with its dependencies resolved through the lockfile. The MSI's
SBOM is derived from its inputs: the Go executables and the bundled Z3
declared from packaging/msi/z3.pin, listed in SHA256SUMS-windows-msi.txt.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

…re/release-sbom-remaining

Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	tests/hygiene/release_config_test.go
Base automatically changed from feature/release-sbom to develop October 28, 2026 01:40
@HuiJun
HuiJun marked this pull request as ready for review October 28, 2026 03:04
devin-ai-integration[bot]

This comment was marked as resolved.

…the signed MSI SBOM

An optional dependency the lockfile cannot resolve yet (the platform packages a
release publishes beside the tarball) is recorded from the manifest's exact pin
with a sourceInfo saying so, instead of failing the npm SBOM; required
dependencies still must resolve. The signed installer's SBOM is written by the
sign job from the executables SignPath returned, so its file digests are those
of the bytes the signed MSI ships.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…the lockfile lacks them

The manifest-only fallback of the npm SBOM applies to @openmbee/ optional
dependencies pinned at the tarball's own version — the platform packages the
release publishes beside it — so a third-party optional dependency the
lockfile does not resolve is still refused.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit 438babd into develop Oct 28, 2026
51 of 90 checks passed
@HuiJun
HuiJun deleted the feature/release-sbom-remaining branch October 28, 2026 13:05
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