How to report a vulnerability and what to expect, which versions get fixes, how to verify a
release before running it, how to harden a served instance, and where advisories are published.
The policy below is SECURITY.md at the repository root, embedded when
this site is built, and the site also serves it as
/.well-known/security.txt
(RFC 9116).
The site build replaces this block with SECURITY.md; read that file
on GitHub for the reporting channel, the response deadlines, coordinated disclosure, the
supported versions and the scope.
Every stable release publishes one checksum manifest, SHA256SUMS.txt, covering every asset of
the release — archives, bare binaries, the Python wheel and sdist, the WebAssembly builds, and
the SBOM of each of them — and signs it with cosign from the
release pipeline's identity (keyless; the certificate names the CircleCI project, not a person),
as SHA256SUMS.txt.bundle. A SLSA provenance statement, provenance.intoto.json, is signed the
same way. Verify the manifest first; everything else is checked against it. The commands below
were run against v0.11.0;
substitute the tag you downloaded.
R=https://github.com/Open-MBEE/OpenSysML/releases/download/v0.11.0
curl -fsSLO $R/SHA256SUMS.txt
curl -fsSLO $R/SHA256SUMS.txt.bundle
cosign verify-blob SHA256SUMS.txt --bundle SHA256SUMS.txt.bundle \
--certificate-oidc-issuer https://oidc.circleci.com/org/1169df8b-0b59-400f-82d2-c9d8e98bdb62 \
--certificate-identity-regexp '^https://circleci\.com/api/v2/projects/eeb0dddd-237f-4f02-9e51-8e24caef589d/pipeline-definitions/[0-9a-f-]+$'
sha256sum -c SHA256SUMS.txt --ignore-missingcosign prints Verified OK when the manifest was signed by this project's release pipeline;
sha256sum prints one OK per downloaded asset it finds in the manifest. The issuer and the
identity pattern are the pipeline's and do not change between releases; a bundle that verifies
under a different identity is not a release of this project. The installer does this check for
you with --verify-signature (see Install). The nightly prereleases are
signed by GitHub Actions instead; their identity is on the
nightly snapshot page.
provenance.intoto.json is an in-toto Statement with a
SLSA v1 provenance predicate: the tag and commit the
assets were built from, and the digest of every asset. Its signature covers the statement, and
cosign checks that the asset you name is one of its subjects:
curl -fsSLO $R/provenance.intoto.json
curl -fsSLO $R/provenance.intoto.json.bundle
curl -fsSLO $R/opensysml-linux-amd64.tar.gz
cosign verify-blob-attestation opensysml-linux-amd64.tar.gz \
--bundle provenance.intoto.json.bundle --type slsaprovenance1 \
--certificate-oidc-issuer https://oidc.circleci.com/org/1169df8b-0b59-400f-82d2-c9d8e98bdb62 \
--certificate-identity-regexp '^https://circleci\.com/api/v2/projects/eeb0dddd-237f-4f02-9e51-8e24caef589d/pipeline-definitions/[0-9a-f-]+$'
jq -r '.predicate.buildDefinition.buildType,
(.predicate.buildDefinition.resolvedDependencies[] | "\(.uri) \(.digest.gitCommit)")' \
provenance.intoto.jsonFor v0.11.0 the build type is https://github.com/Open-MBEE/OpenSysML/.circleci/build-release/v1
and the one resolved dependency is git+https://github.com/Open-MBEE/OpenSysML@refs/tags/v0.11.0
at commit ddf4df00037d6ddbfb1fa9d743a4389f75c9e2dc — the commit the tag points at on GitHub.
Releases after v0.11.0 publish one SPDX 2.3 JSON
software bill of materials per asset, named <asset>.spdx.json: the Go modules and toolchain a
binary or archive was built from (the list go version -m prints), or the Python distribution a
wheel or sdist carries. Each SBOM is a line of the signed manifest, so once the manifest is
verified the digest check vouches for it like any other asset:
curl -fsSLO $R/opensysml-linux-amd64.tar.gz.spdx.json
sha256sum -c SHA256SUMS.txt --ignore-missing
jq -r '.packages[] | "\(.name) \(.versionInfo)"' opensysml-linux-amd64.tar.gz.spdx.jsonHow the SBOMs are produced and checked against the binaries is in Releasing § The software bills of materials.
The bare service binaries (sysml-grpc-*, sysml-jupyter-kernel-*) and the WebAssembly builds
carry a <asset>.sha256 sidecar for clients that fetch one file. A sidecar is a convenience,
not a trust anchor: it is served from the same place as the asset, so check it against the
signed manifest.
curl -fsSLO $R/sysml-grpc-linux-amd64.sha256
grep ' sysml-grpc-linux-amd64$' SHA256SUMS.txt | diff - sysml-grpc-linux-amd64.sha256The Python and Node clients, which download sysml-grpc for you, use pinned digests stamped
into the package at release time or the signed manifest, never a sidecar alone; a digest
mismatch or an invalid signature is an error, not a fallback to unverified bytes
(Python client § The service).
The wheel and sdist uploaded to PyPI are the same files as on the GitHub release, and the manifest lists them, so a package downloaded from PyPI can be checked against the signed manifest:
curl -fsSLO $R/opensysml-0.11.0-py3-none-any.whl
curl -fsSLO $R/opensysml-0.11.0.tar.gz
sha256sum -c SHA256SUMS.txt --ignore-missingPin the same digest in a requirements file
(opensysml==0.11.0 --hash=sha256:a4bb6cb481bf008f336bc4dce71b9fd345de971268ebc5874e0a36b84eb5503d
for the v0.11.0 wheel) and pip install --require-hashes refuses anything else. The Jupyter
kernel's platform wheels (jupyter_opensysml_kernel-*.whl) are on the release and in the
manifest too.
Releases after v0.11.0 are uploaded to PyPI by the repository's
release-pypi.yml
workflow with trusted publishing, after it has checked the files against the signed manifest
above, so each file also carries a PEP 740 attestation
naming that workflow — PyPI shows it under Verified details, and
pypi-attestations checks it against the
publishing repository without downloading the release:
pip install pypi-attestations
python -m pypi_attestations verify pypi --repository https://github.com/Open-MBEE/OpenSysML \
pypi:opensysml-<x.y.z>-py3-none-any.whlThe nightly snapshots on PyPI (<next>.dev<yyyymmdd> versions) have carried the same
attestation, from the nightly workflow, since the first one. v0.10.0, v0.10.1 and v0.11.0
of both packages do not: they were uploaded by a CircleCI job with an API token, which PyPI
cannot attest, and PyPI marks each of them Loss of provenance against the attested
snapshot before it. That was the publishing path of the time, not a compromise; the files
are the ones each release's signed manifest lists, and the sha256sum check above is how to
verify them. An attestation is attached only at upload and a version is never re-uploaded,
so those releases keep the mark.
@openmbee/opensysml and its platform packages are published to the npm registry, which records
a subresource integrity digest per tarball that npm install checks on every download; a
lockfile pins it. Read the registry's record before pinning:
npm view @openmbee/opensysml@0.11.0 dist.integrityThe platform packages that carry sysml-grpc embed the binary from the release's assets.
org.openmbee:opensysml is on Maven Central from 0.10.1
(pkg:maven/org.openmbee/opensysml@0.11.0). Central publishes a detached GPG signature
(.asc) and checksums beside every artifact, as it requires of every publisher, and Maven and
Gradle check the checksums on download; pin the version in the build file so a resolved
artifact cannot change under it.
Cargo verifies every crate it downloads against the checksum recorded in the registry index, so
cargo add opensysml@0.11.0 with a committed Cargo.lock pins the exact crate. The registry
reports the same checksum:
curl -fsS -A 'opensysml-docs (curl)' https://crates.io/api/v1/crates/opensysml/0.11.0 \
| jq -r '.version | .num, .checksum, .yanked'openmbee/opensysml:<version> is a multi-platform image whose index carries a BuildKit
provenance attestation
and an SPDX SBOM per platform. Pin the index digest and read the attestations with
docker buildx imagetools:
docker buildx imagetools inspect openmbee/opensysml:0.11.0
docker buildx imagetools inspect openmbee/opensysml:0.11.0 \
--format '{{ range $k, $v := .Provenance }}{{ $k }}: {{ json $v.SLSA.buildDefinition.externalParameters.request.root.request.args }}{{ "\n" }}{{ end }}'
docker buildx imagetools inspect openmbee/opensysml:0.11.0 \
--format '{{ range $k, $v := .SBOM }}{{ $k }}: {{ $v.SPDX.spdxVersion }} {{ len $v.SPDX.packages }} packages{{ "\n" }}{{ end }}'The first command prints the index digest (sha256:e3c7a9dc… for v0.11.0) and one manifest per
platform plus one attestation manifest each. The provenance names the source the image was built
from — vcs:source https://github.com/Open-MBEE/OpenSysML.git, vcs:revision
ddf4df00037d6ddbfb1fa9d743a4389f75c9e2dc, build-arg:VERSION v0.11.0 for v0.11.0 — which
must match the release's provenance above. Run the image by digest
(openmbee/opensysml@sha256:…) once you have checked it.
The MSI and the Windows executables are Authenticode signed through SignPath Foundation once
the project's application is approved, and published as separate *-signed* assets with their
digests in SHA256SUMS-windows-signed.txt; the unsigned MSI's digest is in
SHA256SUMS-windows-msi.txt. Both digest files are produced by the GitHub Actions workflow that
builds the installer, not by the CircleCI pipeline, so they are not covered by the cosign
signature above — check the signature on the file itself (Get-AuthenticodeSignature in
PowerShell, or the file's Properties → Digital Signatures) and see the
code signing policy for who may
approve a signature. macOS binaries are not Developer ID signed or notarized.
sysml-grpc and sysml-mcp -http bind loopback unless the address says otherwise. Before an
address other machines can reach:
sysml-grpchas no authentication. Nothing in the service tells one caller from another: every client that can reach the address can call every RPC the capability list advertises, edits and runs included. Keep it on loopback, or reach it only through something that does authenticate — a reverse proxy or gateway, a VPN, a network policy — and never from an address the public internet routes to.- TLS.
-tls-certand-tls-key(both or neither) serve every protocol over HTTPS on the one port, TLS 1.2 or later; it encrypts the connection and proves the server, not the client. Service transports is the reference, including the browser-origin allow-list, which is not authentication either. sysml-mcprequires a bearer token on a non-loopback address —-token-file,-tokenorOPENSYSML_MCP_TOKEN— and refuses to start without one; every request must carry it. Seesysml-mcp§ Transports.- A crafted model, project file, import or query must never execute or disclose anything on the host; a case where one does is in scope above, and a denial of service against a served instance is too.
Fixes are announced as GitHub Security Advisories on this repository, with a CVE requested through GitHub, and the fix release's notes link the advisory. Dependabot alerts and SonarCloud code-scanning results are watched by the code owners on the deadlines in the policy above. Every release's notes end with the support period in force and a link back to Verifying a release.