Compare commits

...

6 Commits

Author SHA1 Message Date
dependabot[bot]
fea9633766 chore(deps): bump pyasn1 from 0.6.2 to 0.6.3 in /api
Bumps [pyasn1](https://github.com/pyasn1/pyasn1) from 0.6.2 to 0.6.3.
- [Release notes](https://github.com/pyasn1/pyasn1/releases)
- [Changelog](https://github.com/pyasn1/pyasn1/blob/main/CHANGES.rst)
- [Commits](https://github.com/pyasn1/pyasn1/compare/v0.6.2...v0.6.3)

---
updated-dependencies:
- dependency-name: pyasn1
  dependency-version: 0.6.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-25 12:30:03 +00:00
Adrián Peña
45f0909c3e chore(api): pin all unpinned dependencies to exact versions (#10469) 2026-03-25 13:27:04 +01:00
Alan Buscaglia
b01fcc6cb2 fix(ui): refine filter clear and undo behavior in Findings page (#10446) 2026-03-25 13:20:10 +01:00
Adrián Peña
2ddd5b3091 chore: bump minimum Python to 3.10 and pin SDK dependencies (#10464) 2026-03-25 12:32:28 +01:00
Raajhesh Kannaa Chidambaram
6100932c60 feat(glue): add check for plaintext secrets in ETL job arguments (#10368)
Co-authored-by: Raajhesh Kannaa Chidambaram <495042+raajheshkannaa@users.noreply.github.com>
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2026-03-25 12:25:36 +01:00
lydiavilchez
1c2b146e6e fix(docs): replace Google Workspace customer ID image with English version (#10467) 2026-03-25 11:49:30 +01:00
18 changed files with 792 additions and 329 deletions

View File

@@ -4,6 +4,10 @@ All notable changes to the **Prowler API** are documented in this file.
## [1.24.0] (Prowler UNRELEASED)
### 🔐 Security
- Pin all unpinned dependencies to exact versions to prevent supply chain attacks and ensure reproducible builds [(#10469)](https://github.com/prowler-cloud/prowler/pull/10469)
### 🐞 Fixed
- Finding groups list/latest now apply computed status/severity filters and finding-level prefilters (delta, region, service, category, resource group, scan, resource type), plus `check_title` support for sort/filter consistency [(#10428)](https://github.com/prowler-cloud/prowler/pull/10428)

193
api/poetry.lock generated
View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
[[package]]
name = "about-time"
@@ -2469,22 +2469,18 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
[[package]]
name = "cron-descriptor"
version = "2.0.6"
version = "1.4.5"
description = "A Python library that converts cron expressions into human readable strings."
optional = false
python-versions = ">=3.9"
python-versions = "*"
groups = ["main"]
files = [
{file = "cron_descriptor-2.0.6-py3-none-any.whl", hash = "sha256:3a1c0d837c0e5a32e415f821b36cf758eb92d510e6beff8fbfe4fa16573d93d6"},
{file = "cron_descriptor-2.0.6.tar.gz", hash = "sha256:e39d2848e1d8913cfb6e3452e701b5eec662ee18bea8cc5aa53ee1a7bb217157"},
{file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"},
{file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"},
]
[package.dependencies]
typing_extensions = "*"
[package.extras]
dev = ["mypy", "polib", "ruff"]
test = ["pytest"]
dev = ["polib"]
[[package]]
name = "crowdstrike-falconpy"
@@ -2801,14 +2797,14 @@ bcrypt = ["bcrypt"]
[[package]]
name = "django-allauth"
version = "65.14.0"
version = "65.15.0"
description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication."
optional = false
python-versions = ">=3.8"
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "django_allauth-65.14.0-py3-none-any.whl", hash = "sha256:448f5f7877f95fcbe1657256510fe7822d7871f202521a29e23ef937f3325a97"},
{file = "django_allauth-65.14.0.tar.gz", hash = "sha256:5529227aba2b1377d900e9274a3f24496c645e65400fbae3cad5789944bc4d0b"},
{file = "django_allauth-65.15.0-py3-none-any.whl", hash = "sha256:ad9fc49c49a9368eaa5bb95456b76e2a4f377b3c6862ee8443507816578c098d"},
{file = "django_allauth-65.15.0.tar.gz", hash = "sha256:b404d48cf0c3ee14dacc834c541f30adedba2ff1c433980ecc494d6cb0b395a8"},
]
[package.dependencies]
@@ -2831,20 +2827,20 @@ steam = ["python3-openid (>=3.0.8,<4)"]
[[package]]
name = "django-celery-beat"
version = "2.8.1"
version = "2.9.0"
description = "Database-backed Periodic Tasks."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171"},
{file = "django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a"},
{file = "django_celery_beat-2.9.0-py3-none-any.whl", hash = "sha256:4a9e5ebe26d6f8d7215e1fc5c46e466016279dc102435a28141108649bdf2157"},
{file = "django_celery_beat-2.9.0.tar.gz", hash = "sha256:92404650f52fcb44cf08e2b09635cb1558327c54b1a5d570f0e2d3a22130934c"},
]
[package.dependencies]
celery = ">=5.2.3,<6.0"
cron-descriptor = ">=1.2.32"
Django = ">=2.2,<6.0"
cron-descriptor = ">=1.2.32,<2.0.0"
Django = ">=2.2,<6.1"
django-timezone-field = ">=5.0"
python-crontab = ">=2.3.4"
tzdata = "*"
@@ -3376,62 +3372,62 @@ dotenv = ["python-dotenv"]
[[package]]
name = "fonttools"
version = "4.61.1"
version = "4.62.1"
description = "Tools to manipulate font files"
optional = false
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24"},
{file = "fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958"},
{file = "fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da"},
{file = "fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6"},
{file = "fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1"},
{file = "fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881"},
{file = "fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47"},
{file = "fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6"},
{file = "fonttools-4.61.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09"},
{file = "fonttools-4.61.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37"},
{file = "fonttools-4.61.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb"},
{file = "fonttools-4.61.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9"},
{file = "fonttools-4.61.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87"},
{file = "fonttools-4.61.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56"},
{file = "fonttools-4.61.1-cp311-cp311-win32.whl", hash = "sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a"},
{file = "fonttools-4.61.1-cp311-cp311-win_amd64.whl", hash = "sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7"},
{file = "fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e"},
{file = "fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2"},
{file = "fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796"},
{file = "fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d"},
{file = "fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8"},
{file = "fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0"},
{file = "fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261"},
{file = "fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9"},
{file = "fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c"},
{file = "fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e"},
{file = "fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5"},
{file = "fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd"},
{file = "fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3"},
{file = "fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d"},
{file = "fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c"},
{file = "fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b"},
{file = "fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd"},
{file = "fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e"},
{file = "fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c"},
{file = "fonttools-4.61.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75"},
{file = "fonttools-4.61.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063"},
{file = "fonttools-4.61.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2"},
{file = "fonttools-4.61.1-cp314-cp314-win32.whl", hash = "sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c"},
{file = "fonttools-4.61.1-cp314-cp314-win_amd64.whl", hash = "sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c"},
{file = "fonttools-4.61.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa"},
{file = "fonttools-4.61.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91"},
{file = "fonttools-4.61.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19"},
{file = "fonttools-4.61.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba"},
{file = "fonttools-4.61.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7"},
{file = "fonttools-4.61.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118"},
{file = "fonttools-4.61.1-cp314-cp314t-win32.whl", hash = "sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5"},
{file = "fonttools-4.61.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b"},
{file = "fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371"},
{file = "fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69"},
{file = "fonttools-4.62.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ad5cca75776cd453b1b035b530e943334957ae152a36a88a320e779d61fc980c"},
{file = "fonttools-4.62.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b3ae47e8636156a9accff64c02c0924cbebad62854c4a6dbdc110cd5b4b341a"},
{file = "fonttools-4.62.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b9e288b4da2f64fd6180644221749de651703e8d0c16bd4b719533a3a7d6e3"},
{file = "fonttools-4.62.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7bca7a1c1faf235ffe25d4f2e555246b4750220b38de8261d94ebc5ce8a23c23"},
{file = "fonttools-4.62.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4e0fcf265ad26e487c56cb12a42dffe7162de708762db951e1b3f755319507d"},
{file = "fonttools-4.62.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d850f66830a27b0d498ee05adb13a3781637b1826982cd7e2b3789ef0cc71ae"},
{file = "fonttools-4.62.1-cp310-cp310-win32.whl", hash = "sha256:486f32c8047ccd05652aba17e4a8819a3a9d78570eb8a0e3b4503142947880ed"},
{file = "fonttools-4.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:5a648bde915fba9da05ae98856987ca91ba832949a9e2888b48c47ef8b96c5a9"},
{file = "fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7"},
{file = "fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14"},
{file = "fonttools-4.62.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7"},
{file = "fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b"},
{file = "fonttools-4.62.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1"},
{file = "fonttools-4.62.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416"},
{file = "fonttools-4.62.1-cp311-cp311-win32.whl", hash = "sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53"},
{file = "fonttools-4.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2"},
{file = "fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974"},
{file = "fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9"},
{file = "fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936"},
{file = "fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392"},
{file = "fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04"},
{file = "fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d"},
{file = "fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c"},
{file = "fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42"},
{file = "fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c22b1014017111c401469e3acc5433e6acf6ebcc6aa9efb538a533c800971c79"},
{file = "fonttools-4.62.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68959f5fc58ed4599b44aad161c2837477d7f35f5f79402d97439974faebfebe"},
{file = "fonttools-4.62.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef46db46c9447103b8f3ff91e8ba009d5fe181b1920a83757a5762551e32bb68"},
{file = "fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6706d1cb1d5e6251a97ad3c1b9347505c5615c112e66047abbef0f8545fa30d1"},
{file = "fonttools-4.62.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e7abd2b1e11736f58c1de27819e1955a53267c21732e78243fa2fa2e5c1e069"},
{file = "fonttools-4.62.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9"},
{file = "fonttools-4.62.1-cp313-cp313-win32.whl", hash = "sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24"},
{file = "fonttools-4.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056"},
{file = "fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca"},
{file = "fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca"},
{file = "fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782"},
{file = "fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae"},
{file = "fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7"},
{file = "fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a"},
{file = "fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800"},
{file = "fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e"},
{file = "fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82"},
{file = "fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260"},
{file = "fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4"},
{file = "fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b"},
{file = "fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87"},
{file = "fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c"},
{file = "fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a"},
{file = "fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e"},
{file = "fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd"},
{file = "fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d"},
]
[package.extras]
@@ -5046,18 +5042,18 @@ tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"]
[[package]]
name = "markdown"
version = "3.9"
version = "3.10.2"
description = "Python implementation of John Gruber's Markdown."
optional = false
python-versions = ">=3.9"
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280"},
{file = "markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a"},
{file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"},
{file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"},
]
[package.extras]
docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"]
testing = ["coverage", "pyyaml"]
[[package]]
@@ -6636,10 +6632,10 @@ files = [
[[package]]
name = "prowler"
version = "5.22.0"
version = "5.23.0"
description = "Prowler is an Open Source security tool to perform AWS, GCP and Azure security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness. It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme) and your custom security frameworks."
optional = false
python-versions = ">3.9.1,<3.13"
python-versions = ">=3.10,<3.13"
groups = ["main"]
files = []
develop = false
@@ -6702,7 +6698,7 @@ google-auth-httplib2 = ">=0.1,<0.3"
h2 = "4.3.0"
jsonschema = "4.23.0"
kubernetes = "32.0.1"
markdown = "3.9.0"
markdown = "3.10.2"
microsoft-kiota-abstractions = "1.9.2"
msgraph-sdk = "1.23.0"
numpy = "2.0.2"
@@ -6726,7 +6722,7 @@ uuid6 = "2024.7.10"
type = "git"
url = "https://github.com/prowler-cloud/prowler.git"
reference = "master"
resolved_reference = "41629137efdec1ade078e4386f738c8e0ffce94b"
resolved_reference = "2ddd5b3091bcdd8c7d44aba73b13c5c6f8f99e35"
[[package]]
name = "psutil"
@@ -6891,14 +6887,14 @@ pydantic = ">=2.12.0,<3.0.0"
[[package]]
name = "pyasn1"
version = "0.6.2"
version = "0.6.3"
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pyasn1-0.6.2-py3-none-any.whl", hash = "sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf"},
{file = "pyasn1-0.6.2.tar.gz", hash = "sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b"},
{file = "pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde"},
{file = "pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf"},
]
[[package]]
@@ -7349,14 +7345,14 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
[[package]]
name = "pytest-celery"
version = "1.2.1"
version = "1.3.0"
description = "Pytest plugin for Celery"
optional = false
python-versions = "<4.0,>=3.8"
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "pytest_celery-1.2.1-py3-none-any.whl", hash = "sha256:0441ab0c2a712b775be16ffda3d7deb31995fd7b5e9d71630e7ea98b474346a3"},
{file = "pytest_celery-1.2.1.tar.gz", hash = "sha256:7873fb3cf4fbfe9b0dd15d359bdb8bbab4a41c7e48f5b0adb7d36138d3704d52"},
{file = "pytest_celery-1.3.0-py3-none-any.whl", hash = "sha256:f02201d7770584a0c412a1ded329a142170c24012467c7046f2c72cc8205ad5d"},
{file = "pytest_celery-1.3.0.tar.gz", hash = "sha256:bd9e5b0f594ec5de9ab97cf27e3a11c644718a761bab6b997d01800fd7394f64"},
]
[package.dependencies]
@@ -7367,14 +7363,13 @@ kombu = "*"
psutil = ">=7.0.0"
pytest-docker-tools = ">=3.1.3"
redis = {version = "*", optional = true, markers = "extra == \"all\" or extra == \"redis\""}
setuptools = {version = ">=75.8.0", markers = "python_version >= \"3.9\" and python_version < \"4.0\""}
tenacity = ">=9.0.0"
[package.extras]
all = ["boto3", "botocore", "python-memcached", "redis", "urllib3 (>=1.26.16,<2.0)"]
all = ["boto3", "botocore", "pycurl (>=7.43) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\"", "python-memcached", "redis", "urllib3 (>=1.26.16,<2.0)"]
memcached = ["python-memcached"]
redis = ["redis"]
sqs = ["boto3", "botocore", "urllib3 (>=1.26.16,<2.0)"]
sqs = ["boto3", "botocore", "pycurl (>=7.43) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\"", "urllib3 (>=1.26.16,<2.0)"]
[[package]]
name = "pytest-cov"
@@ -7859,14 +7854,14 @@ files = [
[[package]]
name = "reportlab"
version = "4.4.9"
version = "4.4.10"
description = "The Reportlab Toolkit"
optional = false
python-versions = "<4,>=3.9"
groups = ["main"]
files = [
{file = "reportlab-4.4.9-py3-none-any.whl", hash = "sha256:68e2d103ae8041a37714e8896ec9b79a1c1e911d68c3bd2ea17546568cf17bfd"},
{file = "reportlab-4.4.9.tar.gz", hash = "sha256:7cf487764294ee791a4781f5a157bebce262a666ae4bbb87786760a9676c9378"},
{file = "reportlab-4.4.10-py3-none-any.whl", hash = "sha256:5abc815746ae2bc44e7ff25db96814f921349ca814c992c7eac3c26029bf7c24"},
{file = "reportlab-4.4.10.tar.gz", hash = "sha256:5cbbb34ac3546039d0086deb2938cdec06b12da3cdb836e813258eb33cd28487"},
]
[package.dependencies]
@@ -8288,14 +8283,14 @@ contextlib2 = ">=0.5.5"
[[package]]
name = "sentry-sdk"
version = "2.51.0"
version = "2.56.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "sentry_sdk-2.51.0-py2.py3-none-any.whl", hash = "sha256:e21016d318a097c2b617bb980afd9fc737e1efc55f9b4f0cdc819982c9717d5f"},
{file = "sentry_sdk-2.51.0.tar.gz", hash = "sha256:b89d64577075fd8c13088bc3609a2ce77a154e5beb8cba7cc16560b0539df4f7"},
{file = "sentry_sdk-2.56.0-py2.py3-none-any.whl", hash = "sha256:5afafb744ceb91d22f4cc650c6bd048ac6af5f7412dcc6c59305a2e36f4dbc02"},
{file = "sentry_sdk-2.56.0.tar.gz", hash = "sha256:fdab72030b69625665b2eeb9738bdde748ad254e8073085a0ce95382678e8168"},
]
[package.dependencies]
@@ -8768,14 +8763,14 @@ test = ["pytest", "websockets"]
[[package]]
name = "werkzeug"
version = "3.1.6"
version = "3.1.7"
description = "The comprehensive WSGI web application library."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "werkzeug-3.1.6-py3-none-any.whl", hash = "sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131"},
{file = "werkzeug-3.1.6.tar.gz", hash = "sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25"},
{file = "werkzeug-3.1.7-py3-none-any.whl", hash = "sha256:4b314d81163a3e1a169b6a0be2a000a0e204e8873c5de6586f453c55688d422f"},
{file = "werkzeug-3.1.7.tar.gz", hash = "sha256:fb8c01fe6ab13b9b7cdb46892b99b1d66754e1d7ab8e542e865ec13f526b5351"},
]
[package.dependencies]
@@ -9377,4 +9372,4 @@ files = [
[metadata]
lock-version = "2.1"
python-versions = ">=3.11,<3.13"
content-hash = "2ed5b4e47d81da81963814f21702220ac5619f50cd605fd779be53c8c46ffca5"
content-hash = "167d4549788b8bc8bb7772b9a81ade1eab73d8f354251a8d6af4901223cc7f67"

View File

@@ -5,21 +5,21 @@ requires = ["poetry-core"]
[project]
authors = [{name = "Prowler Engineering", email = "engineering@prowler.com"}]
dependencies = [
"celery (>=5.4.0,<6.0.0)",
"celery (==5.6.2)",
"dj-rest-auth[with_social,jwt] (==7.0.1)",
"django (==5.1.15)",
"django-allauth[saml] (>=65.13.0,<66.0.0)",
"django-celery-beat (>=2.7.0,<3.0.0)",
"django-celery-results (>=2.5.1,<3.0.0)",
"django-allauth[saml] (==65.15.0)",
"django-celery-beat (==2.9.0)",
"django-celery-results (==2.6.0)",
"django-cors-headers==4.4.0",
"django-environ==0.11.2",
"django-filter==24.3",
"django-guid==3.5.0",
"django-postgres-extra (>=2.0.8,<3.0.0)",
"django-postgres-extra (==2.0.9)",
"djangorestframework==3.15.2",
"djangorestframework-jsonapi==7.0.2",
"djangorestframework-simplejwt (>=5.3.1,<6.0.0)",
"drf-nested-routers (>=0.94.1,<1.0.0)",
"djangorestframework-simplejwt (==5.5.1)",
"drf-nested-routers (==0.95.0)",
"drf-spectacular==0.27.2",
"drf-spectacular-jsonapi==0.5.1",
"defusedxml==0.7.1",
@@ -27,22 +27,22 @@ dependencies = [
"lxml==5.3.2",
"prowler @ git+https://github.com/prowler-cloud/prowler.git@master",
"psycopg2-binary==2.9.9",
"pytest-celery[redis] (>=1.0.1,<2.0.0)",
"sentry-sdk[django] (>=2.20.0,<3.0.0)",
"pytest-celery[redis] (==1.3.0)",
"sentry-sdk[django] (==2.56.0)",
"uuid6==2024.7.10",
"openai (>=1.82.0,<2.0.0)",
"openai (==1.109.1)",
"xmlsec==1.3.14",
"h2 (==4.3.0)",
"markdown (>=3.9,<4.0)",
"markdown (==3.10.2)",
"drf-simple-apikey (==2.2.1)",
"matplotlib (>=3.10.6,<4.0.0)",
"reportlab (>=4.4.4,<5.0.0)",
"neo4j (>=6.0.0,<7.0.0)",
"matplotlib (==3.10.8)",
"reportlab (==4.4.10)",
"neo4j (==6.1.0)",
"cartography (==0.132.0)",
"gevent (>=25.9.1,<26.0.0)",
"werkzeug (>=3.1.4)",
"sqlparse (>=0.5.4)",
"fonttools (>=4.60.2)"
"gevent (==25.9.1)",
"werkzeug (==3.1.7)",
"sqlparse (==0.5.5)",
"fonttools (==4.62.1)"
]
description = "Prowler's API (Django/DRF)"
license = "Apache-2.0"
@@ -62,7 +62,7 @@ django-silk = "5.3.2"
docker = "7.1.0"
filelock = "3.20.3"
freezegun = "1.5.1"
marshmallow = ">=3.15.0,<4.0.0"
marshmallow = "==3.26.2"
mypy = "1.10.1"
pylint = "3.2.5"
pytest = "8.2.2"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 KiB

After

Width:  |  Height:  |  Size: 318 KiB

199
poetry.lock generated
View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
[[package]]
name = "about-time"
@@ -808,7 +808,7 @@ description = "Timeout context manager for asyncio programs"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.10\""
markers = "python_version == \"3.10\""
files = [
{file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
@@ -1544,10 +1544,7 @@ files = [
[package.dependencies]
jmespath = ">=0.7.1,<2.0.0"
python-dateutil = ">=2.1,<3.0.0"
urllib3 = [
{version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""},
{version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""},
]
urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}
[package.extras]
crt = ["awscrt (==0.27.6)"]
@@ -1827,22 +1824,6 @@ files = [
{file = "circuitbreaker-2.1.3.tar.gz", hash = "sha256:1a4baee510f7bea3c91b194dcce7c07805fe96c4423ed5594b75af438531d084"},
]
[[package]]
name = "click"
version = "8.1.8"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
groups = ["main", "dev"]
markers = "python_version < \"3.10\""
files = [
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "click"
version = "8.2.1"
@@ -1850,7 +1831,6 @@ description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.10"
groups = ["main", "dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"},
{file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"},
@@ -1908,6 +1888,7 @@ files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
markers = {dev = "platform_system == \"Windows\" or sys_platform == \"win32\""}
[[package]]
name = "contextlib2"
@@ -2255,33 +2236,6 @@ docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"]
ssh = ["paramiko (>=2.4.3)"]
websockets = ["websocket-client (>=1.3.0)"]
[[package]]
name = "dogpile-cache"
version = "1.4.1"
description = "A caching front-end based on the Dogpile lock."
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version < \"3.10\""
files = [
{file = "dogpile_cache-1.4.1-py3-none-any.whl", hash = "sha256:99130ce990800c8d89c26a5a8d9923cbe1b78c8a9972c2aaa0abf3d2ef2984ad"},
{file = "dogpile_cache-1.4.1.tar.gz", hash = "sha256:e25c60e677a5e28ff86124765fbf18c53257bcd7830749cd5ba350ace2a12989"},
]
[package.dependencies]
decorator = ">=4.0.0"
stevedore = ">=3.0.0"
typing_extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
[package.extras]
bmemcached = ["python-binary-memcached"]
memcached = ["python-memcached"]
pifpaf = ["pifpaf (>=3.2.0)"]
pylibmc = ["pylibmc"]
pymemcache = ["pymemcache"]
redis = ["redis"]
valkey = ["valkey"]
[[package]]
name = "dogpile-cache"
version = "1.5.0"
@@ -2289,7 +2243,6 @@ description = "A caching front-end based on the Dogpile lock."
optional = false
python-versions = ">=3.10"
groups = ["main"]
markers = "python_version >= \"3.10\""
files = [
{file = "dogpile_cache-1.5.0-py3-none-any.whl", hash = "sha256:dc7b47d37844db15e8fdc0243c1b58857a2ddc52a5118237a97127bac200e18d"},
{file = "dogpile_cache-1.5.0.tar.gz", hash = "sha256:849c5573c9a38f155cd4173103c702b637ede0361c12e864876877d0cd125eec"},
@@ -2414,7 +2367,7 @@ description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
groups = ["main", "dev"]
markers = "python_version <= \"3.10\""
markers = "python_version == \"3.10\""
files = [
{file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"},
{file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"},
@@ -2441,19 +2394,6 @@ files = [
[package.extras]
testing = ["hatch", "pre-commit", "pytest", "tox"]
[[package]]
name = "filelock"
version = "3.19.1"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
markers = "python_version < \"3.10\""
files = [
{file = "filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d"},
{file = "filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58"},
]
[[package]]
name = "filelock"
version = "3.20.3"
@@ -2461,7 +2401,6 @@ description = "A platform independent file lock."
optional = false
python-versions = ">=3.10"
groups = ["main", "dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1"},
{file = "filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1"},
@@ -2499,7 +2438,6 @@ files = [
[package.dependencies]
blinker = ">=1.9.0"
click = ">=8.1.3"
importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
itsdangerous = ">=2.2.0"
jinja2 = ">=3.1.2"
markupsafe = ">=2.1.1"
@@ -2771,9 +2709,6 @@ files = [
{file = "graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab"},
]
[package.dependencies]
typing-extensions = {version = ">=4,<5", markers = "python_version < \"3.10\""}
[[package]]
name = "h11"
version = "0.16.0"
@@ -2937,12 +2872,11 @@ version = "8.7.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
groups = ["main"]
files = [
{file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"},
{file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"},
]
markers = {dev = "python_version < \"3.10\""}
[package.dependencies]
zipp = ">=3.20"
@@ -3137,7 +3071,7 @@ files = [
[package.dependencies]
attrs = ">=22.2.0"
jsonschema-specifications = ">=2023.03.6"
jsonschema-specifications = ">=2023.3.6"
referencing = ">=0.28.4"
rpds-py = ">=0.7.1"
@@ -3178,34 +3112,6 @@ files = [
[package.dependencies]
referencing = ">=0.31.0"
[[package]]
name = "keystoneauth1"
version = "5.11.1"
description = "Authentication Library for OpenStack Identity"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version < \"3.10\""
files = [
{file = "keystoneauth1-5.11.1-py3-none-any.whl", hash = "sha256:4525adf03b6e591f4b9b8a72c3b14f6510a04816dd5a7aca6ebaa6dfc90b69e6"},
{file = "keystoneauth1-5.11.1.tar.gz", hash = "sha256:806f12c49b7f4b2cad3f5a460f7bdd81e4247c81b6042596a7fea8575f6591f3"},
]
[package.dependencies]
iso8601 = ">=2.0.0"
os-service-types = ">=1.2.0"
pbr = ">=2.0.0"
requests = ">=2.14.2"
stevedore = ">=1.20.0"
typing-extensions = ">=4.12"
[package.extras]
betamax = ["PyYAML (>=3.13)", "betamax (>=0.7.0)", "fixtures (>=3.0.0)"]
kerberos = ["requests-kerberos (>=0.8.0)"]
oauth1 = ["oauthlib (>=0.6.2)"]
saml2 = ["lxml (>=4.2.0)"]
test = ["PyYAML (>=3.12)", "bandit (>=1.7.6,<1.8.0)", "betamax (>=0.7.0)", "coverage (>=4.0)", "fixtures (>=3.0.0)", "flake8-docstrings (>=1.7.0,<1.8.0)", "flake8-import-order (>=0.18.2,<0.19.0)", "hacking (>=6.1.0,<6.2.0)", "lxml (>=4.2.0)", "oauthlib (>=0.6.2)", "oslo.config (>=5.2.0)", "oslo.utils (>=3.33.0)", "oslotest (>=3.2.0)", "requests-kerberos (>=0.8.0)", "requests-mock (>=1.2.0)", "stestr (>=1.0.0)", "testresources (>=2.0.0)", "testtools (>=2.2.0)"]
[[package]]
name = "keystoneauth1"
version = "5.13.0"
@@ -3213,7 +3119,6 @@ description = "Authentication Library for OpenStack Identity"
optional = false
python-versions = ">=3.10"
groups = ["main"]
markers = "python_version >= \"3.10\""
files = [
{file = "keystoneauth1-5.13.0-py3-none-any.whl", hash = "sha256:5ab81412eb0923ceb9c602cc3decce514b399523cb83d16b409ed3b0f9b03d41"},
{file = "keystoneauth1-5.13.0.tar.gz", hash = "sha256:57c9ca407207899b50d8ff1ca8abb4a4e7427461bfc1877eb8519c3989ce63ec"},
@@ -3246,7 +3151,7 @@ files = [
]
[package.dependencies]
certifi = ">=14.05.14"
certifi = ">=14.5.14"
durationpy = ">=0.7"
google-auth = ">=1.0.1"
oauthlib = ">=3.2.2"
@@ -3359,21 +3264,18 @@ tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"]
[[package]]
name = "markdown"
version = "3.9"
version = "3.10.2"
description = "Python implementation of John Gruber's Markdown."
optional = false
python-versions = ">=3.9"
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280"},
{file = "markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a"},
{file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"},
{file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"},
]
[package.dependencies]
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
[package.extras]
docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"]
testing = ["coverage", "pyyaml"]
[[package]]
@@ -4017,26 +3919,6 @@ files = [
{file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
]
[[package]]
name = "networkx"
version = "3.2.1"
description = "Python package for creating and manipulating graphs and networks"
optional = false
python-versions = ">=3.9"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"},
{file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"},
]
[package.extras]
default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"]
developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"]
doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"]
extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"]
test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"]
[[package]]
name = "networkx"
version = "3.4.2"
@@ -4324,22 +4206,6 @@ files = [
opentelemetry-api = "1.35.0"
typing-extensions = ">=4.5.0"
[[package]]
name = "os-service-types"
version = "1.7.0"
description = "Python library for consuming OpenStack sevice-types-authority data"
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version < \"3.10\""
files = [
{file = "os-service-types-1.7.0.tar.gz", hash = "sha256:31800299a82239363995b91f1ebf9106ac7758542a1e4ef6dc737a5932878c6c"},
{file = "os_service_types-1.7.0-py2.py3-none-any.whl", hash = "sha256:0505c72205690910077fb72b88f2a1f07533c8d39f2fe75b29583481764965d6"},
]
[package.dependencies]
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
[[package]]
name = "os-service-types"
version = "1.8.2"
@@ -4347,7 +4213,6 @@ description = "Python library for consuming OpenStack sevice-types-authority dat
optional = false
python-versions = ">=3.10"
groups = ["main"]
markers = "python_version >= \"3.10\""
files = [
{file = "os_service_types-1.8.2-py3-none-any.whl", hash = "sha256:f78890d71814deffabf0ed4358288ec2ced579bc4d0bb87a79ae806cbb4deb6e"},
{file = "os_service_types-1.8.2.tar.gz", hash = "sha256:ab7648d7232849943196e1bb00a30e2e25e600fa3b57bb241d15b7f521b5b575"},
@@ -4856,7 +4721,7 @@ description = "C parser in Python"
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
markers = "implementation_name != \"PyPy\" and platform_python_implementation != \"PyPy\""
markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
@@ -5098,7 +4963,7 @@ files = [
]
[package.dependencies]
astroid = ">=3.3.8,<=3.4.0-dev0"
astroid = ">=3.3.8,<=3.4.0.dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = [
{version = ">=0.2", markers = "python_version < \"3.11\""},
@@ -5110,7 +4975,6 @@ mccabe = ">=0.6,<0.8"
platformdirs = ">=2.2.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
tomlkit = ">=0.10.1"
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
[package.extras]
spelling = ["pyenchant (>=3.2,<4.0)"]
@@ -5266,7 +5130,6 @@ files = [
]
[package.dependencies]
importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""}
pytest = "*"
[[package]]
@@ -5945,10 +5808,10 @@ files = [
]
[package.dependencies]
botocore = ">=1.37.4,<2.0a.0"
botocore = ">=1.37.4,<2.0a0"
[package.extras]
crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"]
crt = ["botocore[crt] (>=1.37.4,<2.0a0)"]
[[package]]
name = "safety"
@@ -6217,7 +6080,7 @@ description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version <= \"3.10\""
markers = "python_version == \"3.10\""
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
@@ -6374,24 +6237,6 @@ files = [
{file = "uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e"},
]
[[package]]
name = "urllib3"
version = "1.26.20"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
groups = ["main", "dev"]
markers = "python_version < \"3.10\""
files = [
{file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"},
{file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"},
]
[package.extras]
brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "urllib3"
version = "2.6.3"
@@ -6399,7 +6244,6 @@ description = "HTTP library with thread-safe connection pooling, file post, and
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"},
{file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"},
@@ -6732,12 +6576,11 @@ version = "3.23.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
groups = ["main"]
files = [
{file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"},
{file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"},
]
markers = {dev = "python_version < \"3.10\""}
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
@@ -6885,5 +6728,5 @@ files = [
[metadata]
lock-version = "2.1"
python-versions = ">3.9.1,<3.13"
content-hash = "fa67f98ae1b75ec5a54d1d6a1c33c5412d888ec60cf35fc407606dc48329c0bf"
python-versions = ">=3.10,<3.13"
content-hash = "65f1f9833d61f90f1f89ed70b3677f76c0693bae275dd39699df01c05050bbe6"

View File

@@ -9,6 +9,11 @@ All notable changes to the **Prowler SDK** are documented in this file.
- `apikeys_api_restricted_with_gemini_api` check for GCP provider [(#10280)](https://github.com/prowler-cloud/prowler/pull/10280)
- `gemini_api_disabled` check for GCP provider [(#10280)](https://github.com/prowler-cloud/prowler/pull/10280)
- `cloudfront_distributions_logging_enabled` detects Standard Logging v2 via CloudWatch Log Delivery [(#10090)](https://github.com/prowler-cloud/prowler/pull/10090)
- `glue_etl_jobs_no_secrets_in_arguments` check for plaintext secrets in AWS Glue ETL job arguments [(#10368)](https://github.com/prowler-cloud/prowler/pull/10368)
### 🔄 Changed
- Minimum Python version from 3.9 to 3.10 and updated classifiers to reflect supported versions (3.10, 3.11, 3.12) [(#10464)](https://github.com/prowler-cloud/prowler/pull/10464)
---

View File

@@ -0,0 +1,43 @@
{
"Provider": "aws",
"CheckID": "glue_etl_jobs_no_secrets_in_arguments",
"CheckTitle": "Glue ETL job has no secrets in default arguments",
"CheckType": [
"Software and Configuration Checks/AWS Security Best Practices",
"TTPs/Credential Access",
"Effects/Data Exposure",
"Sensitive Data Identifications/Security"
],
"ServiceName": "glue",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "critical",
"ResourceType": "Other",
"ResourceGroup": "analytics",
"Description": "**AWS Glue ETL jobs** are inspected for **default arguments** (`DefaultArguments`) that resemble **secrets** (keys, tokens, passwords).\n\nSuch values indicate sensitive data is stored directly in job arguments instead of being sourced securely from AWS Secrets Manager or Systems Manager Parameter Store.",
"Risk": "Plaintext secrets in default arguments reduce confidentiality: values can be viewed in consoles, CLI output, and CloudTrail logs. Compromised credentials enable unauthorized AWS actions, data exfiltration, and lateral movement across the environment.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://docs.aws.amazon.com/glue/latest/dg/aws-glue-programming-etl-glue-arguments.html",
"https://docs.aws.amazon.com/glue/latest/webapi/API_Job.html",
"https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html"
],
"Remediation": {
"Code": {
"CLI": "aws glue update-job --job-name <job_name> --job-update '{\"DefaultArguments\":{\"--secret_name\":\"{{resolve:secretsmanager:my-secret}}\"}}'",
"NativeIaC": "```yaml\nResources:\n GlueJob:\n Type: AWS::Glue::Job\n Properties:\n Name: <job_name>\n Role: <role_arn>\n Command:\n Name: glueetl\n ScriptLocation: \"s3://<bucket>/script.py\"\n DefaultArguments:\n \"--secret_name\": !Sub \"{{resolve:secretsmanager:${MySecret}}}\" # Reference secret from Secrets Manager instead of plaintext\n```",
"Other": "1. Open the AWS Glue console and go to Jobs\n2. Select the job and click Edit\n3. Under Job parameters, identify any arguments containing sensitive values\n4. Store those values in AWS Secrets Manager or Systems Manager Parameter Store\n5. Update the job arguments to reference the secret by name or ARN instead of the plaintext value\n6. Save the job",
"Terraform": "```hcl\nresource \"aws_glue_job\" \"example\" {\n name = \"<job_name>\"\n role_arn = \"<role_arn>\"\n\n command {\n script_location = \"s3://<bucket>/script.py\"\n }\n\n default_arguments = {\n \"--secret_name\" = aws_secretsmanager_secret_version.example.secret_string # Reference secret from Secrets Manager instead of plaintext\n }\n}\n```"
},
"Recommendation": {
"Text": "Store secrets in **AWS Secrets Manager** or **AWS Systems Manager Parameter Store** and reference them by name or ARN in job arguments instead of embedding plaintext values. Enforce **least privilege** on the Glue job IAM role, rotate secrets regularly, and avoid logging or exporting argument values.",
"Url": "https://hub.prowler.com/check/glue_etl_jobs_no_secrets_in_arguments"
}
},
"Categories": [
"secrets"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}

View File

@@ -0,0 +1,52 @@
import json
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.lib.utils.utils import detect_secrets_scan
from prowler.providers.aws.services.glue.glue_client import glue_client
class glue_etl_jobs_no_secrets_in_arguments(Check):
"""Check if Glue ETL jobs have secrets in their default arguments.
Scans the DefaultArguments of each Glue job for hardcoded credentials,
tokens, passwords, and other sensitive values that should be stored in
Secrets Manager or Parameter Store instead.
"""
def execute(self):
findings = []
secrets_ignore_patterns = glue_client.audit_config.get(
"secrets_ignore_patterns", []
)
for job in glue_client.jobs:
report = Check_Report_AWS(metadata=self.metadata(), resource=job)
report.status = "PASS"
report.status_extended = (
f"No secrets found in Glue job {job.name} default arguments."
)
if job.arguments:
secrets_found = []
for arg_name, arg_value in job.arguments.items():
detect_secrets_output = detect_secrets_scan(
data=json.dumps({arg_name: arg_value}),
excluded_secrets=secrets_ignore_patterns,
detect_secrets_plugins=glue_client.audit_config.get(
"detect_secrets_plugins",
),
)
if detect_secrets_output:
secrets_found.extend(
[
f"{secret['type']} in argument {arg_name}"
for secret in detect_secrets_output
]
)
if secrets_found:
report.status = "FAIL"
report.status_extended = f"Potential secrets found in Glue job {job.name} default arguments: {', '.join(secrets_found)}."
findings.append(report)
return findings

View File

@@ -7,7 +7,9 @@ requires = ["poetry-core>=2.0"]
authors = [{name = "Toni de la Fuente", email = "toni@blyx.com"}]
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: Apache Software License"
]
dependencies = [
@@ -54,7 +56,7 @@ dependencies = [
"google-auth-httplib2>=0.1,<0.3",
"jsonschema==4.23.0",
"kubernetes==32.0.1",
"markdown==3.9.0",
"markdown==3.10.2",
"microsoft-kiota-abstractions==1.9.2",
"msgraph-sdk==1.23.0",
"numpy==2.0.2",
@@ -93,7 +95,7 @@ license = "Apache-2.0"
maintainers = [{name = "Prowler Engineering", email = "engineering@prowler.com"}]
name = "prowler"
readme = "README.md"
requires-python = ">3.9.1,<3.13"
requires-python = ">=3.10,<3.13"
version = "5.23.0"
[project.scripts]
@@ -117,13 +119,10 @@ bandit = "1.8.3"
black = "25.1.0"
coverage = "7.6.12"
docker = "7.1.0"
filelock = [
{version = "3.20.3", python = ">=3.10"},
{version = "3.19.1", python = "<3.10"}
]
filelock = "3.20.3"
flake8 = "7.1.2"
freezegun = "1.5.1"
marshmallow = ">=3.15.0,<4.0.0"
marshmallow = "==3.26.2"
mock = "5.2.0"
moto = {extras = ["all"], version = "5.1.11"}
openapi-schema-validator = "0.6.3"

View File

@@ -0,0 +1,190 @@
from unittest import mock
from boto3 import client
from moto import mock_aws
from tests.providers.aws.utils import (
AWS_ACCOUNT_NUMBER,
AWS_REGION_US_EAST_1,
set_mocked_aws_provider,
)
class Test_glue_etl_jobs_no_secrets_in_arguments:
@mock_aws
def test_glue_no_jobs(self):
from prowler.providers.aws.services.glue.glue_service import Glue
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments.glue_client",
new=Glue(aws_provider),
):
from prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments import (
glue_etl_jobs_no_secrets_in_arguments,
)
check = glue_etl_jobs_no_secrets_in_arguments()
result = check.execute()
assert len(result) == 0
@mock_aws
def test_glue_job_no_secrets(self):
glue_client = client("glue", region_name=AWS_REGION_US_EAST_1)
job_name = "test-job"
job_arn = (
f"arn:aws:glue:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:job/{job_name}"
)
glue_client.create_job(
Name=job_name,
Role="role_test",
Command={"Name": "name_test", "ScriptLocation": "script_test"},
DefaultArguments={
"--enable-continuous-cloudwatch-log": "true",
"--TempDir": "s3://my-bucket/temp/",
},
Tags={"key_test": "value_test"},
GlueVersion="1.0",
MaxCapacity=0.0625,
MaxRetries=0,
Timeout=10,
NumberOfWorkers=2,
WorkerType="G.1X",
)
from prowler.providers.aws.services.glue.glue_service import Glue
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments.glue_client",
new=Glue(aws_provider),
):
from prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments import (
glue_etl_jobs_no_secrets_in_arguments,
)
check = glue_etl_jobs_no_secrets_in_arguments()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"No secrets found in Glue job {job_name} default arguments."
)
assert result[0].resource_id == job_name
assert result[0].resource_arn == job_arn
assert result[0].resource_tags == [{"key_test": "value_test"}]
@mock_aws
def test_glue_job_with_secrets(self):
glue_client = client("glue", region_name=AWS_REGION_US_EAST_1)
job_name = "test-job"
job_arn = (
f"arn:aws:glue:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:job/{job_name}"
)
glue_client.create_job(
Name=job_name,
Role="role_test",
Command={"Name": "name_test", "ScriptLocation": "script_test"},
DefaultArguments={
"--db-password": "AKIAsupersecretkey1234",
"--TempDir": "s3://my-bucket/temp/",
},
Tags={"key_test": "value_test"},
GlueVersion="1.0",
MaxCapacity=0.0625,
MaxRetries=0,
Timeout=10,
NumberOfWorkers=2,
WorkerType="G.1X",
)
from prowler.providers.aws.services.glue.glue_service import Glue
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments.glue_client",
new=Glue(aws_provider),
):
from prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments import (
glue_etl_jobs_no_secrets_in_arguments,
)
check = glue_etl_jobs_no_secrets_in_arguments()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert "Potential secrets found" in result[0].status_extended
assert job_name in result[0].status_extended
assert "--db-password" in result[0].status_extended
assert result[0].resource_id == job_name
assert result[0].resource_arn == job_arn
assert result[0].resource_tags == [{"key_test": "value_test"}]
@mock_aws
def test_glue_job_empty_arguments(self):
glue_client = client("glue", region_name=AWS_REGION_US_EAST_1)
job_name = "test-job"
job_arn = (
f"arn:aws:glue:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:job/{job_name}"
)
glue_client.create_job(
Name=job_name,
Role="role_test",
Command={"Name": "name_test", "ScriptLocation": "script_test"},
DefaultArguments={},
Tags={"key_test": "value_test"},
GlueVersion="1.0",
MaxCapacity=0.0625,
MaxRetries=0,
Timeout=10,
NumberOfWorkers=2,
WorkerType="G.1X",
)
from prowler.providers.aws.services.glue.glue_service import Glue
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments.glue_client",
new=Glue(aws_provider),
):
from prowler.providers.aws.services.glue.glue_etl_jobs_no_secrets_in_arguments.glue_etl_jobs_no_secrets_in_arguments import (
glue_etl_jobs_no_secrets_in_arguments,
)
check = glue_etl_jobs_no_secrets_in_arguments()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"No secrets found in Glue job {job_name} default arguments."
)
assert result[0].resource_id == job_name
assert result[0].resource_arn == job_arn
assert result[0].resource_tags == [{"key_test": "value_test"}]

View File

@@ -2,6 +2,14 @@
All notable changes to the **Prowler UI** are documented in this file.
## [1.23.0] (Prowler UNRELEASED)
### 🐞 Fixed
- Clear Filters now resets all filters including muted findings and auto-applies, Clear all in pills only removes pill-visible sub-filters, and the discard icon is now an Undo text button [(#10446)](https://github.com/prowler-cloud/prowler/pull/10446)
---
## [1.22.0] (Prowler v5.22.0)
### 🚀 Added

View File

@@ -5,7 +5,6 @@ import { describe, expect, it, vi } from "vitest";
// Mock lucide-react to avoid SVG rendering issues in jsdom
vi.mock("lucide-react", () => ({
Check: () => <svg data-testid="check-icon" />,
X: () => <svg data-testid="x-icon" />,
}));
// Mock @/components/shadcn to avoid next-auth import chain
@@ -74,7 +73,7 @@ describe("ApplyFiltersButton", () => {
expect(applyButton).toBeDisabled();
});
it("should NOT render the discard (X) button when there are no changes", () => {
it("should NOT render the Undo button when there are no changes", () => {
// Given / When
render(
<ApplyFiltersButton
@@ -88,7 +87,7 @@ describe("ApplyFiltersButton", () => {
// Then
expect(
screen.queryByRole("button", {
name: /discard/i,
name: /undo/i,
}),
).not.toBeInTheDocument();
});
@@ -166,7 +165,7 @@ describe("ApplyFiltersButton", () => {
).toBeInTheDocument();
});
it("should render the discard (X) button", () => {
it("should render the Undo button", () => {
// Given / When
render(
<ApplyFiltersButton
@@ -179,7 +178,7 @@ describe("ApplyFiltersButton", () => {
// Then
expect(
screen.getByRole("button", { name: /discard pending filter changes/i }),
screen.getByRole("button", { name: /undo pending filter changes/i }),
).toBeInTheDocument();
});
});
@@ -237,7 +236,7 @@ describe("ApplyFiltersButton", () => {
// ── onDiscard interaction ────────────────────────────────────────────────
describe("onDiscard", () => {
it("should call onDiscard when the Discard button is clicked", async () => {
it("should call onDiscard when the Undo button is clicked", async () => {
// Given
const user = userEvent.setup();
const onApply = vi.fn();
@@ -254,7 +253,7 @@ describe("ApplyFiltersButton", () => {
// When
await user.click(
screen.getByRole("button", { name: /discard pending filter changes/i }),
screen.getByRole("button", { name: /undo pending filter changes/i }),
);
// Then

View File

@@ -1,6 +1,6 @@
"use client";
import { Check, X } from "lucide-react";
import { Check } from "lucide-react";
import { Button } from "@/components/shadcn";
import { cn } from "@/lib/utils";
@@ -12,7 +12,7 @@ export interface ApplyFiltersButtonProps {
changeCount: number;
/** Called when the user clicks "Apply Filters" */
onApply: () => void;
/** Called when the user clicks the discard (X) action */
/** Called when the user clicks the discard (Undo) action */
onDiscard: () => void;
/** Optional extra class names for the outer wrapper */
className?: string;
@@ -23,7 +23,7 @@ export interface ApplyFiltersButtonProps {
*
* - Shows the count of pending changes when `hasChanges` is true.
* - The apply button is disabled (and visually muted) when there are no changes.
* - The discard (X) button only appears when there are pending changes.
* - The Undo button only appears when there are pending changes.
* - Uses Prowler's shadcn `Button` component.
*/
export const ApplyFiltersButton = ({
@@ -52,11 +52,11 @@ export const ApplyFiltersButton = ({
{hasChanges && (
<Button
variant="ghost"
size="icon-sm"
size="sm"
onClick={onDiscard}
aria-label="Discard pending filter changes"
aria-label="Undo pending filter changes"
>
<X className="size-4" />
Undo
</Button>
)}
</div>

View File

@@ -2,7 +2,6 @@
import { XCircle } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useCallback } from "react";
import { Button } from "../shadcn";
@@ -52,7 +51,7 @@ export const ClearFiltersButton = ({
const filterCount = activeFilters.length;
// Clear all filters except excluded ones (muted, search)
const clearFiltersPreservingExcluded = useCallback(() => {
const clearFiltersPreservingExcluded = () => {
const params = new URLSearchParams(searchParams.toString());
Array.from(params.keys()).forEach((key) => {
if (
@@ -64,7 +63,7 @@ export const ClearFiltersButton = ({
});
params.delete("page");
router.push(`${pathname}?${params.toString()}`, { scroll: false });
}, [router, searchParams, pathname]);
};
// In batch mode: use pendingCount if provided; otherwise fall back to URL count.
// In instant mode: always use URL count.

View File

@@ -118,7 +118,8 @@ export const FindingsFilters = ({
setPending,
applyAll,
discardAll,
clearAll,
clearAndApply,
clearKeys,
hasChanges,
changeCount,
getFilterValue,
@@ -198,6 +199,20 @@ export const FindingsFilters = ({
setPending(filterKey, nextValues);
};
// Handler for clearing all chips: clears only the filter keys visible as chips,
// without touching provider/account selectors.
const PROVIDER_KEYS = new Set([
"filter[provider_type__in]",
"filter[provider_id__in]",
]);
const handleClearAllChips = () => {
const chipKeys = Array.from(new Set(filterChips.map((c) => c.key))).filter(
(k) => !PROVIDER_KEYS.has(k),
);
clearKeys(chipKeys);
};
// Derive pending muted state for the checkbox.
// Note: "filter[muted]" participates in batch mode — applyAll includes it
// when present in pending state, and the defaultParams option ensures
@@ -252,7 +267,7 @@ export const FindingsFilters = ({
)}
<ClearFiltersButton
showCount
onClear={clearAll}
onClear={clearAndApply}
pendingCount={
Object.entries(pendingFilters).filter(([key, values]) => {
if (!values || values.length === 0) return false;
@@ -279,7 +294,7 @@ export const FindingsFilters = ({
<FilterSummaryStrip
chips={filterChips}
onRemove={handleChipRemove}
onClearAll={clearAll}
onClearAll={handleClearAllChips}
/>
{/* Expandable filters section */}

View File

@@ -585,4 +585,264 @@ describe("useFilterBatch", () => {
]);
});
});
// ── clearAndApply ──────────────────────────────────────────────────────────
describe("clearAndApply", () => {
it("should clear all batch-managed filters and push URL immediately", () => {
// Given
setSearchParams({
"filter[severity__in]": "critical",
"filter[status__in]": "FAIL",
});
const { result } = renderHook(() => useFilterBatch());
// Pre-condition — pending is loaded from URL
expect(result.current.pendingFilters["filter[severity__in]"]).toEqual([
"critical",
]);
expect(result.current.pendingFilters["filter[status__in]"]).toEqual([
"FAIL",
]);
// When
act(() => {
result.current.clearAndApply();
});
// Then — pending is empty
expect(result.current.pendingFilters).toEqual({});
// And router.push was called
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
// The pushed URL must NOT contain severity or status
expect(calledUrl).not.toContain("severity");
expect(calledUrl).not.toContain("status");
});
it("should apply defaultParams when clearing", () => {
// Given
setSearchParams({ "filter[severity__in]": "critical" });
const { result } = renderHook(() =>
useFilterBatch({ defaultParams: { "filter[muted]": "false" } }),
);
// When
act(() => {
result.current.clearAndApply();
});
// Then — pushed URL contains the defaultParam
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("filter%5Bmuted%5D=false");
});
it("should preserve filter[search] (excluded from batch)", () => {
// Given — URL has both a search param (excluded) and a batch filter
mockSearchParamsValue = new URLSearchParams({
"filter[search]": "test",
"filter[severity__in]": "critical",
});
const { result } = renderHook(() => useFilterBatch());
// When
act(() => {
result.current.clearAndApply();
});
// Then — search param is preserved; severity is gone
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("filter%5Bsearch%5D=test");
expect(calledUrl).not.toContain("severity");
});
it("should reset pagination to page 1", () => {
// Given — URL already has a page param
mockSearchParamsValue = new URLSearchParams({
"filter[severity__in]": "critical",
page: "3",
});
const { result } = renderHook(() => useFilterBatch());
// When
act(() => {
result.current.clearAndApply();
});
// Then — page is reset to 1
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("page=1");
});
});
// ── clearKeys ─────────────────────────────────────────────────────────────
describe("clearKeys", () => {
it("should remove only specified keys and push URL", () => {
// Given
setSearchParams({});
const { result } = renderHook(() => useFilterBatch());
act(() => {
result.current.setPending("filter[severity__in]", ["critical"]);
result.current.setPending("filter[status__in]", ["FAIL"]);
result.current.setPending("filter[region__in]", ["us-east-1"]);
});
// When
act(() => {
result.current.clearKeys(["filter[severity__in]"]);
});
// Then — severity is gone; status and region remain
expect(
result.current.pendingFilters["filter[severity__in]"],
).toBeUndefined();
expect(result.current.pendingFilters["filter[status__in]"]).toEqual([
"FAIL",
]);
expect(result.current.pendingFilters["filter[region__in]"]).toEqual([
"us-east-1",
]);
// And the pushed URL contains the remaining keys but not severity
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("status");
expect(calledUrl).toContain("region");
expect(calledUrl).not.toContain("severity");
});
it("should accept keys without 'filter[' prefix", () => {
// Given
setSearchParams({});
const { result } = renderHook(() => useFilterBatch());
act(() => {
result.current.setPending("filter[severity__in]", ["critical"]);
});
// When — pass key without filter[] wrapper
act(() => {
result.current.clearKeys(["severity__in"]);
});
// Then — severity is cleared
expect(
result.current.pendingFilters["filter[severity__in]"],
).toBeUndefined();
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).not.toContain("severity");
});
it("should preserve provider/account keys not in the cleared list", () => {
// Given
setSearchParams({});
const { result } = renderHook(() => useFilterBatch());
act(() => {
result.current.setPending("filter[provider_type__in]", ["aws"]);
result.current.setPending("filter[severity__in]", ["critical"]);
result.current.setPending("filter[status__in]", ["FAIL"]);
});
// When — clear only severity and status; leave provider untouched
act(() => {
result.current.clearKeys([
"filter[severity__in]",
"filter[status__in]",
]);
});
// Then — provider_type__in is still in pending
expect(
result.current.pendingFilters["filter[provider_type__in]"],
).toEqual(["aws"]);
expect(
result.current.pendingFilters["filter[severity__in]"],
).toBeUndefined();
expect(
result.current.pendingFilters["filter[status__in]"],
).toBeUndefined();
// And the pushed URL retains provider but not severity/status
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("provider_type__in");
expect(calledUrl).not.toContain("severity");
expect(calledUrl).not.toContain("status__in");
});
it("should apply defaultParams after clearing", () => {
// Given
setSearchParams({});
const { result } = renderHook(() =>
useFilterBatch({ defaultParams: { "filter[muted]": "false" } }),
);
act(() => {
result.current.setPending("filter[severity__in]", ["critical"]);
});
// When
act(() => {
result.current.clearKeys(["filter[severity__in]"]);
});
// Then — defaultParam is present in the pushed URL
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("filter%5Bmuted%5D=false");
});
it("should reset pagination to page 1", () => {
// Given — URL already has a page param
mockSearchParamsValue = new URLSearchParams({
"filter[severity__in]": "critical",
page: "5",
});
const { result } = renderHook(() => useFilterBatch());
// When
act(() => {
result.current.clearKeys(["filter[severity__in]"]);
});
// Then — page is reset to 1
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("page=1");
});
it("should handle empty keys array gracefully", () => {
// Given
setSearchParams({});
const { result } = renderHook(() => useFilterBatch());
act(() => {
result.current.setPending("filter[severity__in]", ["critical"]);
});
// When — clear no keys at all
act(() => {
result.current.clearKeys([]);
});
// Then — pending is unchanged
expect(result.current.pendingFilters["filter[severity__in]"]).toEqual([
"critical",
]);
// And router.push was still called (navigates with current state)
expect(mockPush).toHaveBeenCalledTimes(1);
const calledUrl: string = mockPush.mock.calls[0][0];
expect(calledUrl).toContain("severity");
});
});
});

View File

@@ -32,6 +32,19 @@ export interface UseFilterBatchReturn {
* Includes provider/account keys and all batch-managed filter keys.
*/
clearAll: () => void;
/**
* Clear all batch-managed filters and immediately navigate (router.push)
* with defaultParams applied. Equivalent to clearAll() + applyAll() but
* avoids the async state gap between the two calls.
*/
clearAndApply: () => void;
/**
* Clear only the specified filter keys from pending state and immediately
* navigate (router.push) with the remaining pending filters + defaultParams.
* Used by "Clear all" in the pills strip to remove only pill-visible filters
* without touching provider/account selectors.
*/
clearKeys: (keys: string[]) => void;
/** Remove a single filter key from pending state */
removePending: (key: string) => void;
/** Whether pending state differs from the current URL */
@@ -164,20 +177,19 @@ export const useFilterBatch = (
});
};
const applyAll = () => {
// Start from the current URL params to preserve non-batch params.
// Only filter[search] is excluded from batch management and preserved from the URL as-is.
/** Private helper — builds URLSearchParams from a pending state and pushes. */
const buildAndPush = (nextPending: PendingFilters) => {
const params = new URLSearchParams(searchParams.toString());
// Remove all existing batch-managed filter params
// Remove all batch-managed filter params
Array.from(params.keys()).forEach((key) => {
if (key.startsWith("filter[") && !EXCLUDED_FROM_BATCH.includes(key)) {
params.delete(key);
}
});
// Write the pending state
Object.entries(pendingFilters).forEach(([key, values]) => {
// Re-apply the given pending filters
Object.entries(nextPending).forEach(([key, values]) => {
const nonEmpty = values.filter(Boolean);
if (nonEmpty.length > 0) {
params.set(key, nonEmpty.join(","));
@@ -203,6 +215,10 @@ export const useFilterBatch = (
router.push(targetUrl, { scroll: false });
};
const applyAll = () => {
buildAndPush(pendingFilters);
};
const discardAll = () => {
const applied = deriveAppliedFromUrl(
new URLSearchParams(searchParams.toString()),
@@ -230,6 +246,39 @@ export const useFilterBatch = (
setPendingFilters({});
};
/**
* Clears ALL batch-managed filters and immediately navigates (router.push).
*
* Works around the async gap between clearAll() + applyAll(): instead of
* setting pending to `{}` and then calling applyAll() (which would still
* read the old pendingFilters from the closure), this function builds the
* target URL directly from an empty pending state and pushes it in one step.
* defaultParams (e.g. filter[muted]=false) are applied as usual.
*/
const clearAndApply = () => {
setPendingFilters({});
buildAndPush({});
};
/**
* Removes only the specified filter keys from pending state and immediately
* navigates (router.push) with the remaining filters + defaultParams.
*
* Used by the pills strip "Clear all" to remove pill-visible filters (severity,
* status, delta, region, service, etc.) without touching provider/account selectors.
*/
const clearKeys = (keys: string[]) => {
const normalizedKeys = keys.map((k) =>
k.startsWith("filter[") ? k : `filter[${k}]`,
);
const nextPending: PendingFilters = { ...pendingFilters };
normalizedKeys.forEach((k) => {
delete nextPending[k];
});
setPendingFilters(nextPending);
buildAndPush(nextPending);
};
const getFilterValue = (key: string): string[] => {
const filterKey = key.startsWith("filter[") ? key : `filter[${key}]`;
return pendingFilters[filterKey] ?? [];
@@ -249,6 +298,8 @@ export const useFilterBatch = (
applyAll,
discardAll,
clearAll,
clearAndApply,
clearKeys,
removePending,
hasChanges,
changeCount,