From 05a8791471b7ad44275da378de29c5ec99e6d3ed Mon Sep 17 00:00:00 2001 From: Nachiket Roy Date: Tue, 3 Nov 2026 23:48:41 +0530 Subject: [PATCH 1/6] ci(spdx): validate SPDX SBOM with official spdx-tools validator in CI --- .github/workflows/ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3b7cef95..ea9c38edd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,19 @@ jobs: - name: Test run: npm test + - name: Setup Python + uses: actions/setup-python@42375524e2e2a3c749eb3544d935cd61e389e6e8 # v5.4.0 + with: + python-version: "3.x" + + - name: Install spdx-tools + run: pip install spdx-tools + + - name: Validate SPDX SBOM with official spdx-tools validator + run: | + node dist/index.js . --sbom spdx --output sbom.spdx.json + pyspdxtools --infile sbom.spdx.json + node-floor: name: Node 22 floor runs-on: ubuntu-latest From 41395cbc44043e835ac8ae67b36923275d09830a Mon Sep 17 00:00:00 2001 From: Nachiket Roy Date: Tue, 3 Nov 2026 23:52:56 +0530 Subject: [PATCH 2/6] fix(ci): use correct commit SHA for actions/setup-python@v5.4.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea9c38edd..0f5c05942 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: run: npm test - name: Setup Python - uses: actions/setup-python@42375524e2e2a3c749eb3544d935cd61e389e6e8 # v5.4.0 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: "3.x" From eb34835dd09811bdaa7fc029a313a308ef8a7805 Mon Sep 17 00:00:00 2001 From: Nachiket Roy Date: Thu, 5 Nov 2026 20:08:34 +0530 Subject: [PATCH 3/6] ci(spdx): pin spdx-tools with hashes and isolate scan severity gate --- .github/workflows/ci.yml | 13 +- .github/workflows/spdx-tools-requirements.txt | 121 ++++++++++++++++++ 2 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/spdx-tools-requirements.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f5c05942..323c9b423 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,17 +46,24 @@ jobs: - name: Test run: npm test + # Verify that emitted SPDX 2.3 documents strictly conform to the specification + # using the Linux Foundation's official Python reference tool (spdx-tools). + # The SBOM is generated from this repo; findings at or above the default severity gate + # (exit code 1) must not fail this step since vulnerability gating is handled separately. - name: Setup Python uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: - python-version: "3.x" + python-version: "3.12" - name: Install spdx-tools - run: pip install spdx-tools + run: pip install --require-hashes -r .github/workflows/spdx-tools-requirements.txt - name: Validate SPDX SBOM with official spdx-tools validator run: | - node dist/index.js . --sbom spdx --output sbom.spdx.json + node dist/index.js . --sbom spdx --output sbom.spdx.json || status=$? + if [ "${status:-0}" -gt 1 ]; then + exit "$status" + fi pyspdxtools --infile sbom.spdx.json node-floor: diff --git a/.github/workflows/spdx-tools-requirements.txt b/.github/workflows/spdx-tools-requirements.txt new file mode 100644 index 000000000..39c9d6b5c --- /dev/null +++ b/.github/workflows/spdx-tools-requirements.txt @@ -0,0 +1,121 @@ +# Pinned dependencies with hashes for spdx-tools CLI validation in CI. +# Autogenerated with pip-compile --generate-hashes for Python 3.12. +beartype==0.23.1 \ + --hash=sha256:4461b4dc57e3fdd6c8a8464b22cf118002eea107c33e9fef651c69068ab3cce3 \ + --hash=sha256:8b805f246b32931c74f2b321ea0939fe5bb2ff43c12a3eff19cc4c854b832e1d + # via spdx-tools +boolean-py==5.0 \ + --hash=sha256:60cbc4bad079753721d32649545505362c754e121570ada4658b852a3a318d95 \ + --hash=sha256:ef28a70bd43115208441b53a045d1549e2f0ec6e3d08a9d142cbc41c1938e8d9 + # via license-expression +click==8.5.0 \ + --hash=sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360 \ + --hash=sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34 + # via spdx-tools +license-expression==30.4.4 \ + --hash=sha256:421788fdcadb41f049d2dc934ce666626265aeccefddd25e162a26f23bcbf8a4 \ + --hash=sha256:73448f0aacd8d0808895bdc4b2c8e01a8d67646e4188f887375398c761f340fd + # via spdx-tools +ply==3.11 \ + --hash=sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3 \ + --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce + # via spdx-tools +pyparsing==3.3.3 \ + --hash=sha256:928ae7e20211f3b6f3915a72f06a0cfd29ab9d24279dd6346b6b1a7146397d36 \ + --hash=sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4 + # via rdflib +pyyaml==6.0.3 \ + --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ + --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \ + --hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \ + --hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \ + --hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \ + --hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \ + --hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \ + --hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \ + --hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \ + --hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \ + --hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \ + --hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \ + --hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \ + --hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \ + --hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \ + --hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \ + --hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \ + --hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \ + --hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \ + --hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \ + --hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \ + --hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \ + --hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \ + --hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \ + --hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \ + --hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \ + --hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \ + --hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \ + --hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \ + --hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \ + --hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \ + --hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \ + --hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \ + --hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \ + --hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \ + --hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \ + --hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \ + --hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \ + --hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \ + --hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \ + --hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \ + --hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \ + --hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \ + --hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \ + --hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \ + --hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \ + --hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \ + --hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \ + --hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \ + --hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \ + --hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \ + --hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \ + --hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \ + --hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \ + --hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \ + --hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \ + --hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \ + --hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \ + --hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \ + --hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \ + --hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \ + --hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \ + --hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \ + --hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \ + --hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \ + --hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \ + --hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \ + --hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \ + --hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \ + --hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \ + --hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \ + --hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \ + --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 + # via spdx-tools +rdflib==7.6.0 \ + --hash=sha256:30c0a3ebf4c0e09215f066be7246794b6492e054e782d7ac2a34c9f70a15e0dd \ + --hash=sha256:6c831288d5e4a5a7ece85d0ccde9877d512a3d0f02d7c06455d00d6d0ea379df + # via spdx-tools +semantic-version==2.10.0 \ + --hash=sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c \ + --hash=sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177 + # via spdx-tools +spdx-tools==0.8.5 \ + --hash=sha256:7c2d5865941be9d2e898f5b084e8d5422dd298dc5a29320ddb198fec304f59c4 \ + --hash=sha256:be600beb2f762f0116025e05490d399e724f668bef84025a7c421bb266688bdb + # via -r spdx-input.in +uritools==6.1.4 \ + --hash=sha256:7e48617975c3ccd3ee11da4641af8f8c9b97dcd7e75969a4cdfd7c8ce177f4e3 \ + --hash=sha256:d0b0b589582c29c5085aa1815e4abca59ded3d4420315743328166d65ee73429 + # via spdx-tools +xmltodict==1.0.4 \ + --hash=sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61 \ + --hash=sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a + # via spdx-tools From b304a5015e7a2e29b3276859db287bc9f2839c6d Mon Sep 17 00:00:00 2001 From: Nachiket Roy Date: Thu, 5 Nov 2026 20:10:00 +0530 Subject: [PATCH 4/6] style: add trailing newline to spdx-tools-requirements.txt --- .github/workflows/spdx-tools-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/spdx-tools-requirements.txt b/.github/workflows/spdx-tools-requirements.txt index 39c9d6b5c..9300d0e99 100644 --- a/.github/workflows/spdx-tools-requirements.txt +++ b/.github/workflows/spdx-tools-requirements.txt @@ -119,3 +119,4 @@ xmltodict==1.0.4 \ --hash=sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61 \ --hash=sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a # via spdx-tools + From 79de148986425ad11a6813beed28a395130e0a8c Mon Sep 17 00:00:00 2001 From: Nachiket Roy Date: Thu, 5 Nov 2026 20:21:17 +0530 Subject: [PATCH 5/6] ci(spdx): use local advisory database for validation with --offline --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 323c9b423..2eac87d72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,7 +60,7 @@ jobs: - name: Validate SPDX SBOM with official spdx-tools validator run: | - node dist/index.js . --sbom spdx --output sbom.spdx.json || status=$? + node dist/index.js . --sbom spdx --output sbom.spdx.json --offline || status=$? if [ "${status:-0}" -gt 1 ]; then exit "$status" fi From 73db6d9621de6ad51e5fb786dae374423599fcd9 Mon Sep 17 00:00:00 2001 From: Nachiket Roy Date: Thu, 5 Nov 2026 20:31:09 +0530 Subject: [PATCH 6/6] ci(spdx): remove stale SBOM file and assert output existence before validation --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2eac87d72..04f03181c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,10 +60,12 @@ jobs: - name: Validate SPDX SBOM with official spdx-tools validator run: | + rm -f sbom.spdx.json node dist/index.js . --sbom spdx --output sbom.spdx.json --offline || status=$? if [ "${status:-0}" -gt 1 ]; then exit "$status" fi + test -f sbom.spdx.json || exit 1 pyspdxtools --infile sbom.spdx.json node-floor: