Software Bill of Materials
Current OpenIAP release workflows attach a machine-readable inventory of direct runtime components and dependency contracts, including first-party OpenIAP native contracts, to each GitHub Release as a CycloneDX 1.6 JSON file. A daily repair job fills missed latest-stable-release assets; prereleases rely on their release-time dispatch. Exact application exposure comes from the consumer's resolved dependency graph.
Finding one#
SBOMs are release assets, named after the package and version they describe:
<package>-<version>.cdx.json
react-native-iap-16.3.0.cdx.json
openiap-google-3.3.0.cdx.json
flutter_inapp_purchase-10.3.0.cdx.jsonDownload one from its release:
gh release download react-native-iap-16.3.0 \
--repo hyodotdev/openiap -p '*.cdx.json'One SBOM is published per releasable component — the SDKs, the native packages, and the specification — rather than one for the whole monorepo, because a repository-wide document would describe something nobody installs.
Verifying it#
The SBOM carries a build provenance attestation, so you can confirm OpenIAP's CI produced it rather than trusting the file on sight:
CERT_IDENTITY=https://github.com/hyodotdev/openiap
CERT_IDENTITY="$CERT_IDENTITY/.github/workflows/sbom.yml@refs/heads/main"
gh attestation verify react-native-iap-16.3.0.cdx.json \
--repo hyodotdev/openiap --cert-identity "$CERT_IDENTITY" \
--deny-self-hosted-runnersAnd validate it against the CycloneDX schema:
cyclonedx validate --input-file react-native-iap-16.3.0.cdx.json \
--input-format json --input-version v1_6 --fail-on-errorsEvery tool below is independent of this repository, so verification never requires trusting our tooling:
| Tool | Role | License |
|---|---|---|
gh attestation verify | Confirm CI provenance against Sigstore | MIT |
cyclonedx-cli | Validate against the published schema | Apache-2.0 |
sbomqs | Score quality and NTIA compliance | Apache-2.0 |
osv-scanner | Match components against the OSV database | Apache-2.0 |
grype | Match components against vulnerability feeds | Apache-2.0 |
What is inside#
Each document records:
- The component's name, version, and package URL (purl), matching the published package
- The repository URL and the exact commit the release was built from
- The exact generator commit used to create the SBOM
- The release tag, so an artifact and its inventory cannot be mismatched
- Every direct runtime dependency, with version or constraint, purl, and available supplier and license data
Deliberately excluded: test and build-only dependencies. Peer dependencies from JavaScript manifests are not counted as bundled npm runtime code, while native CocoaPods and Maven contracts shipped through framework SDKs are listed separately. Operating-system frameworks such as StoreKit are not distributed packages and are likewise absent.
Vulnerability analysis (VEX)#
When a scanner flags a CVE against a dependency, the useful question is whether it is reachable through OpenIAP's use of that dependency. Where that has been analysed, the judgement travels in the same SBOM as a CycloneDX vulnerabilities entry, with a state such as not_affected and a required justification.
If a release's SBOM has no vulnerabilities section, it means no CVE has been analysed for that release — not that a scan was run and came back clean.
Standards and tooling#
Everything here is an open standard, most of it maintained under the Linux Foundation or OWASP.
| Concern | Standard |
|---|---|
| Document format | CycloneDX 1.6 |
| Component identity | Package URL (purl) |
| License identity | SPDX identifiers |
| Required data fields | NTIA minimum elements |
| Vulnerability analysis | CycloneDX VEX |
| Provenance | SLSA in in-toto statements, signed via Sigstore |
Current limits#
Stated plainly, so you can judge the evidence:
- Transitive dependencies are included only where the ecosystem's resolver output is available. Release SBOMs otherwise describe the documented direct-dependency source.
- Licenses and suppliers combine reviewed local metadata with point-in-time registry enrichment. Unavailable metadata is omitted, and pub.dev and some NuGet packages do not expose a standard value.
- Version constraints remain constraints when a library manifest does not select one exact version. Use the consuming application lockfile for exact CVE matching.
- KMP target scope uses the published canonical/common KMP POM plus exact Apple, Play, Horizon, and Amazon contracts. A single-platform application should use its resolved target graph.
- MAUI target scope is the union of the published nuspec's target-framework groups. Grouped dependencies remain optional and platform-labelled; use the consuming application's resolved graph to narrow the aggregate.
Where a dependency cannot be resolved, generation fails rather than emitting a shorter list — an inventory that silently omits something is worse than none, because it is trusted.