This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 01ce2deda4e CI: Publish canary SBOMs with main docs (#63310)
01ce2deda4e is described below

commit 01ce2deda4e23d6bd6310f7f4b1b8b9f5e9b6eac
Author: Aaron Chen <[email protected]>
AuthorDate: Fri Mar 13 06:36:51 2026 -0700

    CI: Publish canary SBOMs with main docs (#63310)
---
 .github/workflows/ci-image-checks.yml              |  33 +++++
 .../images/output_sbom_update-sbom-information.svg |  72 ++++++-----
 .../images/output_sbom_update-sbom-information.txt |   2 +-
 .../src/airflow_breeze/commands/sbom_commands.py   |  18 ++-
 .../commands/sbom_commands_config.py               |   1 +
 dev/breeze/src/airflow_breeze/utils/cdxgen.py      |   4 +-
 dev/breeze/tests/test_sbom_commands.py             | 133 +++++++++++++++++++++
 7 files changed, 228 insertions(+), 35 deletions(-)

diff --git a/.github/workflows/ci-image-checks.yml 
b/.github/workflows/ci-image-checks.yml
index 126bf9fd1f7..de3d48ca581 100644
--- a/.github/workflows/ci-image-checks.yml
+++ b/.github/workflows/ci-image-checks.yml
@@ -316,6 +316,39 @@ jobs:
         with:
           name: airflow-docs
           path: './generated/_build'
+      - name: "Make sure SBOM dir exists and has the right permissions"
+        run: |
+          sudo mkdir -vp ./files/sbom
+          sudo chown -R "${USER}" .
+        if: >
+          inputs.canary-run == 'true' &&
+          (github.event_name == 'schedule' || github.event_name == 
'workflow_dispatch')
+      - name: "Determine Airflow version for SBOMs"
+        run: |
+          AIRFLOW_VERSION=$(awk -F'"' '/^__version__ = / {print $2}' 
airflow-core/src/airflow/__init__.py)
+          test -n "${AIRFLOW_VERSION}"
+          echo "AIRFLOW_VERSION=${AIRFLOW_VERSION}" >> "${GITHUB_ENV}"
+        if: >
+          inputs.canary-run == 'true' &&
+          (github.event_name == 'schedule' || github.event_name == 
'workflow_dispatch')
+      - name: "Prepare SBOMs"
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: >
+          breeze sbom update-sbom-information
+          --airflow-version ${AIRFLOW_VERSION} --remote-name origin --force
+          --all-combinations --run-in-parallel --airflow-root-path 
"${GITHUB_WORKSPACE}"
+          --airflow-constraints-reference constraints-main
+        if: >
+          inputs.canary-run == 'true' &&
+          (github.event_name == 'schedule' || github.event_name == 
'workflow_dispatch')
+      - name: "Generated SBOM files"
+        run: |
+          echo "Generated SBOM files:"
+          find ./generated/_build/docs/apache-airflow/stable/sbom/ -type f | 
sort
+        if: >
+          inputs.canary-run == 'true' &&
+          (github.event_name == 'schedule' || github.event_name == 
'workflow_dispatch')
       - name: Check disk space available
         run: df -H
       - name: Create /mnt/airflow-site directory
diff --git a/dev/breeze/doc/images/output_sbom_update-sbom-information.svg 
b/dev/breeze/doc/images/output_sbom_update-sbom-information.svg
index 152fea8b5fd..7fe1a450eee 100644
--- a/dev/breeze/doc/images/output_sbom_update-sbom-information.svg
+++ b/dev/breeze/doc/images/output_sbom_update-sbom-information.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1270.0" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 1318.8" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-sbom-update-sbom-information-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="1219.0" />
+      <rect x="0" y="0" width="1463.0" height="1267.8" />
     </clipPath>
     <clipPath id="breeze-sbom-update-sbom-information-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -192,9 +192,15 @@
 <clipPath id="breeze-sbom-update-sbom-information-line-48">
     <rect x="0" y="1172.7" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-sbom-update-sbom-information-line-49">
+    <rect x="0" y="1197.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-update-sbom-information-line-50">
+    <rect x="0" y="1221.5" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1268" rx="8"/><text 
class="breeze-sbom-update-sbom-information-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;sbom&#160;update-sbom-information</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1316.8" rx="8"/><text 
class="breeze-sbom-update-sbom-information-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;sbom&#160;update-sbom-information</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -225,35 +231,37 @@
 </text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="459.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-18)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="488" y="459.2" 
textLength="85.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-18)">origin)</text><text
 class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="459.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-18)">│</text>< [...]
 </text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="483.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-19)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="483.6" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-19)">--airflow-version&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom- [...]
 </text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="508" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-20)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="508" textLength="122" 
clip-path="url(#breeze-sbom-update-sbom-information-line-20)">versions)&#160;</text><text
 class="breeze-sbom-update-sbom-information-r6" x="610" y="508" 
textLength="73.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-20)">(TEXT)</tex [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="532.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-21)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="532.4" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-21)">--python-versions&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom- [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="556.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-22)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="556.8" 
textLength="341.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-22)">historical&#160;python&#160;versions)&#160;</text><text
 class="breeze-sbom-update-sbom-information-r6" x="829.6" y="556.8" 
textLength="561.2" clip-path="url(#breeze-sbom-update [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="581.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-23)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="488" y="581.2" 
textLength="61" 
clip-path="url(#breeze-sbom-update-sbom-information-line-23)">3.13)</text><text 
class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="581.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-23)">│</text><text 
[...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="605.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-24)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="605.6" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-24)">--include-provider-dependencies&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="488" y="605.6" 
textLength="732" clip-path="url(#bre [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="630" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-25)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="630" 
textLength="195.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-25)">--include-python</text><text
 class="breeze-sbom-update-sbom-information-r1" x="219.6" y="630" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-25)">/</te [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="654.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-26)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="654.4" 
textLength="158.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-26)">--include-npm</text><text
 class="breeze-sbom-update-sbom-information-r1" x="183" y="654.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-26)">/</t [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="678.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-27)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="678.8" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-27)">--all-combinations&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-infor [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="703.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-28)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="488" y="703.2" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-28)">--include</text><text
 class="breeze-sbom-update-sbom-information-r1" x="597.8" y="703.2" 
textLength="841.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-28)">&#160; [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="727.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-29)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="727.6" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-29)">--package-filter&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update- [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="752" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-30)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="752" 
textLength="951.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-30)">matching&#160;the&#160;full&#160;package&#160;name,&#160;for&#160;example&#160;`apache-airflow-providers-*`.&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbo [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="776.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-31)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="776.4" 
textLength="951.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-31)">Useful&#160;when&#160;you&#160;want&#160;to&#160;selectseveral&#160;similarly&#160;named&#160;packages&#160;together.&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="bre [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="800.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-32)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="488" y="800.8" 
textLength="524.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-32)">(apache-airflow-providers&#160;|&#160;apache-airflow)</text><text
 class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="800.8" 
textLength="12.2" clip-path="url(#breeze-s [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="825.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-33)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="825.2" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-33)">--force&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="849.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-34)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="849.6" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-34)">--github-token&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sb [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="874" 
textLength="1464" 
clip-path="url(#breeze-sbom-update-sbom-information-line-35)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-update-sbom-information-r1" x="1464" y="874" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-35)">
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="898.4" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-36)">╭─</text><text 
class="breeze-sbom-update-sbom-information-r5" x="24.4" y="898.4" 
textLength="219.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-36)">&#160;Parallel&#160;running&#160;</text><text
 class="breeze-sbom-update-sbom-information-r5" x="244" y="898.4" 
textLength="1195.6" clip-path="url(#breeze-sbom-update-sbom-inf [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="922.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-37)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="922.8" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-37)">--run-in-parallel&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="922.8" 
textLength="854" clip-path="url( [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="947.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-38)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="947.2" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-38)">--parallelism&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="947.2" 
textLength=" [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="971.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-39)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="353.8" y="971.6" 
textLength="280.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-39)">(INTEGER&#160;RANGE&#160;1&lt;=x&lt;=8)</text><text
 class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="971.6" 
textLength="12.2" clip-path="url(#breeze-sbom-update-s [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="996" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-40)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="996" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-40)">--skip-cleanup&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="996" 
textLength="732" clip-p [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1020.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-41)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1020.4" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-41)">--debug-resources&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="1020.4" 
textLength="768.6" clip-path= [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1044.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-42)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1044.8" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-42)">--include-success-outputs</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="1044.8" 
textLength="841.8" clip-path="url(#breeze-sbom-update-sbom-informatio [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1069.2" 
textLength="1464" 
clip-path="url(#breeze-sbom-update-sbom-information-line-43)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-update-sbom-information-r1" x="1464" y="1069.2" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-43)">
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1093.6" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-44)">╭─</text><text 
class="breeze-sbom-update-sbom-information-r5" x="24.4" y="1093.6" 
textLength="195.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-44)">&#160;Common&#160;options&#160;</text><text
 class="breeze-sbom-update-sbom-information-r5" x="219.6" y="1093.6" 
textLength="1220" clip-path="url(#breeze-sbom-update-sbom-in [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1118" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-45)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1118" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-45)">--verbose</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1118" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-45)">-v</text> [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1142.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-46)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1142.4" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-46)">--dry-run</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1142.4" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-46)">-D< [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1166.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-47)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1166.8" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-47)">--answer&#160;</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1166.8" 
textLength="24.4" clip-path="url(#breeze-sbom-update-sbom-information-line-47) 
[...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1191.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-48)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1191.2" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-48)">--help&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1191.2" 
textLength="24.4" clip-path="url(#breeze-sbom-update-sbom-informatio [...]
-</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1215.6" 
textLength="1464" 
clip-path="url(#breeze-sbom-update-sbom-information-line-49)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-update-sbom-information-r1" x="1464" y="1215.6" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-49)">
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="532.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-21)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="532.4" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-21)">--airflow-constraints-reference&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="488" y="532.4" 
textLength="951.6" clip-path="url(#b [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="556.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-22)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="556.8" 
textLength="597.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-22)">generation.&#160;Defaults&#160;to&#160;constraints&#160;derived&#160;from&#160;</text><text
 class="breeze-sbom-update-sbom-information-r4" x="1085.8" y="556.8" 
textLength="207. [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="581.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-23)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="581.2" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-23)">--python-versions&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom- [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="605.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-24)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="605.6" 
textLength="341.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-24)">historical&#160;python&#160;versions)&#160;</text><text
 class="breeze-sbom-update-sbom-information-r6" x="829.6" y="605.6" 
textLength="561.2" clip-path="url(#breeze-sbom-update [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="630" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-25)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="488" y="630" textLength="61" 
clip-path="url(#breeze-sbom-update-sbom-information-line-25)">3.13)</text><text 
class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="630" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-25)">│</text><text 
class [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="654.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-26)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="654.4" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-26)">--include-provider-dependencies&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="488" y="654.4" 
textLength="732" clip-path="url(#bre [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="678.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-27)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="678.8" 
textLength="195.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-27)">--include-python</text><text
 class="breeze-sbom-update-sbom-information-r1" x="219.6" y="678.8" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-27)" 
[...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="703.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-28)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="703.2" 
textLength="158.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-28)">--include-npm</text><text
 class="breeze-sbom-update-sbom-information-r1" x="183" y="703.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-28)">/</t [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="727.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-29)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="727.6" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-29)">--all-combinations&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-infor [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="752" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-30)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="488" y="752" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-30)">--include</text><text
 class="breeze-sbom-update-sbom-information-r1" x="597.8" y="752" 
textLength="841.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-30)">&#160;flags& [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="776.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-31)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="776.4" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-31)">--package-filter&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update- [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="800.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-32)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="800.8" 
textLength="951.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-32)">matching&#160;the&#160;full&#160;package&#160;name,&#160;for&#160;example&#160;`apache-airflow-providers-*`.&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="825.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-33)">│</text><text 
class="breeze-sbom-update-sbom-information-r1" x="488" y="825.2" 
textLength="951.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-33)">Useful&#160;when&#160;you&#160;want&#160;to&#160;selectseveral&#160;similarly&#160;named&#160;packages&#160;together.&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="bre [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="849.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-34)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="488" y="849.6" 
textLength="524.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-34)">(apache-airflow-providers&#160;|&#160;apache-airflow)</text><text
 class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="849.6" 
textLength="12.2" clip-path="url(#breeze-s [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="874" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-35)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="874" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-35)">--force&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="898.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-36)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="898.4" 
textLength="439.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-36)">--github-token&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sb [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="922.8" 
textLength="1464" 
clip-path="url(#breeze-sbom-update-sbom-information-line-37)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-update-sbom-information-r1" x="1464" y="922.8" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-37)">
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="947.2" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-38)">╭─</text><text 
class="breeze-sbom-update-sbom-information-r5" x="24.4" y="947.2" 
textLength="219.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-38)">&#160;Parallel&#160;running&#160;</text><text
 class="breeze-sbom-update-sbom-information-r5" x="244" y="947.2" 
textLength="1195.6" clip-path="url(#breeze-sbom-update-sbom-inf [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="971.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-39)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="971.6" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-39)">--run-in-parallel&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="971.6" 
textLength="854" clip-path="url( [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="996" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-40)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="996" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-40)">--parallelism&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="996" 
textLength="927.2" [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1020.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-41)">│</text><text 
class="breeze-sbom-update-sbom-information-r6" x="353.8" y="1020.4" 
textLength="280.6" 
clip-path="url(#breeze-sbom-update-sbom-information-line-41)">(INTEGER&#160;RANGE&#160;1&lt;=x&lt;=8)</text><text
 class="breeze-sbom-update-sbom-information-r5" x="1451.8" y="1020.4" 
textLength="12.2" clip-path="url(#breeze-sbom-updat [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1044.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-42)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1044.8" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-42)">--skip-cleanup&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="1044.8" 
textLength="73 [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1069.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-43)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1069.2" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-43)">--debug-resources&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="1069.2" 
textLength="768.6" clip-path= [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1093.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-44)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1093.6" 
textLength="305" 
clip-path="url(#breeze-sbom-update-sbom-information-line-44)">--include-success-outputs</text><text
 class="breeze-sbom-update-sbom-information-r1" x="353.8" y="1093.6" 
