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: 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: 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 that release managers can use to prepare sbom 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)"> Common options </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 this message and 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)"> SBOM commands </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                     </text><text
class="breeze-sbom-r1" x="585.6" y="239.6" textLength="854"
clip-path="url(#breeze-sbom-line-9)">Update 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                    </text><text
class="breeze-sbom-r1" x="585.6" y="264" textLength="854"
clip-path="url(#breeze-sbom-line-10)">Generate 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             </text><text
class="breeze-sbom-r1" x="585.6" y="288.4" textLength="854"
clip-path="url(#breeze-sbom-line-11)">Generate requirements for 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)"> Commands </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                    </text><text
class="breeze-sbom-r1" x="646.6" y="361.6" textLength="793"
clip-path="url(#breeze-sbom-line-14)">Export  [...]
+</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: sbom 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 sbom 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 dependency information from 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)"> Export dependency information flags </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)">(>3.8< | 3.9 | 3.10 | 3.11 | 3.12)            &#
[...]
+</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: 3.8]                       
[...]
+</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)"> Common options </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: setup 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: setup 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 | release-management:start-release |            
[...]
</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 | release-management:update-constraints |           
[...]
</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 | sbom | sbom:build-all-airflow-images |         
[...]
-</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 | sbom:update-sbom-information | setup | setup:autocomplete |    &#
[...]
-</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 | setup:config | setup:regenerate-command-images | setup:self-upgrade </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)">| setup:synchronize-local-mounts | setup:version | shell | start-airflow | static-checks | testing 
[...]
-</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 | testing:docker-compose-tests | testing:helm-tests | testing:integration-tests |    &#
[...]
-</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 | testing:tests)                   &#
[...]
-</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)"> Common options </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 | sbom:generate-providers-requirements |           
[...]
+</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 | setup | setup:autocomplete | setup:check-all-params-in-groups |     
[...]
+</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 | setup:regenerate-command-images | setup:self-upgrade | setup:synchronize-local-mounts | </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 | shell | start-airflow | static-checks | testing | testing:db-tests |   &#
[...]
+</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 | testing:helm-tests | testing:integration-tests | testing:non-db-tests | </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)                        &
[...]
+</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)"> Common options </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: setup 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: setup 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 | release-management:start-release |             &#
[...]
</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 | release-management:update-constraints |            &#
[...]
</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 | sbom | sbom:build-all-airflow-images |         
[...]
-</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 | sbom:update-sbom-information | setup | setup:autocomplete |  </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 | setup:config | setup:regenerate-command-images |         &
[...]
-</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 | setup:synchronize-local-mounts | setup:version | shell | start-airflow |     
[...]
-</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 | testing | testing:db-tests | testing:docker-compose-tests | testing:helm-tests |   
[...]
-</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 | testing:non-db-tests | testing:tests)             
[...]
-</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 with </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)"> Common options </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 | sbom:generate-providers-requirements |            &
[...]
+</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 | setup | setup:autocomplete | setup:check-all-params-in-groups |     
[...]
+</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 | setup:regenerate-command-images | setup:self-upgrade | 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)">| setup:version | shell | start-airflow | static-checks | testing | testing:db-tests |   
[...]
+</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 | testing:helm-tests | testing:integration-tests | 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)">| testing:tests)                       
[...]
+</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 with </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)"> Common options </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