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 03263b68db Add exporting of dependency information from SBOM to CSV 
file (#41254)
03263b68db is described below

commit 03263b68db03c7d4780e54f531273246b26d5d89
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon Aug 5 08:01:38 2024 +0200

    Add exporting of dependency information from SBOM to CSV file (#41254)
    
    This new sbom command uses the SBOM we have generated for Airflow and
    exports information about all our dependencies, enhanced by using
    various sources of information about them.
---
 .rat-excludes                                      |   3 +
 dev/breeze/doc/09_release_management_tasks.rst     |  12 ++
 dev/breeze/doc/images/output_sbom.svg              |  20 ++-
 dev/breeze/doc/images/output_sbom.txt              |   2 +-
 .../output_sbom_export-dependency-information.svg  | 134 +++++++++++++++++++++
 .../output_sbom_export-dependency-information.txt  |   1 +
 .../output_setup_check-all-params-in-groups.svg    |  32 ++---
 .../output_setup_check-all-params-in-groups.txt    |   2 +-
 .../output_setup_regenerate-command-images.svg     |  36 +++---
 .../output_setup_regenerate-command-images.txt     |   2 +-
 .../src/airflow_breeze/commands/common_options.py  |   8 ++
 .../src/airflow_breeze/commands/sbom_commands.py   |  86 +++++++++++++
 .../commands/sbom_commands_config.py               |  11 ++
 dev/breeze/src/airflow_breeze/global_constants.py  |   2 +
 dev/breeze/src/airflow_breeze/utils/cdxgen.py      | 132 +++++++++++++++++++-
 dev/get_devel_deps.sh                              |  29 +++++
 generated/README.md                                |   3 +
 generated/devel_deps.txt                           | 105 ++++++++++++++++
 18 files changed, 582 insertions(+), 38 deletions(-)

diff --git a/.rat-excludes b/.rat-excludes
index be0a11a905..d8aaa88afa 100644
--- a/.rat-excludes
+++ b/.rat-excludes
@@ -122,6 +122,9 @@ chart/Chart.yaml
 # Generated autocomplete files
 ./dev/breeze/autocomplete/*
 
+# Generated devel_deps files
+devel_deps.txt
+
 # Newsfragments are snippets that will be, eventually, consumed into 
RELEASE_NOTES
 newsfragments/*
 
diff --git a/dev/breeze/doc/09_release_management_tasks.rst 
b/dev/breeze/doc/09_release_management_tasks.rst
index 35e4ff21b8..930f61159d 100644
--- a/dev/breeze/doc/09_release_management_tasks.rst
+++ b/dev/breeze/doc/09_release_management_tasks.rst
@@ -650,6 +650,18 @@ This command will build one docker image per python 
version, with all the airflo
   :width: 100%
   :alt: Breeze build all airflow images
 
+
+Exporting SBOM information
+""""""""""""""""""""""""""
+
+The SBOM information published on our website can be converted into a 
spreadsheet that we are using to analyse security
+properties of the dependencies. This is done by the 
``export-dependency-information`` command.
+
+.. image:: ./images/output_sbom_export-dependency-information.svg
+  :target: 
https://raw.githubusercontent.com/apache/airflow/main/dev/breeze/images/output_sbom_export-dependency-information.svg
+  :width: 100%
+  :alt: Breeze sbom export dependency information
+
 -----
 
 Next step: Follow the `Advanced Breeze topics 
<10_advanced_breeze_topics.rst>`_ to
diff --git a/dev/breeze/doc/images/output_sbom.svg 
b/dev/breeze/doc/images/output_sbom.svg
index 9ee73ec331..6f81c933de 100644
--- a/dev/breeze/doc/images/output_sbom.svg
+++ b/dev/breeze/doc/images/output_sbom.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 367.2" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 440.4" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -42,7 +42,7 @@
 
     <defs>
     <clipPath id="breeze-sbom-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="316.2" />
+      <rect x="0" y="0" width="1463.0" height="389.4" />
     </clipPath>
     <clipPath id="breeze-sbom-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -80,9 +80,18 @@
 <clipPath id="breeze-sbom-line-11">
     <rect x="0" y="269.9" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-sbom-line-12">
+    <rect x="0" y="294.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-line-13">
+    <rect x="0" y="318.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-line-14">
+    <rect x="0" y="343.1" 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="365.2" rx="8"/><text class="breeze-sbom-title" 
fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command:&#160;sbom</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="438.4" rx="8"/><text class="breeze-sbom-title" 
fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command:&#160;sbom</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -98,13 +107,16 @@
 </text><text class="breeze-sbom-r1" x="12.2" y="93.2" textLength="768.6" 
clip-path="url(#breeze-sbom-line-3)">Tools&#160;that&#160;release&#160;managers&#160;can&#160;use&#160;to&#160;prepare&#160;sbom&#160;information</text><text
 class="breeze-sbom-r1" x="1464" y="93.2" textLength="12.2" 
clip-path="url(#breeze-sbom-line-3)">
 </text><text class="breeze-sbom-r1" x="1464" y="117.6" textLength="12.2" 
clip-path="url(#breeze-sbom-line-4)">
 </text><text class="breeze-sbom-r5" x="0" y="142" textLength="24.4" 
clip-path="url(#breeze-sbom-line-5)">╭─</text><text class="breeze-sbom-r5" 
x="24.4" y="142" textLength="195.2" 
clip-path="url(#breeze-sbom-line-5)">&#160;Common&#160;options&#160;</text><text
 class="breeze-sbom-r5" x="219.6" y="142" textLength="1220" 
clip-path="url(#breeze-sbom-line-5)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-sbom-r5"  [...]
-</text><text class="breeze-sbom-r5" x="0" y="166.4" textLength="12.2" 
clip-path="url(#breeze-sbom-line-6)">│</text><text class="breeze-sbom-r4" 
x="24.4" y="166.4" textLength="12.2" 
clip-path="url(#breeze-sbom-line-6)">-</text><text class="breeze-sbom-r4" 
x="36.6" y="166.4" textLength="61" 
clip-path="url(#breeze-sbom-line-6)">-help</text><text class="breeze-sbom-r6" 
x="122" y="166.4" textLength="24.4" 
clip-path="url(#breeze-sbom-line-6)">-h</text><text class="breeze-sbom-r1" 
x="170.8" y=" [...]
+</text><text class="breeze-sbom-r5" x="0" y="166.4" textLength="12.2" 
clip-path="url(#breeze-sbom-line-6)">│</text><text class="breeze-sbom-r4" 
x="24.4" y="166.4" textLength="73.2" 
clip-path="url(#breeze-sbom-line-6)">--help</text><text class="breeze-sbom-r6" 
x="122" y="166.4" textLength="24.4" 
clip-path="url(#breeze-sbom-line-6)">-h</text><text class="breeze-sbom-r1" 
x="170.8" y="166.4" textLength="329.4" 
clip-path="url(#breeze-sbom-line-6)">Show&#160;this&#160;message&#160;and&#160;exi
 [...]
 </text><text class="breeze-sbom-r5" x="0" y="190.8" textLength="1464" 
clip-path="url(#breeze-sbom-line-7)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-r1" x="1464" y="190.8" textLength="12.2" 
clip-path="url(#breeze-sbom-line-7)">
 </text><text class="breeze-sbom-r5" x="0" y="215.2" textLength="24.4" 
clip-path="url(#breeze-sbom-line-8)">╭─</text><text class="breeze-sbom-r5" 
x="24.4" y="215.2" textLength="183" 
clip-path="url(#breeze-sbom-line-8)">&#160;SBOM&#160;commands&#160;</text><text 
class="breeze-sbom-r5" x="207.4" y="215.2" textLength="1232.2" 
clip-path="url(#breeze-sbom-line-8)">─────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-sbo [...]
 </text><text class="breeze-sbom-r5" x="0" y="239.6" textLength="12.2" 
clip-path="url(#breeze-sbom-line-9)">│</text><text class="breeze-sbom-r4" 
x="24.4" y="239.6" textLength="536.8" 
clip-path="url(#breeze-sbom-line-9)">update-sbom-information&#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-r1" x="585.6" y="239.6" textLength="854" 
clip-path="url(#breeze-sbom-line-9)">Update&#160;SB [...]
 </text><text class="breeze-sbom-r5" x="0" y="264" textLength="12.2" 
clip-path="url(#breeze-sbom-line-10)">│</text><text class="breeze-sbom-r4" 
x="24.4" y="264" textLength="536.8" 
clip-path="url(#breeze-sbom-line-10)">build-all-airflow-images&#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-r1" x="585.6" y="264" textLength="854" 
clip-path="url(#breeze-sbom-line-10)">Generate&#160;images&# [...]
 </text><text class="breeze-sbom-r5" x="0" y="288.4" textLength="12.2" 
clip-path="url(#breeze-sbom-line-11)">│</text><text class="breeze-sbom-r4" 
x="24.4" y="288.4" textLength="536.8" 
clip-path="url(#breeze-sbom-line-11)">generate-providers-requirements&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-sbom-r1" x="585.6" y="288.4" textLength="854" 
clip-path="url(#breeze-sbom-line-11)">Generate&#160;requirements&#160;for&#160;selected&#
 [...]
 </text><text class="breeze-sbom-r5" x="0" y="312.8" textLength="1464" 
clip-path="url(#breeze-sbom-line-12)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-r1" x="1464" y="312.8" textLength="12.2" 
clip-path="url(#breeze-sbom-line-12)">
+</text><text class="breeze-sbom-r5" x="0" y="337.2" textLength="24.4" 
clip-path="url(#breeze-sbom-line-13)">╭─</text><text class="breeze-sbom-r5" 
x="24.4" y="337.2" textLength="122" 
clip-path="url(#breeze-sbom-line-13)">&#160;Commands&#160;</text><text 
class="breeze-sbom-r5" x="146.4" y="337.2" textLength="1293.2" 
clip-path="url(#breeze-sbom-line-13)">──────────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-sbom- [...]
+</text><text class="breeze-sbom-r5" x="0" y="361.6" textLength="12.2" 
clip-path="url(#breeze-sbom-line-14)">│</text><text class="breeze-sbom-r4" 
x="24.4" y="361.6" textLength="597.8" 
clip-path="url(#breeze-sbom-line-14)">export-dependency-information&#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-r1" x="646.6" y="361.6" textLength="793" 
clip-path="url(#breeze-sbom-line-14)">Export&#160 [...]
+</text><text class="breeze-sbom-r5" x="0" y="386" textLength="1464" 
clip-path="url(#breeze-sbom-line-15)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-r1" x="1464" y="386" textLength="12.2" 
clip-path="url(#breeze-sbom-line-15)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_sbom.txt 
b/dev/breeze/doc/images/output_sbom.txt
index 0edd5ebec9..472454d810 100644
--- a/dev/breeze/doc/images/output_sbom.txt
+++ b/dev/breeze/doc/images/output_sbom.txt
@@ -1 +1 @@
-924eca934035f16d89ba69e74761336f
+b03d6ab68f41027663d36fe101214323
diff --git 
a/dev/breeze/doc/images/output_sbom_export-dependency-information.svg 
b/dev/breeze/doc/images/output_sbom_export-dependency-information.svg
new file mode 100644
index 0000000000..e9387591c9
--- /dev/null
+++ b/dev/breeze/doc/images/output_sbom_export-dependency-information.svg
@@ -0,0 +1,134 @@
+<svg class="rich-terminal" viewBox="0 0 1482 489.2" 
xmlns="http://www.w3.org/2000/svg";>
+    <!-- Generated with Rich https://www.textualize.io -->
+    <style>
+
+    @font-face {
+        font-family: "Fira Code";
+        src: local("FiraCode-Regular"),
+                
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2";)
 format("woff2"),
+                
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff";)
 format("woff");
+        font-style: normal;
+        font-weight: 400;
+    }
+    @font-face {
+        font-family: "Fira Code";
+        src: local("FiraCode-Bold"),
+                
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2";)
 format("woff2"),
+                
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff";)
 format("woff");
+        font-style: bold;
+        font-weight: 700;
+    }
+
+    .breeze-sbom-export-dependency-information-matrix {
+        font-family: Fira Code, monospace;
+        font-size: 20px;
+        line-height: 24.4px;
+        font-variant-east-asian: full-width;
+    }
+
+    .breeze-sbom-export-dependency-information-title {
+        font-size: 18px;
+        font-weight: bold;
+        font-family: arial;
+    }
+
+    .breeze-sbom-export-dependency-information-r1 { fill: #c5c8c6 }
+.breeze-sbom-export-dependency-information-r2 { fill: #d0b344 }
+.breeze-sbom-export-dependency-information-r3 { fill: #c5c8c6;font-weight: 
bold }
+.breeze-sbom-export-dependency-information-r4 { fill: #68a0b3;font-weight: 
bold }
+.breeze-sbom-export-dependency-information-r5 { fill: #868887 }
+.breeze-sbom-export-dependency-information-r6 { fill: #cc555a }
+.breeze-sbom-export-dependency-information-r7 { fill: #98a84b;font-weight: 
bold }
+.breeze-sbom-export-dependency-information-r8 { fill: #8d7b39 }
+.breeze-sbom-export-dependency-information-r9 { fill: #8a4346 }
+    </style>
+
+    <defs>
+    <clipPath id="breeze-sbom-export-dependency-information-clip-terminal">
+      <rect x="0" y="0" width="1463.0" height="438.2" />
+    </clipPath>
+    <clipPath id="breeze-sbom-export-dependency-information-line-0">
+    <rect x="0" y="1.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-1">
+    <rect x="0" y="25.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-2">
+    <rect x="0" y="50.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-3">
+    <rect x="0" y="74.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-4">
+    <rect x="0" y="99.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-5">
+    <rect x="0" y="123.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-6">
+    <rect x="0" y="147.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-7">
+    <rect x="0" y="172.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-8">
+    <rect x="0" y="196.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-9">
+    <rect x="0" y="221.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-10">
+    <rect x="0" y="245.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-11">
+    <rect x="0" y="269.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-12">
+    <rect x="0" y="294.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-13">
+    <rect x="0" y="318.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-14">
+    <rect x="0" y="343.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-15">
+    <rect x="0" y="367.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-sbom-export-dependency-information-line-16">
+    <rect x="0" y="391.9" 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="487.2" rx="8"/><text 
class="breeze-sbom-export-dependency-information-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;sbom&#160;export-dependency-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"/>
+            <circle cx="44" cy="0" r="7" fill="#28c840"/>
+            </g>
+        
+    <g transform="translate(9, 41)" 
clip-path="url(#breeze-sbom-export-dependency-information-clip-terminal)">
+    
+    <g class="breeze-sbom-export-dependency-information-matrix">
+    <text class="breeze-sbom-export-dependency-information-r1" x="1464" y="20" 
textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-0)">
+</text><text class="breeze-sbom-export-dependency-information-r2" x="12.2" 
y="44.4" textLength="73.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-1)">Usage:</text><text
 class="breeze-sbom-export-dependency-information-r3" x="97.6" y="44.4" 
textLength="500.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-1)">breeze&#160;sbom&#160;export-dependency-information</text><text
 class="breeze-sbom-export-dependency-information-r1" x="610" y="44.4" 
textLength="1 [...]
+</text><text class="breeze-sbom-export-dependency-information-r1" x="1464" 
y="68.8" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-2)">
+</text><text class="breeze-sbom-export-dependency-information-r1" x="12.2" 
y="93.2" textLength="488" 
clip-path="url(#breeze-sbom-export-dependency-information-line-3)">Export&#160;dependency&#160;information&#160;from&#160;SBOM.</text><text
 class="breeze-sbom-export-dependency-information-r1" x="1464" y="93.2" 
textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-3)">
+</text><text class="breeze-sbom-export-dependency-information-r1" x="1464" 
y="117.6" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-4)">
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="142" textLength="24.4" 
clip-path="url(#breeze-sbom-export-dependency-information-line-5)">╭─</text><text
 class="breeze-sbom-export-dependency-information-r5" x="24.4" y="142" 
textLength="451.4" 
clip-path="url(#breeze-sbom-export-dependency-information-line-5)">&#160;Export&#160;dependency&#160;information&#160;flags&#160;</text><text
 class="breeze-sbom-export-dependency-information-r5" x="475.8" y="142" 
textLength [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="166.4" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-6)">│</text><text
 class="breeze-sbom-export-dependency-information-r6" x="24.4" y="166.4" 
textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-6)">*</text><text
 class="breeze-sbom-export-dependency-information-r4" x="61" y="166.4" 
textLength="122" clip-path="url(#breeze-sbom-export-dependency-informa [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="190.8" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-7)">│</text><text
 class="breeze-sbom-export-dependency-information-r6" x="24.4" y="190.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-7)">*</text><text
 class="breeze-sbom-export-dependency-information-r4" x="61" y="190.8" 
textLength="207.4" clip-path="url(#breeze-sbom-export-dependency-infor [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="215.2" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-8)">│</text><text
 class="breeze-sbom-export-dependency-information-r4" x="61" y="215.2" 
textLength="97.6" 
clip-path="url(#breeze-sbom-export-dependency-information-line-8)">--python</text><text
 class="breeze-sbom-export-dependency-information-r7" x="427" y="215.2" 
textLength="24.4" clip-path="url(#breeze-sbom-export-dependency- [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="239.6" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-9)">│</text><text
 class="breeze-sbom-export-dependency-information-r8" x="475.8" y="239.6" 
textLength="732" 
clip-path="url(#breeze-sbom-export-dependency-information-line-9)">(&gt;3.8&lt;&#160;|&#160;3.9&#160;|&#160;3.10&#160;|&#160;3.11&#160;|&#160;3.12)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="264" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-10)">│</text><text
 class="breeze-sbom-export-dependency-information-r5" x="475.8" y="264" 
textLength="732" 
clip-path="url(#breeze-sbom-export-dependency-information-line-10)">[default:&#160;3.8]&#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-export-dependency-information-r5" x="0" 
y="288.4" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-11)">│</text><text
 class="breeze-sbom-export-dependency-information-r4" x="61" y="288.4" 
textLength="341.6" 
clip-path="url(#breeze-sbom-export-dependency-information-line-11)">--include-open-psf-scorecard</text><text
 class="breeze-sbom-export-dependency-information-r7" x="427" y="288.4" 
textLength="24.4" clip-path="url(#breeze- [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="312.8" textLength="1464" 
clip-path="url(#breeze-sbom-export-dependency-information-line-12)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-export-dependency-information-r1" x="1464" y="312.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-12)">
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="337.2" textLength="24.4" 
clip-path="url(#breeze-sbom-export-dependency-information-line-13)">╭─</text><text
 class="breeze-sbom-export-dependency-information-r5" x="24.4" y="337.2" 
textLength="195.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-13)">&#160;Common&#160;options&#160;</text><text
 class="breeze-sbom-export-dependency-information-r5" x="219.6" y="337.2" 
textLength="1220" clip-path="url( [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="361.6" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-14)">│</text><text
 class="breeze-sbom-export-dependency-information-r4" x="24.4" y="361.6" 
textLength="109.8" 
clip-path="url(#breeze-sbom-export-dependency-information-line-14)">--dry-run</text><text
 class="breeze-sbom-export-dependency-information-r7" x="158.6" y="361.6" 
textLength="24.4" clip-path="url(#breeze-sbom-export-dep [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="386" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-15)">│</text><text
 class="breeze-sbom-export-dependency-information-r4" x="24.4" y="386" 
textLength="97.6" 
clip-path="url(#breeze-sbom-export-dependency-information-line-15)">--answer</text><text
 class="breeze-sbom-export-dependency-information-r7" x="158.6" y="386" 
textLength="24.4" clip-path="url(#breeze-sbom-export-dependency- [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="410.4" textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-16)">│</text><text
 class="breeze-sbom-export-dependency-information-r4" x="24.4" y="410.4" 
textLength="73.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-16)">--help</text><text
 class="breeze-sbom-export-dependency-information-r7" x="158.6" y="410.4" 
textLength="24.4" clip-path="url(#breeze-sbom-export-depende [...]
+</text><text class="breeze-sbom-export-dependency-information-r5" x="0" 
y="434.8" textLength="1464" 
clip-path="url(#breeze-sbom-export-dependency-information-line-17)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-sbom-export-dependency-information-r1" x="1464" y="434.8" 
textLength="12.2" 
clip-path="url(#breeze-sbom-export-dependency-information-line-17)">
+</text>
+    </g>
+    </g>
+</svg>
diff --git 
a/dev/breeze/doc/images/output_sbom_export-dependency-information.txt 
b/dev/breeze/doc/images/output_sbom_export-dependency-information.txt
new file mode 100644
index 0000000000..30128b0e80
--- /dev/null
+++ b/dev/breeze/doc/images/output_sbom_export-dependency-information.txt
@@ -0,0 +1 @@
+24dce1db728b2c24782375cd3c18600c
diff --git a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg 
b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
index efad3b6f28..75be29be0a 100644
--- a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
+++ b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 952.8" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 977.1999999999999" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-setup-check-all-params-in-groups-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="901.8" />
+      <rect x="0" y="0" width="1463.0" height="926.1999999999999" />
     </clipPath>
     <clipPath id="breeze-setup-check-all-params-in-groups-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -153,9 +153,12 @@
 <clipPath id="breeze-setup-check-all-params-in-groups-line-35">
     <rect x="0" y="855.5" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-setup-check-all-params-in-groups-line-36">
+    <rect x="0" y="879.9" 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="950.8" rx="8"/><text 
class="breeze-setup-check-all-params-in-groups-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;setup&#160;check-all-params-in-groups</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="975.2" rx="8"/><text 
class="breeze-setup-check-all-params-in-groups-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;setup&#160;check-all-params-in-groups</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -191,17 +194,18 @@
 </text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="581.2" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-23)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="581.2" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-23)">release-management:start-rc-process&#160;|&#160;release-management:start-release&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
 </text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="605.6" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-24)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="605.6" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-24)">release-management:tag-providers&#160;|&#160;release-management:update-constraints&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
 </text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="630" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-25)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="630" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-25)">release-management:verify-provider-packages&#160;|&#160;sbom&#160;|&#160;sbom:build-all-airflow-images&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="654.4" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-26)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="654.4" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-26)">sbom:generate-providers-requirements&#160;|&#160;sbom:update-sbom-information&#160;|&#160;setup&#160;|&#160;setup:autocomplete&#160;|&#160;&#160;&#160;&#160;&#
 [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="678.8" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-27)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="678.8" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-27)">setup:check-all-params-in-groups&#160;|&#160;setup:config&#160;|&#160;setup:regenerate-command-images&#160;|&#160;setup:self-upgrade&#160;</text><text
 class="b [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="703.2" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-28)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="703.2" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-28)">|&#160;setup:synchronize-local-mounts&#160;|&#160;setup:version&#160;|&#160;shell&#160;|&#160;start-airflow&#160;|&#160;static-checks&#160;|&#160;testing&#160;
 [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="727.6" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-29)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="727.6" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-29)">testing:db-tests&#160;|&#160;testing:docker-compose-tests&#160;|&#160;testing:helm-tests&#160;|&#160;testing:integration-tests&#160;|&#160;&#160;&#160;&#160;&#
 [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="752" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-30)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="752" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-30)">testing:non-db-tests&#160;|&#160;testing:tests)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="776.4" textLength="1464" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-31)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="776.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-31)">
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="800.8" textLength="24.4" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-32)">╭─</text><text
 class="breeze-setup-check-all-params-in-groups-r5" x="24.4" y="800.8" 
textLength="195.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-32)">&#160;Common&#160;options&#160;</text><text
 class="breeze-setup-check-all-params-in-groups-r5" x="219.6" y="800.8" 
textLength="1220" clip-path="url(#breeze-se [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="825.2" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-33)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="825.2" 
textLength="109.8" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-33)">--verbose</text><text
 class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="825.2" 
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="849.6" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-34)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="849.6" 
textLength="109.8" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-34)">--dry-run</text><text
 class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="849.6" 
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="874" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-35)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="874" 
textLength="73.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-35)">--help</text><text
 class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="874" 
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in-groups-li 
[...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="898.4" textLength="1464" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-36)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="898.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-36)">
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="654.4" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-26)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="654.4" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-26)">sbom:export-dependency-information&#160;|&#160;sbom:generate-providers-requirements&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="678.8" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-27)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="678.8" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-27)">sbom:update-sbom-information&#160;|&#160;setup&#160;|&#160;setup:autocomplete&#160;|&#160;setup:check-all-params-in-groups&#160;|&#160;&#160;&#160;&#160;&#160;
 [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="703.2" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-28)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="703.2" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-28)">setup:config&#160;|&#160;setup:regenerate-command-images&#160;|&#160;setup:self-upgrade&#160;|&#160;setup:synchronize-local-mounts&#160;|&#160;</text><text
 cla [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="727.6" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-29)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="727.6" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-29)">setup:version&#160;|&#160;shell&#160;|&#160;start-airflow&#160;|&#160;static-checks&#160;|&#160;testing&#160;|&#160;testing:db-tests&#160;|&#160;&#160;&#160;&#
 [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="752" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-30)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="752" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-30)">testing:docker-compose-tests&#160;|&#160;testing:helm-tests&#160;|&#160;testing:integration-tests&#160;|&#160;testing:non-db-tests&#160;|&#160;</text><text
 class=" [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="776.4" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-31)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r6" x="183" y="776.4" 
textLength="1256.6" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-31)">testing:tests)&#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-setup-check-all-params-in-groups-r5" x="0" 
y="800.8" textLength="1464" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-32)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="800.8" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-32)">
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="825.2" textLength="24.4" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-33)">╭─</text><text
 class="breeze-setup-check-all-params-in-groups-r5" x="24.4" y="825.2" 
textLength="195.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-33)">&#160;Common&#160;options&#160;</text><text
 class="breeze-setup-check-all-params-in-groups-r5" x="219.6" y="825.2" 
textLength="1220" clip-path="url(#breeze-se [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="849.6" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-34)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="849.6" 
textLength="109.8" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-34)">--verbose</text><text
 class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="849.6" 
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="874" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-35)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="874" 
textLength="109.8" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-35)">--dry-run</text><text
 class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="874" 
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in-group [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="898.4" textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-36)">│</text><text 
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="898.4" 
textLength="73.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-36)">--help</text><text
 class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="898.4" 
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in-gro [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" 
y="922.8" textLength="1464" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-37)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="922.8" 
textLength="12.2" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-37)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt 
b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
index dde69858d3..8f29b3ec7f 100644
--- a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
+++ b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
@@ -1 +1 @@
-6116b55f7002255a8fd08d4a4ce912d1
+255cdc8d6d0b3caef587689d639cb33b
diff --git a/dev/breeze/doc/images/output_setup_regenerate-command-images.svg 
b/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
index 4bf6163a93..6a0f3adff5 100644
--- a/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
+++ b/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1050.4" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 1074.8" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-setup-regenerate-command-images-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="999.4" />
+      <rect x="0" y="0" width="1463.0" height="1023.8" />
     </clipPath>
     <clipPath id="breeze-setup-regenerate-command-images-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -165,9 +165,12 @@
 <clipPath id="breeze-setup-regenerate-command-images-line-39">
     <rect x="0" y="953.1" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-setup-regenerate-command-images-line-40">
+    <rect x="0" y="977.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="1048.4" rx="8"/><text 
class="breeze-setup-regenerate-command-images-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;setup&#160;regenerate-command-images</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1072.8" rx="8"/><text 
class="breeze-setup-regenerate-command-images-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;setup&#160;regenerate-command-images</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -205,19 +208,20 @@
 </text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="630" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-25)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="630" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-25)">release-management:start-rc-process&#160;|&#160;release-management:start-release&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
 </text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="654.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-26)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="654.4" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-26)">release-management:tag-providers&#160;|&#160;release-management:update-constraints&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
 </text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="678.8" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-27)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="678.8" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-27)">release-management:verify-provider-packages&#160;|&#160;sbom&#160;|&#160;sbom:build-all-airflow-images&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="703.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-28)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="703.2" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-28)">sbom:generate-providers-requirements&#160;|&#160;sbom:update-sbom-information&#160;|&#160;setup&#160;|&#160;setup:autocomplete&#160;|&#160;&#160;</text><text
 class [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="727.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-29)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="727.6" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-29)">setup:check-all-params-in-groups&#160;|&#160;setup:config&#160;|&#160;setup:regenerate-command-images&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="752" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-30)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="752" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-30)">setup:self-upgrade&#160;|&#160;setup:synchronize-local-mounts&#160;|&#160;setup:version&#160;|&#160;shell&#160;|&#160;start-airflow&#160;|&#160;&#160;&#160;&#160;&#160
 [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="776.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-31)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="776.4" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-31)">static-checks&#160;|&#160;testing&#160;|&#160;testing:db-tests&#160;|&#160;testing:docker-compose-tests&#160;|&#160;testing:helm-tests&#160;|&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="800.8" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-32)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="800.8" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-32)">testing:integration-tests&#160;|&#160;testing:non-db-tests&#160;|&#160;testing:tests)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="825.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-33)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="825.2" 
textLength="146.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-33)">--check-only</text><text
 class="breeze-setup-regenerate-command-images-r1" x="219.6" y="825.2" 
textLength="1220" clip-path="url(#breeze-setup-regenerate-command-im [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="849.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-34)">│</text><text 
class="breeze-setup-regenerate-command-images-r1" x="219.6" y="849.6" 
textLength="170.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-34)">together&#160;with&#160;</text><text
 class="breeze-setup-regenerate-command-images-r4" x="390.4" y="849.6" 
textLength="109.8" clip-path="url(#breeze-setup-regener [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="874" 
textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-35)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="874" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-35)">
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="898.4" 
textLength="24.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-36)">╭─</text><text 
class="breeze-setup-regenerate-command-images-r5" x="24.4" y="898.4" 
textLength="195.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-36)">&#160;Common&#160;options&#160;</text><text
 class="breeze-setup-regenerate-command-images-r5" x="219.6" y="898.4" 
textLength="1220" clip-path="url(#breeze-setup-r [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="922.8" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-37)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="922.8" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-37)">--verbose</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="922.8" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-image [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="947.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-38)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="947.2" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-38)">--dry-run</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="947.2" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-image [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="971.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-39)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="971.6" 
textLength="73.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-39)">--help</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="971.6" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-images-li 
[...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="996" 
textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-40)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="996" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-40)">
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="703.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-28)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="703.2" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-28)">sbom:export-dependency-information&#160;|&#160;sbom:generate-providers-requirements&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="727.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-29)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="727.6" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-29)">sbom:update-sbom-information&#160;|&#160;setup&#160;|&#160;setup:autocomplete&#160;|&#160;setup:check-all-params-in-groups&#160;|&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="752" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-30)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="752" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-30)">setup:config&#160;|&#160;setup:regenerate-command-images&#160;|&#160;setup:self-upgrade&#160;|&#160;setup:synchronize-local-mounts</text><text
 class="breeze-setup-rege [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="776.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-31)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="776.4" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-31)">|&#160;setup:version&#160;|&#160;shell&#160;|&#160;start-airflow&#160;|&#160;static-checks&#160;|&#160;testing&#160;|&#160;testing:db-tests&#160;|&#160;&#160;&#160
 [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="800.8" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-32)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="800.8" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-32)">testing:docker-compose-tests&#160;|&#160;testing:helm-tests&#160;|&#160;testing:integration-tests&#160;|&#160;testing:non-db-tests</text><text
 class="breeze-setup- [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="825.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-33)">│</text><text 
class="breeze-setup-regenerate-command-images-r6" x="219.6" y="825.2" 
textLength="1220" 
clip-path="url(#breeze-setup-regenerate-command-images-line-33)">|&#160;testing:tests)&#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-setup-regenerate-command-images-r5" x="0" y="849.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-34)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="849.6" 
textLength="146.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-34)">--check-only</text><text
 class="breeze-setup-regenerate-command-images-r1" x="219.6" y="849.6" 
textLength="1220" clip-path="url(#breeze-setup-regenerate-command-im [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="874" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-35)">│</text><text 
class="breeze-setup-regenerate-command-images-r1" x="219.6" y="874" 
textLength="170.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-35)">together&#160;with&#160;</text><text
 class="breeze-setup-regenerate-command-images-r4" x="390.4" y="874" 
textLength="109.8" clip-path="url(#breeze-setup-regenerate-co [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="898.4" 
textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-36)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="898.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-36)">
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="922.8" 
textLength="24.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-37)">╭─</text><text 
class="breeze-setup-regenerate-command-images-r5" x="24.4" y="922.8" 
textLength="195.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-37)">&#160;Common&#160;options&#160;</text><text
 class="breeze-setup-regenerate-command-images-r5" x="219.6" y="922.8" 
textLength="1220" clip-path="url(#breeze-setup-r [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="947.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-38)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="947.2" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-38)">--verbose</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="947.2" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-image [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="971.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-39)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="971.6" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-39)">--dry-run</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="971.6" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-image [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="996" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-40)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="996" 
textLength="73.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-40)">--help</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="996" 
textLength="24.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-40) [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1020.4" textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-41)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="1020.4" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-41)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_setup_regenerate-command-images.txt 
b/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
index 30ab217578..50a209110a 100644
--- a/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
+++ b/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
@@ -1 +1 @@
-36065ee5753333c55ee95e23da3dcf2f
+d8b4c5d290f72a66c75d9e04a7b27653
diff --git a/dev/breeze/src/airflow_breeze/commands/common_options.py 
b/dev/breeze/src/airflow_breeze/commands/common_options.py
index ceb3db7e12..6ef6e01a3f 100644
--- a/dev/breeze/src/airflow_breeze/commands/common_options.py
+++ b/dev/breeze/src/airflow_breeze/commands/common_options.py
@@ -398,6 +398,14 @@ option_use_airflow_version = click.option(
     type=UseAirflowVersionType(ALLOWED_USE_AIRFLOW_VERSIONS),
     envvar="USE_AIRFLOW_VERSION",
 )
+option_airflow_version = click.option(
+    "-A",
+    "--airflow-version",
+    help="Airflow version to use for the command.",
+    type=str,
+    envvar="AIRFLOW_VERSION",
+    required=True,
+)
 option_verbose = click.option(
     "-v",
     "--verbose",
diff --git a/dev/breeze/src/airflow_breeze/commands/sbom_commands.py 
b/dev/breeze/src/airflow_breeze/commands/sbom_commands.py
index aae162293a..e7ecdb4d63 100644
--- a/dev/breeze/src/airflow_breeze/commands/sbom_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/sbom_commands.py
@@ -17,6 +17,7 @@
 
 from __future__ import annotations
 
+import csv
 import json
 import os
 import sys
@@ -25,12 +26,14 @@ from pathlib import Path
 import click
 
 from airflow_breeze.commands.common_options import (
+    option_airflow_version,
     option_answer,
     option_debug_resources,
     option_dry_run,
     option_historical_python_version,
     option_include_success_outputs,
     option_parallelism,
+    option_python,
     option_run_in_parallel,
     option_skip_cleanup,
     option_verbose,
@@ -38,6 +41,7 @@ from airflow_breeze.commands.common_options import (
 from airflow_breeze.global_constants import (
     AIRFLOW_PYTHON_COMPATIBILITY_MATRIX,
     ALL_HISTORICAL_PYTHON_VERSIONS,
+    DEVEL_DEPS_PATH,
     PROVIDER_DEPENDENCIES,
 )
 from airflow_breeze.utils.cdxgen import (
@@ -46,9 +50,12 @@ from airflow_breeze.utils.cdxgen import (
     SbomCoreJob,
     SbomProviderJob,
     build_all_airflow_versions_base_image,
+    convert_sbom_to_csv,
     get_cdxgen_port_mapping,
+    get_field_names,
     get_requirements_for_provider,
     list_providers_from_providers_requirements,
+    normalize_package_name,
 )
 from airflow_breeze.utils.ci_group import ci_group
 from airflow_breeze.utils.click_utils import BreezeGroup
@@ -627,3 +634,82 @@ def generate_providers_requirements(
                 force=force,
                 output=None,
             )
+
+
[email protected](name="export-dependency-information", help="Export dependency 
information from SBOM.")
+@option_airflow_version
+@option_python
[email protected](
+    "-f",
+    "--csv-file",
+    type=click.Path(file_okay=True, dir_okay=False, path_type=Path, 
writable=True),
+    help="CSV file to produce.",
+    envvar="CSV_FILE",
+    required=True,
+)
[email protected](
+    "-s",
+    "--include-open-psf-scorecard",
+    is_flag=True,
+    default=False,
+)
+@option_dry_run
+@option_answer
+def export_dependency_information(
+    python: str,
+    airflow_version: str,
+    csv_file: Path,
+    include_open_psf_scorecard: bool,
+):
+    import requests
+
+    base_url = 
f"https://airflow.apache.org/docs/apache-airflow/{airflow_version}/sbom";
+    sbom_file_base = 
f"apache-airflow-sbom-{airflow_version}-python{python}-python-only"
+
+    sbom_core_url = f"{base_url}/{sbom_file_base}.json"
+    sbom_full_url = f"{base_url}/{sbom_file_base}-full.json"
+    core_sbom_r = requests.get(sbom_core_url)
+    core_sbom_r.raise_for_status()
+    full_sbom_r = requests.get(sbom_full_url)
+    full_sbom_r.raise_for_status()
+
+    core_dependencies = set()
+
+    core_sbom = core_sbom_r.json()
+
+    full_sbom = full_sbom_r.json()
+
+    dev_deps = set(normalize_package_name(name) for name in 
DEVEL_DEPS_PATH.read_text().splitlines())
+    num_deps = 0
+    with csv_file.open("w") as csvfile:
+        fieldnames = get_field_names(include_open_psf_scorecard)
+        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
+        writer.writeheader()
+        for dependency in core_sbom["components"]:
+            name = dependency["name"]
+            normalized_name = normalize_package_name(name)
+            core_dependencies.add(normalized_name)
+            is_devel = normalized_name in dev_deps
+            convert_sbom_to_csv(
+                writer,
+                dependency,
+                is_core=True,
+                is_devel=is_devel,
+                include_open_psf_scorecard=include_open_psf_scorecard,
+            )
+            num_deps += 1
+        for dependency in full_sbom["components"]:
+            name = dependency["name"]
+            normalized_name = normalize_package_name(name)
+            if normalized_name not in core_dependencies:
+                is_devel = normalized_name in dev_deps
+                convert_sbom_to_csv(
+                    writer,
+                    dependency,
+                    is_core=False,
+                    is_devel=is_devel,
+                    include_open_psf_scorecard=include_open_psf_scorecard,
+                )
+                num_deps += 1
+
+    get_console().print(f"[info]Exported {num_deps} dependencies to 
{csv_file}")
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 ebebeb7ec7..d5b26a6a29 100644
--- a/dev/breeze/src/airflow_breeze/commands/sbom_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/sbom_commands_config.py
@@ -91,4 +91,15 @@ SBOM_PARAMETERS: dict[str, list[dict[str, str | list[str]]]] 
= {
             ],
         },
     ],
+    "breeze sbom export-dependency-information": [
+        {
+            "name": "Export dependency information flags",
+            "options": [
+                "--csv-file",
+                "--airflow-version",
+                "--python",
+                "--include-open-psf-scorecard",
+            ],
+        }
+    ],
 }
diff --git a/dev/breeze/src/airflow_breeze/global_constants.py 
b/dev/breeze/src/airflow_breeze/global_constants.py
index bfa0a812dd..9991ef7858 100644
--- a/dev/breeze/src/airflow_breeze/global_constants.py
+++ b/dev/breeze/src/airflow_breeze/global_constants.py
@@ -422,6 +422,8 @@ PROVIDER_RUNTIME_DATA_SCHEMA_PATH = AIRFLOW_SOURCES_ROOT / 
"airflow" / "provider
 with Path(AIRFLOW_SOURCES_ROOT, "generated", 
"provider_dependencies.json").open() as f:
     PROVIDER_DEPENDENCIES = json.load(f)
 
+DEVEL_DEPS_PATH = AIRFLOW_SOURCES_ROOT / "generated" / "devel_deps.txt"
+
 # Initialize files for rebuild check
 FILES_FOR_REBUILD_CHECK = [
     "pyproject.toml",
diff --git a/dev/breeze/src/airflow_breeze/utils/cdxgen.py 
b/dev/breeze/src/airflow_breeze/utils/cdxgen.py
index a7cf28dd23..3d129b4674 100644
--- a/dev/breeze/src/airflow_breeze/utils/cdxgen.py
+++ b/dev/breeze/src/airflow_breeze/utils/cdxgen.py
@@ -24,10 +24,11 @@ import signal
 import sys
 import time
 from abc import abstractmethod
+from csv import DictWriter
 from dataclasses import dataclass
 from multiprocessing.pool import Pool
 from pathlib import Path
-from typing import Generator
+from typing import Any, Generator
 
 import yaml
 
@@ -514,3 +515,132 @@ def produce_sbom_for_application_via_cdxgen_server(
         port = port_map[multiprocessing.current_process().name]
         get_console(output=output).print(f"[info]Using port {port}")
     return job.produce(output, port)
+
+
+def convert_licenses(licenses: list[dict[str, Any]]) -> str:
+    license_strings = []
+    for license in licenses:
+        if "license" in license:
+            if "id" in license["license"]:
+                license_strings.append(license["license"]["id"])
+            elif "name" in license["license"]:
+                license_strings.append(license["license"]["name"])
+            else:
+                raise ValueError(f"Unknown license format: {license}")
+        elif "expression" in license:
+            license_strings.append(license["expression"])
+        else:
+            raise ValueError(f"Unknown license format: {license}")
+    return ", ".join(license_strings)
+
+
+def get_vcs(dependency: dict[str, Any]) -> str:
+    if "externalReferences" in dependency:
+        for reference in dependency["externalReferences"]:
+            if reference["type"] == "vcs":
+                return reference["url"]
+    return ""
+
+
+def get_pypi_link(dependency: dict[str, Any]) -> str:
+    if "purl" in dependency and "pkg:pypi" in dependency["purl"]:
+        package, version = dependency["purl"][len("pkg:pypi/") :].split("@")
+        return f"https://pypi.org/project/{package}/{version}/";
+    return ""
+
+
+OPEN_PSF_CHECKS = [
+    "Code-Review",
+    "Maintained",
+    "CII-Best-Practices",
+    "License",
+    "Binary-Artifacts",
+    "Dangerous-Workflow",
+    "Token-Permissions",
+    "Pinned-Dependencies",
+    "Branch-Protection",
+    "Signed-Releases",
+    "Security-Policy",
+    "Dependency-Update-Tool",
+    "Contributors",
+    "CI-Tests",
+    "Fuzzing",
+    "Packaging",
+    "Vulnerabilities",
+    "SAST",
+]
+
+
+def get_open_psf_scorecard(vcs):
+    import requests
+
+    repo_url = vcs.split("://")[1]
+    open_psf_url = f"https://api.securityscorecards.dev/projects/{repo_url}";
+    scorecard_response = requests.get(open_psf_url)
+    if scorecard_response.status_code == 404:
+        return {}
+    scorecard_response.raise_for_status()
+    open_psf_scorecard = scorecard_response.json()
+    results = {}
+    results["OPSF-Score"] = open_psf_scorecard["score"]
+    if "checks" in open_psf_scorecard:
+        for check in open_psf_scorecard["checks"]:
+            check_name = check["name"]
+            results["OPSF-" + check_name] = check["score"]
+            reason = check.get("reason") or ""
+            if check.get("details"):
+                reason += "\n".join(check["details"])
+            results["OPSF-Details-" + check_name] = reason
+    return results
+
+
+def convert_sbom_to_csv(
+    writer: DictWriter,
+    dependency: dict[str, Any],
+    is_core: bool,
+    is_devel: bool,
+    include_open_psf_scorecard: bool = False,
+) -> None:
+    """
+    Convert SBOM to CSV
+    :param writer: CSV writer
+    :param dependency: Dependency to convert
+    :param is_core: Whether the dependency is core or not
+    """
+    get_console().print(f"[info]Converting {dependency['name']} to CSV")
+    vcs = get_vcs(dependency)
+    name = dependency.get("name", "")
+    if name.startswith("apache-airflow"):
+        return
+    row = {
+        "Name": dependency.get("name", ""),
+        "Author": dependency.get("author", ""),
+        "Version": dependency.get("version", ""),
+        "Description": dependency.get("description"),
+        "Core": is_core,
+        "Devel": is_devel,
+        "Licenses": convert_licenses(dependency.get("licenses", [])),
+        "Purl": dependency.get("purl"),
+        "Pypi": get_pypi_link(dependency),
+        "Vcs": vcs,
+    }
+    if vcs and include_open_psf_scorecard:
+        open_psf_scorecard = get_open_psf_scorecard(vcs)
+        row.update(open_psf_scorecard)
+    writer.writerow(row)
+
+
+def get_field_names(include_open_psf_scorecard: bool) -> list[str]:
+    names = ["Name", "Author", "Version", "Description", "Core", "Devel", 
"Licenses", "Purl", "Pypi", "Vcs"]
+    if include_open_psf_scorecard:
+        names.append("OPSF-Score")
+        for check in OPEN_PSF_CHECKS:
+            names.append("OPSF-" + check)
+            names.append("OPSF-Details-" + check)
+    return names
+
+
+def normalize_package_name(name):
+    import re
+
+    return re.sub(r"[-_.]+", "-", name).lower()
diff --git a/dev/get_devel_deps.sh b/dev/get_devel_deps.sh
new file mode 100755
index 0000000000..915d52dab2
--- /dev/null
+++ b/dev/get_devel_deps.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+
+# 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.
+
+# Run this script in Breeze to get the list of all devel dependencies
+VERSION=2.9.3
+uv pip freeze --python /usr/local/bin/python | grep -v "pip==" | grep -v 
"uv==" > freeze.txt
+uv pip uninstall -r freeze.txt --python /usr/local/bin/python
+uv pip install "apache-airflow[all]==${VERSION}" --constraint 
"https://raw.githubusercontent.com/apache/airflow/constraints-${VERSION}/constraints-${PYTHON_MAJOR_MINOR_VERSION}.txt";
 --python /usr/local/bin/python
+uv pip freeze --python /usr/local/bin/python >non-devel-freeze.txt
+sed "s/==.*//" < freeze.txt > all_deps.txt
+sed "s/==.*//" < non-devel-freeze.txt > all_non_devel_deps.txt
+grep -v -f all_non_devel_deps.txt all_deps.txt
diff --git a/generated/README.md b/generated/README.md
index f364806014..6544ce34d2 100644
--- a/generated/README.md
+++ b/generated/README.md
@@ -36,3 +36,6 @@ You can read more about pre-commit hooks 
[here](../contributing-docs/08_static_c
   focusing on select sections. This subset is produced by the 
`generate-pypi-readme` pre-commit hook specified in
   the `.pre-commit-config.yaml` file. This hook triggers automatically 
whenever the related sections in the
   `README.md` change, ensuring alignment between the two files.
+
+* `devel_deps.txt` is a file containing development-only dependencies of 
Airflow. They were generated
+  for Airflow 2.9.3 by running `./dev/get_devel_deps.sh` script.
diff --git a/generated/devel_deps.txt b/generated/devel_deps.txt
new file mode 100644
index 0000000000..22839b75a8
--- /dev/null
+++ b/generated/devel_deps.txt
@@ -0,0 +1,105 @@
+aiohappyeyeballs
+aioresponses
+alabaster
+anyascii
+astroid
+aws-sam-translator
+aws-xray-sdk
+backports-tarfile
+cfgv
+cfn-lint
+checksumdir
+coverage
+deltalake
+diagrams
+duckdb
+eralchemy2
+execnet
+gitdb
+gitpython
+graphql-core
+hatch
+hatchling
+hyperlink
+icdiff
+identify
+imagesize
+incremental
+iniconfig
+ipdb
+jaraco-classes
+jaraco-context
+jaraco-functools
+jeepney
+joserfc
+jsondiff
+jsonpatch
+jsonpointer
+keyring
+mmh3
+mongomock
+moto
+mpmath
+mypy
+networkx
+nh3
+nodeenv
+openapi-schema-validator
+openapi-spec-validator
+pathable
+pinecone-plugin-inference
+pkginfo
+pprintpp
+py-partiql-parser
+pyenchant
+pyiceberg
+pytest
+pytest-asyncio
+pytest-cov
+pytest-custom-exit-code
+pytest-icdiff
+pytest-instafail
+pytest-mock
+pytest-rerunfailures
+pytest-timeouts
+pytest-xdist
+readme-renderer
+responses
+restructuredtext-lint
+rfc3986
+ruff
+secretstorage
+semver
+sentinels
+shellingham
+smmap
+snowballstemmer
+sphinx
+sphinx-airflow-theme
+sphinx-argparse
+sphinx-autoapi
+sphinx-copybutton
+sphinx-design
+sphinx-jinja
+sphinx-rtd-theme
+sphinxcontrib-applehelp
+sphinxcontrib-devhelp
+sphinxcontrib-htmlhelp
+sphinxcontrib-httpdomain
+sphinxcontrib-jquery
+sphinxcontrib-jsmath
+sphinxcontrib-qthelp
+sphinxcontrib-redoc
+sphinxcontrib-serializinghtml
+sphinxcontrib-spelling
+strictyaml
+sympy
+towncrier
+trove-classifiers
+twine
+typed-ast
+types-pymysql
+types-toml
+userpath
+wheel
+yamllint

Reply via email to