textLength="841.8" clip-path="url(#breeze-sbom-update-sbom-informatio [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1118" 
textLength="1464" 
clip-path="url(#breeze-sbom-update-sbom-information-line-45)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-update-sbom-information-r1" x="1464" y="1118" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-45)">
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1142.4" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-46)">╭─</text><text 
class="breeze-sbom-update-sbom-information-r5" x="24.4" y="1142.4" 
textLength="195.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-46)">&#160;Common&#160;options&#160;</text><text
 class="breeze-sbom-update-sbom-information-r5" x="219.6" y="1142.4" 
textLength="1220" clip-path="url(#breeze-sbom-update-sbom-in [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1166.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-47)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1166.8" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-47)">--verbose</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1166.8" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-47)">-v< [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1191.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-48)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1191.2" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-48)">--dry-run</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1191.2" 
textLength="24.4" 
clip-path="url(#breeze-sbom-update-sbom-information-line-48)">-D< [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1215.6" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-49)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1215.6" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-49)">--answer&#160;</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1215.6" 
textLength="24.4" clip-path="url(#breeze-sbom-update-sbom-information-line-49) 
[...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1240" 
textLength="12.2" 
clip-path="url(#breeze-sbom-update-sbom-information-line-50)">│</text><text 
class="breeze-sbom-update-sbom-information-r4" x="24.4" y="1240" 
textLength="109.8" 
clip-path="url(#breeze-sbom-update-sbom-information-line-50)">--help&#160;&#160;&#160;</text><text
 class="breeze-sbom-update-sbom-information-r7" x="158.6" y="1240" 
textLength="24.4" clip-path="url(#breeze-sbom-update-sbom-information-line [...]
+</text><text class="breeze-sbom-update-sbom-information-r5" x="0" y="1264.4" 
textLength="1464" 
clip-path="url(#breeze-sbom-update-sbom-information-line-51)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-update-sbom-information-r1" x="1464" y="1264.4" 
textLength="12.2" clip-path="url(#breeze-sbom-update-sbom-information-line-51)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_sbom_update-sbom-information.txt 
b/dev/breeze/doc/images/output_sbom_update-sbom-information.txt
index 709b6ebb3e1..82bf8b08614 100644
--- a/dev/breeze/doc/images/output_sbom_update-sbom-information.txt
+++ b/dev/breeze/doc/images/output_sbom_update-sbom-information.txt
@@ -1 +1 @@
-16159ccbed065c1e19a36d024ef2144c
+1787b9c259a81b9bfb7837050ea87b42
diff --git a/dev/breeze/src/airflow_breeze/commands/sbom_commands.py 
b/dev/breeze/src/airflow_breeze/commands/sbom_commands.py
index ef50c1f41a8..0b864e278fa 100644
--- a/dev/breeze/src/airflow_breeze/commands/sbom_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/sbom_commands.py
@@ -150,6 +150,14 @@ SBOM_INDEX_TEMPLATE = """
     envvar="AIRFLOW_VERSION",
     help="Version of airflow to update sbom from. (defaulted to all active 
airflow versions)",
 )
[email protected](
+    "--airflow-constraints-reference",
+    type=str,
+    required=False,
+    envvar="AIRFLOW_CONSTRAINTS_REFERENCE",
+    help="Constraint reference to use when downloading Airflow constraints for 
SBOM generation. "
+    "Defaults to constraints derived from --airflow-version.",
+)
 @option_historical_python_versions
 @click.option(
     "--include-provider-dependencies",
@@ -222,6 +230,7 @@ def update_sbom_information(
     airflow_root_path: Path | None,
     airflow_site_archive_path: Path | None,
     airflow_version: str | None,
+    airflow_constraints_reference: str | None,
     all_combinations: bool,
     debug_resources: bool,
     force: bool,
@@ -252,7 +261,10 @@ def update_sbom_information(
         all_airflow_versions = airflow_versions.copy()
     else:
         airflow_versions = [airflow_version]
-        all_airflow_versions = get_active_airflow_versions(confirm=False, 
remote_name=remote_name)
+        if airflow_site_archive_path and add_stable:
+            all_airflow_versions, _ = 
get_active_airflow_versions(confirm=False, remote_name=remote_name)
+        else:
+            all_airflow_versions = airflow_versions.copy()
     if python_versions:
         python_versions_list = python_versions.split(",")
     else:
@@ -308,6 +320,7 @@ def update_sbom_information(
                     include_provider_dependencies,
                     include_python,
                     jobs_to_run,
+                    
airflow_constraints_reference=airflow_constraints_reference,
                     python_versions=use_python_versions,
                 )
         else:
@@ -325,6 +338,7 @@ def update_sbom_information(
                 include_provider_dependencies,
                 include_python,
                 jobs_to_run,
+                airflow_constraints_reference=airflow_constraints_reference,
                 python_versions=use_python_versions,
             )
         if add_stable and airflow_site_archive_path and 
all_airflow_versions[-1] in airflow_versions:
@@ -491,6 +505,7 @@ def core_jobs(
     include_provider_dependencies: bool,
     include_python: bool,
     jobs_to_run: list[SbomApplicationJob],
+    airflow_constraints_reference: str | None,
     python_versions: list[str],
 ):
     for airflow_v in airflow_versions:
@@ -550,6 +565,7 @@ def core_jobs(
                     target_path=target_sbom_path,
                     include_python=include_python,
                     include_npm=include_npm,
+                    constraints_reference=airflow_constraints_reference,
                 )
             )
 
diff --git a/dev/breeze/src/airflow_breeze/commands/sbom_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/sbom_commands_config.py
index 1a0ceda2620..0ff0c9c3889 100644
--- a/dev/breeze/src/airflow_breeze/commands/sbom_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/sbom_commands_config.py
@@ -37,6 +37,7 @@ SBOM_PARAMETERS: dict[str, list[dict[str, str | list[str]]]] 
= {
             "options": [
                 "--remote-name",
                 "--airflow-version",
+                "--airflow-constraints-reference",
                 "--python-versions",
                 "--include-provider-dependencies",
                 "--include-python",
diff --git a/dev/breeze/src/airflow_breeze/utils/cdxgen.py 
b/dev/breeze/src/airflow_breeze/utils/cdxgen.py
index 43507c2ed85..de28f626633 100644
--- a/dev/breeze/src/airflow_breeze/utils/cdxgen.py
+++ b/dev/breeze/src/airflow_breeze/utils/cdxgen.py
@@ -348,6 +348,7 @@ class SbomCoreJob(SbomApplicationJob):
     include_provider_dependencies: bool
     include_python: bool
     include_npm: bool
+    constraints_reference: str | None = None
 
     def get_job_name(self) -> str:
         name = f"{self.airflow_version}"
@@ -393,8 +394,9 @@ class SbomCoreJob(SbomApplicationJob):
         else:
             source_dir_with_file.unlink(missing_ok=True)
         if self.include_python:
+            constraints_reference = self.constraints_reference or 
f"constraints-{self.airflow_version}"
             if not download_constraints_file(
-                constraints_reference=f"constraints-{self.airflow_version}",
+                constraints_reference=constraints_reference,
                 python_version=self.python_version,
                 airflow_constraints_mode="constraints"
                 if self.include_provider_dependencies
diff --git a/dev/breeze/tests/test_sbom_commands.py 
b/dev/breeze/tests/test_sbom_commands.py
new file mode 100644
index 00000000000..2370bdccc32
--- /dev/null
+++ b/dev/breeze/tests/test_sbom_commands.py
@@ -0,0 +1,133 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from pathlib import Path
+from unittest.mock import patch
+
+import pytest
+
+from airflow_breeze.commands.sbom_commands import update_sbom_information
+from airflow_breeze.utils.cdxgen import SbomCoreJob
+from airflow_breeze.utils.path_utils import FILES_SBOM_PATH
+
+
[email protected](
+    ("constraints_reference", "expected_constraints_reference"),
+    [
+        ("constraints-main", "constraints-main"),
+        (None, "constraints-3.2.0"),
+    ],
+)
+def test_sbom_core_job_resolves_constraints_reference(
+    tmp_path, constraints_reference, expected_constraints_reference
+):
+    job = SbomCoreJob(
+        python_version="3.10",
+        target_path=tmp_path / "output.json",
+        airflow_version="3.2.0",
+        application_root_path=FILES_SBOM_PATH,
+        include_provider_dependencies=False,
+        include_python=True,
+        include_npm=False,
+        constraints_reference=constraints_reference,
+    )
+    with patch(
+        "airflow_breeze.utils.cdxgen.download_constraints_file", 
autospec=True, return_value=True
+    ) as mock_dl:
+        job.download_dependency_files(output=None, github_token=None)
+
+    mock_dl.assert_called_once()
+    assert mock_dl.call_args.kwargs["constraints_reference"] == 
expected_constraints_reference
+
+
+def 
test_update_sbom_information_with_airflow_root_path_skips_released_versions_lookup(tmp_path):
+    airflow_root_path = Path(tmp_path)
+    airflow_docs_dir = airflow_root_path / "generated" / "_build" / "docs" / 
"apache-airflow" / "stable"
+    airflow_docs_dir.mkdir(parents=True)
+
+    with (
+        patch("airflow_breeze.utils.cdxgen.start_cdxgen_servers", 
autospec=True),
+        patch(
+            "airflow_breeze.utils.github.get_active_airflow_versions",
+            autospec=True,
+            return_value=(["3.2.0"], {}),
+        ) as mock_get_active_airflow_versions,
+        patch("airflow_breeze.commands.sbom_commands.core_jobs", 
autospec=True) as mock_core_jobs,
+    ):
+        update_sbom_information.callback(
+            airflow_root_path=airflow_root_path,
+            airflow_site_archive_path=None,
+            airflow_version="3.2.0",
+            airflow_constraints_reference="constraints-main",
+            all_combinations=False,
+            debug_resources=False,
+            force=False,
+            github_token=None,
+            include_npm=True,
+            include_provider_dependencies=False,
+            include_python=True,
+            include_success_outputs=False,
+            package_filter="apache-airflow",
+            parallelism=1,
+            python_versions="3.10",
+            remote_name="origin",
+            run_in_parallel=False,
+            skip_cleanup=False,
+            add_stable=True,
+        )
+
+    mock_get_active_airflow_versions.assert_not_called()
+    mock_core_jobs.assert_called_once()
+    assert mock_core_jobs.call_args.kwargs["airflow_constraints_reference"] == 
"constraints-main"
+
+
+def 
test_update_sbom_information_with_site_archive_path_keeps_stable_lookup(tmp_path):
+    airflow_site_archive_path = Path(tmp_path)
+
+    with (
+        patch("airflow_breeze.utils.cdxgen.start_cdxgen_servers", 
autospec=True),
+        patch(
+            "airflow_breeze.utils.github.get_active_airflow_versions",
+            autospec=True,
+            return_value=(["3.1.0"], {}),
+        ) as mock_get_active_airflow_versions,
+        patch("airflow_breeze.commands.sbom_commands.core_jobs", 
autospec=True),
+    ):
+        update_sbom_information.callback(
+            airflow_root_path=None,
+            airflow_site_archive_path=airflow_site_archive_path,
+            airflow_version="3.2.0",
+            airflow_constraints_reference=None,
+            all_combinations=False,
+            debug_resources=False,
+            force=False,
+            github_token=None,
+            include_npm=True,
+            include_provider_dependencies=False,
+            include_python=True,
+            include_success_outputs=False,
+            package_filter="apache-airflow",
+            parallelism=1,
+            python_versions="3.10",
+            remote_name="origin",
+            run_in_parallel=False,
+            skip_cleanup=False,
+            add_stable=True,
+        )
+
+    mock_get_active_airflow_versions.assert_called_once_with(confirm=False, 
remote_name="origin")


Reply via email to