diff --git a/.gitleaksignore b/.gitleaksignore
index eae290df9d4d1b32df6ca200d40d0a451860fc11..bb79c807a160af9fd98c2a262ab9bddf2df6f1f5 100644
--- a/.gitleaksignore
+++ b/.gitleaksignore
@@ -1 +1,2 @@
-dda82d21c9ba0e572abb74e0adb97268dc46d438:README.md:private-key:320
\ No newline at end of file
+dda82d21c9ba0e572abb74e0adb97268dc46d438:README.md:private-key:320
+ff8b9856a0bb045932f4810410404261cd848ea4:README.md:private-key:320
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2416236ca43f408a9f54003a29dbd77fb43b904b..29b7c8b897fc45b0871c6beb40d1d58799f9fd73 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,115 @@
-## [7.0.2](https://git.code.tecnalia.com/smartdatalab/public/ci-cd-components/python/compare/7.0.1...7.0.2) (2024-07-26)
+## [7.7.1](https://gitlab.com/to-be-continuous/python/compare/7.7.0...7.7.1) (2025-01-12)
 
 
 ### Bug Fixes
 
-* issue [#73](https://git.code.tecnalia.com/smartdatalab/public/ci-cd-components/python/issues/73) github_get_latest_version ([ce26d5a](https://git.code.tecnalia.com/smartdatalab/public/ci-cd-components/python/commit/ce26d5abba8950f30bad1d992a2481bf252359b7))
-* README for trivy now enabled by default ([f5d5f2e](https://git.code.tecnalia.com/smartdatalab/public/ci-cd-components/python/commit/f5d5f2e9c186b6aeb0c55ef45a65b85615b9ad7b))
+* move back 'reports' dir creation at job level to fix variants missing reports dir ([bf15efe](https://gitlab.com/to-be-continuous/python/commit/bf15efe4b008a5f292e782d0363a52000bf43f37))
+
+# [7.7.0](https://gitlab.com/to-be-continuous/python/compare/7.6.0...7.7.0) (2025-01-12)
+
+
+### Features
+
+* add auto-release as an optional feature for releases ([9db709a](https://gitlab.com/to-be-continuous/python/commit/9db709ad8fe96c7ed524f8083e57b845914e4009))
+
+# [7.6.0](https://gitlab.com/to-be-continuous/python/compare/7.5.2...7.6.0) (2025-01-08)
+
+
+### Features
+
+* add separate 'publish-enabled' to enable publishing package ([6f9ee56](https://gitlab.com/to-be-continuous/python/commit/6f9ee56d00ee5408953fa24323dbba81aa2d4f3a))
+
+## [7.5.2](https://gitlab.com/to-be-continuous/python/compare/7.5.1...7.5.2) (2024-12-22)
+
+
+### Bug Fixes
+
+* **test:** handle decimal coverage ([4fb81f8](https://gitlab.com/to-be-continuous/python/commit/4fb81f8b66bf285f173a2335f8c34523d0f7ca3d))
+
+## [7.5.1](https://gitlab.com/to-be-continuous/python/compare/7.5.0...7.5.1) (2024-11-21)
+
+
+### Bug Fixes
+
+* **CodeArtifact:** fix AWS CodeArtifact variant ([c913e65](https://gitlab.com/to-be-continuous/python/commit/c913e6538d88efaf1d6f0eb7742e7531d66a32c2))
+
+# [7.5.0](https://gitlab.com/to-be-continuous/python/compare/7.4.0...7.5.0) (2024-11-11)
+
+
+### Features
+
+* **Ruff:** add `ruff-format` job for code formatting ([142589f](https://gitlab.com/to-be-continuous/python/commit/142589f2c260336d3a703af3e149c1c666fd5373))
+
+# [7.4.0](https://gitlab.com/to-be-continuous/python/compare/7.3.3...7.4.0) (2024-11-08)
+
+
+### Features
+
+* add AWS CodeArtifact support (variant) ([128fb99](https://gitlab.com/to-be-continuous/python/commit/128fb9950c1354c211abe17d5cba19d75dd66ecc))
+
+## [7.3.3](https://gitlab.com/to-be-continuous/python/compare/7.3.2...7.3.3) (2024-11-06)
+
+
+### Bug Fixes
+
+* correct bandit exclude of .venv and .cache ([ed95527](https://gitlab.com/to-be-continuous/python/commit/ed955279f56f2d66a2a7532b35515f2309f05f5c)), closes [#92](https://gitlab.com/to-be-continuous/python/issues/92)
+
+## [7.3.2](https://gitlab.com/to-be-continuous/python/compare/7.3.1...7.3.2) (2024-11-02)
+
+
+### Bug Fixes
+
+* limit security reports access to developer role or higher ([40c85ef](https://gitlab.com/to-be-continuous/python/commit/40c85eff562a00ceb9b381ef72472ce1910b97ab))
+
+## [7.3.1](https://gitlab.com/to-be-continuous/python/compare/7.3.0...7.3.1) (2024-10-25)
+
+
+### Bug Fixes
+
+* **Trivy:** trivy scan fails when issues are found ([671b781](https://gitlab.com/to-be-continuous/python/commit/671b78142c08cdd5bbf1441a81705b96dbf0740f))
+* use right options for uv with extras deps ([354af5a](https://gitlab.com/to-be-continuous/python/commit/354af5ad8294ad8f3de3f7ad6aeaf8752d5f2625))
+
+# [7.3.0](https://gitlab.com/to-be-continuous/python/compare/7.2.0...7.3.0) (2024-10-15)
+
+
+### Features
+
+* **uv:** add uv support as a new build system ([8aeb20b](https://gitlab.com/to-be-continuous/python/commit/8aeb20b09347ff35398a4a707852a9cc17cc6842)), closes [#80](https://gitlab.com/to-be-continuous/python/issues/80)
+* **uv:** add uv support as a new build system ([d22ffba](https://gitlab.com/to-be-continuous/python/commit/d22ffbacb4228cb4ffdc6396bca9e43ad194bfff))
+
+# [7.2.0](https://gitlab.com/to-be-continuous/python/compare/7.1.1...7.2.0) (2024-10-04)
+
+
+### Bug Fixes
+
+* **release:** support full semantic-versioning specifcation (with prerelease and build metadata) ([08e9d7e](https://gitlab.com/to-be-continuous/python/commit/08e9d7e9f7f1bdd43a2070c9ee5abb16a8b8aaa0))
+* **trivy:** use --pkg-types instead of deprecated --vuln-type option ([5e0a0d2](https://gitlab.com/to-be-continuous/python/commit/5e0a0d2918fd7539bd2e1cb955e99ef5857db1f5))
+
+
+### Features
+
+* **trivy:** enable comprehensive priority ([322eb1b](https://gitlab.com/to-be-continuous/python/commit/322eb1b88c49d9a1662ad6b6199541f1a82860ef))
+
+## [7.1.1](https://gitlab.com/to-be-continuous/python/compare/7.1.0...7.1.1) (2024-10-03)
+
+
+### Bug Fixes
+
+* Poetry Build system test ([9505604](https://gitlab.com/to-be-continuous/python/commit/95056049e7ee8239b6358def7c594e7002036574))
+
+# [7.1.0](https://gitlab.com/to-be-continuous/python/compare/7.0.2...7.1.0) (2024-09-15)
+
+
+### Bug Fixes
+
+* check trivy activity to match new log format ([edd8fcf](https://gitlab.com/to-be-continuous/python/commit/edd8fcf71f1b251c467d6bbce6e8a190d4584dda))
+* pylint --ignore .cache not working now use find to exclude .cache ([e1463bc](https://gitlab.com/to-be-continuous/python/commit/e1463bc750fbd24b12d407267061d8ae8a3718f1))
+
+
+### Features
+
+* isort exclude .cache ([e333183](https://gitlab.com/to-be-continuous/python/commit/e333183ca48aa98baf9d510caf0c8f3f93d04b82))
+* remove unnecesary install when use poetry or pipenv ([f025c6d](https://gitlab.com/to-be-continuous/python/commit/f025c6df22d48bd735458fc478b18d2235a715a2))
 
 ## [7.0.2](https://gitlab.com/to-be-continuous/python/compare/7.0.1...7.0.2) (2024-05-20)
 
diff --git a/README.md b/README.md
index 8c0c22d93f5953ef8b6569e692b6786cfc35a6b4..6549aefb50989cb2d57c442119b2028b1b5a3a84 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Add the following to your `.gitlab-ci.yml`:
 ```yaml
 include:
   # 1: include the component
-  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.0.2
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.7.1
     # 2: set/override component inputs
     inputs:
       image: registry.hub.docker.com/library/python:3.12-slim
@@ -29,7 +29,7 @@ Add the following to your `.gitlab-ci.yml`:
 include:
   # 1: include the template
   - project: 'to-be-continuous/python'
-    ref: '7.0.2'
+    ref: '7.7.1'
     file: '/templates/gitlab-ci-python.yml'
 
 variables:
@@ -65,12 +65,13 @@ By default it tries to auto-detect the build system used by the project (based o
 and/or `setup.py` and/or `requirements.txt`), but the build system might also be set explicitly using the
 `$PYTHON_BUILD_SYSTEM` variable:
 
-| Value            | Build System (scope)                                       |
-| ---------------- | ---------------------------------------------------------- |
-| _none_ (default) or `auto` | The template tries to **auto-detect** the actual build system |
-| `setuptools`     | [Setuptools](https://setuptools.pypa.io/) (dependencies, build & packaging) |
-| `poetry`         | [Poetry](https://python-poetry.org/) (dependencies, build, test & packaging) |
-| `pipenv`         | [Pipenv](https://pipenv.pypa.io/) (dependencies only) |
+| Value            | Build System (scope)                                                                                   |
+| ---------------- |--------------------------------------------------------------------------------------------------------|
+| _none_ (default) or `auto` | The template tries to **auto-detect** the actual build system                                          |
+| `setuptools`     | [Setuptools](https://setuptools.pypa.io/) (dependencies, build & packaging)                            |
+| `poetry`         | [Poetry](https://python-poetry.org/) (dependencies, build, test & packaging)                           |
+| `uv`             | [uv](https://docs.astral.sh/uv/) (dependencies, build, test & packaging)|
+| `pipenv`         | [Pipenv](https://pipenv.pypa.io/) (dependencies only)                                                  |
 | `reqfile`        | [Requirements Files](https://pip.pypa.io/en/stable/user_guide/#requirements-files) (dependencies only) |
 
 :warning: You can explicitly set the build tool version by setting `$PYTHON_BUILD_SYSTEM` variable including a [version identification](https://peps.python.org/pep-0440/). For example `PYTHON_BUILD_SYSTEM="poetry==1.1.15"`
@@ -108,7 +109,7 @@ In addition to a textual report in the console, this job produces the following
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
 | `$PYTHON_PROJECT_DIR/reports/py-lint.codeclimate.json` | [Code Climate](https://docs.codeclimate.com/docs/pylint) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscodequality) |
-| `$PYTHON_PROJECT_DIR/reports/py-lint.parseable.txt` | [parseable](https://pylint.pycqa.org/en/latest/user_guide/usage/output.html) | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/) |
+| `$PYTHON_PROJECT_DIR/reports/py-lint.parseable.txt` | [parseable](https://pylint.pycqa.org/en/latest/user_guide/usage/output.html) | [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/importing-external-issues/external-analyzer-reports/) |
 
 ### Test jobs
 
@@ -152,8 +153,8 @@ In addition to a textual report in the console, this job produces the following
 
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
-| `$PYTHON_PROJECT_DIR/reports/TEST-*.xml` | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) & [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/test-execution-parameters/#header-8) |
-| `$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report) & [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/python-test-coverage/) |
+| `$PYTHON_PROJECT_DIR/reports/TEST-*.xml` | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) & [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/test-execution-parameters/#python) |
+| `$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report) & [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/python-test-coverage/) |
 
 #### `py-pytest` job
 
@@ -186,8 +187,8 @@ In addition to a textual report in the console, this job produces the following
 
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
-| `$PYTHON_PROJECT_DIR/reports/TEST-*.xml` | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) & [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/test-execution-parameters/#header-8) |
-| `$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report) & [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/python-test-coverage/) |
+| `$PYTHON_PROJECT_DIR/reports/TEST-*.xml` | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) & [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/test-execution-parameters/#python) |
+| `$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report) & [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/python-test-coverage/) |
 
 #### `py-nosetests` job
 
@@ -211,8 +212,8 @@ In addition to a textual report in the console, this job produces the following
 
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
-| `$PYTHON_PROJECT_DIR/reports/TEST-*.xml` | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) & [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/test-execution-parameters/#header-8) |
-| `$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report) & [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/python-test-coverage/) |
+| `$PYTHON_PROJECT_DIR/reports/TEST-*.xml` | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) & [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/test-execution-parameters/#python) |
+| `$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report) & [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/python-test-coverage/) |
 
 #### `py-compile` job
 
@@ -238,16 +239,16 @@ It is bound to the `test` stage, and uses the following variables:
 | `bandit-args` / `BANDIT_ARGS`    | Additional [Bandit CLI options](https://github.com/PyCQA/bandit#usage) | `--recursive .`   |
 | `py-bandit-job-tags` / `PY_BANDIT_JOB_TAGS` | Tags to be used for selecting runners for the job | `[]`            |
 
-In addition to a textual report in the console, this job produces the following reports, kept for one day:
+In addition to a textual report in the console, this job produces the following reports, kept for one day and only available for download by users with the Developer role or higher:
 
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
-| `$PYTHON_PROJECT_DIR/reports/py-bandit.bandit.csv` | [CSV](https://bandit.readthedocs.io/en/latest/formatters/csv.html) | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/)<br/>_This report is generated only if SonarQube template is detected_ |
-| `$PYTHON_PROJECT_DIR/reports/py-bandit.bandit.json` | [JSON](https://bandit.readthedocs.io/en/latest/formatters/json.html) | [DefectDojo integration](https://defectdojo.github.io/django-DefectDojo/integrations/parsers/#bandit)<br/>_This report is generated only if DefectDojo template is detected_ |
+| `$PYTHON_PROJECT_DIR/reports/py-bandit.bandit.csv` | [CSV](https://bandit.readthedocs.io/en/latest/formatters/csv.html) | [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/importing-external-issues/external-analyzer-reports/)<br/>_This report is generated only if SonarQube template is detected_ |
+| `$PYTHON_PROJECT_DIR/reports/py-bandit.bandit.json` | [JSON](https://bandit.readthedocs.io/en/latest/formatters/json.html) | [DefectDojo integration](https://docs.defectdojo.com/en/connecting_your_tools/parsers/file/bandit/)<br/>_This report is generated only if DefectDojo template is detected_ |
 
 ### `py-trivy` job (dependency check)
 
-This job performs a dependency check analysis using [Trivy](https://github.com/aquasecurity/trivy/).
+This job performs a dependency check analysis using [Trivy](https://aquasecurity.github.io/trivy).
 :warning:  This job is now **enabled by default** since version 7.0.0
 
 
@@ -260,11 +261,21 @@ It is bound to the `test` stage, and uses the following variables:
 | `trivy-args` / `PYTHON_TRIVY_ARGS`       | Additional [Trivy CLI options](https://aquasecurity.github.io/trivy/v0.21.1/getting-started/cli/fs/) | `--vuln-type library`   |
 | `py-trivy-job-tags` / `PY_TRIVY_JOB_TAGS` | Tags to be used for selecting runners for the job | `[]`            |
 
-In addition to a textual report in the console, this job produces the following reports, kept for one day:
+Other Trivy parameters shall be configured using [Trivy environment variables](https://aquasecurity.github.io/trivy/latest/docs/references/configuration/cli/trivy_filesystem/#options).
+Examples:
+* `TRIVY_SEVERITY`: severities of security issues to be displayed (comma separated values: `UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`)
+* `TRIVY_SERVER`: server address (enables [client/server mode](https://trivy.dev/latest/docs/references/modes/client-server/))
+* `TRIVY_DB_REPOSITORY`: OCI repository to retrieve Trivy Database from
+* ...
+
+:warning: if you're using Trivy in multiple templates with different parameter values (ex: different `TRIVY_SEVERITY` threshold with Python and - says - Docker templates), then it is
+recommanded to pass the configuration as CLI options using the `trivy-args` input / `PYTHON_TRIVY_ARGS` variable.
+
+In addition to a textual report in the console, this job produces the following reports, kept for one day and only available for download by users with the Developer role or higher:
 
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
-| `$PYTHON_PROJECT_DIR/reports/py-trivy.trivy.json` | [JSON](https://aquasecurity.github.io/trivy/latest/docs/configuration/reporting/#json) | [DefectDojo integration](https://defectdojo.github.io/django-DefectDojo/integrations/parsers/#trivy)<br/>_This report is generated only if DefectDojo template is detected_ |
+| `$PYTHON_PROJECT_DIR/reports/py-trivy.trivy.json` | [JSON](https://aquasecurity.github.io/trivy/latest/docs/configuration/reporting/#json) | [DefectDojo integration](https://docs.defectdojo.com/en/connecting_your_tools/parsers/file/trivy/)<br/>_This report is generated only if DefectDojo template is detected_ |
 
 ### `py-sbom` job
 
@@ -315,14 +326,24 @@ This job **disabled by default** and runs [Ruff](https://docs.astral.sh/ruff/) o
 | `ruff-ext-exclude` / `RUFF_EXT_EXCLUDE` | Define [extend-exclude](https://docs.astral.sh/ruff/settings/#extend-exclude) files                             | _.venv,.cache_   |
 | `py-ruff-job-tags` / `PY_RUFF_JOB_TAGS` | Tags to be used for selecting runners for the job | `[]`            |
 
-:warning: Ruff can replace isort, Black, Bandit, Pylint and much more. [More info](https://github.com/astral-sh/ruff/blob/main/docs/faq.md#which-tools-does-ruff-replace). 
+:warning: Ruff can replace isort, Bandit, Pylint and much more. [More info](https://github.com/astral-sh/ruff/blob/main/docs/faq.md#which-tools-does-ruff-replace).
 
 In addition to logs in the console, this job produces the following reports, kept for one week:
 
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
 | `$PYTHON_PROJECT_DIR/reports/py-ruff.gitlab.json` | [GitLab](https://docs.astral.sh/ruff/settings/#output-format) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscodequality) |
-| `$PYTHON_PROJECT_DIR/reports/py-ruff.native.json` | [JSON](https://docs.astral.sh/ruff/settings/#output-format) | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/)<br/>_This report is generated only if SonarQube template is detected_ |
+| `$PYTHON_PROJECT_DIR/reports/py-ruff.native.json` | [JSON](https://docs.astral.sh/ruff/settings/#output-format) | [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/importing-external-issues/external-analyzer-reports/)<br/>_This report is generated only if SonarQube template is detected_ |
+
+### `py-ruff-format` job
+
+This job **disabled by default** and runs [Ruff](https://docs.astral.sh/ruff/) on the repo. It is bound to the build stage.
+
+| Input / Variable | Description                                                             | Default value     |
+| ---------------- | ----------------------------------------------------------------------- | ----------------- |
+| `ruff-format-enabled` / `RUFF_FORMAT_ENABLED` | Set to `true` to enable ruff job                  | _none_ (disabled) |
+
+:warning: Ruff can replace Black and much more. [More info](https://github.com/astral-sh/ruff/blob/main/docs/faq.md#which-tools-does-ruff-replace).
 
 #### `py-mypy` job
 
@@ -343,14 +364,14 @@ In addition to a textual report in the console, this job produces the following
 | Report         | Format                                                                       | Usage             |
 | -------------- | ---------------------------------------------------------------------------- | ----------------- |
 | `$PYTHON_PROJECT_DIR/reports/py-mypy.codeclimate.json` | [Code Climate](https://github.com/soul-catcher/mypy-gitlab-code-quality) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscodequality) |
-| `$PYTHON_PROJECT_DIR/reports/py-mypy.console.txt` | [mypy console output](https://mypy.readthedocs.io/) | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/) |
+| `$PYTHON_PROJECT_DIR/reports/py-mypy.console.txt` | [mypy console output](https://mypy.readthedocs.io/) | [SonarQube integration](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/importing-external-issues/external-analyzer-reports/) |
 
 ### SonarQube analysis
 
 If you're using the SonarQube template to analyse your Python code, here is a sample `sonar-project.properties` file:
 
 ```properties
-# see: https://docs.sonarqube.org/latest/analyzing-source-code/test-coverage/python-test-coverage/
+# see: https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/python-test-coverage/
 # set your source directory(ies) here (relative to the sonar-project.properties file)
 sonar.sources=.
 # exclude unwanted directories and files from being analysed
@@ -376,9 +397,9 @@ sonar.python.mypy.reportPaths=reports/py-mypy.console.txt
 
 More info:
 
-* [Python language support](https://docs.sonarqube.org/latest/analyzing-source-code/test-coverage/python-test-coverage/)
-* [test coverage & execution parameters](https://docs.sonarqube.org/latest/analysis/coverage/)
-* [third-party issues](https://docs.sonarqube.org/latest/analysis/external-issues/)
+* [Python language support](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/python-test-coverage/)
+* [test coverage](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/test-coverage-parameters/) & [test execution](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/test-execution-parameters/) parameters
+* [external analyzer reports](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/importing-external-issues/external-analyzer-reports/)
 
 ### `py-release` job
 
@@ -389,9 +410,10 @@ This job is **disabled by default** and allows to perform a complete release of
 3. build the [Python packages](https://packaging.python.org/),
 4. publish the built packages to a PyPI compatible repository ([GitLab packages](https://docs.gitlab.com/ee/user/packages/pypi_repository/) by default).
 
-The Python template supports two packaging systems:
+The Python template supports three packaging systems:
 
 * [Poetry](https://python-poetry.org/): uses Poetry-specific [version](https://python-poetry.org/docs/cli/#version), [build](https://python-poetry.org/docs/cli/#build) and [publish](https://python-poetry.org/docs/cli/#publish) commands.
+* [uv](https://docs.astral.sh/uv/): uses [uv](https://docs.astral.sh/uv/) as version management, [build](https://docs.astral.sh/uv/guides/publish/#building-your-package) as package builder and [publish](https://docs.astral.sh/uv/guides/publish/) to publish.
 * [Setuptools](https://setuptools.pypa.io/): uses [bump-my-version](https://github.com/callowayproject/bump-my-version) as version management, [build](https://pypa-build.readthedocs.io/) as package builder and [Twine](https://twine.readthedocs.io/) to publish.
 
 The release job is bound to the `publish` stage, appears only on production and integration branches and uses the following variables:
@@ -399,17 +421,37 @@ The release job is bound to the `publish` stage, appears only on production and
 | Input / Variable        | Description                                                             | Default value     |
 | ----------------------- | ----------------------------------------------------------------------- | ----------------- |
 | `release-enabled` / `PYTHON_RELEASE_ENABLED`| Set to `true` to enable the release job                                 | _none_ (disabled) |
+| `auto-release-enabled` / `PYTHON_AUTO_RELEASE_ENABLED`| When set the job start automatically on production branch. When not set (default), the job is manual. Note that this behavior also depends on release-enabled being set. | _none_ (disabled) |
 | `release-next` / `PYTHON_RELEASE_NEXT`   | The part of the version to increase (one of: `major`, `minor`, `patch`) | `minor`           |
 | `semrel-release-disabled` / `PYTHON_SEMREL_RELEASE_DISABLED`| Set to `true` to disable [semantic-release integration](#semantic-release-integration)   | _none_ (disabled) |
 | `GIT_USERNAME`          | Git username for Git push operations (see below)                        | _none_            |
 | :lock: `GIT_PASSWORD`   | Git password for Git push operations (see below)                        | _none_            |
 | :lock: `GIT_PRIVATE_KEY`| SSH key for Git push operations (see below)                             | _none_            |
 | `release-commit-message` / `PYTHON_RELEASE_COMMIT_MESSAGE`| The Git commit message to use on the release commit. This is templated using the [Python Format String Syntax](http://docs.python.org/2/library/string.html#format-string-syntax). Available in the template context are current_version and new_version. | `chore(python-release): {current_version} → {new_version}` |
+
+When `py-release` job is enabled, `py-publish` job is automatically enabled too.
+
+### `py-publish` job
+
+This job is **disabled by default** and allow to publish the built packages to a PyPI compatible repository ([GitLab packages](https://docs.gitlab.com/ee/user/packages/pypi_repository/) by default.
+
+The Python template supports three packaging systems:
+
+* [Poetry](https://python-poetry.org/): uses Poetry-specific [version](https://python-poetry.org/docs/cli/#version), [build](https://python-poetry.org/docs/cli/#build) and [publish](https://python-poetry.org/docs/cli/#publish) commands.
+* [uv](https://docs.astral.sh/uv/): uses [uv](https://docs.astral.sh/uv/) as version management, [build](https://docs.astral.sh/uv/guides/publish/#building-your-package) as package builder and [publish](https://docs.astral.sh/uv/guides/publish/) to publish.
+* [Setuptools](https://setuptools.pypa.io/): uses [bump-my-version](https://github.com/callowayproject/bump-my-version) as version management, [build](https://pypa-build.readthedocs.io/) as package builder and [Twine](https://twine.readthedocs.io/) to publish.
+
+The publish job is bound to the `publish` stage, is executed on a Git tag matching [semantic versioning pattern](https://semver.org/) and uses the following variables:
+
+| Input / Variable        | Description                                                             | Default value     |
+| ----------------------- | ----------------------------------------------------------------------- | ----------------- |
+| `publish-enabled` / `PYTHON_PUBLISH_ENABLED`| Set to `true` to enable the publish job                                 | _none_ (disabled) |
 | `repository-url` / `PYTHON_REPOSITORY_URL`| Target PyPI repository to publish packages                              | _[GitLab project's PyPI packages repository](https://docs.gitlab.com/ee/user/packages/pypi_repository/)_ |
 | `PYTHON_REPOSITORY_USERNAME`| Target PyPI repository username credential                              | `gitlab-ci-token` |
 | :lock: `PYTHON_REPOSITORY_PASSWORD`| Target PyPI repository password credential                              | `$CI_JOB_TOKEN` |
 | `py-release-job-tags` / `PY_RELEASE_JOB_TAGS` | Tags to be used for selecting runners for the job | `[]`            |
 
+
 #### Setuptools tip
 
 If you're using a  Setuptools configuration, then you will have to write a `.bumpversion.toml` or `pyproject.toml` file.
@@ -512,10 +554,12 @@ In order to be able to communicate with the Vault server, the variant requires t
 | Input / Variable  | Description                            | Default value     |
 | ----------------- | -------------------------------------- | ----------------- |
 | `TBC_VAULT_IMAGE` | The [Vault Secrets Provider](https://gitlab.com/to-be-continuous/tools/vault-secrets-provider) image to use (can be overridden) | `registry.gitlab.com/to-be-continuous/tools/vault-secrets-provider:latest` |
-| `vault-base-url` / `VAULT_BASE_URL`  | The Vault server base API url          | _none_ |
+| `vault-base-url` / `VAULT_BASE_URL`  | The Vault server base API url          | **must be defined** |
 | `vault-oidc-aud` / `VAULT_OIDC_AUD`  | The `aud` claim for the JWT | `$CI_SERVER_URL` |
-| :lock: `VAULT_ROLE_ID`   | The [AppRole](https://www.vaultproject.io/docs/auth/approle) RoleID | **must be defined** |
-| :lock: `VAULT_SECRET_ID` | The [AppRole](https://www.vaultproject.io/docs/auth/approle) SecretID | **must be defined** |
+| :lock: `VAULT_ROLE_ID`   | The [AppRole](https://www.vaultproject.io/docs/auth/approle) RoleID | _none_ |
+| :lock: `VAULT_SECRET_ID` | The [AppRole](https://www.vaultproject.io/docs/auth/approle) SecretID | _none_ |
+
+By default, the variant will authentifacte using a [JWT ID token](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html). To use [AppRole](https://www.vaultproject.io/docs/auth/approle) instead the `VAULT_ROLE_ID` and `VAULT_SECRET_ID` should be defined as secret project variables.
 
 #### Usage
 
@@ -537,9 +581,9 @@ With:
 ```yaml
 include:
   # main component
-  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.0.2
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.7.1
   # Vault variant
-  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python-vault@7.0.2
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python-vault@7.7.1
     inputs:
       vault-base-url: "https://vault.acme.host/v1"
       # audience claim for JWT
@@ -550,12 +594,11 @@ variables:
     GIT_PASSWORD: "@url@http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/git/semantic-release?field=group-access-token"
     GIT_PRIVATE_KEY: "@url@http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/git/semantic-release?field=private-key"
     PYTHON_REPOSITORY_PASSWORD: "@url@http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/pip-repo/repository?field=password"
-    # $VAULT_ROLE_ID and $VAULT_SECRET_ID defined as a secret CI/CD variable
 ```
 
 ### Google Cloud variant
 
-This variant allows to use Python Google Clients. The variant follow the recommendation [Authenticate for using client libraries](https://cloud.google.com/docs/authentication/client-libraries) with [ADC](https://cloud.google.com/docs/authentication/application-default-credentials) 
+This variant allows to use Python Google Clients. The variant follow the recommendation [Authenticate for using client libraries](https://cloud.google.com/docs/authentication/client-libraries) with [ADC](https://cloud.google.com/docs/authentication/application-default-credentials)
 
 [Detailed article on internal OIDC impersonated with Workload Identify Federation](https://blog.salrashid.dev/articles/2021/understanding_workload_identity_federation/#oidc-impersonated)
 
@@ -579,15 +622,84 @@ The variant requires the additional configuration parameters:
 
 ```yaml
 include:
-  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.0.2
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.7.1
     # 2: set/override component inputs
     inputs:
       image: registry.hub.docker.com/library/python:3.12-slim
       pytest-enabled: true
 
-  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python-gcp@7.0.2
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python-gcp@7.7.1
     inputs:
       # common OIDC config for non-prod envs
       gcp-oidc-provider: "projects/<gcp_nonprod_proj_id>/locations/global/workloadIdentityPools/<pool_id>/providers/<provider_id>"
       gcp-oidc-account: "<name>@$<gcp_nonprod_proj_id>.iam.gserviceaccount.com"
 ```
+
+### AWS CodeArtifact variant
+
+This variant allows to use PyPi packages from AWS CodeArtifact. The variant follow the recommendation [Authenticate for using client libraries](https://docs.aws.amazon.com/codeartifact/latest/ug/python-configure.html) 
+
+It authenticates with AWS CodeArtifact, retrieves and sets the following environment variable:
+
+- `CODEARTIFACT_AUTH_TOKEN` - the AWS CodeArtifact authentication token
+- `CODEARTIFACT_REPOSITORY_ENDPOINT` - the AWS CodeArtifact repository endpoint
+- `CODEARTIFACT_URL` - Formatted URL for the AWS CodeArtifact repository
+
+Most importantly, the variant sets the `pip global.index-url` to the CodeArtifact url.
+
+The variant supports two authentication methods:
+
+1. [federated authentication using OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/aws/) (**recommended method**),
+2. or basic authentication with AWS access key ID & secret access key.
+
+:warning: when using this variant, you must have created the CodeArtifact repository.
+
+#### Configuration
+
+The variant *requires* the additional configuration parameters:
+
+| Input / Variable                              | Description                                                                                                           | Default value                                                         |
+| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
+| `TBC_AWS_PROVIDER_IMAGE`                      | The [AWS Auth Provider](https://gitlab.com/to-be-continuous/tools/aws-auth-provider) image to use (can be overridden) | `registry.gitlab.com/to-be-continuous/tools/aws-auth-provider:latest` |
+| `aws-region` / `AWS_REGION`                   | Default region (where the Codeartifact repository is located)                                                         | _none_                                                                |
+| `aws-codeartifact-domain` / `AWS_CODEARTIFACT_DOMAIN` | The CodeArtifact domain name                                                                                       | _none_                                                                |
+| `aws-codeartifact-domain-owner` / `AWS_CODEARTIFACT_DOMAIN_OWNER` | The CodeArtifact domain owner account ID                                                                      | _none_                                                                |
+| `aws-codeartifact-repository` / `AWS_CODEARTIFACT_REPOSITORY` | The CodeArtifact repository name                                                                                 | _none_                                                                |
+
+##### OIDC authentication config
+
+This is the recommended authentication method. In order to use it, first carefuly follow [GitLab's documentation](https://docs.gitlab.com/ee/ci/cloud_services/aws/),
+then set the required configuration.
+
+| Input / Variable                                            | Description                                                                                    | Default value    |
+| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------- |
+| `aws-oidc-aud` / `AWS_OIDC_AUD`                             | The `aud` claim for the JWT token                                                              | `$CI_SERVER_URL` |
+| `aws-oidc-role-arn` / `AWS_OIDC_ROLE_ARN`                   | Default IAM Role ARN associated with GitLab                                                    | _none_           |
+
+##### Basic authentication config
+
+| Variable                                | Description                                                                  | Default value     |
+| --------------------------------------- | ---------------------------------------------------------------------------- | ----------------- |
+| :lock: `AWS_ACCESS_KEY_ID`              | Default access key ID                                                        | _none_ (disabled) |
+| :lock: `AWS_SECRET_ACCESS_KEY`          | Default secret access key                                                    | _none_ (disabled) |
+
+
+#### Example
+
+```yaml
+include:
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.7.1
+    # 2: set/override component inputs
+    inputs:
+      image: registry.hub.docker.com/library/python:3.12-slim
+      pytest-enabled: true
+
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python-aws-codeartifact@7.7.1
+    inputs:
+      aws-region: "us-east-1"
+      aws-codeartifact-domain: "acme"
+      aws-codeartifact-domain-owner: "123456789012"
+      aws-codeartifact-repository: "my-repo"
+      # common OIDC config for non-prod envs
+      aws-oidc-role-arn: "arn:aws:iam::123456789012:role/gitlab-ci"
+```
\ No newline at end of file
diff --git a/bumpversion.sh b/bumpversion.sh
index 329e866dac988c049574a0a9f26ba89979c523a8..708faf434d2459d63b2bdaceada5eb32b0fd39eb 100755
--- a/bumpversion.sh
+++ b/bumpversion.sh
@@ -27,7 +27,7 @@ if [[ "$curVer" ]]; then
   log_info "Bump version from \\e[33;1m${curVer}\\e[0m to \\e[33;1m${nextVer}\\e[0m (release type: $relType)..."
 
   # replace in README
-  sed -e "s/ref: *'$curVer'/ref: '$nextVer'/" -e "s/ref: *\"$curVer\”/ref: \”$nextVer\”/" -e "s/component: *\(.*\)@$curVer/component: \1@$nextVer/" README.md > README.md.next
+  sed -e "s/ref: *'$curVer'/ref: '$nextVer'/" -e "s/ref: *\"$curVer\"/ref: \"$nextVer\"/" -e "s/component: *\(.*\)@$curVer/component: \1@$nextVer/" README.md > README.md.next
   mv -f README.md.next README.md
 
   # replace in template and variants
diff --git a/kicker.json b/kicker.json
index 21f7e470f6c038d696697c5b1c75838f9f0c97b3..5cbcf8f5dad02b7326364dc34afe6d07e50da0ce 100644
--- a/kicker.json
+++ b/kicker.json
@@ -21,7 +21,7 @@
       "name": "PYTHON_BUILD_SYSTEM",
       "description": "Python build-system to use to install dependencies, build and package the project",
       "type": "enum",
-      "values": ["auto", "setuptools", "poetry", "pipenv", "reqfile"],
+      "values": ["auto", "setuptools", "poetry", "pipenv", "reqfile", "uv"],
       "default": "auto",
       "advanced": true
     },
@@ -83,6 +83,12 @@
         }
       ]
     },
+    {
+      "id":"publish",
+      "name":"publish",
+      "description":"This job allows publishing the built packages to a PyPI compatible repository ([GitLab packages](https://docs.gitlab.com/ee/user/packages/pypi_repository/) by default.",
+      "enable_with": "PYTHON_PUBLISH_ENABLED"
+    },    
     {
       "id": "pylint",
       "name": "pylint",
@@ -192,7 +198,7 @@
     {
       "id": "trivy",
       "name": "Trivy",
-      "description": "Detect security vulnerabilities with [Trivy](https://github.com/aquasecurity/trivy/) (dependencies analysis)",
+      "description": "Detect security vulnerabilities with [Trivy](https://aquasecurity.github.io/trivy) (dependencies analysis)",
       "disable_with": "PYTHON_TRIVY_DISABLED",
       "variables": [
         {
@@ -202,8 +208,8 @@
         },
         {
           "name": "PYTHON_TRIVY_ARGS",
-          "description": "Additional [Trivy CLI options](https://aquasecurity.github.io/trivy/v0.21.1/getting-started/cli/fs/)",
-          "default": "--vuln-type library",
+          "description": "Additional [Trivy CLI options](https://aquasecurity.github.io/trivy/latest/docs/references/configuration/cli/trivy_filesystem/)",
+          "default": "--ignore-unfixed --pkg-types library --detection-priority comprehensive",
           "advanced": true
         },
         {
@@ -253,6 +259,12 @@
       "description": "Manually trigger a release of your code (uses [bumpversion](https://pypi.org/project/bumpversion/))",
       "enable_with": "PYTHON_RELEASE_ENABLED",
       "variables": [
+        {
+          "name": "PYTHON_AUTO_RELEASE_ENABLED",
+          "description": "When set the job start automatically. When not set (default), the job is manual. Note that this behavior also depends on release-enabled being set.",
+          "type": "boolean",
+          "advanced": true
+        },        
         {
           "name": "PYTHON_RELEASE_NEXT",
           "type": "enum",
@@ -375,6 +387,14 @@
         }
       ]
     },
+    {
+      "id": "ruff-format",
+      "name": "Ruff Format",
+      "description": "An extremely fast Python linter and code formatter, written in Rust. [Ruff](https://docs.astral.sh/ruff/)",
+      "enable_with": "RUFF_FORMAT_ENABLED",
+      "variables": [
+      ]
+    },
     {
       "id": "mypy",
       "name": "mypy",
@@ -459,6 +479,61 @@
           "description": "Default Workload Identity Provider associated with GitLab to [authenticate with OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/google_cloud/)"
         }
       ]
+    },
+    {
+      "id": "aws-codeartifact",
+      "name": "AWS CodeArtifact",
+      "description": "Retrieves AWS CodeArtifact credentials",
+      "template_path": "templates/gitlab-ci-python-aws-codeartifact.yml",
+      "variables": [
+        {
+          "name": "TBC_AWS_PROVIDER_IMAGE",
+          "description": "The [AWS Auth Provider](https://gitlab.com/to-be-continuous/tools/aws-auth-provider) image to use",
+          "default": "registry.gitlab.com/to-be-continuous/tools/aws-auth-provider:latest",
+          "advanced": true
+        },
+        {
+          "name": "AWS_REGION",
+          "description": "Default region (where the codeartifact repository is located)"
+        },
+        {
+          "name": "AWS_OIDC_AUD",
+          "description": "The `aud` claim for the JWT token _(only required for [OIDC authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_",
+          "default": "$CI_SERVER_URL",
+          "advanced": true
+        },
+        {
+          "name": "AWS_OIDC_ROLE_ARN",
+          "description": "Default IAM Role ARN associated with GitLab _(only required for [OIDC authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_"
+        },
+        {
+          "name": "AWS_ACCESS_KEY_ID",
+          "description": "Default access key ID (only required for basic authentication)",
+          "secret": true,
+          "advanced": true
+        },
+        {
+          "name": "AWS_SECRET_ACCESS_KEY",
+          "description": "Default secret access key (only required for basic authentication)",
+          "secret": true,
+          "advanced": true
+        },
+        {
+          "name": "AWS_CODEARTIFACT_DOMAIN",
+          "description": "The AWS CodeArtifact domain",
+          "mandatory": true
+        },
+        {
+          "name": "AWS_CODEARTIFACT_DOMAIN_OWNER",
+          "description": "The AWS CodeArtifact domain owner",
+          "mandatory": true
+        },
+        {
+          "name": "AWS_CODEARTIFACT_REPOSITORY",
+          "description": "The AWS CodeArtifact repository",
+          "mandatory": true
+        }
+      ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/templates/gitlab-ci-python-aws-codeartifact.yml b/templates/gitlab-ci-python-aws-codeartifact.yml
new file mode 100644
index 0000000000000000000000000000000000000000..60baea0c05de835f801a4090f0b0db3977dc2641
--- /dev/null
+++ b/templates/gitlab-ci-python-aws-codeartifact.yml
@@ -0,0 +1,61 @@
+# =====================================================================================================================
+# === AWS CodeArtifact Auth template variant
+# =====================================================================================================================
+spec:
+  inputs:
+    aws-codeartifact-domain:
+      description: AWS CodeArtifact domain name
+      default: ''
+    aws-codeartifact-domain-owner:
+      description: AWS CodeArtifact domain owner account ID
+      default: ''
+    aws-codeartifact-repository:
+      description: AWS CodeArtifact repository name
+      default: ''
+    aws-region:
+      description: Default region (where the Codeartifact registry is located)
+      default: ''
+    aws-oidc-aud:
+      description: The `aud` claim for the JWT token _(only required for [OIDC authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_
+      default: $CI_SERVER_URL
+    aws-oidc-role-arn:
+      description: Default IAM Role ARN associated with GitLab _(only required for [OIDC
+        authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_
+      default: ''
+---
+variables:
+  TBC_AWS_PROVIDER_IMAGE: registry.gitlab.com/to-be-continuous/tools/aws-auth-provider:latest
+  AWS_OIDC_AUD: $[[ inputs.aws-oidc-aud ]]
+  AWS_REGION: $[[ inputs.aws-region ]]
+  AWS_OIDC_ROLE_ARN: $[[ inputs.aws-oidc-role-arn ]]
+  AWS_CODEARTIFACT_DOMAIN: $[[ inputs.aws-codeartifact-domain ]]
+  AWS_CODEARTIFACT_DOMAIN_OWNER: $[[ inputs.aws-codeartifact-domain-owner ]]
+  AWS_CODEARTIFACT_REPOSITORY: $[[ inputs.aws-codeartifact-repository ]]
+
+
+.codeartifact-pip-config:
+  before_script:
+    - CODEARTIFACT_URL=https://aws:${PYTHON_REPOSITORY_PASSWORD}@${PYTHON_REPOSITORY_URL#https://}simple
+    - pip config set global.index-url $CODEARTIFACT_URL
+
+.python-base:
+  services:
+    - name: "$TBC_TRACKING_IMAGE"
+      command: ["--service", "python", "7.3.0"]
+    - name: "$TBC_AWS_PROVIDER_IMAGE"
+      alias: "aws-auth-provider"
+  id_tokens:
+    # required for OIDC auth
+    AWS_JWT:
+      aud: "$AWS_OIDC_AUD"
+  variables:
+    PYTHON_REPOSITORY_USERNAME: aws
+    PYTHON_REPOSITORY_PASSWORD: "@url@http://aws-auth-provider/codeartifact/auth/token"
+    PYTHON_REPOSITORY_URL: "@url@http://aws-auth-provider/codeartifact/repository/endpoint?format=pypi"
+    AWS_JWT: "$AWS_JWT"
+  before_script:
+    - !reference [.python-scripts]
+    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
+    - cd ${PYTHON_PROJECT_DIR}
+    - guess_build_system
+    - !reference [.codeartifact-pip-config, before_script]
diff --git a/templates/gitlab-ci-python-gcp.yml b/templates/gitlab-ci-python-gcp.yml
index f39d794c55f45d2c7edd5dba586666cc853483db..b93ad6a4db137b134a74d07fb3d3daa5da704d1a 100644
--- a/templates/gitlab-ci-python-gcp.yml
+++ b/templates/gitlab-ci-python-gcp.yml
@@ -44,7 +44,7 @@ variables:
   image: $PYTHON_IMAGE
   services:
     - name: "$TBC_TRACKING_IMAGE"
-      command: ["--service", "python", "7.0.2"]
+      command: ["--service", "python", "7.7.1"]
   variables:
     GCP_JWT: $GCP_JWT
   before_script:
diff --git a/templates/gitlab-ci-python-vault.yml b/templates/gitlab-ci-python-vault.yml
index 41370aace3fec112bfec7b8bc800570041a5f1de..349cd49e0b53812b4d4e94f585e2cc03942e38d0 100644
--- a/templates/gitlab-ci-python-vault.yml
+++ b/templates/gitlab-ci-python-vault.yml
@@ -22,7 +22,7 @@ variables:
 .python-base:
   services:
     - name: "$TBC_TRACKING_IMAGE"
-      command: ["--service", "python", "7.0.2"]
+      command: ["--service", "python", "7.7.1"]
     - name: "$TBC_VAULT_IMAGE"
       alias: "vault-secrets-provider"
   variables:
diff --git a/templates/gitlab-ci-python.yml b/templates/gitlab-ci-python.yml
index 1376a989395d2cee17ada305fd3c7178ea8735f3..2ccfa2773350027f5bb06ab0cc54ce54f3b632ff 100644
--- a/templates/gitlab-ci-python.yml
+++ b/templates/gitlab-ci-python.yml
@@ -29,6 +29,7 @@ spec:
       - poetry
       - pipenv
       - reqfile
+      - uv
       default: auto
     reqs-file:
       description: |-
@@ -107,8 +108,8 @@ spec:
         _When unset, the latest version will be used_
       default: ''
     trivy-args:
-      description: Additional [Trivy CLI options](https://aquasecurity.github.io/trivy/v0.21.1/getting-started/cli/fs/)
-      default: --vuln-type library
+      description: Additional [Trivy CLI options](https://aquasecurity.github.io/trivy/latest/docs/references/configuration/cli/trivy_filesystem/)
+      default: --ignore-unfixed --pkg-types library --detection-priority comprehensive
     sbom-disabled:
       description: Disable Software Bill of Materials
       type: boolean
@@ -129,6 +130,14 @@ spec:
       description: Enable Release
       type: boolean
       default: false
+    auto-release-enabled:
+      description: When set the job start automatically on production branch. When not set (default), the job is manual. Note that this behavior also depends on release-enabled being set.
+      type: boolean
+      default: false
+    publish-enabled:
+      description: Enable Publish Package
+      type: boolean
+      default: false    
     release-next:
       description: 'The part of the version to increase (one of: `major`, `minor`, `patch`)'
       options:
@@ -165,9 +174,10 @@ spec:
     ruff-args:
       description: Additional [Ruff Linter CLI options](https://docs.astral.sh/ruff/configuration/#full-command-line-interface)
       default: ""
-    ruff-ext-exclude:
-      description: Define [extend-exclude](https://docs.astral.sh/ruff/settings/#extend-exclude) files
-      default: ""
+    ruff-format-enabled:
+      description: Enable Ruff
+      type: boolean
+      default: false
     mypy-enabled:
       description: Enable mypy
       type: boolean
@@ -301,7 +311,7 @@ variables:
   # default integration ref name (pattern)
   INTEG_REF: '/^develop$/'
   # default release tag name (pattern)
-  RELEASE_REF: '/^v?[0-9]+\.[0-9]+\.[0-9]+$/'
+  RELEASE_REF: '/^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9-\.]+)?(\+[a-zA-Z0-9-\.]+)?$/'
 
   # compileall
   PYTHON_COMPILE_ARGS: $[[ inputs.compile-args ]]
@@ -346,12 +356,14 @@ variables:
   BANDIT_ENABLED: $[[ inputs.bandit-enabled ]]
   PYTHON_SBOM_DISABLED: $[[ inputs.sbom-disabled ]]
   PYTHON_RELEASE_ENABLED: $[[ inputs.release-enabled ]]
+  PYTHON_PUBLISH_ENABLED: $[[ inputs.publish-enabled ]]
+  PYTHON_AUTO_RELEASE_ENABLED: $[[ inputs.auto-release-enabled ]]
 
   PYTHON_BLACK_ENABLED: $[[ inputs.black-enabled ]]
   PYTHON_ISORT_ENABLED: $[[ inputs.isort-enabled ]]
   RUFF_ENABLED: $[[ inputs.ruff-enabled ]]
   RUFF_ARGS: $[[ inputs.ruff-args ]]
-  RUFF_EXT_EXCLUDE: $[[ inputs.ruff-ext-exclude ]]
+  RUFF_FORMAT_ENABLED: $[[ inputs.ruff-format-enabled ]]
   MYPY_ENABLED: $[[ inputs.mypy-enabled ]]
   MYPY_ARGS: $[[ inputs.mypy-args ]]
   MYPY_FILES: $[[ inputs.mypy-files ]]
@@ -582,9 +594,9 @@ variables:
         decoded=$(mktemp)
         errors=$(mktemp)
         # shellcheck disable=SC2086
-        if python3 -c "import urllib.request ; urllib.request.urlretrieve(\"$url\",\"${decoded}\")" > "${errors}" 2>&1 
+        if python3 -c "import urllib.request ; urllib.request.urlretrieve(\"$url\",\"${decoded}\")" > "${errors}" 2>&1
         then
-          export ${name}="$(cat ${decoded})" 
+          export ${name}="$(cat ${decoded})"
           log_info "Successfully fetched secret \\e[33;1m${name}\\e[0m"
         else
           log_warn "Failed getting secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")"
@@ -630,7 +642,7 @@ variables:
     case "${PYTHON_BUILD_SYSTEM:-auto}" in
     auto)
       ;;
-    poetry*|setuptools*|pipenv*)
+    poetry*|setuptools*|pipenv*|uv*)
       log_info "--- Build system explicitly declared: ${PYTHON_BUILD_SYSTEM}"
       return
       ;;
@@ -649,6 +661,17 @@ variables:
       export PYTHON_BUILD_SYSTEM="reqfile"
       return
     fi
+  
+    if [[ -f "uv.lock" ]]
+    then
+      if [[ -f "pyproject.toml" ]]
+      then
+        log_info "--- Build system auto-detected: uv (uv.lock and pyproject.toml)"
+        export PYTHON_BUILD_SYSTEM="uv"
+        return
+      fi
+      log_error "--- Build system auto-detected: uv (uv.lock) but no pyproject.toml found: please read template doc"
+    fi
 
     if [[ -f "pyproject.toml" ]]
     then
@@ -691,7 +714,14 @@ variables:
   }
 
   function maybe_install_poetry() {
-    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^poetry.* ]] && ! command -v poetry > /dev/null
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^poetry ]] && ! command -v poetry > /dev/null
+    then
+      # shellcheck disable=SC2086
+      pip install ${PIP_OPTS} "$PYTHON_BUILD_SYSTEM"
+    fi
+  }
+  function maybe_install_uv() {
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^uv ]] && ! command -v uv > /dev/null
     then
       # shellcheck disable=SC2086
       pip install ${PIP_OPTS} "$PYTHON_BUILD_SYSTEM"
@@ -741,14 +771,25 @@ variables:
         log_warn "--- requirements build system defined, but no ${PYTHON_REQS_FILE} file found"
       fi
       ;;
+    uv*)
+      if  [[ ! -f "uv.lock" ]]; then
+        log_warn "Using uv but \\e[33;1muv.lock\\e[0m file not found: you shall commit it with your project files"
+      fi
+      maybe_install_uv
+      uv sync --frozen ${PYTHON_EXTRA_DEPS:+--extra "$PYTHON_EXTRA_DEPS"}
+      ;;
     esac
   }
 
   function _run() {
-    if [[ "$PYTHON_BUILD_SYSTEM" == poetry* ]]
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^poetry ]]
     then
       maybe_install_poetry
       poetry run "$@"
+    elif [[ "$PYTHON_BUILD_SYSTEM" =~ ^uv ]]
+    then
+      maybe_install_uv
+      uv run "$@"
     else
       "$@"
     fi
@@ -759,15 +800,26 @@ variables:
   }
 
   function _pip() {
-    # shellcheck disable=SC2086
-    _run pip ${PIP_OPTS} "$@"
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^uv ]]
+    then
+      maybe_install_uv
+      # shellcheck disable=SC2086
+      uv pip ${PIP_OPTS} "$@"
+    else
+      # shellcheck disable=SC2086
+      _run pip ${PIP_OPTS} "$@"
+    fi
   }
 
   function py_package() {
-    if [[ "$PYTHON_BUILD_SYSTEM" == poetry* ]]
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^poetry ]]
     then
       maybe_install_poetry
       poetry build
+    elif [[ "$PYTHON_BUILD_SYSTEM" =~ ^uv ]]
+    then
+      maybe_install_uv
+      uv build
     else
       # shellcheck disable=SC2086
       pip install ${PIP_OPTS} build
@@ -815,7 +867,7 @@ variables:
     fi
 
     # 2: bump-my-version (+ Git commit & tag)
-    if [[ "$PYTHON_BUILD_SYSTEM" == poetry* ]]
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^poetry ]]
     then
       maybe_install_poetry
       if [[ -z "$py_next_version" ]]
@@ -833,6 +885,33 @@ variables:
       py_commit_message=$(python -c "print('$PYTHON_RELEASE_COMMIT_MESSAGE'.format(current_version='$py_cur_version', new_version='$py_next_version'))")
       git commit -m "$py_commit_message"
       git tag "$py_next_version"
+    elif [[ "$PYTHON_BUILD_SYSTEM" =~ ^uv ]]
+    then
+      maybe_install_uv
+      if [[ -z "$py_next_version" ]]
+      then
+        # quick version waiting for uv to manage bump
+        # related uv MR https://github.com/astral-sh/uv/pull/7248#issuecomment-2395465334 
+        mkdir -p -m 777 tbc_tmp
+        uvx --from toml-cli toml get --toml-path pyproject.toml project.version > tbc_tmp/version.txt
+        py_cur_version=$(cat tbc_tmp/version.txt)
+
+        py_release_part="$PYTHON_RELEASE_NEXT"
+        log_info "[bump-my-version] increase \\e[1;94m${py_release_part}\\e[0m (from current \\e[1;94m${py_cur_version}\\e[0m)"
+        uvx bump-my-version bump ${TRACE+--verbose} --current-version "$py_cur_version" "$py_release_part" tbc_tmp/version.txt
+        py_next_version=$(cat tbc_tmp/version.txt)
+        rm -fr tbc_tmp/version.txt
+      fi
+
+      log_info "[uv] change version \\e[1;94m${py_cur_version}\\e[0m → \\e[1;94m${py_next_version}\\e[0m"
+      uvx --from toml-cli toml set --toml-path pyproject.toml project.version "$py_next_version"
+
+      # Git commit and tag
+      git add pyproject.toml
+      # emulate bump-my-version to generate commit message
+      py_commit_message=$(python -c "print('$PYTHON_RELEASE_COMMIT_MESSAGE'.format(current_version='$py_cur_version', new_version='$py_next_version'))")
+      git commit -m "$py_commit_message"
+      git tag --force "$py_next_version"
     else
       # Setuptools / bump-my-version
       # shellcheck disable=SC2086
@@ -873,10 +952,10 @@ variables:
   }
 
   function py_publish() {
-    if [[ "$PYTHON_BUILD_SYSTEM" == poetry* ]]
+    if [[ "$PYTHON_BUILD_SYSTEM" =~ ^poetry ]]
     then
       maybe_install_poetry
- 
+
       if [[ "$PYTHON_PACKAGE_ENABLED" != "true" ]]
       then
         log_info "--- build packages (poetry)..."
@@ -886,10 +965,22 @@ variables:
       log_info "--- publish packages (poetry) to $PYTHON_REPOSITORY_URL with user $PYTHON_REPOSITORY_USERNAME..."
       poetry config repositories.user_defined "$PYTHON_REPOSITORY_URL"
       poetry publish ${TRACE+--verbose} --username "$PYTHON_REPOSITORY_USERNAME" --password "$PYTHON_REPOSITORY_PASSWORD" --repository user_defined
+    elif [[ "$PYTHON_BUILD_SYSTEM" =~ ^uv ]]
+    then
+      maybe_install_uv
+  
+      if [[ "$PYTHON_PACKAGE_ENABLED" != "true" ]]
+      then
+        log_info "--- build packages (uv)..."
+        uv build ${TRACE+--verbose}
+      fi
+
+      log_info "--- publish packages (uv) to $PYTHON_REPOSITORY_URL with user $PYTHON_REPOSITORY_USERNAME..."
+      uv publish ${TRACE+--verbose} --username "$PYTHON_REPOSITORY_USERNAME" --password "$PYTHON_REPOSITORY_PASSWORD" --publish-url "$PYTHON_REPOSITORY_URL"
     else
       # shellcheck disable=SC2086
       pip install ${PIP_OPTS} build twine
- 
+
       if [[ "$PYTHON_PACKAGE_ENABLED" != "true" ]]
       then
         log_info "--- build packages (build)..."
@@ -935,19 +1026,20 @@ stages:
   - production
 
 ###############################################################################################
-#                                      Generic python job                                     #
+#                                      Generic python jobs                                    #
 ###############################################################################################
 .python-base:
   image: $PYTHON_IMAGE
   services:
     - name: "$TBC_TRACKING_IMAGE"
-      command: ["--service", "python", "7.0.2"]
+      command: ["--service", "python", "7.7.1"]
   variables:
     # set local cache dir; most Python tools honour XDG specs
     XDG_CACHE_HOME: "$CI_PROJECT_DIR/.cache"
     PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
     POETRY_CACHE_DIR: "$CI_PROJECT_DIR/.cache/poetry"
     PIPENV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pipenv"
+    UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"
     POETRY_VIRTUALENVS_IN_PROJECT: "false"
   cache:
     key: "$CI_COMMIT_REF_SLUG-python"
@@ -960,6 +1052,24 @@ stages:
     - cd ${PYTHON_PROJECT_DIR}
     - guess_build_system
 
+.python-test:
+  extends: .python-base
+  stage: build
+  coverage: /^TOTAL.+?(\d+(?:\.\d+)?\%)$/
+  artifacts:
+    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
+    expire_in: 1 day
+    when: always
+    reports:
+      junit:
+        - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
+      coverage_report:
+        coverage_format: cobertura
+        path: "$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml"
+    paths:
+      - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
+      - "$PYTHON_PROJECT_DIR/reports/py-coverage.*"
+
 ###############################################################################################
 #                                      build stage                                             #
 ###############################################################################################
@@ -985,7 +1095,7 @@ py-lint:
     - install_requirements
     - _pip install pylint_gitlab # codeclimate reports
     # run pylint and generate reports all at once
-    - _run pylint --ignore=.cache --output-format=colorized,pylint_gitlab.GitlabCodeClimateReporter:reports/py-lint.codeclimate.json,parseable:reports/py-lint.parseable.txt ${PYLINT_ARGS} ${PYLINT_FILES:-$(find -type f -name "*.py")}
+    - _run pylint --output-format=colorized,pylint_gitlab.GitlabCodeClimateReporter:reports/py-lint.codeclimate.json,parseable:reports/py-lint.parseable.txt ${PYLINT_ARGS} ${PYLINT_FILES:-$(find -type f -name "*.py" -not -path "./.cache/*")}
   artifacts:
     name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
     expire_in: 1 day
@@ -1020,7 +1130,7 @@ py-black:
   script:
     - install_requirements
     - _pip install black
-    - _run black . --check
+    - _run black . --check --extend-exclude '(\/\.cache\/|\/\.venv\/)'
   rules:
     # exclude if $PYTHON_BLACK_ENABLED not set
     - if: '$PYTHON_BLACK_ENABLED != "true"'
@@ -1034,7 +1144,7 @@ py-isort:
   script:
     - install_requirements
     - _pip install isort
-    - _run isort . --check-only
+    - _run isort . --check-only --extend-skip .cache --extend-skip .venv
   rules:
     # exclude if $PYTHON_ISORT_ENABLED not set
     - if: '$PYTHON_ISORT_ENABLED != "true"'
@@ -1047,9 +1157,9 @@ py-ruff:
   stage: build
   script:
     - mkdir -p -m 777 reports
-    - |  
-      if [[  ${BANDIT_ENABLED} == "true" || ${PYLINT_ENABLED} == "true" || ${PYTHON_ISORT_ENABLED} == "true" || ${PYTHON_BLACK_ENABLED} == "true" ]]; then
-        log_warn "Ruff can replace isort, Black, Bandit, Pylint"
+    - |
+      if [[ ${BANDIT_ENABLED} == "true" || ${PYLINT_ENABLED} == "true" || ${PYTHON_ISORT_ENABLED} == "true" ]]; then
+        log_warn "Ruff can replace isort, Bandit, Pylint"
       fi
     # Ruff is self dependent tool (written in Rust), it can be installed without project dependencies (_pip and _run don't look required here)
     - pip install ${PIP_OPTS} ruff
@@ -1057,10 +1167,10 @@ py-ruff:
     - |
       if [[ "$SONAR_HOST_URL" ]]
       then
-        ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --exit-zero --output-format json --output-file reports/py-ruff.native.json
+        ruff check . ${RUFF_ARGS} --extend-exclude .venv,.cache --exit-zero --output-format json --output-file reports/py-ruff.native.json
       fi
     # then GitLab and grouped/console formats
-    - ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --output-format gitlab --output-file reports/py-ruff.gitlab.json || ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --output-format grouped 
+    - ruff check . ${RUFF_ARGS} --extend-exclude .venv,.cache --output-format gitlab --output-file reports/py-ruff.gitlab.json || ruff check . ${RUFF_ARGS} --extend-exclude .venv,.cache --output-format grouped
   artifacts:
     name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
     expire_in: 1 day
@@ -1076,6 +1186,23 @@ py-ruff:
     - !reference [.test-policy, rules]
   tags: $[[ inputs.py-ruff-job-tags ]]
 
+py-ruff-format:
+  extends: .python-base
+  stage: build
+  script:
+    - |
+      if [[ ${PYTHON_BLACK_ENABLED} == "true" ]]; then
+        log_warn "Ruff can replace Black"
+      fi
+    # Ruff is self dependent tool (written in Rust), it can be installed without project dependencies (_pip and _run don't look required here)
+    - pip install ${PIP_OPTS} ruff
+    - ruff format --check . --exclude .venv,.cache
+  rules:
+    # exclude if $RUFF_FORMAT_ENABLED not set
+    - if: '$RUFF_FORMAT_ENABLED != "true"'
+      when: never
+    - !reference [.test-policy, rules]
+
 py-mypy:
   extends: .python-base
   stage: build
@@ -1085,7 +1212,7 @@ py-mypy:
     - mkdir -p -m 777 reports
     - install_requirements
     - _pip install mypy mypy-to-codeclimate
-    - _run mypy ${MYPY_ARGS} ${MYPY_FILES:-$(find -type f -name "*.py" -not -path "./.cache/*")} | tee reports/py-mypy.console.txt || true
+    - _run mypy ${MYPY_ARGS} ${MYPY_FILES:-$(find -type f -name "*.py" -not -path "./.cache/*" -not -path "./.venv/*")} | tee reports/py-mypy.console.txt || true
     # mypy-to-codeclimate will fail if any error was found
     - _run mypy-to-codeclimate reports/py-mypy.console.txt reports/py-mypy.codeclimate.json
   artifacts:
@@ -1107,8 +1234,7 @@ py-mypy:
 #                                      test stage                                             #
 ###############################################################################################
 py-unittest:
-  extends: .python-base
-  stage: build
+  extends: .python-test
   script:
     - mkdir -p -m 777 reports
     - install_requirements
@@ -1119,20 +1245,6 @@ py-unittest:
     - _run coverage run -m xmlrunner discover -o "reports/" $UNITTEST_ARGS
     - _run coverage report -m
     - _run coverage xml -o "reports/py-coverage.cobertura.xml"
-  coverage: /^TOTAL.+?(\d+\%)$/
-  artifacts:
-    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
-    expire_in: 1 day
-    when: always
-    reports:
-      junit:
-        - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
-      coverage_report:
-        coverage_format: cobertura
-        path: "$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml"
-    paths:
-      - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
-      - "$PYTHON_PROJECT_DIR/reports/py-coverage.*"
   rules:
     # skip if $UNITTEST_ENABLED not set
     - if: '$UNITTEST_ENABLED != "true"'
@@ -1141,27 +1253,12 @@ py-unittest:
   tags: $[[ inputs.py-unittest-job-tags ]]
 
 py-pytest:
-  extends: .python-base
-  stage: build
+  extends: .python-test
   script:
     - mkdir -p -m 777 reports
     - install_requirements
     - _pip install pytest pytest-cov coverage
     - _python -m pytest --junit-xml=reports/TEST-pytests.xml --cov --cov-report term  --cov-report xml:reports/py-coverage.cobertura.xml ${PYTEST_ARGS}
-  coverage: /^TOTAL.+?(\d+\%)$/
-  artifacts:
-    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
-    expire_in: 1 day
-    when: always
-    reports:
-      junit:
-        - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
-      coverage_report:
-        coverage_format: cobertura
-        path: "$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml"
-    paths:
-      - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
-      - "$PYTHON_PROJECT_DIR/reports/py-coverage.*"
   rules:
     # skip if $PYTEST_ENABLED not set
     - if: '$PYTEST_ENABLED != "true"'
@@ -1170,26 +1267,11 @@ py-pytest:
   tags: $[[ inputs.py-pytest-job-tags ]]
 
 py-nosetests:
-  extends: .python-base
-  stage: build
+  extends: .python-test
   script:
     - mkdir -p -m 777 reports
     - install_requirements
     - _run nosetests --with-xunit --xunit-file=reports/TEST-nosetests.xml --with-coverage --cover-erase --cover-xml --cover-xml-file=reports/py-coverage.cobertura.xml ${NOSETESTS_ARGS}
-  coverage: /^TOTAL.+?(\d+\%)$/
-  artifacts:
-    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
-    expire_in: 1 day
-    when: always
-    reports:
-      junit:
-        - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
-      coverage_report:
-        coverage_format: cobertura
-        path: "$PYTHON_PROJECT_DIR/reports/py-coverage.cobertura.xml"
-    paths:
-      - "$PYTHON_PROJECT_DIR/reports/TEST-*.xml"
-      - "$PYTHON_PROJECT_DIR/reports/py-coverage.*"
   rules:
     # skip if $NOSETESTS_ENABLED not set
     - if: '$NOSETESTS_ENABLED != "true"'
@@ -1211,19 +1293,20 @@ py-bandit:
     - |
       if [[ "$SONAR_HOST_URL" ]]
       then
-        _run bandit ${TRACE+--verbose} --exit-zero --exclude ./.cache --format csv --output reports/py-bandit.bandit.csv ${BANDIT_ARGS}
+        _run bandit ${TRACE+--verbose} --exit-zero --exclude ./.cache,./.venv --format csv --output reports/py-bandit.bandit.csv ${BANDIT_ARGS}
       fi
     # JSON (for DefectDojo)
     - |
       if [[ "$DEFECTDOJO_BANDIT_REPORTS" ]]
       then
-        _run bandit ${TRACE+--verbose} --exit-zero --exclude ./.cache --format json --output reports/py-bandit.bandit.json ${BANDIT_ARGS}
+        _run bandit ${TRACE+--verbose} --exit-zero --exclude ./.cache,./.venv --format json --output reports/py-bandit.bandit.json ${BANDIT_ARGS}
       fi
-    - _run bandit ${TRACE+--verbose} --exclude ./.cache ${BANDIT_ARGS}
+    - _run bandit ${TRACE+--verbose} --exclude ./.cache,./.venv ${BANDIT_ARGS}
   artifacts:
     when: always
     name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
     expire_in: 1 day
+    access: developer
     paths:
       - "$PYTHON_PROJECT_DIR/reports/py-bandit.*"
   rules:
@@ -1241,7 +1324,6 @@ py-trivy:
   dependencies: []
   script:
     - mkdir -p -m 777 reports
-    - install_requirements
     - |
       if [[ -z "$PYTHON_TRIVY_DIST_URL" ]]
       then
@@ -1260,17 +1342,24 @@ py-trivy:
         tar zxf trivy.tar.gz trivy
         mkdir -p $XDG_CACHE_HOME
         mv ./trivy $python_trivy
-      fi  
-    - |
-      if [[ "$PYTHON_BUILD_SYSTEM" == poetry* ]]
-      then
-        # When using Poetry, `pip freeze` outputs a requirements.txt with @file URLs for each wheel
-        # These @file URLs in requirements.txt are not supported by Trivy
-        # So instead of simply using pip freeze, we use `poetry export`
-        poetry export -f requirements.txt --without-hashes --output reports/requirements.txt
-      else
-        _pip freeze | tee ./reports/requirements.txt
       fi
+    - |
+      case "$PYTHON_BUILD_SYSTEM" in
+        poetry*|pipenv*)
+          log_info "$PYTHON_BUILD_SYSTEM build system (\\e[32muse lock file\\e[0m)"
+          cp poetry.lock Pipfile.lock ./reports 2>/dev/null || true
+          ;;
+        uv*)
+          log_info "$PYTHON_BUILD_SYSTEM build system used (\\e[32mmust generate pinned requirements.txt from uv.lock\\e[0m)"
+          maybe_install_uv
+          uv export > ./reports/requirements.txt
+          ;;
+        *)
+          log_info "$PYTHON_BUILD_SYSTEM build system used (\\e[32mmust generate pinned requirements.txt\\e[0m)"
+          install_requirements
+          _pip freeze | tee ./reports/requirements.txt
+          ;;
+      esac
       if [[ -f "./requirements.txt" ]]
       then
         sort -u ./requirements.txt | grep -v "^[  ]*$" > ./requirements.txt.sorted
@@ -1280,18 +1369,22 @@ py-trivy:
           log_warn "The ./requirements.txt file does not match the ./reports/requirements.txt file generated via pip freeze. Make sure to include all dependencies with pinned versions in ./requirements.txt and re-commit the file."
         fi
       fi
-      if [ $($python_trivy fs ${PYTHON_TRIVY_ARGS} --format table --exit-code 0 ./reports/ | grep -c "Number of language-specific files: 0") -eq 1 ]; then
+
+      # Generate the native JSON report that can later be converted to other formats
+      $python_trivy fs ${PYTHON_TRIVY_ARGS} --format json --list-all-pkgs --output reports/py-trivy.trivy.json --exit-code 1 ./reports/ > ./reports/trivy.log 2>&1 || exit_code=$?
+      cat ./reports/trivy.log
+      if [ $(grep -ic "Number of language-specific files[^0-9]*0$" ./reports/trivy.log) -eq 1 ]; then
         log_error "Could not find a file listing all dependencies with their versions."
         exit 1
       fi
-      if [[ "$DEFECTDOJO_TRIVY_REPORTS" ]]
-      then
-        $python_trivy fs ${PYTHON_TRIVY_ARGS} --exit-code 0 --list-all-pkgs --format json --output reports/py-trivy.trivy.json ./reports/
-      fi
-      $python_trivy fs ${PYTHON_TRIVY_ARGS} --format table ./reports/
+      rm ./reports/trivy.log
+      # console output
+      $python_trivy convert --format table reports/py-trivy.trivy.json
+      exit $exit_code
   artifacts:
     name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
     expire_in: 1 day
+    access: developer
     when: always
     paths:
       - "$PYTHON_PROJECT_DIR/reports/py-trivy.*"
@@ -1311,10 +1404,19 @@ py-sbom:
   needs: []
   script:
     - mkdir -p -m 777 reports
-    - install_requirements
     - |
       case "$PYTHON_BUILD_SYSTEM" in
-        setuptools*|reqfile)
+        poetry*|pipenv*)
+          log_info "$PYTHON_BUILD_SYSTEM build system (\\e[32muse lock file\\e[0m)"
+          ;;
+        uv*)
+          log_info "$PYTHON_BUILD_SYSTEM build system used (\\e[32mmust generate pinned requirements.txt from uv.lock\\e[0m)"
+          maybe_install_uv
+          uv export > ./reports/requirements.txt
+          ;;
+        *)
+          log_info "$PYTHON_BUILD_SYSTEM build system used (\\e[32mmust generate pinned requirements.txt\\e[0m)"
+          install_requirements
           _pip freeze > "${PYTHON_REQS_FILE}"
           ;;
       esac
@@ -1342,7 +1444,7 @@ py-sbom:
     paths:
       - "$PYTHON_PROJECT_DIR/reports/py-sbom.cyclonedx.json"
     reports:
-      cyclonedx: 
+      cyclonedx:
         - "$PYTHON_PROJECT_DIR/reports/py-sbom.cyclonedx.json"
   rules:
     # exclude if disabled
@@ -1372,6 +1474,8 @@ py-release:
     # exclude if $PYTHON_RELEASE_ENABLED not set
     - if: '$PYTHON_RELEASE_ENABLED != "true"'
       when: never
+    # on production branch: auto if $PYTHON_AUTO_RELEASE_ENABLED set and implicitly $PYTHON_RELEASE_ENABLED set
+    - if: '$PYTHON_AUTO_RELEASE_ENABLED == "true" && $CI_COMMIT_REF_NAME =~ $PROD_REF'
     # on production or integration branch: manual, non blocking
     - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF'
       when: manual
@@ -1393,7 +1497,7 @@ py-publish:
       - $PYTHON_PROJECT_DIR/dist/*
   rules:
     # exclude if $PYTHON_RELEASE_ENABLED not set
-    - if: '$PYTHON_RELEASE_ENABLED != "true"'
+    - if: '$PYTHON_RELEASE_ENABLED != "true" && $PYTHON_PUBLISH_ENABLED != "true"'
       when: never
     # on tag with release pattern: auto
     - if: '$CI_COMMIT_TAG =~ $RELEASE_REF'