Compare commits

..
Author SHA1 Message Date
Adrián Jesús Peña Rodríguez ae08623b75 docs(api): update README to emphasize environment variable requirements for production deployment 2025-09-26 11:16:50 +02:00
César Arroba ab727e6816 chore(gha): fix e2e workflow (#8769) 2025-09-25 22:13:53 +05:45
Rubén De la Torre Vico 23d882d7ab feat(mcp): add Prowler App MCP Server (#8744) 2025-09-25 15:21:34 +02:00
Alejandro Bailo 59435167ea fix(scans): update link disable condition for findings table (#8762) 2025-09-25 12:57:22 +02:00
Andoni Alonso 77cdd793f8 fix(aws): cover SNS ResourceID in Quick Inventory output (#8763) 2025-09-25 11:14:32 +02:00
Andoni Alonso d13f3f0e0c docs(gcp): refactor getting started and auth (#8758) 2025-09-25 10:19:01 +02:00
Víctor Fernández Poyatos 56821de2f4 feat(tasks): Move compliance tasks to compliance queue (#8755) 2025-09-24 14:00:17 +02:00
Daniel BarranqueroandAndoni A. 92190fa69f feat(docs): add renaming checks to developer guide (#8717)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-09-24 11:46:52 +02:00
Prowler Botandprowler-bot 85db7c5183 chore(regions_update): Changes in regions for AWS services (#8736)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-09-24 10:38:12 +02:00
Josema Camacho a55ac266bf chore(django): update django to 5.1.12 due to security problems (#8693) 2025-09-23 16:35:25 +05:45
Andoni Alonso 90622e0437 docs: update Entra SSO SAML video link (#8745) 2025-09-23 12:43:51 +02:00
Pepe Fagoaga 81596250dc fix(actions): lock poetry after changes (#8477) 2025-09-23 14:31:45 +05:45
Rubén De la Torre Vico 43db5fe527 feat(mcp): add basic logger (#8740) 2025-09-23 09:09:38 +02:00
Pepe Fagoaga dfb479fa80 chore(readme): remove deprecations and fix typo (#8739) 2025-09-22 20:31:42 +05:45
Pedro Martín aa88b453ff fix(compliance): change order in models and remove prints (#8738) 2025-09-22 15:45:09 +02:00
Pedro MartínandPepe Fagoaga fbda66c6d1 feat(compliance): add name for each compliance (#7920)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-09-22 14:53:27 +02:00
Adrián Jesús Peña Rodríguez 2200e65519 feat(auth): add safeguards to prevent self-role removal and enforce MANAGE_ACCOUNT role presence (#8729) 2025-09-22 14:04:39 +02:00
Josema Camacho b8537aa22d feat(config): add generation for JWT keys if missing (#8655) 2025-09-22 13:14:54 +02:00
Rubén De la Torre Vico cb4a5dec79 chore: set an appropiate User-Agent in requests (#8724) 2025-09-22 12:48:13 +02:00
Rubén De la Torre Vico 0286de7ce2 chore: add mcp_server component labeler configuration (#8737) 2025-09-22 15:40:23 +05:45
b00602f109 fix(users): only list roles and memberships with manage_account (#8281)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-09-22 11:25:24 +02:00
Adrián Jesús Peña Rodríguez 1cfae546a0 chore(deps): add markdown package version 3.9 to dependencies (#8735) 2025-09-22 10:44:26 +02:00
Sergio Garcia 05dae4e8d1 fix(iac): handle empty results (#8733) 2025-09-16 14:20:15 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MrCloudSec
52ddaca4c5 chore(deps-dev): bump moto from 5.0.28 to 5.1.11 (#7100)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-09-16 14:17:47 +02:00
Alejandro BailoandPepe Fagoaga 940a1202b3 fix: handle 4XX and 204 properly (#8722)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-09-15 17:07:15 +02:00
ec27451199 chore(regions_update): Changes in regions for AWS services (#8728)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-09-15 15:02:37 +02:00
Sergio Garcia 60e06dcc6e chore(html): support markdown in HTML (#8727) 2025-09-15 11:38:18 +02:00
Hugo Pereira Britoandalejandrobailo 7733aab088 feat: add additional_urls to finding details and markdown (#8704)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-09-15 11:33:27 +02:00
Pepe Fagoaga 5c6fadcfe7 chore(changelog): remove whitespace in links (#8712) 2025-09-12 17:09:19 +05:45
César Arroba 1bdb314e2c chore(gha): permissions missed for conflict checker action (#8714) 2025-09-12 12:37:12 +02:00
Rubén De la Torre Vico 5b0365947f feat: add first Prowler MCP server version (#8695) 2025-09-12 09:56:36 +02:00
Daniel BarranqueroandSergio Garcia b512f6c421 fix(firehose): false positive in firehose_stream_encrypted_at_rest (#8599)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-09-11 09:55:16 -04:00
Alejandro Bailo c4a8771647 chore(dependencies): update package versions and track them (#8696) 2025-09-11 15:36:06 +02:00
Alejandro Bailo 6f967c6da7 fix(auth): validate email field (#8698) 2025-09-11 15:29:49 +02:00
Alejandro Bailo 82cd29d595 fix(auth): add method attribute to form for proper submission handling (#8699) 2025-09-11 15:02:36 +02:00
Daniel Barranquero 14c2334e1b fix(defender): change policies rules key (#8702) 2025-09-11 13:46:21 +02:00
Rubén De la Torre VicoandHugoPBrito 3598514cb4 chore(aws/config): adapt metadata to new standarized format (#8641)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
2025-09-10 17:46:11 +02:00
Hugo Pereira Brito c4ba061f30 chore(outputs): adapt to new metadata specification (#8651) 2025-09-10 17:21:19 +02:00
Chandrapal BadshahandChandrapal Badshah f4530b21d2 fix(lighthouse): make Enter submit text (#8664)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-09-10 16:34:35 +02:00
Chandrapal BadshahandChandrapal Badshah 3949ab736d fix(lighthouse): allow scrolling during AI response streaming (#8669)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-09-10 16:34:24 +02:00
sumit-tftandalejandrobailo 9da5066b18 feat(ui): add copy link icon to finding detail page (#8685)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-09-10 16:30:16 +02:00
941539616c chore(aws/neptune): adapt some metadata fields to new format (#8494)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-09-10 16:21:30 +02:00
sumit-tftandalejandrobailo 135fa044b7 feat(ui): Add Prowler Hub menu item with tooltip (#8692)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-09-10 16:09:09 +02:00
Andoni Alonso 48913c1886 docs(aws): refactor getting started and auth (#8683) 2025-09-10 13:45:36 +02:00
Pedro Martín ea20943f83 feat(actions): support dashboard changes in changelog (#8694) 2025-09-10 11:05:56 +02:00
Hugo Pereira Brito 2738cfd1bd feat(dashboard): add Description and markdown support (#8667) 2025-09-10 10:53:53 +02:00
Rubén De la Torre VicoandHugoPBrito 265c3d818e docs(developer-guide): enhance check metadata format (#8411)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
2025-09-10 09:19:08 +02:00
c0a9fdf8c8 docs(jira): add comprehensive guide for Jira integration in Prowler App (#8681)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-09-09 17:01:12 +02:00
Rubén De la Torre Vico 8b3335f426 chore: add metadata-review label for .metadata.json files (#8689) 2025-09-09 20:32:04 +05:45
Daniel Barranquero 252033d113 fix(compliance): replace old check id with new one (#8682) 2025-09-09 14:25:56 +02:00
Prowler Botandprowler-bot 0bc00dbca4 chore(release): Bump version to v5.13.0 (#8679)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-09-09 16:36:22 +05:45
Adrián Jesús Peña Rodríguez 3f5178bffb chore: update api changelog (#8677) 2025-09-09 10:23:55 +02:00
Josema Camacho e08b272a1d fix(login): add DRF throttle option for dj-rest-auth lib (#8672) 2025-09-09 09:34:02 +02:00
Pedro Martín 64c43a288d feat(jira): add force accept language for requests (#8674) 2025-09-09 13:17:25 +05:45
Daniel Barranquero 74bf0e6b47 fix(aws): nonetype errors in opensearch, firehose and cognito (#8670) 2025-09-09 13:12:57 +05:45
Andoni AlonsoandDaniel Barranquero 02b7c5328f docs: update providers table (#8676)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2025-09-09 09:25:20 +02:00
Alejandro Bailo bb02004e7c fix: social auth buttons showed for sign-up (#8673) 2025-09-09 09:23:56 +02:00
Andoni AlonsoandDaniel Barranquero 82cf216a74 feat(mongodbatlas): add MongoDB Atlas provider PoC (#8312)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2025-09-09 09:18:37 +02:00
Daniel Barranquero 7916425ed4 fix(memorydb): handle clusters with no security groups (#8666) 2025-09-08 15:05:13 -04:00
Andoni Alonso d98063ed47 docs: add interface column to providers (#8675) 2025-09-08 15:03:17 -04:00
Andoni Alonso 27bf78a3a1 docs: update providers list (#8671) 2025-09-08 17:12:16 +02:00
Andoni Alonso f50bd50d60 docs: add SSO with SAML Entra ID video link (#8668) 2025-09-08 14:57:38 +02:00
Alejandro Bailo 80665e0396 feat(ui): send a finding to Jira (#8649) 2025-09-08 14:15:23 +02:00
Pedro Martín 4b259fa8dd chore(changelog): update with latest changes (#8665) 2025-09-08 17:24:31 +05:45
Hugo Pereira Brito 10db2ed6d8 chore(docs): add notes regarding gov accounts support (#8656) 2025-09-08 11:07:00 +02:00
Chandrapal BadshahandChandrapal Badshah 422a8a0f62 fix: change title in lighthouse settings (#8615)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-09-08 10:34:09 +02:00
Daniel Barranquero 906a2cc651 fix(entra): add metadata description for check entra_admin_users_phishing_resistant_mfa_enabled (#8654) 2025-09-08 08:11:46 +02:00
Víctor Fernández Poyatos 43fe9c6860 feat(integrations): allow sending findings to Jira from the API (#8645) 2025-09-05 14:28:34 +02:00
Andoni Alonso f87b2089fb docs: remove llms.txt (#8653) 2025-09-05 17:08:42 +05:45
Samuele PasiniandDaniel Barranquero 1884874ab6 fix: typo ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_* CheckID (#8294)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2025-09-05 13:16:12 +02:00
Andoni Alonso cd6d29e176 docs: reorg tutorials (#8652) 2025-09-05 16:49:14 +05:45
Pedro Martín 0b7055e983 feat(jira): add send_finding method with specific finding fields (#8648) 2025-09-05 12:25:53 +02:00
Josema Camacho ae53b76d78 feat(login): add DJANGO_THROTTLE_TOKEN_OBTAIN to main .env file (#8650) 2025-09-05 16:01:48 +05:45
Josema Camacho 406e473b5c feat(login): add throttling option for the /api/v1/tokens endpoint (#8647) 2025-09-05 14:37:31 +05:45
Pedro Martín 1a2bf461f0 feat(jira): support labels in jira tickets (#8603) 2025-09-05 09:53:24 +02:00
Samuele Pasiniandpedrooot 1b49c0b27f feat: add --excluded-checks-file flag (#8301)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-09-05 09:33:21 +02:00
Pablo LaraandAdrián Jesús Peña Rodríguez 12ada66978 feat: add status filter to /overviews endpoint (#8186)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-09-04 18:46:14 +02:00
Alejandro Bailo daa2536005 feat: Jira UI integration - pages and server actions (#8640) 2025-09-04 15:59:37 +02:00
Chandrapal BadshahandChandrapal Badshah 69a62db19a chore: rename to lighthouse ai (#8614)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-09-04 15:30:07 +05:45
Pedro MartínandHugo Pereira Brito 79450d6977 fix(securityhub): resolve TypeError from Python3.9 (#8619)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-09-03 17:52:09 +02:00
Víctor Fernández Poyatos 0463fd0830 refactor(integrations-jira): Move domain to credentials and retrieve metadata during connection test (#8637) 2025-09-03 17:24:42 +02:00
Alejandro Bailo b15e3d339c fix(saml): remove validation call on email domain change (#8638) 2025-09-03 17:04:51 +02:00
Pedro Martín 1fc12952ba feat(jira): add color for manual status (#8642) 2025-09-03 16:53:31 +02:00
sumit-tftandalejandrobailo 088a6bcbda feat(ui): handle no-permissions on scan page (#8624)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-09-03 15:51:14 +02:00
Hugo Pereira Brito a3b0bb6d4b refactor(models): rename AdditionalUrls to AdditionalURLs (#8639) 2025-09-03 19:34:06 +05:45
Pedro Martín 3c819f8875 chore(changelog): update with latest changes (#8636) 2025-09-03 12:54:50 +02:00
Pedro Martín cdf0292bbc feat(jira): add get_metadata (#8630) 2025-09-03 10:59:07 +02:00
César Arroba 987121051b chore(sdk): comment push readme to dockerhub steps (#8628) 2025-09-02 21:48:42 +05:45
Hugo Pereira Brito c9ed7773d2 feat(models): add AdditionalUrls field to check metadata (#8590) 2025-09-02 21:27:21 +05:45
Pepe Fagoaga fdf45aac51 fix(img): prowler architecture (#8635) 2025-09-02 21:15:40 +05:45
Alejandro Bailo 3ded224a4b fix: new errors detected through the app (#8629) 2025-09-02 12:35:06 +02:00
sumit-tft 230a085c76 fix(ui): display NoProvidersAdded when no cloud providers are configured (#8626) 2025-09-02 12:33:58 +02:00
Chandrapal BadshahandChandrapal Badshah 8cd90e07dc chore(ui): eslint nextjs files (#8627)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-09-02 12:15:48 +02:00
Pedro Martín 06ded98d05 feat(jira): add data to table and error handling (#8601) 2025-09-02 11:48:52 +02:00
Pedro Martín a5066326bd chore(changelog): update with latests changes (#8620) 2025-09-02 11:27:13 +02:00
Alejandro Bailo 83a9ac2109 chore(ui): update CHANGELOG (#8625) 2025-09-02 10:45:34 +02:00
Alejandro Bailo 136eb4facd feat: 50X errors handler (#8621) 2025-09-02 10:12:03 +02:00
Víctor Fernández Poyatos d4eb4bdca7 feat(integrations): Support JIRA integration in the API (#8622) 2025-09-02 09:53:36 +02:00
Alejandro Bailo 665c9d878a chore(ui): update Next.js and ESLint dependencies to version 14.2.32 (#8623) 2025-09-01 18:38:39 +02:00
Hugo Pereira Britoandalejandrobailo a064e43302 chore(ui): render attributes as markdown (#8604)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-09-01 16:43:36 +02:00
Daniel Barranquero fdb76e7820 feat(docs): update mfa enforcement date for m365 (#8610) 2025-09-01 09:48:21 +02:00
Pepe Fagoaga 1259bb85e3 fix: remove dot (#8613) 2025-08-29 14:46:19 +05:45
Pepe Fagoaga 0db9ab91b2 chore(docs): review stats, imgs and update copy (#8612) 2025-08-29 14:44:01 +05:45
César Arroba f6ea314ec0 chore(sdk): push readme file to docker hub (#8611) 2025-08-29 14:43:53 +05:45
9e02da342b docs: Security Hub API and UI documentation (#8576)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-08-28 20:43:42 +05:45
Prowler Botandprowler-bot 358d4239c7 chore(release): Bump version to v5.12.0 (#8605)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-08-28 16:56:24 +02:00
Víctor Fernández Poyatos b003fca377 fix(docs): remove empty sections (#8600) 2025-08-28 12:55:46 +02:00
Víctor Fernández Poyatos b4deda3c3f docs(api): fix API response samples (#8592) 2025-08-28 12:39:07 +02:00
Sergio Garcia 338bb74c0c fix(azure): query API management logs with not empty operations (#8598) 2025-08-28 12:03:35 +02:00
Alejandro Bailo 7342a8901f chore: update CHANGELOG.md for Prowler v5.11.0 release (#8597) 2025-08-28 11:43:24 +02:00
Sergio GarciaandRubén De la Torre Vico f484b83f15 feat(azure): Add APIM threat detection for LLM jacking attacks (#8571)
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-08-28 11:42:07 +02:00
Adrián Jesús Peña Rodríguez c69187f484 chore: prepare api changelog for 5.11 (#8596) 2025-08-28 10:25:08 +02:00
Alejandro Bailo 5038afeb26 fix(security-hub): copy updated (#8594) 2025-08-27 18:42:34 +02:00
Sergio Garcia fce43cea16 chore: update changelog (#8593) 2025-08-27 17:57:07 +02:00
Andoni Alonso 43a14b89bc fix(github): provider always scans user instead of organization when using provider UID (#8587) 2025-08-27 17:45:13 +02:00
TomandSergio Garcia 24364bd73e feat(gcp): Add support for skipping APIs check (#8575)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2025-08-27 14:44:34 +02:00
Adrián Jesús Peña Rodríguez a1abe6dd2d fix(sh): reset regions information if connection fails (#8588) 2025-08-27 14:15:09 +02:00
César Arroba 25098bc82a chore(gha): fix conflict checker action (#8586) 2025-08-27 13:41:39 +02:00
sumit-tftandalejandrobailo 20f2f45610 feat(ui): add S3 bucket link with folder for each integration (#8554)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-08-27 12:40:37 +02:00
Alejandro Bailo 06c2608a05 feat(integrations): external links and copies changed (#8574) 2025-08-27 12:40:25 +02:00
Alejandro Bailo 329ac113f2 chore(docs): update CHANGELOG properly (#8585) 2025-08-27 11:57:12 +02:00
Hugo Pereira Brito 97179d2b43 fix(docs): incorrect permission in sp creation guide (#8581) 2025-08-27 11:01:37 +02:00
sumit-tft 8317ea783f feat(ui): show all provider UIDs in scan page filter regardless of co… (#8375) 2025-08-27 10:50:16 +02:00
Andoni Alonso 65e7e89d61 fix(github): GitHub Personal Access Token authentication fails without user:email scope (#8580) 2025-08-27 09:57:32 +02:00
Víctor Fernández Poyatos 26a4dd4e8d chore: bump h2 to 4.3.0 (#8573) 2025-08-26 15:17:06 +02:00
Alejandro Bailo dab0cea2dd feat(ui): Security Hub (#8552) 2025-08-26 14:30:45 +02:00
Daniel Barranquero 3b42eb3818 fix(s3): resource metadata error in s3_bucket_shadow_resource_vulnerability (#8572) 2025-08-26 13:30:49 +02:00
Prowler Botandprowler-bot a5ba950627 chore(regions_update): Changes in regions for AWS services (#8567)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-08-26 09:57:45 +02:00
Andoni Alonso a1232446c1 docs: refactor several sections (#8570) 2025-08-26 09:55:18 +02:00
Pedro MartínandAndoni A. aa6f851887 docs(aws): deploying prowler iam roles across aws organizations (#8427)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-08-26 09:45:14 +02:00
Adrián Jesús Peña Rodríguez 25f972e910 feat(sh): create asff of there is an enabled SecurityHub integration (#8569) 2025-08-25 16:58:21 +02:00
Pedro Martín 7216e5ce3d chore(github): improve pull request template (#7910) 2025-08-25 16:22:55 +02:00
Adrián Jesús Peña Rodríguez 83242da0ab feat(integrations): implement AWS Security Hub integration (#8365) 2025-08-25 15:53:48 +02:00
Alejandro Bailo d457166a0c fix(ui): AWS form selector default values (#8553) 2025-08-25 12:30:02 +02:00
Daniel Barranquero 88f38b2d2a feat(docs): remove old requirements links (#8561) 2025-08-22 14:22:50 +02:00
Pepe Fagoaga c2e0849d5f fix(conflict-checker): use prowler-bot (#8560) 2025-08-22 17:27:44 +05:45
Andoni Alonso 1fdebfa295 docs: remove "Requirements" page (#8559) 2025-08-22 15:55:25 +05:45
Sergio GarciaandAdrián Jesús Peña Rodríguez ea6d04ed3a chore(securityhub): add static credentials and role assumption support (#8539)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-08-22 11:58:35 +02:00
Sergio Garcia 2167683851 feat(aws): add Resource Explorer enumeration actions (#8557) 2025-08-22 11:47:51 +02:00
Pepe Fagoaga 6324be31ab fix(api): poetry lock up to date with the SDK (#8558) 2025-08-22 11:05:14 +02:00
Alejandro Bailo 525f152e51 fix(ui): update authorization logic to match right paths (#8556) 2025-08-22 10:35:28 +02:00
Sergio GarciaandAndoni A. c3a2d79234 chore(iac): change engine to trivy (#8466)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-08-22 10:17:51 +02:00
Andoni Alonso cefa708322 docs: add provider bulk provisioning (#8551) 2025-08-21 16:33:45 +02:00
Andoni Alonso 1a9e14ab2a chore(bulk-provisioning-tool): add script to bulk provision providers (#8540) 2025-08-21 13:11:46 +02:00
Chandrapal BadshahandChandrapal Badshah b1c6094b6d fix: Remove temperature for GPT-5 models (#8550)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-21 12:40:49 +02:00
Pablo Lara 1038b11fe3 docs: update changelog (#8549) 2025-08-21 12:22:27 +02:00
Chandrapal BadshahandChandrapal Badshah d54e3b25db fix: Refactor getting lighthouse config (#8546)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-21 11:14:21 +02:00
Pepe Fagoaga 6a8e8750bb chore(actions): conflict checker (#8547) 2025-08-21 14:28:18 +05:45
Hugo Pereira Brito ad3d4536fb fix(m365): only evaluate enabled users in entra_users_mfa_capable (#8544) 2025-08-20 16:45:00 +02:00
Andoni Alonso 46c24055ee docs: refactor Overview into several files (#8543) 2025-08-20 17:44:06 +05:45
Pepe Fagoaga 4c6a1592ac chore(actions): update docs comment with link (#8448) 2025-08-20 17:42:32 +05:45
Hugo Pereira BritoandMrCloudSec 89e657561c feat(github): add User Email and APP name/installations information (#8501)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-20 12:26:38 +02:00
Hugo Pereira BritoandMrCloudSec 55099abc86 fix(organization): list all accessible organizations (#8535)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-20 12:13:01 +02:00
Andoni Alonso 3c599a75cc feat(iam): add ECS privilege escalation patterns to IAM checks (#8541) 2025-08-20 09:23:30 +02:00
f77897f813 feat: gpt-5 and gpt-5-mini integration with lighthouse (#8527)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-08-19 16:49:21 +02:00
Sergio Garcia 30518f2e0e feat(aws): new check eks_cluster_deletion_protection_enabled (#8536) 2025-08-19 10:25:24 +02:00
Chandrapal BadshahandChandrapal Badshah efdeb431ba feat: Add resource agent to supervisor (#8509)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-19 09:40:14 +02:00
Sergio Garcia bb07cf9147 fix(aws): exact match in resource-arn filtering (#8533) 2025-08-18 12:11:13 +02:00
Prowler Botandprowler-bot 9214b5c26f chore(regions_update): Changes in regions for AWS services (#8531)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-08-18 11:58:41 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d57df3cc28 chore(deps): bump actions/upload-artifact from 4.5.0 to 4.6.2 (#8154)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 11:43:41 +02:00
Andoni Alonso 2f5fce41dc feat(iam): remove standalone iam:PassRole from privesc detection and add missing patterns (#8530) 2025-08-18 11:35:14 +02:00
Chandrapal BadshahandChandrapal Badshah 6918a75449 fix: add business context to lighthouse chat (#8528)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-18 09:49:23 +02:00
Pablo Lara 3aeaa3d992 feat(filters): improve provider connection filter UX (#8520) 2025-08-18 09:10:16 +02:00
Sergio Garcia fd833eecf0 fix(github): solve Github APP auth method (#8529) 2025-08-18 08:35:19 +02:00
Andoni Alonso 39e4d20b24 feat(iam): add Bedrock AgentCore privilege escalation combo (#8526) 2025-08-15 13:25:15 +02:00
Sergio Garcia dfdd45e4d0 fix(github): list all accessible repositories (#8522) 2025-08-14 10:38:38 +02:00
Hugo Pereira Brito 81478dfed3 fix(compliance): GitHub CIS 1.0 (#8519) 2025-08-13 16:45:36 +02:00
Chandrapal BadshahandChandrapal Badshah 2854f8405c fix: simplify error handling to use only error.message (#8518)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-13 10:59:47 +02:00
Jaen-923andghkim583 0e1578cfbc chore(aws): Refine kisa isms-p compliance mapping (#8479)
Co-authored-by: ghkim583 <203069125+ghkim583@users.noreply.github.com>
2025-08-13 09:08:37 +02:00
Hugo Pereira Brito f5b1532647 fix(kafka): false positives in kafka_cluster_is_public check (#8514) 2025-08-13 09:05:09 +02:00
Sergio Garcia d9f3a6b88e docs(github): add Github onboarding documentation (#8510) 2025-08-12 17:11:30 +02:00
Hugo Pereira BritoandSergio Garcia b0c386fc60 fix(app): fix false positives in app_http_logs_enabled (#8507)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-08-12 14:47:17 +02:00
Hugo Pereira Brito 72b06261df fix(storage): fall positives in storage_geo_redundant_enabled (#8504) 2025-08-12 12:30:43 +02:00
sumit-tftandPablo Lara 1562b77581 fix(ui): redirection after deleting providers group and improve erro… (#8389)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-08-12 11:31:45 +02:00
Daniel Barranquero 10e38ca407 fix: missing resource_name in GCP and Azure Defender checks (#8352) 2025-08-11 16:16:08 +02:00
Rubén De la Torre VicoandMrCloudSec 5842f2df37 feat(azure/vm): add new check vm_jit_access_enabled (#8202)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-11 13:12:36 +02:00
Prowler Botandprowler-bot 8b3b9ffd99 chore(regions_update): Changes in regions for AWS services (#8499)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-08-11 12:00:02 +02:00
Rubén De la Torre VicoandMrCloudSec d238050065 feat(azure/vm): add new check vm_sufficient_daily_backup_retention_period (#8200)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-11 11:44:45 +02:00
sumit-tft 5572d476ad fix(ui): adjust table headers to be single-line and consistent (#8480) 2025-08-11 10:47:10 +02:00
sumit-tftandPablo Lara 3c94d3a56f fix(ui): disable See Compliance button until scan completes (#8487)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-08-11 10:37:35 +02:00
Hugo Pereira BritoandSergio Garcia 85af4ff77c feat(m365): add certificate auth method to cli (#8404)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-08-11 09:47:56 +02:00
Daniel Barranquero dcee114ef3 fix: validation errors in azure and m365 (#8368) 2025-08-11 09:42:30 +02:00
Pedro MartínandSergio Garcia 760723874c fix(prowler-threatscore): order the requirements by id (#8495)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-08-11 08:20:10 +02:00
Pedro Martín c0a4898074 chore(changelog): update (#8496) 2025-08-11 07:48:23 +02:00
Alejandro BailoandPablo Lara 03c0533b58 feat(ui): overview charts display improved (#8491)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-08-08 10:59:15 +02:00
sumit-tftandPablo Lara c8dcb0edb0 feat(ui): add GitHub submenu under High Risk Findings (#8488)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-08-08 10:36:36 +02:00
Pablo Lara 82171ee916 docs: update changelog (#8489) 2025-08-08 10:20:53 +02:00
df4bf18b97 feat(ui): add Mutelist menu item under Configuration (#8444)
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-08-08 09:09:37 +02:00
Alejandro Bailo 94e60f7329 fix(ui): assume role fields shown (#8484) 2025-08-07 17:44:46 +02:00
Rubén De la Torre VicoandClaude f1ba5abbec chore(docs): update provider statistics in README.md (#8483)
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-07 17:10:56 +02:00
Hugo Pereira BritoandMrCloudSec 6cc1a9a2cb fix(compliance): delete invalid requirements for GitHub CIS 1.0 (#8472)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-07 20:51:20 +07:00
Pablo Lara 31f98092bf feat(ui): add provider type filter to providers page (#8473) 2025-08-07 14:34:04 +02:00
Pepe Fagoaga 85197036ca chore(env): Update NEXT_PUBLIC_PROWLER_RELEASE_VERSION (#8476) 2025-08-07 17:50:18 +05:45
Pepe Fagoaga be43025f00 fix(actions): always get latest SDK reference (#8474) 2025-08-07 17:38:40 +05:45
César Arroba c6b34f0a85 chore(api): open PR with API prowler version (#8475) 2025-08-07 13:49:39 +02:00
Prowler Botandprowler-bot 675698a26a chore(release): Bump version to v5.11.0 (#8470)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-08-07 12:40:55 +02:00
8d9bf2384f docs: S3 tutorial documentation (#8414)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-08-07 16:04:42 +05:45
César Arroba ff900a2a45 chore(gha): use prowler-bot for push in action (#8469) 2025-08-07 10:50:58 +02:00
César Arroba a41663fb0d chore(gha): fix release preparation workflow (#8468) 2025-08-07 10:41:16 +02:00
César Arroba 033e9fd58c chore(gha): fix release preparation workflow (#8467) 2025-08-07 10:36:22 +02:00
240b02b498 feat(ui): add SAML documentation link in config modal (#8461)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
2025-08-07 10:23:07 +02:00
Rubén De la Torre Vico 87eb2dfdf7 chore(changelog): move fixes from version 5.9.3 to 5.10 (#8464) 2025-08-07 13:43:56 +05:45
Alejandro Bailo b4d8d64f0e feat: update AWS role credentials form to set default credentials typ… (#8459) 2025-08-07 09:54:48 +02:00
Pablo Lara 7944ebe83a docs: update changelog (#8462) 2025-08-07 09:39:24 +02:00
Pepe Fagoaga bd138114c9 fix: changelog check update messages (#8465) 2025-08-07 13:22:54 +05:45
Adrián Jesús Peña Rodríguez d527a3f12b chore: update changelog (#8463) 2025-08-07 09:35:16 +02:00
Pepe Fagoaga 260fada3eb fix(s3): Use HeadBucket instead of GetBucketLocation (#8456) 2025-08-06 19:20:52 +05:45
Pepe Fagoaga 0ee0fc082a chore(s3): remove trailing 's' from docs helper (#8458) 2025-08-06 14:21:39 +02:00
Hugo Pereira Brito 9d66d86f66 fix(docs): m365 requirements Needed permissions link (#8457) 2025-08-06 13:51:16 +02:00
Alejandro Bailo 825e53c38f feat(ui): add a default Mutelist placeholder (#8455) 2025-08-06 13:11:31 +02:00
Daniel BarranqueroandSergio Garcia 196c17d44d feat(gcp): add retry to avoid quota limit errors (#8412)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-08-06 16:59:41 +07:00
Andoni AlonsoandSergio Garcia fc69e195e4 fix(github): handle GithubAppIdentityInfo in output generation (#8423)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-08-06 16:55:44 +07:00
Prowler Botandprowler-bot 5f53a9ec6f chore(regions_update): Changes in regions for AWS services (#8437)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-08-06 16:53:43 +07:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 5e72a40898 chore(deps): bump github/codeql-action from 3.29.2 to 3.29.5 (#8434)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-06 16:52:09 +07:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 496ada3cba chore(deps): bump trufflesecurity/trufflehog from 3.89.2 to 3.90.2 (#8433)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-06 16:51:42 +07:00
Adrián Jesús Peña Rodríguez 481a43f3f6 chore(integrations): remove unnecessary error alerts (#8453) 2025-08-06 09:16:26 +02:00
Pepe Fagoaga 58298706d4 docs(saml): IdP initiated flow (#8435) 2025-08-06 12:46:18 +05:45
Pepe Fagoaga e75a760da0 fix(ui): cfn quick link (#8452) 2025-08-05 22:42:57 +05:45
Pepe Fagoaga c313757ef2 fix(templates): only one cloudformation template (#8451) 2025-08-05 18:17:50 +02:00
Adrián Jesús Peña Rodríguez 284678fe48 fix(export): remove static timestamp (#8449) 2025-08-05 18:12:04 +02:00
Alejandro Bailo c3d25e6f39 feat(ui): S3 integrations pagination added (#8450) 2025-08-05 18:11:32 +02:00
Adrián Jesús Peña Rodríguez a9d16bbbce chore: change output folder (#8447) 2025-08-05 14:07:35 +02:00
Pepe Fagoaga 92bc992e7f feat(s3): templates for permissions (#8395) 2025-08-05 17:36:04 +05:45
Alejandro Bailo 903e4f8b9f feat(integrations): add enabled attribute to S3 integration (#8446) 2025-08-05 13:13:58 +02:00
Alejandro Bailo 2c09076f91 feat: output_directory default value added (#8445) 2025-08-05 12:20:31 +02:00
Adrián Jesús Peña Rodríguez 3d4902b057 feat(integrations): integrations enabled by default (#8439) 2025-08-05 11:25:42 +02:00
Chandrapal BadshahandChandrapal Badshah b30eab7935 fix: Don't invoke tools if no providers or completed scans (#8443)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-05 09:32:35 +02:00
sumit-tftandPablo Lara cf8402e013 feat(ui): add notification system (#8394)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-08-05 09:06:15 +02:00
af8fbaf2cd docs(mutelist): improve mutelist docs across all the providers (#8397)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-08-05 08:38:50 +02:00
Alejandro BailoandPepe Fagoaga c748e57878 feat: manage integration permission behavior (#8441)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-08-04 17:49:04 +02:00
Alejandro Bailo a5187c6a42 feat(ui): S3 integration retouches (#8438) 2025-08-04 16:04:10 +02:00
Alejandro Bailo e19ed30ac7 feat(UI): xml validation (#8429) 2025-08-04 12:09:18 +02:00
Hugo Pereira Brito 96ce1461b9 chore(sentry): add powershell user auth module connection errors to ignored list (#8420) 2025-08-04 11:58:05 +02:00
Alejandro Bailo 9da5fb67c3 feat(ui): S3 integration (#8391) 2025-08-04 11:43:14 +02:00
Chandrapal BadshahandChandrapal Badshah eb1c1791e4 fix: clear only last message on error (#8431)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-08-04 10:33:45 +02:00
581afd38e6 fix: add default values for S3 class (#8417)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-01 13:50:51 +02:00
sumit-tft 19a735aafe chore(ui): remove misconfigurations from Top Failed Findings in the s… (#8426) 2025-08-01 12:47:17 +02:00
Paul NegeduandMrCloudSec 2170fbb1ab feat(aws): add s3_bucket_shadow_resource_vulnerability check (#8398)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-08-01 18:26:03 +08:00
Pablo Lara 90c6c6b98d feat: add new provider GitHub and update enum source of truth (#8421) 2025-08-01 10:03:47 +02:00
sumit-tft 02b416b4f8 chore(ui): remove browse all resources from the sidebar (#8418) 2025-07-31 16:13:30 +02:00
Hugo Pereira Brito 1022b5e413 chore(docs): add a step to check development guide (#8416) 2025-07-31 12:45:15 +02:00
Pablo Lara d1bad9d9ab chore: rename menu item (#8415) 2025-07-31 12:10:07 +02:00
Rubén De la Torre Vico 178f3850be chore: add M365 provider to PR labeler (#8406) 2025-07-31 17:32:18 +08:00
Adrián Jesús Peña Rodríguez d239d299e2 fix(s3): use enabled to filter (#8409) 2025-07-31 10:00:05 +02:00
Pepe Fagoaga 88fae9ecae chore(ui): remove changelog entry (#8410) 2025-07-31 09:27:11 +02:00
Hugo Pereira Brito a3bff9705c fix(tests): github and iac providers arguments_test naming and structure (#8408) 2025-07-30 17:16:34 +02:00
César Arroba 75989b09d7 chore(gha): fix payload on merged PR action (#8407) 2025-07-30 16:59:40 +02:00
Pablo Lara 9a622f60fe feat(providers): add GitHub provider support with credential types (#8405) 2025-07-30 15:55:40 +02:00
Rubén De la Torre Vico 7cd1966066 fix(azure,m365): use default tenant domain instead of first domain in list (#8402) 2025-07-30 13:23:25 +02:00
Pedro Martín 77e59203ae feat(prowler-threatscore): remove and add requirements (#8401) 2025-07-30 13:09:51 +02:00
0a449c7e13 fix(lighthouse): Display errors in Lighthouse & allow resending message (#8358)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-07-30 12:32:48 +02:00
Adrián Jesús Peña Rodríguez 163fbaff19 feat(integrations): add s3 integration (#8056) 2025-07-30 12:05:46 +02:00
Sergio Garcia 7ec514d9dd feat(aws): new check bedrock_api_key_no_long_term_credentials (#8396) 2025-07-30 17:04:16 +08:00
Hugo Pereira Brito b63f70ac82 fix(m365): enhance execution to avoid multiple error calls (#8353) 2025-07-30 14:54:27 +08:00
2c86b3a990 feat: Add lighthouse banner (#8259)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-07-29 12:30:57 +02:00
Daniel Barranquero 12443f7cbb feat(docs): update m365 and azure docs (#8393) 2025-07-29 11:58:03 +02:00
Rubén De la Torre VicoandDaniel Barranquero 3a8c635b75 docs(dev-guide): add generic best practices for checks and services (#8074)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2025-07-29 11:04:26 +02:00
8bc6e8b7ab docs(getting-started): improve quality redrive (#7963)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-07-29 11:04:12 +02:00
9ca1899ebf docs(tutorials): improve quality redrive (#7915)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-07-29 11:03:52 +02:00
Sergio Garcia 1bdcf2c7f1 refactor(iac): revert importingcheckov as python library (#8385) 2025-07-29 15:55:28 +08:00
Pedro MartínandSergio Garcia 92a804bf88 fix(prowler-threatscore): remove typo from description req 1.2.3 - m365 (#8384)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-28 23:55:38 +08:00
ghkim583 f85ad9a7a2 chore(aws): minor fixes for the kisa isms-p compliance (#8386) 2025-07-28 17:51:20 +02:00
Pedro Martín 308c778bad fix(kisa): change the way of counting the PASS/FAILED reqs (#8382) 2025-07-28 21:56:58 +08:00
Jaen-923andghkim583 ee06d3a68a chore(aws): update kisa-isms-p compliance (#8367)
Co-authored-by: ghkim583 <203069125+ghkim583@users.noreply.github.com>
2025-07-28 21:55:50 +08:00
Andoni Alonso 8dc4bd0be8 feat(github): add repository and organization scoping support (#8329) 2025-07-28 21:43:41 +08:00
Pedro Martín bf9e38dc5c fix(docs): remove typo from getting started - github (#8380) 2025-07-28 20:18:13 +08:00
Aviad LevyandMrCloudSec a85b89ffb5 fix(ec2): add check that protocol is matched in security group checks (#8374)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-07-28 19:53:08 +08:00
César Arroba 87da11b712 chore(gha): delete repo limitation for bump workflow (#8379) 2025-07-28 13:22:19 +02:00
César Arroba 8b57f178e0 chore(gha): improve e2e pipeline (#8378) 2025-07-28 13:22:12 +02:00
Prowler Botandprowler-bot 7830ed8b9f chore(regions_update): Changes in regions for AWS services (#8376)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-07-28 17:56:48 +08:00
Kay Agahd d4e66c4a6f chore(sqs): clean up code (#8366) 2025-07-25 20:10:34 +08:00
Rubén De la Torre VicoandSergio Garcia 1cfe610d47 feat(azure/vm): add new check vm_scaleset_not_empty (#8192)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-25 18:42:03 +08:00
Rubén De la Torre VicoandSergio Garcia d9a9236ab7 feat(azure/vm): add new check vm_desired_sku_size (#8191)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-25 17:51:01 +08:00
Hugo Pereira Brito 285aea3458 fix(docs): change Exchange Administrator role to Global Reader for M365 (#8360) 2025-07-25 15:45:30 +08:00
César Arroba b051aeeb64 chore(gha): automate e2e tests with new workflow (#8361) 2025-07-24 16:54:01 +02:00
Pedro Martín b99dce6a43 feat(azure): add CIS 4.0 (#7782) 2025-07-24 22:29:46 +08:00
Andoni AlonsoandMrCloudSec 04749c1da1 fix(aws): sns_topics_not_publicly_accessible false positive with aws:SourceArn conditions (#8340)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-07-24 18:03:30 +08:00
Chandrapal BadshahandChandrapal Badshah 44d70f8467 fix(lighthouse): update prompt and tool schema for checks tool (#8265)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-07-24 10:50:36 +02:00
Andoni AlonsoandSergio Garcia 95791a9909 chore(aws): replace known errors with warnings (#8347)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-24 15:34:45 +08:00
sumit-tftandalejandrobailo ad0b8a4208 feat(ui): create CustomLink component and refactor links to use it (#8341)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-07-23 19:10:51 +02:00
5669a42039 fix(wazuh): patch command injection vulnerability in prowler-wrapper.py (#8331)
Co-authored-by: Test User <test@example.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-07-23 16:06:55 +02:00
Kay AgahdandHugo Pereira Brito 83b328ea92 fix(aws): avoid false positives in SQS encryption check for ephemeral queues (#8330)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-07-23 21:03:02 +08:00
Alejandro Bailo a6c88c0d9e test: timeout updated for E2E (#8351) 2025-07-23 13:11:32 +02:00
Sergio Garcia 922f9d2f91 docs(gcp): update GCP permissions (#8350) 2025-07-23 17:43:42 +08:00
a69d0d16c0 fix(azure/storage): handle when Azure API set values to None (#8325)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-23 17:11:04 +08:00
Alejandro Bailo 676cc44fe2 feat: env keys behavior updated (#8348) 2025-07-23 10:44:28 +02:00
Alejandro BailoandCésar Arroba 3840e40870 test(e2e): Sign-in (#8337)
Co-authored-by: César Arroba <cesar@prowler.com>
2025-07-22 18:04:54 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ab2d57554a chore(deps): bump form-data from 4.0.3 to 4.0.4 in /ui (#8346)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 17:53:32 +02:00
César Arroba cbb5b21e6c chore(gha): e2e tests pipeline with API services (#8338) 2025-07-22 17:49:23 +02:00
Sergio Garcia 1efd5668ce feat(api): add GitHub provider support (#8271) 2025-07-22 23:26:02 +08:00
Sergio Garcia ca86aeb1d7 feat(aws): new check bedrock_api_key_no_administrative_privileges (#8321) 2025-07-22 22:06:17 +08:00
Víctor Fernández Poyatos 4f2a8b71bb feat(performance): resources scenario (#8345) 2025-07-22 13:01:19 +02:00
Prowler Botandprowler-bot 3b0cb3db85 chore(regions_update): Changes in regions for AWS services (#8333)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-07-22 17:23:24 +08:00
Víctor Fernández Poyatos 00c527ff79 chore: update Prowler changelog for v5.9.2 (#8342) 2025-07-22 10:53:22 +02:00
Víctor Fernández Poyatos ab348d5752 feat(resources): Optimize findings prefetching during resource views (#8336) 2025-07-21 16:33:07 +02:00
Daniel Barranquero dd713351dc fix(defender): avoid duplicated findings in check defender_domain_dkim_enabled (#8334) 2025-07-21 13:07:26 +02:00
sumit-tftandalejandrobailo fa722f1dc7 feat(ui): add 32-character limit validation for scan name in create a… (#8319)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-07-21 10:00:25 +02:00
Pedro Martín b0cc3978d0 feat(docs): add info about updating Prowler App (#8320) 2025-07-21 07:44:07 +02:00
César Arroba aa843b823c chore(gha): fix action version (#8327) 2025-07-18 15:00:32 +02:00
Víctor Fernández Poyatos 020edc0d1d fix(tasks): calculate failed findings for resources during scan (#8322) 2025-07-18 13:19:22 +02:00
César Arroba 036da81bbd chore(gha): fix api prowler version (#8323) 2025-07-18 12:43:38 +02:00
sumit-tftandalejandrobailo 4428bcb2c0 feat(ui): update step title and description in cloud provider update … (#8303)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-07-18 10:11:44 +02:00
Prowler Botandprowler-bot 21de9a2f6f chore(release): Bump version to v5.10.0 (#8314)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-07-17 19:38:28 +02:00
231d933b9e chore(docs): SAML documentation (#8137)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-17 23:22:49 +05:45
Alejandro Bailo 2ad360a7f9 docs(ui): Mutelist documentation (#8201) 2025-07-17 23:15:20 +05:45
Víctor Fernández Poyatos 51b67f00d6 chore: update changelogs for v5.9.0 (#8313) 2025-07-17 17:15:58 +02:00
Pepe Fagoaga ab378684ae chore(ui): remove inventory group label (#8311) 2025-07-17 20:29:52 +05:45
e89df617ef chore(lighthouse): Rename to Lighthouse AI (#8262)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-07-17 16:25:32 +02:00
Alejandro Bailo 8496a6b045 fix: muted filter removed from url when value is true (#8310) 2025-07-17 19:12:36 +05:45
Pepe Fagoaga 28f3cf363b fix(actions): build API if the SDK changes (#8309) 2025-07-17 14:35:51 +02:00
Pepe Fagoaga eb3d4b25e3 chore: improve info in the download button (#8307) 2025-07-17 16:38:45 +05:45
Rubén De la Torre Vico 1211fe706e feat(azure/defender): add new check defender_attack_path_notifications_properly_configured (#8245) 2025-07-17 12:40:26 +02:00
Pedro MartínandPepe Fagoaga c4a9280ebb fix(m365): handle tenant_id in mutelist (#8306)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-17 12:37:13 +02:00
Alejandro Bailo 0f12fb92ed fix: Middleware redirection to /profile (#8305) 2025-07-17 11:49:24 +02:00
Víctor Fernández Poyatos ee974a6316 feat(tasks): Improve memory usage and performance in overview tasks (#8300) 2025-07-17 10:49:25 +02:00
d004a0c931 feat(ui): Add resources view as inventory (#7760)
Co-authored-by: sumit_chaturvedi <chaturvedi.sumit@tftus.com>
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-07-17 10:01:05 +02:00
Pepe Fagoaga 087e01cc4f fix(checks_loader): Handle multiple services and severities (#8302) 2025-07-17 13:39:29 +05:45
74940e1fc4 fix(check_metadata): add service name validator (#8289)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-07-17 13:10:30 +05:45
Hugo Pereira Brito 19e35bf9a8 feat: add new check entra_intune_enrollment_sign_in_frequency_every_time (#8223) 2025-07-16 17:13:50 +02:00
César Arroba 7213187e6c chore(gha): add target_commitish to the release creation step (#8297) 2025-07-16 16:07:06 +02:00
Pedro Martín 4b104e92f0 chore(prowler-threatscore): improve the way of calculating the score (#8264) 2025-07-16 15:26:44 +02:00
Hugo Pereira Brito 7179119b0e fix(outputs): identity type and id for prowler cloud (#8243) 2025-07-16 15:23:46 +02:00
César Arroba cf2738810a chore(gha): prowler release preparation workflow (#8268) 2025-07-16 13:45:34 +02:00
Samuele Pasini 389216570a fix: typo documentdb service name (#8293) 2025-07-16 18:39:19 +08:00
Alejandro Bailo 2becf45f33 feat: Next.js middleware improved (#8295) 2025-07-16 12:39:05 +02:00
Sergio Garcia c32ce7eb97 fix(azure): use Subscription ID for mutelist (#8290) 2025-07-16 18:34:38 +08:00
sumit-tftandAlejandro Bailo 94e66a91a6 feat(ui): add link in Scans view to navigate to Compliance overview (#8251)
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
2025-07-16 12:34:21 +02:00
sumit-tftandAlejandro Bailo 1ac4417f74 feat(ui): add status column to findings table in compliance detail view (#8244)
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
2025-07-16 12:23:40 +02:00
Hugo Pereira Brito 57c5f7c12d fix(networkfirewall): ServiceName in checks metadata (#8291) 2025-07-16 16:59:42 +08:00
Alejandro Bailo 19203f92b3 feat: menu label hidden in side-menu if no items (#8292) 2025-07-16 14:37:56 +05:45
Alejandro Bailo c5b1bf3e52 feat: allow to restrict routes based on permissions (#8287) 2025-07-16 14:21:45 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f845176494 chore(deps): bump aiohttp from 3.11.18 to 3.12.14 in /api (#8276)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-16 10:21:06 +02:00
Daniel Barranquero f0ed866946 fix(entra): entra_users_mfa_capable check report (#8288) 2025-07-16 16:06:36 +08:00
Alejandro BailoandPepe Fagoaga 834a7d3b69 fix(scans): capture 403 when no permissions (#8280)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-15 21:43:50 +05:45
Pepe Fagoaga 24a50c6ac2 fix(schedules): returns 409 on conflict (#8258) 2025-07-15 21:29:05 +05:45
Víctor Fernández Poyatos ec8afd773f fix(overviews): apply RBAC to providers overview (#8277) 2025-07-15 17:31:25 +02:00
Rubén De la Torre Vico a09be4c0ba chore(azure/defender): get security contacts from API REST (#8241) 2025-07-15 16:37:43 +02:00
Andoni AlonsoandMrCloudSec 4b62fdcf53 feat(iac): add support for remote repos (#8193)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-07-15 22:08:27 +08:00
Kay AgahdandMrCloudSec bf0013dae3 fix(aws): make is_service_role more restrictive to avoid false positives (#8274)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-07-15 22:02:09 +08:00
Hugo Pereira BritoandAndoni A. c82cd5288c feat(docs): add new docker pull issues section (#7972)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-07-15 16:00:08 +02:00
Sergio Garcia ad31a6b3f5 chore(hadolint): run only when necessary (#8284) 2025-07-15 21:53:05 +08:00
Rubén De la Torre Vico 20c7c9f8de fix(dashboard): count rows in the CSV more efficiently (#8257) 2025-07-15 15:40:36 +02:00
Daniel Barranquero 0cfe41e452 fix(dynamodb): update broken link in dynamodb_tables_kms_cmk_encryption_enabled (#8273) 2025-07-15 14:54:14 +02:00
Hugo Pereira BritoandAndoni A. 1b254feadc feat(docs): add getting-started page (#8275)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-07-15 14:11:20 +02:00
Matt KeelerandSergio Garcia 15954d8a01 fix: reword iam_user_accesskey_unused title & description (#8233)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-15 20:02:34 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ff122c9779 chore(deps): bump aiohttp from 3.12.13 to 3.12.14 (#8278)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-15 19:45:03 +08:00
Daniel Barranquero a012397e55 fix(dashboard): security posture showing incomplete data (#8270) 2025-07-15 13:19:55 +02:00
Sergio Garcia 7da6d7b5dd chore(github): add test_connection function (#8248) 2025-07-15 17:01:40 +08:00
Víctor Fernández Poyatos db6a27d1f5 feat(resources): latest and metadata endpoints and performance (#8112) 2025-07-14 18:02:06 +02:00
Alejandro BailoandPepe Fagoaga e07c833cab feat: SAML toast error (#8267)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-14 17:04:23 +02:00
Adrián Jesús Peña Rodríguez 728fc9d6ff fix(saml): remove user in case of error (#8260) 2025-07-14 14:07:27 +02:00
Prowler Botandprowler-bot cf9ff78605 chore(regions_update): Changes in regions for AWS services (#8263)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-07-14 19:45:38 +08:00
Adrián Jesús Peña Rodríguez a2faf548af chore: update changelog (#8255) 2025-07-11 12:06:03 +02:00
Adrián Jesús Peña Rodríguez 8bcec4926b fix: set lxml version (#8253) 2025-07-11 11:43:31 +02:00
Hugo Pereira Brito a4e96f809b fix(docs): GitHub provider mkdocs and -h (#8246) 2025-07-11 16:32:15 +08:00
Adrián Jesús Peña Rodríguez fa27255dd7 chore(saml): redirect to login page on fail (#8247) 2025-07-11 09:22:38 +02:00
Pepe Fagoaga 05360e469f chore(bump): add no-changelog label (#8240) 2025-07-10 19:14:37 +08:00
Hugo Pereira Brito 9d405ddcbd fix: changelog entries with new specification (#8232) 2025-07-10 14:40:33 +05:45
Víctor Fernández Poyatos 430f831543 feat(exceptions): add custom error for provider connection during scans (#8234) 2025-07-10 14:13:19 +05:45
Pepe Fagoaga da9d7199b7 chore(changelog): add missing entry from the password policy (#8236) 2025-07-10 09:07:04 +02:00
Pepe Fagoagaandalejandrobailo d63a383ec6 feat(security): password strength (#8225)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2025-07-10 11:50:22 +05:45
Víctor Fernández Poyatos 55c226029e feat(resources): optimize include parameters for resources view (#8229) 2025-07-09 16:16:56 +02:00
Alejandro Bailo 8d2f6aa30c feat: Include/exclude muted findings (#8228) 2025-07-09 16:06:05 +02:00
Rubén De la Torre VicoandSergio Garcia a319f80701 feat(storage): add new check storage_smb_protocol_version_is_latest (#8128)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-09 17:28:00 +08:00
Adrián Jesús Peña Rodríguez 15a8671f0d feat(saml): prevent duplicate SAML entityID configuration (#8224) 2025-07-09 09:50:22 +02:00
Rubén De la Torre Vico d34e709d91 fix(azure/storage): use BaseModel for all Storage models (#8222) 2025-07-09 15:49:17 +08:00
Hugo Pereira Brito ddc53c3c6d fix(firehose): list all streams and fix firehose_stream_encrypted_at_rest logic (#8213) 2025-07-09 15:38:54 +08:00
a3aef18cfe feat: Mutelist implementation (#8190)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
Co-authored-by: Drew Kerrigan <drew@prowler.com>
2025-07-09 08:15:23 +02:00
Alejandro Bailo 49ca3ca325 fix: SAML 403 message (#8221) 2025-07-09 08:10:14 +02:00
89c67079a3 feat: Processors API endpoint, implement MuteList (#7993)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-08 21:33:28 +05:45
Pepe Fagoaga 2de8075d87 fix(overview): use findings latest to get new (#8219) 2025-07-08 15:48:19 +02:00
Adrián Jesús Peña Rodríguez e124275dbf fix(saml): ensure SocialApp and SAMLDomainIndex are deleted with SAMLConfiguration (#8210) 2025-07-08 13:57:23 +02:00
Rubén De la Torre Vico 760d28e752 chore(deps): update dash libs (#8215) 2025-07-08 19:55:50 +08:00
Víctor Fernández Poyatos 3fb0733887 feat(tasks): create overview queue for summaries and overviews (#8214) 2025-07-08 13:53:23 +02:00
Pablo LaraandPepe Fagoaga 7de9a37edb fix(api): make invitation email comparison case-insensitive (#8206)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-08 16:39:27 +05:45
Pepe FagoagaandVíctor Fernández Poyatos fe00b788cc fix: Remove type validation while updating provider credentials (#8197)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-07-08 15:27:02 +05:45
Rubén De la Torre VicoandSergio Garcia 4c50f4d811 feat(azure/vm): add new check vm_backup_enabled (#8182)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-08 17:01:22 +08:00
Rubén De la Torre Vico c0c736bffe chore: ignore some files from AI editors (#8209) 2025-07-08 10:43:38 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> a3aa7d0a63 chore(deps): bump python from 3.12.10-slim-bookworm to 3.12.11-slim-bookworm (#8157)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-08 16:43:13 +08:00
Rubén De la Torre Vico 3ceb86c4d9 feat(azure/vm): add new check vm_scaleset_associated_load_balancer (#8181) 2025-07-08 16:40:43 +08:00
Rubén De la Torre Vico 3628e7b3e8 feat(azure/vm): add new check vm_ensure_using_approved_images (#8168) 2025-07-08 16:40:33 +08:00
f29c2ac9f0 docs(lighthouse): Add Lighthouse Docs (#8196)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-08 11:56:23 +05:45
Pablo Lara b4927c3ad1 chore: Update CHANGELOG UI (#8204) 2025-07-07 17:54:44 +02:00
Adrián Jesús Peña Rodríguez 19f3c1d310 chore(saml): restore SAML button (#8203) 2025-07-07 17:34:05 +02:00
Adrián Jesús Peña Rodríguez cd97e57521 fix(saml): restore SAML, deactivate urls, enable idp-initiate (#8175) 2025-07-07 16:42:11 +02:00
Hugo Pereira BritoandSergio Garcia b38207507a chore(docs): enhance M365 auth documentation (#8199)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-07 22:01:41 +08:00
Rubén De la Torre Vico ab96e0aac0 feat(azure/vm): add new check vm_linux_enforce_ssh_authentication (#8149) 2025-07-07 22:01:11 +08:00
Prowler Botandprowler-bot 4477cecc59 chore(regions_update): Changes in regions for AWS services (#8198)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-07-07 18:04:49 +08:00
Pablo Lara 641d671312 chore: upgrade to Next.js 14.2.30 and lock TypeScript to 5.5.4 for ES… (#8189) 2025-07-04 13:20:30 +02:00
Víctor Fernández Poyatos e7c2fa0699 fix(findings): avoid backfill on empty scans (#8183) 2025-07-04 12:24:49 +02:00
Pedro Martín 7eb08b0f14 fix(ec2): allow empty values for http_endpoint in templates (#8184) 2025-07-04 18:03:51 +08:00
Rubén De la Torre VicoandSergio Garcia 6f3112f754 feat(storage): add new check storage_smb_channel_encryption_with_secure_algorithm (#8123)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-04 15:26:33 +08:00
Kay AgahdandSergio Garcia f5ecae6da1 fix(iam): detect wildcarded ARNs in sts:AssumeRole policy resources (#8164)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-03 23:09:48 +08:00
Prowler Botandprowler-bot 1c75f6b804 chore(release): Bump version to v5.9.0 (#8178)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-07-03 23:08:37 +08:00
Daniel BarranqueroandSergio Garcia 91b64d8572 chore(docs): update m365 docs for app auth in cloud (#8147)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-07-03 23:08:15 +08:00
Pablo Lara 233ae74560 fix: disable dynamic filters for now (#8177) 2025-07-03 14:17:02 +02:00
Alejandro Bailo fac97f9785 fix: remove duplicated calls during promise all resolving (#8176) 2025-07-03 14:02:57 +02:00
Pablo Lara e81c7a3893 fix: bug when updating credentials for m365 (#8173) 2025-07-03 11:31:40 +02:00
Adrián Jesús Peña RodríguezandVíctor Fernández Poyatos d6f26df2e8 refactor(migrations): remove saml migrations (#8167)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-07-02 17:23:08 +02:00
Sergio Garcia ece74e15fd chore(sdk): update changelog (#8166) 2025-07-02 16:11:48 +02:00
sumit-tftandPablo Lara eea6d07259 chore(ui): update capitalization of Sign In and Sign Up to match UI s… (#8136)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-07-02 16:01:29 +02:00
Víctor Fernández Poyatos 4a6d7a5be2 chore: bump API changelog to v5.8.0 (#8165) 2025-07-02 16:00:43 +02:00
Alejandro Bailo 883c5d4e56 feat: client side validation (#8161) 2025-07-02 15:43:20 +02:00
Adrián Jesús Peña Rodríguez f1f998c2fa chore: update spec (#8162) 2025-07-02 13:19:57 +02:00
Adrián Jesús Peña Rodríguez 5276e38f1d chore: disable SAML endpoints (#8160) 2025-07-02 12:51:57 +02:00
Pablo Lara ad98a4747f chore: Hide all SAML config for v5.8 (#8159) 2025-07-02 12:46:04 +02:00
Alejandro Bailo 5798321dc6 feat: saml e2e improvements (#8158) 2025-07-02 11:57:56 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> bf58728d29 chore(deps-dev): bump brace-expansion from 1.1.11 to 1.1.12 in /ui (#8003)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 11:25:17 +02:00
Sergio GarciaandRubén De la Torre Vico fcea3b6570 docs(iac): add documentation for IaC (#8150)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-07-02 17:20:34 +08:00
Neil MillardandMrCloudSec 965111245a feat(aws): add new check for Codebuild projects visibility (#8127)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-07-02 17:20:15 +08:00
Rubén De la Torre Vico f78a29206c fix(azure): use Pydantic models in VM service and fix managed disk logic (#8151) 2025-07-02 16:23:51 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> c719d705e0 chore(deps): bump trufflesecurity/trufflehog from 3.88.35 to 3.89.2 (#8156)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 15:36:10 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 8948ee6868 chore(deps): bump docker/setup-buildx-action from 3.10.0 to 3.11.1 (#8153)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 15:29:21 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 24fb31e98f chore(deps): bump github/codeql-action from 3.28.18 to 3.29.2 (#8155)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 14:24:12 +08:00
Adrián Jesús Peña Rodríguez c8b193e658 fix(saml): add user to SAML tenant (#8152) 2025-07-01 18:41:16 +02:00
Alejandro Bailo 6d27738c4d fix: HotFIX related with ACS SAML url (#8148) 2025-07-01 13:10:46 +02:00
Adrián Jesús Peña Rodríguez 17b7becfdf fix(saml): limit attributes length to satisfy the socialapp restriction (#8145) 2025-07-01 12:03:20 +02:00
Alejandro Bailo cfa7f271d2 fix: Minor changes detected while SAML E2E (#8146) 2025-07-01 11:50:47 +02:00
Pedro Martín e61a97cb65 fix(api): handle ISO27001 - M365 in exports (#8143) 2025-07-01 10:19:56 +02:00
Pablo LaraandPepe Fagoaga cd4a1ad8a7 chore: clarify M365 context due to credential changes (#8144)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-07-01 09:01:17 +02:00
Alejandro Bailo e650d19a30 feat: enhance getScans API to support fields and include parameters; … (#8140) 2025-07-01 08:13:48 +02:00
Pedro Martín f930739a3d fix(ui): remove typo from compliance detailed view (#8142) 2025-06-30 18:03:45 +02:00
Sergio Garcia 89fc698a0e fix(m365): handle none attribute in exchange transport rule (#8141) 2025-06-30 23:13:18 +08:00
Pablo Lara 6acb6bbf8e docs: update changelog (#8139) 2025-06-30 16:34:03 +02:00
971424f822 fix: ACS dynamic url and password input visible in sign up (#8131)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-06-30 16:17:34 +02:00
Adrián Jesús Peña Rodríguez 9ba1ae1ced restore: change api redirect (#8138) 2025-06-30 16:15:25 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 062db4cc70 chore(deps): bump protobuf from 6.30.2 to 6.31.1 in /api (#8053)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-30 21:05:10 +08:00
Pepe Fagoaga dc4db10c41 fix(version): only for master branch (#7850) 2025-06-30 16:50:32 +05:45
Rubén De la Torre Vico 68a542ef64 chore(CHANGELOG): put all checks entries in same format (#8134) 2025-06-30 16:50:12 +05:45
32f3787e18 feat(m365powershell): add pwsh authentication via service principal (#7992)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-30 18:42:18 +08:00
Víctor Fernández Poyatos 6792bea319 fix(compliance): Avoid initializing Prowler provider (#8133) 2025-06-30 12:14:03 +02:00
Prowler Botandprowler-bot ae4b43c137 chore(regions_update): Changes in regions for AWS services (#8132)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-06-30 17:53:21 +08:00
Rubén De la Torre Vico d576c4f1c4 docs(developer-guide): add configurable checks documentation (#8122) 2025-06-30 16:47:27 +08:00
Pablo Lara ddc0596aa2 chore: tweaks for SAML config in profile page (#8130) 2025-06-30 09:40:02 +02:00
Rubén De la Torre Vico 636bdb6d0a docs(prowler-app): add new auth method for GCP (#8129) 2025-06-30 15:21:03 +08:00
Alejandro BailoandAdrián Jesús Peña Rodríguez 4a839b0146 feat: update SAML login URL handling and redirect logic (#8095)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-06-27 14:44:04 +02:00
Pablo Lara 73e244dce5 docs: update changelog (#8125) 2025-06-27 13:51:56 +02:00
Adrián Jesús Peña Rodríguez d8ed70236b refactor(s3): adapt test_connection to match AwsProvider (#8088) 2025-06-27 13:23:59 +02:00
Sergio GarciaandPedro Martín bcc96ab4f2 fix(gcp): handle case sensitivity in block-project-ssh-keys (#8115)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-06-27 19:03:51 +08:00
fd53a8c9d0 feat: Playright setup (#8107)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
Co-authored-by: César Arroba <19954079+cesararroba@users.noreply.github.com>
2025-06-27 11:47:21 +02:00
Daniel Barranquero 7b58d1dd56 fix: checks with no resource name (#8120) 2025-06-27 17:40:43 +08:00
Víctor Fernández Poyatos 7858c147f7 fix(spec): API specification (#8119) 2025-06-27 10:49:36 +02:00
Alejandro Bailo 8e635b3bd4 feat: saml sso ui integration (#8094) 2025-06-27 10:45:21 +02:00
Pedro Martín 2e97e37316 feat(dashboard): improve overview page (#8118) 2025-06-27 15:41:48 +08:00
Pedro Martín cd804836a1 docs(dev): add info about installing prowler for a branch (#8116) 2025-06-26 23:00:31 +08:00
Víctor Fernández Poyatos d102ee2fd5 chore: ignore Flask Safety alert in API (#8114) 2025-06-26 16:02:39 +02:00
Pedro Martín 325e5739a2 fix(compliance): handle latest assessment date for each account (#8108) 2025-06-26 17:48:35 +08:00
Sergio Garcia 98da3059b4 refactor(iac): import checkov python library (#8093) 2025-06-25 21:36:21 +08:00
Chandrapal BadshahandChandrapal Badshah 80fd5d1ba6 fix: update lighthouse chat page name (#8106)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-06-25 12:48:20 +02:00
Jack HollowayandMrCloudSec 85242c7909 fix(aws): retrieve correctly ECS Container insights settings (#8097)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-25 15:54:20 +08:00
Daniel BarranqueroandMrCloudSec ea6ab406c8 fix(organizations): Key Error: Statement in check organizations_scp_deny_regions (#8091)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-25 15:23:38 +08:00
Rubén De la Torre VicoandSergio Garcia cbf2a28bac feat(azure): add new check keyvault_access_only_through_private_endpoints (#8072)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-24 22:04:02 +08:00
Adrián Jesús Peña Rodríguez 5b1e7bb7f9 fix(saml): avoid IndexError when some attributes are not specified (#8089) 2025-06-24 15:55:01 +02:00
e108b2caed fix(aws): fix logic in VPC and ELBv2 checks (#8077)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-24 19:13:54 +08:00
Rubén De la Torre VicoandSergio Garcia df1abb2152 feat(azure): add new check monitor_alert_service_health_exists (#8067)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-24 18:04:20 +08:00
Rubén De la Torre Vico e0465f2aa2 fix(azure): consolidate file share properties to the storage account level (#8087) 2025-06-24 17:37:05 +08:00
Drew Kerrigan 51467767cd fix: allow raising exceptions from validate_mutelist (#8086) 2025-06-24 13:14:46 +05:45
Pablo Lara bc71e7fb3b chore: set filters panel to be always open by default (#8085) 2025-06-23 15:05:53 +02:00
sumit-tftandPablo Lara 6a331c05e8 fix(ui): resolve accessibility warnings for Sheet and SVG elements (#8019)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-23 13:25:05 +02:00
César Arroba 7ab503a096 chore(gha): avoid comment on PRs for check-changelog workflow (#8084) 2025-06-23 13:17:03 +02:00
César Arroba b368190c9f chore(gha): avoid comment on PRs for check-changelog workflow (#8083) 2025-06-23 19:13:13 +08:00
Víctor Fernández Poyatos 8915fdff18 fix(scan): set scheduler_task to null when removing periodic tasks (#8082) 2025-06-23 12:53:58 +02:00
Víctor Fernández Poyatos 9bf108e9cc tests(compliance): add performance tests for compliance (#8073) 2025-06-23 12:09:30 +02:00
Prowler Botandprowler-bot 87708e39cf chore(regions_update): Changes in regions for AWS services (#8079)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-06-23 17:54:27 +08:00
César Arroba 44927c44e9 chore(gha): add permissions on check-changelog workflow (#8080) 2025-06-23 11:49:48 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 71aa29cf24 chore(deps): bump urllib3 from 1.26.20 to 2.5.0 (#8063)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-23 17:49:20 +08:00
Víctor Fernández Poyatos aa14daf0db fix(schema): API reference documentation (#8078) 2025-06-23 11:04:25 +02:00
Daniel Barranquero eb5dbab86e feat(docs): update Azure and M365 docs with needed permissions (#8075) 2025-06-23 10:12:11 +02:00
Víctor Fernández Poyatos 223aab8ece chore(API): skip safety vulnerabilities related to asteval (#8076) 2025-06-20 14:28:23 +02:00
César Arroba 3ec57340a0 chore(gha): check changelog when label is added or deleted (#8071) 2025-06-20 16:35:19 +05:45
Pablo Lara 80d73cc05b feat: integrate Google Tag Manager manually to avoid ORB blocking (#8070) 2025-06-20 12:47:17 +02:00
César ArrobaandPepe Fagoaga 94f02df11e chore(gha): check changelog changes on pull request (#7991)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-06-19 14:51:59 +05:45
Pepe Fagoaga c454ceb296 fix(changelog): Add missing entries (#8066) 2025-06-19 14:12:39 +05:45
Pepe Fagoaga 76ec13a1d6 chore(ocsf): remove version number and point to the latest (#8064) 2025-06-19 13:33:28 +05:45
Pepe Fagoaga 783b6ea982 chore(api): clean up old files (#8051) 2025-06-19 11:57:48 +05:45
Alejandro BailoandPablo Lara 6b7b700a98 feat: filters relationships in findings and scans page (#8046)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-18 17:19:41 +02:00
César Arroba b3f2a1c532 chore(ui): add NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID variable on Dockerfile (#8061) 2025-06-18 16:31:55 +02:00
Sergio Garcia c4e1bd3ed2 fix: add missing changelog compliance timestamps (#8060) 2025-06-18 16:28:48 +02:00
Sergio Garcia d0d4e0d483 fix(compliance): use unified timestampt for all requirements (#8052) 2025-06-18 22:00:51 +08:00
Pablo Lara 14a9f0e765 feat: add Google Tag Manager integration (#8058) 2025-06-18 15:47:48 +02:00
Rubén De la Torre VicoandMrCloudSec b572575c8d feat(azure): add new check iam_role_user_access_admin_restricted (#8040)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-18 21:24:23 +08:00
Rubén De la Torre VicoandAndoni Alonso a626e41162 docs: add provider-specific developer guide sections (#7996)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-06-18 21:20:33 +08:00
Hugo Pereira Brito 22343faa1e feat(storage): add new check storage_default_to_entra_authorization_enabled (#7981) 2025-06-18 21:16:07 +08:00
Hugo Pereira Brito c5b37887ef chore: add pr to changelog (#8054) 2025-06-18 14:32:21 +02:00
Rubén De la Torre Vico f9aed36d0b feat(azure): add new check databricks_workspace_cmk_encryption_enabled (#8017) 2025-06-18 18:36:37 +08:00
Hugo Pereira BritoandSergio Garcia facc0627d7 feat(azure): add new check storage_geo_redundant_enabled (#7980)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-18 18:10:02 +08:00
Rubén De la Torre VicoandMrCloudSec 76f0d890e9 feat(azure): add Databricks service and check for workspace VNet injection (#8008)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-18 17:38:09 +08:00
Hugo Pereira Brito 7de7122c3b fix(m365): avoid user requests in setup_identity app context and user auth log enhancement (#8043) 2025-06-18 11:27:11 +02:00
Hugo Pereira BritoandSergio Garcia 1b73ab2fe4 feat(storage): add new check storage_cross_tenant_replication_disabled (#7977)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-18 15:54:13 +08:00
Rubén De la Torre VicoandSergio Garcia cc8f6131e6 feat(azure): add new check storage_blob_versioning_is_enabled (#7927)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-18 15:46:38 +08:00
Andoni AlonsoandSergio Garcia dfd5c9aee7 feat(aws): add check to ensure Codebuild Github projects are only use allowed Github orgs (#7595)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-18 00:17:18 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3986bf3f42 chore(deps): bump asteval from 1.0.5 to 1.0.6 (#8049)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-18 00:11:18 +08:00
Sergio Garcia c45ef1e286 chore(deps): update requests dependency (#8048) 2025-06-18 00:04:09 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 8d8f498dc2 chore(deps): bump asteval from 1.0.5 to 1.0.6 (#8047)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-17 23:32:13 +08:00
Sergio GarciaandAndoni Alonso c4bd9122d4 feat(IaC): PoC for IaC Security Scanner (#7852)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-06-17 23:23:25 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 644cdc81b9 chore(deps): bump requests from 2.32.3 to 2.32.4 in /api (#7986)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-17 16:46:29 +02:00
Pablo Lara e5584f21b3 feat: make user and password fields optional but mutually required fo… (#8044) 2025-06-17 14:46:00 +02:00
Rubén De la Torre Vico b868d39bef chore(deps): add pre-commit as a dev dependency (#8042) 2025-06-17 18:54:32 +08:00
Alejandro Bailo ef9809f61f fix: correct parenthesis around the render condition (#8041) 2025-06-17 12:22:17 +02:00
Alejandro BailoandPablo Lara 9a04ca3611 feat: touching up compliances views (#8022)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-17 11:23:14 +02:00
Pedro MartínandSergio Garcia 1c9b3a1394 feat(m365): add ISO 27001 2022 compliance framework (#7985)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-17 17:04:36 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 5ee7bd6459 chore(deps): bump protobuf from 6.30.2 to 6.31.1 (#8037)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-17 16:31:04 +08:00
Chandrapal BadshahandChandrapal Badshah 05d2b86ba8 feat(lighthouse): update NextJS logic to work with latest APIs (#8033)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-06-17 10:25:37 +02:00
Andoni Alonso 84c30af6f8 chore(sentry): handle exceptions ignores not based in ClassNames (#8034) 2025-06-17 09:42:24 +02:00
e8a829b75e docs(dev-guide): improve quality redrive (#7718)
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-06-17 09:28:22 +02:00
Sergio Garcia a0d169470d chore(metadata): add validator for ResourceType (#8035) 2025-06-17 00:06:32 +08:00
Rubén De la Torre Vico 1fd6046511 chore: add missing init file to check repository_secret_scanning_enabled (#8029) 2025-06-16 21:31:18 +08:00
Sergio GarciaandPepe Fagoaga 524455b0f3 fix(metadata): add missing ResourceType values (#8028)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-06-16 21:30:55 +08:00
Víctor Fernández Poyatos e6e1e37c1e fix(findings): exclude blank resource types from metadata endpoints (#8027) 2025-06-16 18:19:21 +05:45
Prowler Botandprowler-bot 2914510735 chore(regions_update): Changes in regions for AWS services (#8026)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-06-16 19:00:06 +08:00
7e43c7797f fix(eks): add EKS to service without subservices (#7959)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-16 16:46:48 +08:00
Rubén De la Torre Vico 6954ef880e fix(azure): add new way to auth against App Insight (#7763) 2025-06-16 16:46:36 +08:00
5f5e7015a9 feat(lighthouse): Add django endpoints to store config (#7848)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: Víctor Fernández Poyatos <vicferpoy@gmail.com>
2025-06-16 10:11:57 +02:00
Andoni Alonso bfafa518b1 feat(aws): avoid bypassing IAM check using wildcards (#7708) 2025-06-16 07:42:01 +02:00
Hugo Pereira BritoandSergio Garcia e34e59ff2d fix(network): allow 0 as compliant value (#7926)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-13 19:50:19 +08:00
Daniel Barranquero 7f80d2db46 fix(app): change api call for ftps_state (#7923) 2025-06-13 19:28:55 +08:00
sumit-tftandPablo Lara 4a2a3921da feat(UI): Add Provider detail component in Findings, Scan details (#7968)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-13 12:17:18 +02:00
Pedro MartínandVíctor Fernández Poyatos e26b2e6527 feat(api): handle MitreAttack compliance requirements (#7987)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-06-13 10:26:34 +02:00
Mitchell @ SecuremetricsandPedro Martín 954814c1d7 feat(contrib): add PowerBI integration (#7826)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-06-13 09:55:07 +02:00
Andoni Alonso 113224cbd9 chore: update CHANGELOG (#8015) 2025-06-13 15:38:56 +08:00
Andoni Alonso f5f1fce779 fix(iam): check always if root credentials are present (#7967) 2025-06-12 17:48:09 +02:00
Pepe FagoagaandPablo Lara 0ba9383202 chore(changelog): make all consistent (#8010)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-12 20:09:01 +05:45
Adrián Jesús Peña Rodríguez 8e9a9797c7 fix(export): add name sanitization (#8007) 2025-06-12 20:02:18 +05:45
Pablo Lara 2b4e6bffae chore: update package-lock after lighthouse was merged (#8011) 2025-06-12 15:32:58 +02:00
Chandrapal BadshahandChandrapal Badshah 74f7a86c2b feat(lighthouse): Add chat interface (#7878)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
2025-06-12 15:19:41 +02:00
Pablo Lara e218435b2f fix: improve error handling in UpdateViaCredentialsForm with early re… (#7988) 2025-06-12 11:39:49 +02:00
5ec34ad5e7 chore(regions_update): Changes in regions for AWS services (#7973)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-06-12 17:24:15 +08:00
Pedro MartínandSergio Garcia c4b0859efd fix(dashboard): handle account uids with 0 at start and end (#7955)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-12 17:21:52 +08:00
Pedro Martín 1241a490f9 fix(kubernetes): change object type to set for apiserver check (#7952) 2025-06-12 17:02:48 +08:00
Pedro Martín 4ec498a612 fix(k8s): remove typo for PCI 4.0 compliance framework (#7971) 2025-06-12 16:41:58 +08:00
Pedro MartínandSergio Garcia 119c5e80a9 feat(gcp): add NIS 2 compliance framework (#7912)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-06-12 16:40:33 +08:00
sumit-tft d393bc48a2 fix(PRWLR-7380): button nesting hydration error (#7998) 2025-06-12 10:02:20 +02:00
Daniel Barranquero e09e3855b1 fix(gcp): remove azure video from gcp docs (#8001) 2025-06-12 09:54:25 +02:00
Alejandro Bailo 8751615faa feat: MittreAtack compliance detailed view (#8002) 2025-06-12 09:27:47 +02:00
Prowler Botandprowler-bot e7c17ab0b3 chore(regions_update): Changes in regions for AWS services (#7898)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-06-12 15:14:28 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f05d3eb334 chore(deps): bump trufflesecurity/trufflehog from 3.88.26 to 3.88.35 (#7896)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 15:14:02 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> cf449d4607 chore(deps): bump aws-actions/configure-aws-credentials from 4.1.0 to 4.2.1 (#7895)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 15:13:35 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b338ac9add chore(deps): bump codecov/codecov-action from 5.4.2 to 5.4.3 (#7894)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 15:13:12 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 366d2b392a chore(deps): bump docker/build-push-action from 6.16.0 to 6.18.0 (#7893)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 15:12:52 +08:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 41fc536b44 chore(deps): bump github/codeql-action from 3.28.16 to 3.28.18 (#7892)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 15:12:28 +08:00
Adrián Jesús Peña Rodríguez e042445ecf fix(migration): create site stuff before socialaccount (#7999) 2025-06-11 13:34:21 +02:00
Víctor Fernández Poyatos c17129afe3 revert: RLS transactions handling and DB custom backend (#7994) 2025-06-11 14:47:10 +05:45
Alejandro Bailo 4876d8435c feat: generic compliance detailed view (#7990) 2025-06-11 09:40:53 +02:00
Pedro Martín 1bd0d774e5 feat(mutelist): make validate_mutelist method static (#7811) 2025-06-11 11:33:49 +05:45
Alejandro Bailo c119cece89 feat: ThreatScore compliance detailed view (#7979) 2025-06-10 10:43:27 +02:00
Adrián Jesús Peña Rodríguez e24b211d22 feat(sso): add sso with saml to API (#7822) 2025-06-10 10:17:54 +02:00
Hugo Pereira BritoandAndoni Alonso c589c95727 feat(storage): add new check storage_account_key_access_disabled (#7974)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-06-10 08:23:09 +02:00
Hugo Pereira Brito 7e4f1a73bf feat(storage): add new check storage_ensure_file_shares_soft_delete_is_enabled (#7966) 2025-06-10 08:09:11 +02:00
Pepe Fagoaga 4d00aece45 chore(changelog): move entry for their version (#7969) 2025-06-09 21:50:13 +05:45
Hugo Pereira Brito 49aaf011aa fix(parser): add GitHub provider to prowler -h usage section (#7906) 2025-06-09 17:47:29 +02:00
Adrián Jesús Peña Rodríguez 898934c7f8 chore: update django version (#7984) 2025-06-09 17:33:16 +02:00
Pepe Fagoaga 81c4b5a9c1 chore(api): Delete old docker compose file (#7982) 2025-06-09 21:01:52 +05:45
Pepe Fagoaga fe31656ffe fix(k8s): return a session if using kubeconfig_content (#7953) 2025-06-09 19:11:59 +05:45
Hugo Pereira Brito 359059dee6 fix(docs): add Organization.Read.All to M365 provider requirements (#7961) 2025-06-09 12:11:14 +02:00
Alejandro Bailo 2eaa37921d feat: KISA detailed view (#7965) 2025-06-09 09:29:34 +02:00
Pablo Lara 3a99909b75 chore: align Next.js version to 14.2.29 across Prowler and Cloud (#7962) 2025-06-06 13:54:42 +02:00
Pablo Lara 2ecd9ad2c5 docs: update changelog (#7960) 2025-06-06 13:17:38 +02:00
Alejandro BailoandPablo Lara 50dc396aa3 feat: scan id filter drowpdown (#7949)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-06 12:38:14 +02:00
Andoni Alonso acf333493a chore(api): reorder docker layers to speed up build times (#7957) 2025-06-06 10:42:14 +02:00
Pedro Martín bd6272f5a7 feat(docs): add information about tenants and read-only roles (#7956) 2025-06-06 10:14:33 +02:00
Pepe Fagoaga 8c95e1efaf chore: update API changelog for v5.7.3 (#7948) 2025-06-05 15:54:36 +02:00
Hugo Pereira BritoandVíctor Fernández Poyatos 845a0aa0d5 fix(changelog): add entries for password encryption in v5.7.3 (#7939)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-06-05 14:23:12 +02:00
Hugo Pereira Brito 75a11be9e6 fix(docs): add final permission assignments example (#7943) 2025-06-05 18:07:43 +05:45
Hugo Pereira BritoandPepe Fagoaga a778d005b6 fix(docs): add mfa warning for users (#7924)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-06-05 17:55:27 +05:45
Pedro Martín 1281f4ec5e chore(changelog): update following the correct format (#7908) 2025-06-05 17:52:36 +05:45
Víctor Fernández Poyatos 6332427e5e fix(compliance): add manual status to requirements (#7938) 2025-06-05 10:54:51 +02:00
Alejandro Bailo d89df83904 fix: Improve the perfomance removing regions heatmap (#7934) 2025-06-05 08:13:47 +02:00
Víctor Fernández Poyatos be420afebc feat(database): handle already closed connections (#7935) 2025-06-04 16:09:36 +02:00
Adrián Jesús Peña Rodríguez fb914a2c90 revert: remove get_with_retry (#7932) 2025-06-04 15:01:47 +02:00
Pablo Lara 4ac3cfc33d docs: update changelog (#7931) 2025-06-04 13:54:25 +02:00
Alejandro Bailo c74360ab63 fix: clear filters sync (#7928) 2025-06-04 13:32:52 +02:00
Alejandro Bailo 4dc4d82d42 feat: aws-well-architected compliance detailed view (#7925) 2025-06-04 12:26:27 +02:00
Víctor Fernández Poyatos 6e7a32cb51 revert(views): calling order to initial view method (#7921) 2025-06-03 16:38:00 +02:00
Alejandro BailoandVíctor Fernández Poyatos 49e501c4be feat: CIS compliance detail view (#7913)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-06-03 15:47:46 +02:00
Víctor Fernández Poyatos 9ee78fe65f fix(views): calling order to initial view method (#7918) 2025-06-03 13:34:44 +02:00
Víctor Fernández Poyatos 7a0549d39c fix(rls): Apply persistent RLS transactions (#7916) 2025-06-03 13:10:41 +02:00
3e8c86d880 feat: ISO compliance detail view (#7897)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-06-03 09:20:52 +02:00
Pablo Lara e34c18757d fix: Fix named export for addCredentialsServiceAccountFormSchema (#7909) 2025-06-03 08:33:24 +02:00
Alejandro BailoandVíctor Fernández Poyatos 5c1a47d108 feat: compliance detail view + ENS (#7853)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-06-02 18:20:22 +02:00
Víctor Fernández Poyatos 59c51d5a4a feat(compliance): Rework compliance overviews (#7877) 2025-06-02 17:06:24 +02:00
Pedro MartínandRubén De la Torre Vico 66aa67f636 feat(changelog): update version with fixes (#7904)
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-06-02 12:32:45 +02:00
Pablo Lara bdda377482 docs: update the changelog (#7901) 2025-06-02 11:49:04 +02:00
Hugo Pereira Brito aa11ed70bd chore(docs): replace old permission images (#7900) 2025-06-02 11:47:11 +02:00
Adrián Jesús Peña RodríguezandPepe Fagoaga 0580dca6cf fix: set user_id for tenant operations (#7890)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-06-02 11:06:49 +02:00
Pablo Lara 678ef0ab5a feat(providers): setup workflow to support new GCP credential method (#7872) 2025-06-02 10:23:39 +02:00
César Arroba 4888c27713 chore: fix commit sha when a pr is merged (#7889) 2025-05-30 17:40:57 +05:45
Hugo Pereira Brito b256c10622 chore: replace Directory.Read.All permission to Domain.Read.All for Azure (#7888) 2025-05-30 10:24:49 +02:00
Adrián Jesús Peña RodríguezandVíctor Fernández Poyatos 878e4e0bbc fix: add new get method to avoid race conditions when creating async tasks (#7876)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-05-30 10:07:32 +02:00
Hugo Pereira Brito 6c3653c483 fix(docs): remove warning of encrypted password for cloud (#7886) 2025-05-30 12:01:32 +04:00
Daniel BarranqueroandPepe Fagoaga 71ac703e6f fix(api): connection correctly reflected (#7831)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-05-29 20:23:15 +05:45
Sergio Garcia a89e3598f2 fix(gcp): test connection by verifying token (#7882) 2025-05-29 13:20:53 +02:00
Alison Vilela 5d043cc929 fix(awslambda): aws service awslambda not working (#7869) 2025-05-29 12:50:23 +05:45
Pepe Fagoaga 921f94ebbf fix(k8s): UID validation for valid context names (#7871) 2025-05-29 12:32:57 +05:45
sumit-tft 48c9ed8a79 fix(ui): increase limit to retrieve more than 10 scan list (#7865) 2025-05-29 07:52:36 +02:00
Hugo Pereira Brito 12987ec9f9 fix(admincenter): service and group visibility (#7870) 2025-05-28 16:48:49 +02:00
Hugo Pereira Brito 40b90ed063 fix(tests): typo in m365 domain test (#7866) 2025-05-28 16:43:58 +02:00
Alejandro Bailo 60314e781f feat: enhance CustomDropdownFilter (#7868) 2025-05-28 16:30:28 +02:00
Harsh KumarandHarsh Kumar bc56d48595 feat(dashboard): add client-side search functionality to findings table (#7804)
Co-authored-by: Harsh Kumar <harsh.k@cybersecurist.com>
2025-05-28 11:44:01 +02:00
Pedro Martín 2d71cef3d5 feat(azure): add NIS 2 compliance framework (#7857) 2025-05-28 11:35:40 +02:00
Daniel BarranqueroandMrCloudSec 41f6637497 fix(defender): update defender_ensure_notify_alerts_severity_is_high logic (#7862)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-28 10:32:44 +02:00
Pedro MartínandSergio Garcia c2e54bbbcc fix(threatscore): remove compliance name in tests to remove dummy files (#7859)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-28 10:03:20 +02:00
sumit-tft df8aacd09d fix(ui): Added missing icons (kisa, prowlerThreat) on compliance page (#7860) 2025-05-28 09:51:28 +02:00
Matt Keeler 2dd6be59b9 fix(m365): add compliantDevice grant control support (#7844) 2025-05-28 09:05:00 +02:00
9e8e3eb0e6 fix(m365): update documentation (#7823)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2025-05-28 08:52:03 +02:00
Sergio GarciaandPedro Martín 3728430f8c chore: update README (#7842)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-05-27 14:25:37 +02:00
sumit-tftandPablo Lara ea97de7f43 fix(ui): updated to use the correct message when download report clicked (#7758)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-05-27 10:51:08 +02:00
Rubén De la Torre Vico f254a4bc0d feat(app): split SDK App service calls (#7778) 2025-05-27 09:52:50 +02:00
Pedro Martín 66acfd8691 feat(aws): add NIS2 compliance framework (#7839) 2025-05-27 09:35:57 +02:00
Matt Keeler 02ca82004f fix(typo): minor language updates (#7843) 2025-05-27 09:26:51 +02:00
Rubén De la Torre Vico 60b5a79b27 fix(vpc): change the ServiceName from EC2 to VPC (#7840) 2025-05-26 17:52:59 +02:00
be1e3e942b feat(api): support GCP Service Account key (#7824)
Co-authored-by: Sergio Garcia <38561120+garcitm@users.noreply.github.com>
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-05-26 15:42:39 +02:00
Sergio Garcia 3658e85cfc chore(github): add Branch class (#7838) 2025-05-26 14:34:44 +02:00
Adrián Jesús Peña Rodríguez 15e4d1acce refactor(reports): change API response message when tasks are running (#7837) 2025-05-26 12:20:05 +02:00
Andoni Alonso 44afd9ed31 fix: repository repository_dependency_scanning_enabled check logic (#7834) 2025-05-26 10:44:19 +02:00
Andoni Alonso 4f099c5663 refactor(github): use owner instead of repository in findings attributes (#7833) 2025-05-26 10:40:41 +02:00
Andoni AlonsoandSergio Garcia eaec683eb9 feat(repositoy): add new check repository_inactive_not_archived (#7786)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-26 10:39:09 +02:00
Adrián Jesús Peña Rodríguez 50bcd828e9 fix(reports): change invalid search term for tasks (#7830) 2025-05-26 10:24:11 +02:00
Alejandro BailoandPablo Lara 91545e409e feat: change tenant name in /profile page (#7829)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-05-23 14:45:28 +02:00
Alejandro BailoandPablo Lara 33031d2c96 feat: implement provider UID extraction and mapping in scans pages (#7820)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-05-23 13:42:35 +02:00
Hugo Pereira Brito 1b42dda817 fix(formSchemas): encrypted password typo (#7828) 2025-05-23 12:52:17 +02:00
Hugo Pereira Brito f726d964a8 fix(m365): remove last encrypted password appearances (#7825) 2025-05-23 12:27:57 +02:00
Hugo Pereira BritoandDaniel Barranquero 36aaec8a55 chore(m365powershell): manage encryption from plaintext password (#7784)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
2025-05-22 17:36:58 +02:00
Andoni AlonsoandSergio Garcia 99164ce93e feat(repository): add new check repository_default_branch_requires_signed_commits (#7777)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-22 12:45:13 +02:00
Andoni AlonsoandSergio Garcia 7ebc5d3c31 feat(repository): add new check repository_dependency_scanning_enabled (#7771)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-22 12:22:59 +02:00
Andoni AlonsoandSergio Garcia 06ff3db8af feat(repository): add new check repository_secret_scanning_enabled (#7759)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-22 11:23:42 +02:00
Alejandro Bailo c44ea3943e feat: resources in finding tables (#7813) 2025-05-22 08:58:25 +02:00
Andoni AlonsoandSergio Garcia d036e0054b feat(repository): add new check repository_default_branch_requires_codeowners_review (#7753)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-21 16:18:55 +02:00
Pedro Martín f72eb7e212 fix(files): remove empty files (#7819) 2025-05-21 16:15:04 +02:00
Andoni Alonso 62dcbc2961 feat(repository): add new check repository_has_codeowners_file (#7752) 2025-05-21 15:28:30 +02:00
Hugo Pereira Brito dddec4c688 fix(m365): add powershell.close() to msgraph services (#7816) 2025-05-21 15:13:03 +02:00
Sergio GarciaandPepe Fagoaga 6d00554082 chore(readme): add Prowler Hub link (#7814)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-05-21 17:46:54 +05:45
Pedro MartínandSergio Garcia 65d3fcee4c feat(prowler-threatscore): add Weight field inside req (#7795)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-21 12:57:10 +02:00
Pedro MartínandSergio Garcia 16cd0e4661 feat(prowler_threatscore): add a level for accordion in dashboard (#7739)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-21 12:46:47 +02:00
Hugo Pereira BritoandAndoni A. 6e184dae93 fix(admincenter): admincenter_users_admins_reduced_license_footprint logic (#7779)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-21 12:46:35 +02:00
Pablo Lara 118f3d163d docs: update changelog UI (#7808) 2025-05-21 12:39:48 +02:00
Pedro Martín 7d84d67935 feat(gcp): add CIS 4.0 compliance framework (#7785) 2025-05-21 12:38:34 +02:00
Víctor Fernández Poyatos 1c1c58c975 feat(findings): Add new index for finding UID lookup (#7800) 2025-05-21 11:56:54 +02:00
Andoni Alonso 31ea672c61 fix: move changes to release 5.8 (#7801) 2025-05-21 11:45:54 +02:00
Toni de la Fuente 7016779b8e chore(README): update README.md (#7799) 2025-05-21 11:31:23 +02:00
Pedro MartínandMrCloudSec 4e958fdf39 feat(kubernetes): add CIS 1.11 compliance framework (#7790)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-21 11:09:47 +02:00
Pedro Martín c6259b6c75 fix(dashboard): remove typo from subscribe cards (#7792) 2025-05-21 11:08:52 +02:00
Sergio Garcia 021e243ada feat(kubernetes): support HTTPS_PROXY and K8S_SKIP_TLS_VERIFY (#7720) 2025-05-21 10:49:18 +02:00
Alejandro BailoandPablo Lara acdf420941 feat: profile page (#7780)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-05-21 10:47:32 +02:00
Hugo Pereira BritoandAndoni Alonso 4e84507130 feat(entra): add new check entra_users_mfa_capable (#7734)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-05-21 10:31:56 +02:00
Prowler Botandprowler-bot 2a61610fec chore(regions_update): Changes in regions for AWS services (#7774)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-05-21 10:29:08 +02:00
Daniel BarranqueroandAndoni Alonso 9b127eba93 feat(admincenter): add new check admincenter_external_calendar_sharing_disabled (#7733)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-05-21 09:14:45 +02:00
Hugo Pereira BritoandAndoni Alonso 1a89d65516 fix(m365powershell): add sanitize to test_credentials (#7761)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-05-21 08:49:04 +02:00
Daniel BarranqueroandAndoni Alonso 84749df708 feat(admincenter): add new check admincenter_organization_customer_lockbox_enabled (#7732)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-05-21 08:48:36 +02:00
Pepe Fagoaga 6f7cd85a18 chore(backport): create label on minor release (#7791) 2025-05-21 12:14:30 +05:45
Alejandro Bailo ad39061e1a fix: retrieve more than 10 providers (#7793) 2025-05-21 08:07:43 +02:00
Pablo Lara 615bacccaf chore: tweak some wording for consistency (#7794) 2025-05-21 07:59:53 +02:00
Prowler Botandprowler-bot b3a2479fab chore(release): Bump version to v5.8.0 (#7788)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-05-20 22:27:21 +05:45
sumit-tftandPablo Lara 871c877a33 fix: AWS I AM role validation when field is empty (#7787)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-05-20 11:25:40 +02:00
Pedro Martín 7fd58de3bf feat(export): support m365 - prowler threatscore (#7783) 2025-05-19 15:59:42 +02:00
Víctor Fernández Poyatos 40f24b4d70 fix(providers): Fix m365 UID validation (#7781) 2025-05-19 13:34:46 +02:00
Adrián Jesús Peña Rodríguez d8f80699d4 chore: update api changelog (#7775) 2025-05-19 14:52:32 +05:45
Pablo Lara f24d0efc77 docs: update changelog (#7773) 2025-05-19 14:34:28 +05:45
Hugo Pereira Brito a18dd76a5a chore(m365): accept all tenant domains in authentication (#7746) 2025-05-19 13:53:54 +05:45
Pedro Martín a2362b4bbc fix(cis): rename and add sections and subsections (#7738) 2025-05-19 09:42:04 +02:00
Pedro Martín e5f1c2b19c feat(aws): add CIS 5.0 compliance framework (#7766) 2025-05-19 09:41:56 +02:00
Pedro Martín 0490ab6944 docs(checks): improve docs related with checks (#7768) 2025-05-19 09:17:14 +02:00
Sergio Garcia 97baa8a1e6 chore(ec2): improve severity logic in SG all ports open check (#7764) 2025-05-16 15:09:48 +02:00
Hugo Pereira BritoandMrCloudSec 637ebdc3db feat(repository): add new check repository_branch_delete_on_merge_enabled (#6209)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-16 15:03:37 +02:00
Hugo Pereira BritoandMrCloudSec 451b36093f feat(repository): add new check repository_default_branch_requires_conversation_resolution (#6208)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-16 14:57:15 +02:00
Víctor Fernández Poyatos beb0457aff fix(findings): Fix latest metadata backfill condition and optimization (#7765) 2025-05-16 14:50:40 +02:00
Víctor Fernández Poyatos 0335ea4e0b fix(findings): Fix latest metadata backfill condition (#7762) 2025-05-16 12:41:12 +02:00
sumit-tft 355abca5a3 fix(ui): Removed the alias if not available in findings detail page (#7751) 2025-05-16 09:02:47 +02:00
sumit-tft 7d69cc4cd9 fix: Updated the high risk section provider icons to make it consistent (#7706) 2025-05-16 08:53:34 +02:00
Hugo Pereira BritoandMrCloudSec cdc4b362a4 feat(repository): add new check repository_default_branch_protection_applies_to_admins (#6205)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-16 08:29:45 +02:00
Pablo Lara 6417e6bbba feat: use getFindingsLatest when no scan or date filters are applied (#7756) 2025-05-16 08:18:12 +02:00
Víctor Fernández Poyatos b810d45d34 feat(findings): Add /findings/latest and /findings/metadata/latest endpoints (#7743) 2025-05-15 16:08:09 +02:00
Ogonna IwunzeandMrCloudSec f5a2695c3b fix(check): Add support for condition with restriction on SNS endpoint (#7750)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-15 16:00:00 +02:00
Hugo Pereira BritoandMrCloudSec 977c788fff feat(repository): add new check repository_default_branch_status_checks_required (#6204)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-15 15:33:49 +02:00
Hugo Pereira Brito 21f8b5dbad fix(check): add missing __init__.py files (#7748) 2025-05-15 11:22:58 +02:00
1c874d1283 feat(repository): add new check repository_default_branch_deletion_disabled (#6200)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-15 08:33:36 +02:00
Hugo Pereira BritoandMrCloudSec 8f9bdae2b7 feat(repository): add new check repository_default_branch_disallows_force_push (#6197)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-14 16:48:47 +02:00
Pablo LaraandStylusFrost 600813fb99 fix: force z-index componet select provider (#7744)
Co-authored-by: StylusFrost <pm.diaz.pena@gmail.com>
2025-05-14 15:19:41 +02:00
Hugo Pereira BritoandMrCloudSec 5a9ccd60a0 feat(repository): add new check repository_default_branch_requires_linear_history (#6162)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-14 14:37:27 +02:00
beb7a53efe feat(repository): add new check repository_default_branch_protection_enabled (#6161)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-14 13:42:59 +02:00
Hugo Pereira BritoandMrCloudSec 8431ce42a1 feat(organization): add new check organization_members_mfa_required (#6304)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-14 13:29:08 +02:00
Pablo Laraandsumit_chaturvedi c5a9b63970 fix: UID Filter Improvement (#7741)
Co-authored-by: sumit_chaturvedi <chaturvedi.sumit@tftus.com>
2025-05-14 11:36:27 +02:00
a765c1543e feat: add GitHub provider documentation and CIS v1.0.0 compliance (#6116)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-14 10:47:33 +02:00
Hugo Pereira BritoandMrCloudSec 484a773f5b feat(github): add new service Organization (#6300)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-14 10:40:26 +02:00
Hugo Pereira BritoandMrCloudSec 9ecf570790 feat(github): add new check repository_code_changes_multi_approval_requirement (#6160)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-14 10:06:52 +02:00
Adrián Jesús Peña Rodríguez f8c840f283 fix: ensure proper folder creation (#7729) 2025-05-14 10:02:41 +02:00
Pepe Fagoaga deec9efa97 feat(ui): Add AWS CloudFormation Quick Link to deploy the IAM Role (#7735) 2025-05-14 09:30:01 +02:00
César Arroba 2ee62cca8e chore: add ref on checkout step (#7740) 2025-05-14 12:24:49 +05:45
Hugo Pereira BritoandMrCloudSec 413b948ca0 feat(github): add GitHub provider (#5787)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-13 15:28:01 +02:00
Pablo Lara d548e869fa docs: update changelog (#7731) 2025-05-13 13:41:41 +02:00
Sergio Garcia 5c8919372c fix(deps): solve h11 package vulnerability (#7728) 2025-05-13 13:29:22 +02:00
Sergio Garcia 9baac9fd89 fix(deps): solve h11 package vulnerability (#7696) 2025-05-13 13:10:06 +02:00
sumit-tft 252b664e49 fix: Added filter to get connected providers only for banner to show (#7723) 2025-05-13 12:58:23 +02:00
Víctor Fernández Poyatos 496e0f1e0a fix(overviews): Split in n queries to use database indexes for providers (#7725) 2025-05-13 12:34:14 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 80342d612f chore(deps): bump h11 from 0.14.0 to 0.16.0 in /api (#7610)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-13 12:15:14 +02:00
Pablo Lara 02d7eaf268 chore: bump tailwind-merge from 2.5.3 to 3.2.0 (#7722) 2025-05-13 09:27:27 +02:00
1a8df3bf18 fix(defender): enhance policies checks logic (#7666)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-12 17:02:30 +02:00
Pablo Lara 16f2209d3f chore: add M365 to scan page filters (#7704) 2025-05-12 16:20:07 +02:00
Pablo Lara 70e22af550 chore(deps): upgrade recharts from 2.13.0-alpha.4 to 2.15.2 (#7717) 2025-05-12 16:09:54 +02:00
44f26bc0d5 chore(docs): quality redrive to README.md (#7616)
Co-authored-by: dcanotrad <168282715+dcanotrad@users.noreply.github.com>
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-05-12 15:23:14 +02:00
Alejandro Bailo a19f5d9a9a feat: scan label validation (#7693) 2025-05-12 15:07:44 +02:00
Hugo Pereira Brito b78f53a722 chore(findings): enhance m365 authentication method information (#7681) 2025-05-12 18:31:32 +05:45
Víctor Fernández Poyatos c20f07ced4 feat(findings): Improve performance on /findings/metadata, /overviews and filters (#7690) 2025-05-12 14:34:37 +02:00
Hugo Pereira BritoandMrCloudSec 7c3a53908b chore(compliance): update CIS 4.0 for M365 (#7699)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-12 12:59:50 +02:00
Pepe Fagoaga ea3c71e22c fix(bump-version): bump for fix also in minors (#7712) 2025-05-12 12:45:17 +02:00
Pedro MartínandMrCloudSec 40eaa79777 docs(compliance): update compliance page with latest changes (#7694)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-12 12:37:43 +02:00
Prowler Botandprowler-bot aa8119970e chore(regions_update): Changes in regions for AWS services (#7709)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-05-12 12:37:21 +02:00
Pepe Fagoaga 55fc8cb55b chore(api): Set tab name for API reference (#7713) 2025-05-12 16:16:29 +05:45
Andoni Alonso abf51eceee fix(typo): rename generate_compliance_json_from_csv_threatscore (#7698) 2025-05-12 12:29:30 +02:00
Pedro MartínandSergio Garcia 458c51dda3 feat(m365): add Prowler Threatscore (#7692)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-12 12:28:50 +02:00
Sergio Garcia c8d2a44ab0 feat(kubernetes): allow setting cluster name in in-cluster mode (#7695) 2025-05-12 12:28:04 +02:00
César Arroba 0a71628298 chore: add pass PR url (#7711) 2025-05-12 11:55:00 +02:00
Pablo Lara 60e0040577 fix: move ProviderType to shared types and update usages (#7710) 2025-05-12 11:54:42 +02:00
Alejandro Bailo 5c375d63c5 feat: Horizontal bar chart (#7680) 2025-05-12 11:14:10 +02:00
Adrián Jesús Peña Rodríguez 4d84529ba2 docs: update the download export documentation (#7682) 2025-05-12 14:45:53 +05:45
Prowler Botandprowler-bot 0737d9e8bb chore(release): Bump version to v5.7.0 (#7697)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-05-12 14:41:28 +05:45
Alejandro Bailo 50c5294bc0 feat: accordion component (#7700) 2025-05-12 14:17:40 +05:45
Hugo Pereira Brito f63e9e5e77 fix(m365): invalid user credentials exception (#7677) 2025-05-12 13:22:13 +05:45
Hugo Pereira Brito 3cab52772c feat(m365): add categories for tenant type e3 and e5 (#7691) 2025-05-09 08:11:44 +02:00
Pepe Fagoaga 81aa035451 chore(changelog): prepare for v5.6.0 (#7688) 2025-05-08 16:49:56 +05:45
Pedro Martín 899f31f1ee fix(prowler_threatscore): fine-tune LevelOfRisk (#7667) 2025-05-08 15:23:31 +05:45
Pedro Martín e142a9e0f4 fix(dashboard): drop duplicates for rows (#7686) 2025-05-08 14:20:19 +05:45
Sergio Garcia ed26c2c42c fix(mutelist): properly handle wildcards and regex (#7685) 2025-05-08 12:10:55 +05:45
Pedro Martín 1017510a67 fix(dashboard): remove muted findings on compliance page (#7683) 2025-05-07 13:52:14 -04:00
Adrián Jesús Peña RodríguezandPepe Fagoaga bfa16607b0 feat: add compliance to API report files and its endpoint (#7653)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-05-07 20:44:58 +05:45
Hugo Pereira Brito 4c874b68f5 fix(metadata): typo in defender_chat_report_policy_configured (#7678) 2025-05-07 09:30:49 -04:00
Sergio GarciaandAndoni A. 9458e2bbc4 fix(inspector2): handle error when getting active findings (#7670)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-07 14:39:34 +02:00
Alejandro Bailo 2da7b926ed feat: add DeltaIndicator in new findings (#7676) 2025-05-07 17:59:56 +05:45
Daniel Barranquero 8d4f0ab90a feat(docs): add snapshots to M365 docs (#7673) 2025-05-07 12:19:10 +02:00
Hugo Pereira Brito 83aefc42c1 fix(powershell): remove platform-specific execution (#7675) 2025-05-07 11:44:13 +02:00
Alejandro Bailo a6489f39fd refactor(finding-detail): remove "Next Scan" field (#7674) 2025-05-07 14:39:35 +05:45
Pablo Lara 15c34952cf docs: update changelog (#7672) 2025-05-07 09:43:17 +02:00
Alejandro Bailo d002f2f719 feat: diff between providers actions depending on their secrets (#7669) 2025-05-07 09:35:53 +02:00
Sergio Garcia 8530676419 chore(actions): run tests in dependabot updates (#7671) 2025-05-07 11:43:01 +05:45
Pedro Martín fe5a78e4d4 feat(aws): add static credentials for S3 and SH (#7322) 2025-05-06 17:55:53 +02:00
Pablo Lara d823b2b9de chore: tweaks for m365 provider (#7668) 2025-05-06 17:06:44 +02:00
Alejandro Bailo 3b17eb024c feat: add delta attribute in findings detail view with and finding id to the url (#7654) 2025-05-06 16:52:15 +02:00
Pablo Lara 87951a8371 feat(compliance): add a button to download the report in compliance card (#7665) 2025-05-06 14:44:02 +02:00
e5ca51d1e7 feat(teams): add new checks teams_security_reporting_enabled and defender_chat_report_policy_configured (#7614)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-05-06 11:30:00 +02:00
Daniel Barranquero e2fd3fe36e feat(defender): add new check defender_malware_policy_comprehensive_attachments_filter_applied (#7661) 2025-05-06 10:29:36 +02:00
Daniel BarranqueroandMrCloudSec 6b0d73d7f9 feat(exchange): make exchange_user_mailbox_auditing_enabled check configurable (#7662)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-05 15:16:41 -04:00
Hugo Pereira BritoandMrCloudSec 7eec60f4d9 feat(m365): ensure all forms of mail forwarding are blocked or disabled (#7658)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-05-05 11:21:14 -04:00
Daniel BarranqueroandSergio Garcia 9d788af932 docs(m365): add documentation for m365 (#7622)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-05 16:46:32 +02:00
Pedro MartínandSergio Garcia bbc0388d4d chore(changelog): update with latest PR (#7628)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-05 10:40:59 -04:00
Pedro MartínandSergio Garcia 887db29d96 feat(dashboard): support m365 provider (#7633)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-05-05 10:38:06 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ae74cab70a chore(deps): bump docker/build-push-action from 6.15.0 to 6.16.0 (#7650)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 09:58:38 -04:00
Prowler Botandprowler-bot e6d48c1fa4 chore(regions_update): Changes in regions for AWS services (#7657)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-05-05 09:56:16 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d5ab72a97c chore(deps): bump github/codeql-action from 3.28.15 to 3.28.16 (#7649)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 09:54:34 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 473631f83b chore(deps): bump trufflesecurity/trufflehog from 3.88.23 to 3.88.26 (#7648)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 09:54:16 -04:00
drewadwadeandpedrooot a580b1ee04 fix(azure): CIS v2.0 4.4.1 Uses Wrong Check (#7656)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-05-05 15:53:55 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 844dd5ba95 chore(deps): bump actions/setup-python from 5.5.0 to 5.6.0 (#7647)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 09:53:40 -04:00
sumit-tft 44f8e4c488 feat(ui): Page size for datatables (#7634) 2025-05-05 15:42:06 +02:00
Alejandro Bailo 180eb61fee fix: error about page number persistence when filters change (#7655) 2025-05-05 12:23:04 +02:00
Andoni AlonsoandAdrián Jesús Peña Rodríguez 9828824b73 chore(sentry): attach stacktrace to logging events (#7598)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-05-05 10:38:57 +02:00
Daniel BarranqueroandAndoni A. c938a25693 feat(exchange): add new check exchange_organization_modern_authentication_enabled (#7636)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-02 12:44:39 +02:00
Daniel BarranqueroandAndoni A. cccd69f27c feat(exchange): add new check exchange_roles_assignment_policy_addins_disabled (#7644)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-02 11:58:56 +02:00
Daniel BarranqueroandAndoni A. 3949806b5d feat(exchange): add new check exchange_mailbox_properties_auditing_e3_enabled (#7642)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-02 10:48:30 +02:00
Daniel BarranqueroandAndoni A. e7d249784d feat(exchange): add new check exchange_transport_config_smtp_auth_disabled (#7640)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-02 09:05:53 +02:00
Daniel BarranqueroandAndoni A. 25b1efe532 feat(exchange): add new check exchange_organization_mailtips_enabled (#7637)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-05-02 08:46:14 +02:00
Adrián Jesús Peña RodríguezandAndoni A c289ddacf2 feat: add m365 to API (#7563)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com>
2025-04-30 17:09:47 +02:00
3fd9c51086 feat(m365): automate PowerShell modules installation (#7618)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-04-30 16:41:59 +02:00
Pedro MartínandPepe Fagoaga de01087246 fix(s3): add ContentType in upload_file (#7635)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-04-30 19:48:23 +05:45
Pablo Lara fe42bb47f7 fix: set correct default value for session duration (#7639) 2025-04-30 13:00:45 +02:00
Víctor Fernández Poyatos c56bd519bb test(performance): Add base framework for API performance tests (#7632) 2025-04-30 12:36:25 +02:00
Daniel BarranqueroandAndoni A. 79b29d9437 feat(exchange): add new check exchange_mailbox_policy_additional_storage_restricted (#7638)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-04-30 12:05:41 +02:00
Pedro MartínandAndoni A. 82eecec277 feat(sharepoint): add new check related with OneDrive Sync (#7589)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
2025-04-30 11:43:41 +02:00
Pedro Martín ceacd077d2 fix(typos): remove unneeded files (#7627) 2025-04-29 13:24:24 +05:45
Pepe Fagoaga 5a0fb13ece fix(run-sh): Use poetry's env (#7621) 2025-04-29 13:01:12 +05:45
Erlend Ekern 78439b4c0c chore(dockerfile): add image source as docker label (#7617) 2025-04-29 13:00:47 +05:45
Pedro MartínandMrCloudSec 06f94f884f feat(compliance): add new Prowler Threat Score Compliance Framework (#7603)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-28 09:57:52 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b8836c6404 chore(deps): bump @babel/runtime from 7.24.7 to 7.27.0 in /ui (#7502)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-28 08:49:33 +02:00
Andoni AlonsoandSergio Garcia ac79b86810 feat(teams): add new check teams_meeting_presenters_restricted (#7613)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-25 14:34:05 -04:00
Andoni AlonsoandSergio Garcia 793c2ae947 feat(teams): add new check teams_meeting_recording_disabled (#7607)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-25 12:35:54 -04:00
Andoni AlonsoandSergio Garcia cdcc5c6e35 feat(teams): add new check teams_meeting_external_chat_disabled (#7605)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-25 11:30:38 -04:00
Andoni AlonsoandSergio Garcia 51db81aa5c feat(teams): add new check teams_meeting_external_control_disabled (#7604)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-25 10:59:36 -04:00
Hugo Pereira BritoandMrCloudSec a51a185f49 fix(powershell): handle m365 provider execution and logging (#7602)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-25 10:44:25 -04:00
90453fd07e feat(teams): add new check teams_meeting_chat_anonymous_users_disabled (#7579)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-25 09:29:24 -04:00
Pablo Lara d740bf84c3 feat: add new M365 to the provider overview table (#7615) 2025-04-25 15:24:47 +02:00
Pedro MartínandSergio Garcia d13d2677ea fix(compliance): improve compliance and dashboard (#7596)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-24 13:28:18 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b076c98ba1 chore(deps): bump h11 from 0.14.0 to 0.16.0 (#7609)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-24 13:19:11 -04:00
d071dea7f7 feat(teams): add new check teams_meeting_dial_in_lobby_bypass_disabled (#7571)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-24 13:05:52 -04:00
d9782c7b8a feat(teams): add new check teams_meeting_external_lobby_bypass_disabled (#7568)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-24 12:13:42 -04:00
Pedro MartínandSergio Garcia f85450d0b5 fix(html): remove first empty line (#7606)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-24 11:23:24 -04:00
Pepe Fagoaga b129326ed6 chore(actions): Bump Prowler version on release (#7560) 2025-04-24 10:25:36 -04:00
Hugo Pereira BritoandMrCloudSec eaf0d06b63 chore(m365): add test_connection function (#7541)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-24 10:20:58 -04:00
Pedro Martín 87f3e0a138 fix(nhn): remove unneeded parameter (#7600) 2025-04-24 13:21:52 +02:00
Daniel BarranqueroandMrCloudSec 8e3c856a14 feat(exchange): add new check exchange_external_email_tagging_enabled (#7580)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-23 14:11:39 -04:00
12c2439196 feat(exchange): add new check exchange_transport_rules_whitelist_disabled (#7569)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-23 13:47:51 -04:00
deb1e0ff34 feat(defender): Add new check defender_antispam_policy_inbound_no_allowed_domains (#7500)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-23 13:29:24 -04:00
Hugo Pereira Brito 808e8297b0 feat(teams): add new check teams_meeting_anonymous_user_start_disabled (#7567) 2025-04-23 10:31:17 -04:00
Hugo Pereira Brito 738ce56955 fix(docs): overview m365 auth (#7588) 2025-04-23 09:58:32 -04:00
Sergio Garcia 190fd0b93c fix(scan): handle cloud provider errors and ignore expected sentry noise (#7582) 2025-04-23 09:58:04 -04:00
Pablo Lara ca6df26918 chore: remove deprecated launch scan page from old 4-step workflow (#7592) 2025-04-23 15:13:05 +02:00
Pablo Lara bcfeb97e4a feat(m365): add the new provider m365 - UI part (#7591) 2025-04-23 14:23:33 +02:00
0234957907 feat(teams): add new check teams_meeting_anonymous_user_join_disabled (#7565)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 16:02:16 -04:00
Hugo Pereira BritoandMrCloudSec 8713b74204 feat(teams): add new check teams_external_users_cannot_start_conversations (#7562)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 14:36:54 -04:00
Hugo Pereira BritoandMrCloudSec cbaddad358 feat(teams): add new check teams_unmanaged_communication_disabled (#7561)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 13:25:30 -04:00
Hugo Pereira BritoandSergio Garcia 2379544425 feat(teams): add new check teams_external_domains_restricted (#7557)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-22 13:04:51 -04:00
Hugo Pereira Brito 29fefba62e fix(teams): teams_email_sending_to_channel_disabled docstrings (#7559) 2025-04-22 12:57:18 -04:00
098382117e feat(defender): add new check defender_antispam_connection_filter_policy_safe_list_off (#7494)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 12:52:34 -04:00
d816d73174 feat(defender): add new check defender_antispam_connection_filter_policy_empty_ip_allowlist (#7492)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 12:28:18 -04:00
Matt KeelerandMrCloudSec 30eb78c293 fix(aws): use correct ports in ec2_instance_port_cifs_exposed_to_internet recommendation (#7574)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 12:24:12 -04:00
a671b092ee feat(defender): add new check defender_domain_dkim_enabled (#7485)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 11:15:33 -04:00
Pepe Fagoaga 0edf199282 fix(actions): Include files within providers for SDK tests (#7577) 2025-04-22 10:28:43 -04:00
Andoni AlonsoandMrCloudSec 2478555f0e fix(aws): update bucket naming validation to accept dots (#7545)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 10:06:14 -04:00
b07080245d feat(defender): add new check defender_antispam_outbound_policy_configured (#7480)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-22 09:58:07 -04:00
Pepe Fagoaga 2ebf217bb0 fix(k8s): Remove command as it is not needed (#7570) 2025-04-22 09:33:40 -04:00
Prowler Botandprowler-bot bb527024d9 chore(regions_update): Changes in regions for AWS services (#7550)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-22 09:32:22 -04:00
Sergio Garcia e897978c3e fix(azure): handle new FlowLog properties (#7546) 2025-04-22 09:21:17 -04:00
Pepe Fagoaga 00f1c02532 chore(tests): Split by provider in the SDK (#7564) 2025-04-22 16:46:15 +05:45
César Arroba 348d1a2fda chore: pass labels on PR merge trigger (#7558) 2025-04-21 16:43:40 +02:00
César Arroba f1df8ba458 chore: revert pass labels (#7556) 2025-04-21 12:46:42 +02:00
César Arroba b5ea418933 chore: pass labels as json is required (#7555) 2025-04-21 12:10:18 +02:00
César Arroba 734fa5a4e6 chore: fix merged PR action, incorrect order on payload (#7554) 2025-04-21 12:03:14 +02:00
César Arroba 08f6d4b69b chore: pass labels (#7553) 2025-04-21 11:57:50 +02:00
César Arroba 29d3bb9f9a chore: fix json body (#7552) 2025-04-21 15:01:03 +05:45
César Arroba 4d217e642b chore: fix trigger (#7551) 2025-04-21 14:56:17 +05:45
César Arroba bd56e03991 chore(gha): trigger cloud pull-request when a PR is merged (#7212) 2025-04-21 14:54:22 +05:45
Felix Dreissig 0b6aa0ddcd fix(aws): remove SHA-1 from ACM insecure key algorithms (#7547) 2025-04-18 16:25:44 -04:00
Daniel Barranquero 4f3496194d feat(defender): add new check defender_antiphishing_policy_configured (#7453) 2025-04-18 12:42:19 -04:00
d09a680aaa feat(defender): add new check defender_malware_policy_notifications_internal_users_malware_enabled (#7435)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-18 11:08:05 -04:00
56d7431d56 feat(defender): add service and new check defender_malware_policy_common_attachments_filter_enabled (#7425)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-17 13:33:43 -04:00
abae5f1626 feat(exchange): add new check exchange_mailbox_audit_bypass_disabled (#7418)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-16 14:06:32 -04:00
7d0e94eecb feat(exchange): add service and new check exchange_organization_mailbox_auditing_enabled (#7408)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-16 12:19:06 -04:00
Hugo Pereira BritoandSergio Garcia 23b65c7728 feat(teams): add new check teams_email_sending_to_channel_disabled (#7533)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-16 11:13:55 -04:00
Sergio Garcia aa3182ebc5 feat(gcp): support CLOUDSDK_AUTH_ACCESS_TOKEN (#7495) 2025-04-16 10:35:04 -04:00
Sergio Garcia 32d27df0ba chore(regions): change interval to weekly (#7539) 2025-04-16 09:35:30 -04:00
Prowler Botandprowler-bot 6439f0a5f3 chore(regions_update): Changes in regions for AWS services (#7538)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-16 09:25:29 -04:00
Sergio Garcia 19476632ff chore(dependabot): change settings (#7536) 2025-04-16 11:26:57 +05:45
d4c12e4632 fix(iam): change some logger.info values (#7526)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-15 13:25:37 -04:00
Hugo Pereira BritoandMrCloudSec 52bd48168f feat: adapt Microsoft365 provider to use PowerShell (#7331)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-15 13:24:09 -04:00
Bogdan A c0d935e232 docs(gcp): update required permissions for GCP (#7488) 2025-04-15 10:23:45 -04:00
Pepe Fagoaga 24dfd47329 fix(pypi): package name location in pyproject.toml while replicating for prowler-cloud (#7531) 2025-04-15 20:01:27 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> fbae338689 chore(deps): bump python from 3.12.9-alpine3.20 to 3.12.10-alpine3.20 (#7520)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 09:26:04 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 186fd88f8c chore(deps): bump codecov/codecov-action from 5.4.0 to 5.4.2 (#7522)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 09:25:44 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 14ff34c00a chore(deps): bump actions/setup-node from 4.3.0 to 4.4.0 (#7521)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 09:25:23 -04:00
Prowler Botandprowler-bot a66fa394d3 chore(regions_update): Changes in regions for AWS services (#7527)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-15 09:20:20 -04:00
Pepe Fagoaga 931766fe08 chore(action): Remove cache in PyPI release (#7532) 2025-04-15 18:58:26 +05:45
Pepe Fagoaga c134914896 revert: fix(findings): increase uid max length to 600 (#7528) 2025-04-15 15:54:32 +05:45
Pepe Fagoaga 25dac080a5 chore(changelog): prepare for 5.5.1 (#7523) 2025-04-15 11:46:20 +05:45
Sergio Garcia 910d39eee4 chore(sdk): update changelog (#7512) 2025-04-15 11:19:50 +05:45
Pepe Fagoaga d604ae5569 fix(pyproject): Restore packages location (#7510) 2025-04-14 16:50:50 -04:00
Bogdan AandMrCloudSec 42f46b0fb1 feat(gcp): add check for unused Service Accounts (#7419)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-14 11:53:54 -04:00
Pepe Fagoaga abb5864224 chore(release): bump for 5.6.0 (#7503) 2025-04-14 11:50:46 -04:00
Prowler Botandprowler-bot 2e2a2bd89a chore(regions_update): Changes in regions for AWS services (#7491)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-14 10:29:19 -04:00
Sergio Garcia f8ee841921 fix(gcp): handle projects without ID (#7496) 2025-04-14 10:25:54 -04:00
Pedro Martín ceda8c76d2 feat(azure): add SOC2 compliance framework (#7489) 2025-04-14 10:16:20 -04:00
Pedro Martín afe0b7443f fix(defender): add default name to contacts (#7483) 2025-04-14 10:16:07 -04:00
Prowler Botandprowler-bot 9b773897d2 chore(regions_update): Changes in regions for AWS services (#7487)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-14 09:53:40 -04:00
Pedro Martín d6ec4c2c96 feat(sdk): add changelog file (#7499) 2025-04-14 09:22:50 -04:00
Prowler Botandprowler-bot 14ef169e99 chore(regions_update): Changes in regions for AWS services (#7497)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-14 09:22:21 -04:00
Pepe FagoagaandVíctor Fernández Poyatos 22141f9706 fix(findings): increase uid max length to 600 (#7498)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-04-14 17:46:13 +05:45
Pablo Lara a5c6fee5b4 fix: update redirect URL for SSO (#7493) 2025-04-11 18:25:28 +05:45
Pablo Lara d3a5a5c0a1 fix: resolve social login issue in AuthForm on sign-up page (#7490) 2025-04-11 09:59:10 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 5d81869de4 chore(deps): bump tj-actions/changed-files from 46.0.4 to 46.0.5 (#7486)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 22:31:33 -04:00
Pepe Fagoaga 73ebf95d89 chore(changelog): Prepare for v5.5.0 (#7484) 2025-04-09 20:50:56 +05:45
Sergio Garcia 9f4574f4ff fix: handle errors in AWS and Azure (#7482) 2025-04-09 20:19:38 +05:45
Pedro Martín cb239b20ab fix(aws): add default session_duration (#7479) 2025-04-09 19:19:17 +05:45
eecheandMrCloudSec 3ef79588b4 feat(NHN): add NHN cloud provider with 6 checks (#6870)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-04-09 09:13:24 -04:00
Prowler Botandprowler-bot 61000e386b chore(regions_update): Changes in regions for AWS services (#7478)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-09 09:11:29 -04:00
Pablo Lara 53cb57901f fix: fix TS type for session duration (#7481) 2025-04-09 13:44:53 +02:00
Pedro Martín 993ff4d78e feat(gcp): add SOC2 compliance framework (#7476) 2025-04-08 15:04:08 -04:00
Drew Kerrigan 8fb10fbbf7 fix(ui): Remove UTC from timestamps in app (#7474) 2025-04-08 17:43:44 +02:00
Pablo Lara 11e834f639 feat: update the NextJS version to the latest (#7473) 2025-04-08 17:40:39 +02:00
Prowler Botandprowler-bot 62bf2fbb9c chore(regions_update): Changes in regions for AWS services (#7467)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-08 10:21:42 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> e57930d6c2 chore(deps): bump github/codeql-action from 3.28.13 to 3.28.15 (#7463)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-08 09:38:18 -04:00
Pepe Fagoaga e0c417a466 fix(action): Use poetry > v2 (#7472) 2025-04-08 18:34:24 +05:45
Sergio Garcia b55f8efed1 fix: handle errors in AWS, Azure, and GCP (#7456) 2025-04-08 18:05:43 +05:45
Pablo Lara 7cbc60d977 feat: add link with the service status using static icon (#7468) 2025-04-08 12:06:21 +02:00
Adrián Jesús Peña RodríguezandVíctor Fernández Poyatos 5b7912b558 fix(provider): disable periodic task on views before deleting (#7466)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-04-08 15:35:22 +05:45
Pedro Martín 57fca3e54d fix(soc2_aws): update compliance and remove some requirements (#7452) 2025-04-07 15:47:19 -04:00
Pedro Martín e31c27b123 fix(gcp): handle logic for empty project names (#7436) 2025-04-07 11:51:15 -04:00
Sergio Garcia 74f1da818e fix(gcp): ignore redirect balancers and add regional ones (#7442) 2025-04-07 11:47:02 -04:00
Pedro Martín 910cfa601b fix(aws): add resource arn for transit gateways (#7447) 2025-04-07 11:46:53 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> fe321c3f8a chore(deps): bump tj-actions/changed-files from 46.0.3 to 46.0.4 (#7443)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 09:11:54 -04:00
Prowler Botandprowler-bot 43de0d405f chore(regions_update): Changes in regions for AWS services (#7446)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-07 09:11:23 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ac6ed31c8e chore(deps): bump trufflesecurity/trufflehog from 3.88.22 to 3.88.23 (#7444)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 09:11:07 -04:00
Prowler Botandprowler-bot 9d47437de4 chore(regions_update): Changes in regions for AWS services (#7445)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-07 09:10:49 -04:00
Pablo Lara eb7a62ff77 refactor: extract common auth headers into reusable helper (#7439) 2025-04-07 08:16:55 +02:00
Pedro Martín 67bc16b46d fix(defender): add default resource name in contacts (#7438) 2025-04-04 09:35:11 -04:00
Sergio Garcia 8552a578a0 fix(aws): solve multiple errors (#7431) 2025-04-04 09:34:58 -04:00
Sergio Garcia a5d277e045 fix(docs): solve broken links (#7432) 2025-04-04 09:15:48 -04:00
Adrián Jesús Peña Rodríguez 6dbf2ac606 feat: add missing SDK fields to API findings and resources (#7318) 2025-04-04 14:57:49 +02:00
Prowler Botandprowler-bot b1569ac2f3 chore(regions_update): Changes in regions for AWS services (#7434)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-04 08:36:23 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3d0145b522 chore(deps): bump trufflesecurity/trufflehog from 3.88.20 to 3.88.22 (#7433)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 08:34:51 -04:00
Pedro Martín 44174526d6 docs: add onboarding information step by step for each provider (#7362) 2025-04-04 13:00:43 +02:00
Pablo Lara 0fd395ea83 fix: correct fetch variable name from invitations to roles (#7437) 2025-04-04 12:08:57 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
5e9d4a80a1 chore(deps): bump msgraph-sdk from 1.18.0 to 1.23.0 (#7128)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-04-04 11:27:39 +02:00
Pedro Martín e4d234fe03 fix(azure): remove resource_name inside the Check_Report (#7420) 2025-04-03 11:35:02 -04:00
Prowler Botandprowler-bot 3202184718 chore(regions_update): Changes in regions for AWS services (#7424)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-03 09:39:00 -04:00
Sergio Garcia 41e576f4f1 fix(gcp): make logging sink check at project level (#7421) 2025-04-03 09:37:46 -04:00
Pepe FagoagaandVíctor Fernández Poyatos d8dce07019 chore(deletion): Add environment variable for batch size (#7423)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-04-03 15:31:13 +05:45
Prowler Botandprowler-bot 2b0a3144c7 chore(regions_update): Changes in regions for AWS services (#7417)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-04-02 09:59:08 -04:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
62fbce0b5e chore(deps): bump azure-identity from 1.19.0 to 1.21.0 (#7192)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-04-02 11:16:47 +02:00
Pedro Martín 5a59bb335c fix(resources): add the correct id and names for resources (#7410) 2025-04-01 20:30:37 +02:00
Sergio Garcia 2719991630 fix(report): log as error when Resource ID or Name do not exist (#7411) 2025-04-01 20:24:18 +02:00
Daniel Barranquero 6a3b8c4674 feat(entra): add new check entra_admin_users_cloud_only (#7286) 2025-04-01 19:14:15 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
191fbf0177 chore(deps): bump azure-mgmt-applicationinsights from 4.0.0 to 4.1.0 (#7161)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-04-01 14:55:37 +02:00
Víctor Fernández Poyatos 228dd2952a fix(scans): Handle duplicated scan tasks (#7401) 2025-04-01 11:55:14 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
97db38aa25 chore(deps): bump azure-mgmt-containerregistry from 10.3.0 to 12.0.0 (#7025)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-04-01 10:29:31 +02:00
Pedro Martín dc953a6e22 docs(python): add annotations about Python version (#7402) 2025-03-31 18:14:59 +02:00
51e796a48d feat(gcp): add check for dormant (unused) SA keys (#7348)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2025-03-31 18:14:21 +02:00
Hugo Pereira Brito 024f1425df feat(entra): add new check entra_legacy_authentication_blocked (#7240) 2025-03-31 18:12:26 +02:00
Hugo Pereira Brito a7ed610da9 feat(entra): add new check entra_users_mfa_enabled (#7228) 2025-03-31 17:54:52 +02:00
Hugo Pereira BritoandSergio Garcia 7ba99f22cd feat(entra): add new check entra_admin_users_phishing_resistant_mfa_enabled (#7211)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-31 17:52:28 +02:00
Hugo Pereira Brito b8ce09ec34 fix(entra): check name and logic of entra_admin_users_have_mfa_enabled (#7230) 2025-03-31 17:50:51 +02:00
Daniel BarranqueroandSergio Garcia c243110a49 feat(entra): add new check entra_policy_guest_invite_only_for_admin_roles (#7241)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-31 14:53:50 +02:00
Daniel Barranquero ee27636f32 fix(redshift): validation error for Cluster.multi_az (#7381) 2025-03-31 13:55:48 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
f2f41c9c44 chore(deps): bump azure-mgmt-resource from 23.2.0 to 23.3.0 (#7054)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-03-31 13:29:49 +02:00
Daniel Barranquero 9312890e6a feat(entra): add new check entra_policy_guest_users_access_restrictions (#7234) 2025-03-31 12:45:26 +02:00
Daniel Barranquero 9578281b4f feat(entra): add new check entra_policy_restricts_user_consent_for_apps (#7225) 2025-03-31 12:32:51 +02:00
Víctor Fernández PoyatosandPablo Lara 08690068fc feat(findings): Handle muted findings in API and UI (#7378)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-03-31 12:25:58 +02:00
Hugo Pereira BritoandMrCloudSec e06a33de84 feat(entra): add new check entra_managed_device_required_for_mfa_registration (#7203)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-31 12:24:47 +02:00
Prowler Botandprowler-bot 6a3db10fda chore(regions_update): Changes in regions for AWS services (#7395)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-03-31 10:18:53 +02:00
Andoni Alonso bbed445efa chore(sentry): ignore exception when aws service not available in a region (#7352) 2025-03-31 10:13:19 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 9d65fb0bf2 chore(deps): bump trufflesecurity/trufflehog from 3.88.18 to 3.88.20 (#7394)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 10:12:55 +02:00
Prowler Botandprowler-bot 34f03ca110 chore(regions_update): Changes in regions for AWS services (#7391)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-03-27 11:10:07 +01:00
Daniel Barranquero 87c038f0c2 fix(rds): hundle Certificate rds-ca-2019 not found (#7383) 2025-03-27 11:09:33 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b3014f03b1 chore(deps): bump actions/setup-python from 5.4.0 to 5.5.0 (#7390)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-27 09:13:50 +01:00
Daniel Barranquero d39598c9fc fix(stepfunctions): Nonetype object has no attribute level (#7386) 2025-03-26 19:39:27 +01:00
Daniel Barranquero 5ea9106259 fix(fms): resource metadata could not be converted to dict (#7379) 2025-03-26 19:25:00 +01:00
Prowler Botandprowler-bot bcc0b59de1 chore(regions_update): Changes in regions for AWS services (#7382)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-03-26 12:52:35 +01:00
Daniel BarranqueroandSergio Garcia 5d6ed640f0 fix(vm): handle Nonetype is not iterable for extensions (#7360)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-25 12:25:15 +01:00
Sergio Garcia dd1cc2d025 fix(s3): handle None S3 account public access block (#7350) 2025-03-25 11:39:19 +01:00
Andoni Alonso 52e5cc23e4 fix(storagegateway): describe smb/nfs share per region (#7374) 2025-03-25 10:35:37 +01:00
Pablo Lara 76a8e2be1f chore: tweak for button see findings (#7369) 2025-03-25 09:52:36 +01:00
Andoni Alonso d989425490 fix(vm): handle NoneType accessing security_profile (#7221) 2025-03-25 09:33:00 +01:00
Hugo Pereira Brito 1e324b7ed2 fix(network): handle Nonetype is not iterable for security groups (#7208) 2025-03-25 09:28:37 +01:00
Sergio Garcia e68aa62f94 fix(iam): handle none SAML Providers (#7359) 2025-03-25 09:24:32 +01:00
Daniel Barranquero 332b98a1ab fix(iam): handle UnboundLocalError cannot access local variable 'report' (#7361) 2025-03-25 09:22:35 +01:00
Pablo Lara dd05ef7974 chore(scans): properly enable link to findings when scan is completed (#7368) 2025-03-25 08:45:37 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d6862766d3 chore(deps): bump github/codeql-action from 3.28.12 to 3.28.13 (#7367)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-25 12:43:02 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f52d005e2d chore(deps): bump tj-actions/changed-files from 46.0.1 to 46.0.3 (#7363)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-25 12:42:50 +05:45
Víctor Fernández Poyatos bf475234a5 build(api): Force django-allauth==65.4.1 (#7358) 2025-03-24 17:39:47 +01:00
Pablo Lara cd5985c056 docs: update readme (#7357) 2025-03-24 15:41:35 +01:00
Pablo Lara ce33dbf823 chore(findings): apply default filter to show failed findings (#7356) 2025-03-24 15:38:09 +01:00
Pablo Lara 0a9d0688a7 docs(changelog): document addition of download column in scans table … (#7354) 2025-03-24 15:28:13 +01:00
Pablo Lara 24784f2ce5 feat(scans): add download button column for completed scans in table (#7353) 2025-03-24 15:22:36 +01:00
Víctor Fernández Poyatos 7a1e611b88 ref(providers): Refactor provider deletion functions (#7349) 2025-03-24 14:39:14 +01:00
Pepe Fagoaga 3073150008 chore(next): Remove x-powered-by header (#7346) 2025-03-24 16:17:18 +05:45
JonnyandMrCloudSec 9923def4cb chore(awslambda): update obsolete lambda runtimes (#7330)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-24 11:21:01 +01:00
Víctor Fernández Poyatos a7f612303f feat(compliance): Add endpoint to retrieve compliance overviews metadata (#7333) 2025-03-24 10:34:43 +01:00
Pablo Lara 64c2a2217a docs: update changelog with Next.js security patch (#7339) (#7341) 2025-03-24 09:59:59 +01:00
Pablo Lara 4689d7a952 chore: upgrade Next.js to 14.2.25 to fix auth middleware vulnerability (#7339) 2025-03-24 09:48:41 +01:00
Prowler BotandMrCloudSec 87cd143967 chore(regions_update): Changes in regions for AWS services (#7219)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-24 09:46:57 +01:00
Prowler BotandMrCloudSec e37fd05d58 chore(regions_update): Changes in regions for AWS services (#7246)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-24 09:46:26 +01:00
Prowler BotandMrCloudSec acc708bda5 chore(regions_update): Changes in regions for AWS services (#7250)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-24 09:46:08 +01:00
Prowler Botandprowler-bot c7460bb69c chore(regions_update): Changes in regions for AWS services (#7334)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-03-24 09:35:47 +01:00
Pepe Fagoaga 84b273dab9 fix(action): Use Poetry v2 (#7329) 2025-03-20 18:49:32 +01:00
Prowler Botandprowler-bot bb7ce2157e chore(regions_update): Changes in regions for AWS services (#7323)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2025-03-20 18:10:28 +05:45
Pepe Fagoaga 07b9e1d3a4 chore(api): Update CHANGELOG (#7325) 2025-03-20 15:22:00 +05:45
Pepe Fagoaga 96a879d761 fix(scan_id): Read the ID from the Scan object (#7324) 2025-03-20 15:18:31 +05:45
Pepe Fagoaga 283127c3f4 chore(aws-regions): remove backport to v3 (#7319) 2025-03-19 22:14:41 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> beeee80a0b chore(deps): bump github/codeql-action from 3.28.11 to 3.28.12 (#7321)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 22:14:23 +05:45
Pepe Fagoaga 06b62826b4 chore(dependabot): disable for v3 (#7316) 2025-03-19 21:56:52 +05:45
Pedro Martín d0736af209 fix(gcp): make provider id mandatory in test_connection (#7296) 2025-03-19 18:33:49 +05:45
Pablo LaraandVíctor Fernández Poyatos 716c8c1a5f docs: add social login images and update documentation (#7314)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-03-19 17:16:37 +05:45
Pepe Fagoaga e6cdda1bd9 chore(dependabot): Disable for API and UI (#7300) 2025-03-19 14:46:11 +05:45
Pedro Martín 2747a633bc fix(k8s): remove typos from PCI 4.0 (#7294) 2025-03-19 09:31:40 +01:00
Pepe Fagoaga 74118f5cfe chore(social-login): improve copy when not enabled (#7295) 2025-03-19 13:36:22 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 598bdf28bb chore(deps): bump trufflesecurity/trufflehog from 3.88.17 to 3.88.18 (#7297)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 12:31:52 +05:45
Pepe FagoagaandPablo Lara d75f681c87 chore(security): Configure HTTP Security Headers (#7220)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-03-18 17:49:12 +01:00
Pepe Fagoaga c7956ede6a chore(security): Add HTTP Security Headers (#7289) 2025-03-18 17:44:57 +01:00
Pablo Lara 64f5a69e84 fix: prevent SSR mismatch in OAuth URL generation (#7288) 2025-03-18 17:22:29 +01:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
bfb15c34b8 chore(deps): bump azure-mgmt-containerservice from 34.0.0 to 34.1.0 (#6989)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-03-18 17:14:25 +01:00
Pablo Lara 638b3ac0cd chore(providers): change wording when adding a new provider (#7280) 2025-03-18 21:50:56 +05:45
Daniel Barranquero 9d6147a037 fix(route53): solve false positive in route53_public_hosted_zones_cloudwatch_logging_enabled (#7201) 2025-03-18 16:54:49 +01:00
Pepe Fagoaga 802c786ac2 fix(test-connection): Handle provider without secret (#7283) 2025-03-18 21:34:36 +05:45
Pepe Fagoaga c8be8dbd9a fix(aws-regions): Use @prowler-bot as author (#7285) 2025-03-18 20:27:19 +05:45
Pablo LaraandAdrián Jesús Peña Rodríguez 7053b2bb37 chore: add env vars for social login (#7257)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-03-18 13:43:46 +01:00
Prowler BotandMrCloudSec 447bf832cd chore(regions_update): Changes in regions for AWS services (#7281)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-18 17:35:44 +05:45
Pablo Lara 7c4571b55e feat(providers): add component to render a link to the documentation (#7282) 2025-03-18 12:05:38 +01:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Rubén De la Torre Vico
eb7c16aba5 chore(deps): bump azure-mgmt-storage from 21.2.1 to 22.1.1 (#7098)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-03-18 11:06:46 +01:00
Adrián Jesús Peña Rodríguez b09e83b171 chore: add api reference to download report section (#7243) 2025-03-18 14:54:13 +05:45
Hugo Pereira Brito bb149a30a7 fix(microsoft365): typo Microsoft365NotTenantIdButClientIdAndClienSecretError (#7244) 2025-03-17 21:16:47 +05:45
Pablo Lara d5be35af49 chore: Rename keyServer and extract to helper (#7256) 2025-03-17 21:11:27 +05:45
Pedro Martín f6aa56d92b fix(.env): remove spaces (#7255) 2025-03-17 20:48:55 +05:45
Pedro Martín 6a4df15c47 fix(prowler): change from prowler.py to prowler-cli.py (#7253) 2025-03-17 15:44:15 +01:00
Pablo Lara 72de5fdb1b chore: update git ignore file (#7254) 2025-03-17 14:53:58 +01:00
Pedro Martín a7f55d06af feat(jira): add basic auth method (#7233) 2025-03-17 14:31:35 +01:00
Pepe Fagoaga 97da78d4e7 fix(backport): Use container tagged version (#7252) 2025-03-17 18:19:43 +05:45
Pepe Fagoaga c4f6161c73 chore(security): Pin actions to the Full-Length Commit SHA (#7249) 2025-03-17 17:11:28 +05:45
Pablo Lara db7ffea24d chore: add env var for social login (#7251) 2025-03-17 10:23:01 +01:00
Prowler BotandMrCloudSec 489b5abf82 chore(regions_update): Changes in regions for AWS services (#7237)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-17 13:47:56 +05:45
Prowler BotandMrCloudSec 3a55c2ee07 chore(regions_update): Changes in regions for AWS services (#7245)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-17 12:34:44 +05:45
Pedro Martín 64d866271c fix(scan): add compliance info inside finding (#5649) 2025-03-17 12:18:00 +05:45
Pablo Lara 1ab2a80eab chore: improve UX when social login is not enabled (#7242) 2025-03-15 12:12:30 +01:00
Pablo Lara 89d4c521ba chore(social-login): disable social login buttons when env vars are not set (#7238) 2025-03-14 11:32:22 +01:00
Pablo Lara f2e19d377a chore(social-login): rename env.vars for social login (#7232) 2025-03-13 17:07:17 +01:00
Pablo Lara 2b7b887b87 chore: social auth is algo in sign-up page (#7231) 2025-03-13 14:20:09 +01:00
Pablo Lara 44c70b5d01 chore: remove unused regions (#7229) 2025-03-13 13:57:16 +01:00
Pablo Lara 7514484c42 chore: change wording for launching a single scan (#7226) 2025-03-13 13:48:01 +01:00
Adrián Jesús Peña Rodríguez 9594c4c99f fix: add a handled response in case local files are missing (#7183) 2025-03-13 13:47:00 +01:00
Pablo Lara 56445c9753 chore: update changelog (#7223) 2025-03-13 13:39:26 +01:00
Adrián Jesús Peña Rodríguez 07419fd5e1 fix(exports): change the way to remove the local export files after s3 upload (#7172) 2025-03-13 13:37:17 +01:00
Pablo LaraandVíctor Fernández Poyatos 2e4dd12b41 feat(social-login): social login with Google is working (#7218)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-03-13 12:52:30 +01:00
Víctor Fernández Poyatos fed2046c49 fix(migrations): add through parameter to integration.providers (#7222) 2025-03-13 12:47:34 +01:00
Pepe Fagoaga db79db4786 fix(pyproject): Rename prowler.py (#7217) 2025-03-13 16:53:38 +05:45
Víctor Fernández Poyatos 6f027e3c57 feat(integrations): Added new endpoints to allow configuring integrations (#7167) 2025-03-12 19:57:55 +05:45
bdb877009f feat(entra): add new check entra_admin_mfa_enabled_for_administrative_roles (#7181)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-12 14:47:29 +01:00
Sergio Garcia 6564ec1ff5 fix(cloudwatch): handle None metric alarms (#7205) 2025-03-12 14:44:36 +01:00
Pedro Martín 443dc067b3 feat(kubernetes): add ISO 27001 2022 compliance framework (#7204) 2025-03-12 14:24:53 +01:00
Hugo Pereira BritoandMrCloudSec 6221650c5f feat(entra): add new check entra_identity_protection_sign_in_risk_enabled (#7171)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-12 13:53:47 +01:00
Andoni Alonso 034d0fd1f4 refactor(check): add docstrings and improve report handling (#7113) 2025-03-12 13:38:42 +01:00
Hugo Pereira Brito e617ff0460 feat(docs): add microsoft365 configurable checks (#7200) 2025-03-12 12:52:35 +01:00
Hugo Pereira BritoandMrCloudSec 4b1ed607a7 feat(entra): add new check entra_identity_protection_user_risk_enabled (#7126)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-12 12:44:31 +01:00
Pepe Fagoaga 137365a670 chore(poetry): Upgrade to v2 (#7112) 2025-03-12 17:28:34 +05:45
Hugo Pereira BritoandMrCloudSec 1891a1b24f feat(entra): add new check entra_managed_device_required_for_authentication (#7115)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-12 11:34:14 +01:00
Daniel Barranquero e57e070866 feat(entra): add new check entra_password_hash_sync_enabled (#7061) 2025-03-12 11:31:49 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 66998cd1ad chore(deps): bump google-api-python-client from 2.162.0 to 2.163.0 (#7191)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 11:25:24 +01:00
Prowler BotandMrCloudSec c0b1833446 chore(regions_update): Changes in regions for AWS services (#7197)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-12 11:25:06 +01:00
Pablo Lara 329a72c77c chore: update changelog (#7199) 2025-03-12 10:12:33 +01:00
Pablo Lara 2610ee9d0c feat(invitations): Disable editing for accepted invites (#7198) 2025-03-12 10:06:46 +01:00
Pablo Lara a13ca9034e chore(scans): rename type to trigger (#7196) 2025-03-12 09:47:02 +01:00
Pablo Lara 5d1abb3689 chore: auto refresh if the state is also available (#7195) 2025-03-12 09:33:24 +01:00
Pablo Lara e1d1c6d154 styles: tweaks styles (#7194) 2025-03-12 09:23:02 +01:00
Pablo Lara e18e0e7cd4 chore(launch-scan): update wording (#7193) 2025-03-12 08:20:15 +01:00
Pablo Lara eaf3d07a3f chore: update the changelog (#7190) 2025-03-12 08:15:28 +01:00
Hugo Pereira BritoandMrCloudSec c88ae32b7f feat(microsoft365): add new check entra_admin_users_sign_in_frequency_enabled (#7020)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-11 19:18:33 +01:00
Pablo Lara 605613e220 feat(scans): allow running a scan once (#7188) 2025-03-11 17:47:47 +01:00
Sergio Garcia d2772000ec chore(sentry): ignore new exceptions in Sentry (#7187) 2025-03-11 17:46:14 +01:00
Adrián Jesús Peña Rodríguez 42939a79f5 docs: add users, invitations and RBAC (#7109) 2025-03-11 21:59:04 +05:45
Daniel BarranqueroandSergio Garcia ed17931117 feat(entra): add new check entra_dynamic_group_for_guests_created (#7168)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-11 16:21:17 +01:00
66df5f7a1c chore(providers): enhance Remediation.Code.CLI field from check's metadata (#7094)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-03-11 16:15:58 +01:00
Pedro Martín fc6e6696e5 feat(gcp): add ISO 27001 2022 compliance framework (#7185) 2025-03-11 15:16:40 +01:00
Sergio Garcia 465748c8a1 chore(sentry): ignore expected errors in GCP API (#7184) 2025-03-11 14:32:37 +01:00
Pedro Martín e59cd71bbf fix(azure): add remaining checks for reqA.5.25 (#7182) 2025-03-11 14:16:10 +01:00
Daniel Barranquero 8a76fea310 feat(entra): add new check entra_admin_consent_workflow_enabled (#7110) 2025-03-11 13:18:17 +01:00
Adrián Jesús Peña RodríguezandPepe Fagoaga 0e46be54ec docs: add generate_output documentation (#7122)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-03-11 17:23:32 +05:45
Pedro Martín dc81813fdf fix(ens): remove and change duplicated ids (#7165) 2025-03-11 11:35:31 +01:00
Hugo Pereira Brito eaa0df16bb refactor(microsoft365): resource metadata assertions (#7169) 2025-03-11 11:30:37 +01:00
Pedro Martín c23e911028 feat(azure): add ISO 27001 2022 compliance framework (#7170) 2025-03-11 11:29:40 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 06b96a1007 chore(deps): bump tzlocal from 5.3 to 5.3.1 (#7162)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 11:17:50 +01:00
Prowler BotandMrCloudSec fa545c591f chore(regions_update): Changes in regions for AWS services (#7177)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-11 11:17:27 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> e828b780c7 chore(deps): bump trufflesecurity/trufflehog from 3.88.15 to 3.88.16 (#7174)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 11:16:57 +01:00
Harshit Raj Singhandpedrooot eca8c5cabd feat(aws): AWS Found Sec Best Practices & PCI DSS v3.2.1 upgrade (#7017)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-03-11 09:31:16 +01:00
Pablo Lara b7bce6008f fix: tweak z-index for custom inputs (#7166) 2025-03-10 11:55:04 +01:00
Pablo Lara 2fdf89883d feat(scans): improve scan launch provider selection (#7164) 2025-03-10 10:05:33 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 6c5d4bbaaa chore(deps): bump django from 5.1.5 to 5.1.7 in /api (#7145)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 09:50:09 +01:00
Gary Mclean cb2f926d4f fix(azure): correct check title for SQL Server Unrestricted (#7123) 2025-03-07 18:24:24 +01:00
ryan-stavella 12c01b437e fix(metadata): typo in ec2_securitygroup_allow_wide_open_public_ipv4 (#7116) 2025-03-07 15:28:08 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3253a58942 chore(deps-dev): bump mock from 5.1.0 to 5.2.0 (#7099)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 15:01:43 +01:00
Kay Agahd 199f7f14ea fix(doc): event_time has been changed to time_dt but was not documented (#7136) 2025-03-07 14:36:51 +01:00
Andoni Alonso d42406d765 fix(metadata): match type with check results (#7111) 2025-03-07 14:34:07 +01:00
Kay Agahd 2276ffb1f6 fix(aws): ecs_task_definitions_no_environment_secrets.metadata.json (#7135) 2025-03-07 14:31:03 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 218fb3afb0 chore(deps): bump jinja2 from 3.1.5 to 3.1.6 (#7151)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 14:27:29 +01:00
Prowler BotandMrCloudSec a9fb890979 chore(regions_update): Changes in regions for AWS services (#7108)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-07 14:06:28 +01:00
Prowler BotandMrCloudSec 54ebf5b455 chore(regions_update): Changes in regions for AWS services (#7119)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-07 14:04:48 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> c9a0475aa8 chore(deps-dev): bump mkdocs-git-revision-date-localized-plugin from 1.3.0 to 1.4.1 (#7129)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 14:03:44 +01:00
Prowler BotandMrCloudSec 5567d9f88c chore(regions_update): Changes in regions for AWS services (#7131)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-07 13:19:08 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 56f3e661ae chore(deps): bump trufflesecurity/trufflehog from 3.88.14 to 3.88.15 (#7127)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 13:17:45 +01:00
César Arroba 1aa4479a10 chore: increase release to 5.5.0 (#7143) 2025-03-07 13:16:24 +01:00
Prowler BotandMrCloudSec 7b625d0a91 chore(regions_update): Changes in regions for AWS services (#7146)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-07 13:15:51 +01:00
Pablo Lara fd0529529d chore: update changelog (#7149) 2025-03-07 11:47:23 +01:00
Pablo Lara af43191954 fix: tweaks for compliance cards (#7147) 2025-03-07 11:32:58 +01:00
Pablo Lara 2ce2ca7c91 feat: add changelog (#7141) 2025-03-06 16:46:55 +01:00
Víctor Fernández Poyatos a0fc3db665 fix(overviews): manage overview exceptions and use batch_size with bulk (#7140) 2025-03-06 15:35:29 +01:00
César Arroba feb458027f chore(ui-gha): delete double quotes on prowler version (#7139) 2025-03-06 19:48:53 +05:45
Pablo Lara e5a5b7af5c fix(groups): display uid if alias is missing (#7137) 2025-03-06 14:37:36 +01:00
Pablo Lara ad456ae2fe fix(credentials): adjust helper links to fit width (#7133) 2025-03-06 11:42:26 +01:00
Pepe Fagoaga 690cb51f6c revert(findings): change uid from varchar to text (#7132) 2025-03-06 16:24:35 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 14aaa2f376 chore(deps): bump jinja2 from 3.1.5 to 3.1.6 in /api (#7130)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 09:39:24 +01:00
César Arroba 6e47ca2c41 chore(ui-gha): add version prefix (#7125) 2025-03-05 21:13:24 +05:45
Víctor Fernández Poyatos 0d99d2be9b fix(reports): Fix task kwargs and result (#7124) 2025-03-05 21:10:44 +05:45
César Arroba c322ef00e7 chore(ui): add prowler version on build (#7120) 2025-03-05 20:46:16 +05:45
Pablo Lara 3513421225 feat(compliance): new compliance selector (#7118) 2025-03-05 15:12:10 +01:00
Víctor Fernández Poyatos b0e6bfbefe chore(api): Update changelog (#7090) 2025-03-04 17:44:34 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f7a918730e chore(deps-dev): bump pytest from 8.3.4 to 8.3.5 (#7097)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-04 09:16:05 +01:00
Pablo Lara cef33319c5 chore(ui): update label from 'Select a scan job' to 'Select a cloud p… (#7107) 2025-03-04 09:11:39 +01:00
Pablo Lara 2036a59210 fix(roles): show the correct error message (#7089) 2025-03-03 15:46:02 +01:00
Pablo Lara e5eccb6227 fix: bug with create role and unlimited visibility checkbox (#7088) 2025-03-03 15:45:39 +01:00
Sergio Garcia 48c2c8567c feat(aws): add fixers for threat detection checks (#7085) 2025-03-03 14:20:23 +01:00
Pablo Lara bbeef0299f feat(version): add prowler version to the sidebar (#7086) 2025-03-03 13:40:09 +01:00
Pablo Lara bec5584d63 chore: Update the latest table findings with the most recent changes (#7084) 2025-03-03 13:16:30 +01:00
Pablo Lara bdc759d34c feat(sidebar): sidebar with new functionalities (#7018) 2025-03-03 12:30:28 +01:00
Prowler BotandMrCloudSec 8db442d8ba chore(regions_update): Changes in regions for AWS services (#7067)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 09:29:48 +01:00
Sergio Garcia 9e7a0d4175 fix(threat detection): run single threat detection check (#7065) 2025-02-28 13:51:07 +01:00
Pepe Fagoagaandpedrooot 9c33b3f5a9 refactor(stats): Use Finding instead of Check_Report (#7053)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-02-28 10:54:48 +01:00
Pepe Fagoaga 7e7e2c87dc chore(examples): Scan AWS (#7064) 2025-02-28 15:25:10 +05:45
Sergio Garcia 2f741f35a8 chore(gcp): enhance GCP APIs logic (#7046) 2025-02-28 14:55:43 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> c411466df7 chore(deps): bump trufflesecurity/trufflehog from 3.88.13 to 3.88.14 (#7063)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 09:10:47 +01:00
9679939307 feat(m365): add sharepoint service with 4 checks (#7057)
Co-authored-by: MarioRgzLpz <mariorgzlpz1809@gmail.com>
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-27 18:15:17 +01:00
Pedro Martín 8539423b22 feat(docs): add info related with sts assume role and regions (#7062) 2025-02-27 17:40:31 +01:00
Daniel Barranquero 81edafdf09 fix(azure): handle account not supporting Blob (#7060) 2025-02-27 13:20:56 +01:00
Sergio Garcia e0a262882a fix(ecs): ensure unique finding id in ECS checks (#7059) 2025-02-27 13:02:22 +01:00
Prowler BotandMrCloudSec 89237ab99e chore(regions_update): Changes in regions for AWS services (#7056)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-27 11:00:13 +01:00
Hugo Pereira BritoandMrCloudSec 0f414e451e feat(microsoft365): add new check entra_policy_ensure_default_user_cannot_create_tenants (#6918)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-27 10:31:02 +01:00
Pablo Lara 1180522725 feat(exports): download scan exports (#7006) 2025-02-27 14:08:12 +05:45
Pepe Fagoaga 81c7ebf123 fix(env): UI version must be stable (#7055) 2025-02-27 13:32:53 +05:45
Víctor Fernández Poyatos 258f05e6f4 fix(migrations): Fix migration dependency order (#7051) 2025-02-26 17:26:21 +01:00
Víctor Fernández Poyatos 53efb1c153 feat(labeler): apply label on migration changes (#7052) 2025-02-26 17:03:12 +01:00
Pepe Fagoaga 26014a9705 fix(findings): change uid from varchar to text (#7048) 2025-02-26 21:17:16 +05:45
Víctor Fernández Poyatos 00ef037e45 feat(findings): Add Django management command to populate database with dummy data (#7049) 2025-02-26 16:15:37 +01:00
Adrián Jesús Peña Rodríguez 669ec74e67 feat(export): add API export system (#6878) 2025-02-26 15:49:44 +01:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MrCloudSec
c4528200b0 chore(deps-dev): bump black from 24.10.0 to 25.1.0 (#6733)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-26 11:38:09 +01:00
Daniel Barranquero ba7cd0250a fix(elasticache): improve logic in elasticache_redis_cluster_backup_enabled (#7042) 2025-02-26 10:31:14 +01:00
Rubén De la Torre Vico c5e97678a1 fix(azure): migrate resource models to avoid using SDK defaults (#6880) 2025-02-26 09:54:53 +01:00
Pedro MartínandMrCloudSec 337a46cdcc feat(aws): add ISO 27001 2022 compliance framework (#7035)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-26 08:34:08 +01:00
Hugo Pereira Brito 7f74b67f1f chore(iam): enhance iam_role_cross_service_confused_deputy_prevention recommendation (#7023) 2025-02-26 07:37:57 +01:00
Prowler BotandMrCloudSec 5dcc48d2e5 chore(regions_update): Changes in regions for AWS services (#7034)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-26 07:30:07 +01:00
Prowler BotandMrCloudSec 8b04aab07d chore(regions_update): Changes in regions for AWS services (#7015)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-26 07:29:42 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> eab4f6cf2e chore(deps): bump google-api-python-client from 2.161.0 to 2.162.0 (#7037)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-26 07:25:14 +01:00
Hugo Pereira Brito 7f8d623283 refactor(microsoft365): CheckReportMicrosoft365 and resource metadata (#6952) 2025-02-26 07:24:54 +01:00
Víctor Fernández Poyatos dbffed8f1f feat(findings): Optimize findings endpoint (#7019) 2025-02-25 12:41:47 +01:00
Pepe Fagoaga 7e3688fdd0 chore(action): Conventional Commit Check (#7033) 2025-02-25 09:51:55 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 2e111e9ad3 chore(deps): bump trufflesecurity/trufflehog from 3.88.12 to 3.88.13 (#7026)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 14:34:24 +05:45
Pedro Martín 6d6070ff3f feat(outputs): add sample outputs (#6945) 2025-02-25 14:33:16 +05:45
Pedro Martín 391bbde353 fix(cis): show report table on the CLI (#6979) 2025-02-25 14:28:58 +05:45
Pedro Martín 3c56eb3762 feat(azure): add PCI DSS 4.0 (#6982) 2025-02-25 14:27:50 +05:45
Pedro Martín 7c14ea354b feat(kubernetes): add PCI DSS 4.0 (#7013) 2025-02-25 14:27:14 +05:45
Pedro Martín c96aad0b77 feat(dashboard): take the latest finding uid by timestamp (#6987) 2025-02-25 14:25:03 +05:45
Víctor Fernández Poyatos a9dd3e424b feat(tasks): add deletion queue for deletion tasks (#7022) 2025-02-24 18:02:52 +01:00
Pedro Martín 8a144a4046 feat(gcp): add PCI DSS 4.0 (#7010) 2025-02-21 16:19:20 +05:30
Prowler BotandMrCloudSec 75f86d7267 chore(regions_update): Changes in regions for AWS services (#7011)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-21 15:37:15 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> bbf875fc2f chore(deps-dev): bump mkdocs-material from 9.6.4 to 9.6.5 (#7007)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 14:28:18 +05:30
Raj Chowdhury 59d491f61b fix(typo): solve typo in dashboard.md (#7009) 2025-02-21 14:17:08 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ed640a1324 chore(deps): bump trufflesecurity/trufflehog from 3.88.11 to 3.88.12 (#7008)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 14:16:15 +05:30
César Arroba e86fbcaef7 feat(api): setup sentry for OSS API (#6874) 2025-02-20 23:08:01 +05:45
Pablo Lara 7f48212054 chore(users): renaming the account now triggers a re-render in the sidebar (#7005) 2025-02-20 16:58:45 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> a2c5c71baf chore(deps): bump python from 3.12.8-alpine3.20 to 3.12.9-alpine3.20 (#6882)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 21:11:45 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b904f81cb9 chore(deps): bump tzlocal from 5.2 to 5.3 (#6932)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 21:10:46 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d64fe374dd chore(deps): bump cryptography from 43.0.1 to 44.0.1 in /api (#7001)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 12:55:36 +01:00
Hugo Pereira Brito fe25e7938e docs(tutorials): update all deprecated poetry shell references (#7002) 2025-02-20 17:04:19 +05:45
Prowler BotandMrCloudSec 931df361bf chore(regions_update): Changes in regions for AWS services (#6998)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-20 15:52:36 +05:30
Pedro Martín d7c45f4aee chore(github): add compliance to PR labeler (#6996) 2025-02-20 14:50:43 +05:30
Pedro Martín 5e5bef581b fix(soc2_aws): remove duplicated checks (#6995) 2025-02-20 14:38:26 +05:30
Hugo Pereira Brito 2d9e95d812 docs(installation): add warning for poetry shell deprecation in README (#6983) 2025-02-20 14:19:35 +05:45
Pablo Lara e5f979d106 chore(findings): add 'Status Extended' attribute to finding details (#6997) 2025-02-20 09:33:03 +01:00
Sergio Garcia c7a5815203 fix(deps): update vulnerable cryptography dependency (#6993) 2025-02-20 12:18:15 +05:30
Pedro Martín 03e268722e feat(aws): add PCI DSS 4.0 (#6949) 2025-02-20 11:07:06 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 78a2774329 chore(deps): bump trufflesecurity/trufflehog from 3.88.9 to 3.88.11 (#6988)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:04:15 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> c1b5ab7f53 chore(deps): bump kubernetes from 32.0.0 to 32.0.1 (#6992)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 10:46:19 +05:30
Sergio Garcia b861d97ad4 fix(report): remove invalid resources in report (#6852) 2025-02-19 21:27:52 +05:45
Pablo Lara f3abcc9dd6 feat(scans): update the progress for executing scans (#6972) 2025-02-19 16:10:29 +01:00
César Arroba cab13fe018 chore(gha): trigger API or UI deployment when push to master (#6946) 2025-02-19 18:08:51 +05:45
Prowler Bot cc4b19c7ce chore(regions_update): Changes in regions for AWS services (#6978) 2025-02-19 11:04:45 +01:00
Pablo Lara a754d9aee5 fix(roles): handle empty response in deleteRole and ensure revalidation (#6976) 2025-02-19 09:03:49 +01:00
Pedro Martín 22b54b2d8d feat(aws): add compliance CIS 4.0 (#6937) 2025-02-19 08:23:49 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d12ca6301a chore(deps-dev): bump flake8 from 7.1.1 to 7.1.2 (#6954)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-19 08:09:58 +05:30
Hugo Pereira Brito bc1b2ad9ab test(cloudfront): add name retrieval test for cloudfront bucket domains (#6969) 2025-02-19 08:08:55 +05:30
Pepe Fagoaga 1782ab1514 fix(ocsf): Adapt for 1.4.0 (#6971) 2025-02-19 08:06:13 +05:30
Prowler BotandMrCloudSec 0384fc50e3 chore(regions_update): Changes in regions for AWS services (#6968)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-18 18:40:01 +05:30
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> cc46dee9ee chore(deps-dev): bump bandit from 1.8.2 to 1.8.3 (#6955)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 18:39:10 +05:30
Hugo Pereira Brito ed5a0ae45a fix(cloudfront): Incorrect bucket name retrievement (#6947) 2025-02-17 17:08:28 +01:00
Prowler BotandMrCloudSec 928ccfefb8 chore(regions_update): Changes in regions for AWS services (#6944)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-17 16:55:15 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 7f6bfb7b3e chore(deps): bump trufflesecurity/trufflehog from 3.88.8 to 3.88.9 (#6943)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-17 16:54:52 +01:00
Rubén De la Torre Vico bcbc9bf675 fix(gcp): Correct false positive when sslMode=ENCRYPTED_ONLY in CloudSQL (#6936) 2025-02-14 15:16:21 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 0ec4366f4c chore(deps): bump google-api-python-client from 2.160.0 to 2.161.0 (#6933)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-14 10:09:33 -05:00
César Arroba ff72b7eea1 fix(gha): fix short sha step (#6939) 2025-02-14 19:11:26 +05:45
César Arroba a32ca19251 chore(gha): add tag for api and ui images on push to master (#6920) 2025-02-14 18:01:22 +05:45
Pablo Lara b79508956a fix(issue pages): apply sorting by default in issue pages (#6934) 2025-02-14 10:32:34 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d76c5bd658 chore(deps): bump trufflesecurity/trufflehog from 3.88.7 to 3.88.8 (#6931)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-13 18:17:25 -05:00
Kay Agahd 580e11126c fix(aws): codebuild service threw KeyError for projects type CODEPIPELINE (#6919) 2025-02-13 12:22:09 -05:00
Sergio Garcia 736d40546a fix(gcp): handle DNS Managed Zone with no DNSSEC (#6924) 2025-02-13 12:18:50 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 88810d2bb5 chore(deps-dev): bump mkdocs-material from 9.6.3 to 9.6.4 (#6913)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-13 11:36:07 -05:00
Víctor Fernández Poyatos 3a8f4d2ffb feat(social-login): Add social login integration for Google and Github OAuth providers (#6906) 2025-02-13 16:54:38 +01:00
Sergio Garcia 1fe125a65f chore(docs): external K8s cluster Prowler App credentials (#6921) 2025-02-13 09:46:05 -05:00
Kay Agahd 0ff4df0836 fix(aws): SNS threw IndexError if SubscriptionArn is PendingConfirmation (#6896) 2025-02-13 09:34:48 -05:00
Pedro Martín 16b4775e2d fix(gcp): remove typos on CIS 3.0 (#6917) 2025-02-13 13:48:19 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> c3a13b8a29 chore(deps): bump trufflesecurity/trufflehog from 3.88.6 to 3.88.7 (#6915)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-12 19:15:03 -05:00
Sergio GarciaandPedro Martín d1053375b7 fix(aws): handle AccessDenied when retrieving resource policy (#6908)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-12 15:31:26 -05:00
César Arroba 0fa4538256 fix(gha): fix test build containers on pull requests actions (#6909) 2025-02-12 23:26:54 +05:45
Ogonna IwunzeandMrCloudSec 738644f288 fix(kms): Amazon KMS API call error handling (#6843)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-12 10:09:15 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 2f80b055ac chore(deps-dev): bump coverage from 7.6.11 to 7.6.12 (#6897)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-12 10:08:26 -05:00
Prowler BotandMrCloudSec fd62a1df10 chore(regions_update): Changes in regions for AWS services (#6900)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-12 10:06:42 -05:00
César Arroba a85d0ebd0a chore(api): test build container image on pull request (#6850) 2025-02-12 15:44:05 +05:45
César Arroba 2c06902baa chore(ui): test build container image on pull request (#6849) 2025-02-12 15:43:22 +05:45
Pepe Fagoaga 76ac6429fe chore(version): Update version to 5.4.0 (#6894) 2025-02-11 17:51:08 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 43cae66b0d chore(deps-dev): bump coverage from 7.6.10 to 7.6.11 (#6887)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-10 19:30:36 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dacddecc7d chore(deps): bump trufflesecurity/trufflehog from 3.88.5 to 3.88.6 (#6888)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-10 18:15:25 -05:00
dcb9267c2f feat(microsof365): Add documentation and compliance file (#6195)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-02-10 11:13:06 -05:00
Víctor Fernández Poyatos ff35fd90fa chore(api): Update changelog and specs (#6876) 2025-02-10 12:06:34 +01:00
Víctor Fernández Poyatos 7469377079 chore: Add needed steps for API in PR template (#6875) 2025-02-10 15:20:09 +05:45
Pepe FagoagaandSergio Garcia c8441f8d38 fix(kubernetes): Change UID validation (#6869)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-10 14:55:24 +05:45
Pepe FagoagaandPablo Lara abf4eb0ffc chore: Rename dashboard table latest findings (#6873)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-02-10 09:55:44 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 93717cc830 chore(deps-dev): bump mkdocs-material from 9.6.2 to 9.6.3 (#6871)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-07 18:24:49 -05:00
Sergio GarciaandPepe Fagoaga b629bc81f8 docs(eks): add documentation about EKS onboarding (#6853)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-02-07 10:59:01 -05:00
Pedro Martín f628897fe1 fix(dashboard): adjust the bar chart display (#6690) 2025-02-07 10:05:30 -05:00
Prowler BotandMrCloudSec 54b82a78e3 chore(regions_update): Changes in regions for AWS services (#6858)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-07 10:02:28 -05:00
Víctor Fernández PoyatosandPepe Fagoaga 377faf145f feat(findings): Use ArrayAgg and subqueries on metadata endpoint (#6863)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-02-07 19:36:01 +05:45
Kay Agahd 69e316948f fix(aws): key error for detect-secrets (#6710) 2025-02-07 14:48:16 +01:00
Pablo Lara 62cbff4f53 feat: implement new functionality with inserted_at__gte in findings a… (#6864) 2025-02-07 14:25:25 +01:00
Víctor Fernández Poyatos 5582265e9d docs: Add details about user creation in Prowler app (#6862) 2025-02-07 13:29:25 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> fb5ea3c324 chore(deps): bump microsoft-kiota-abstractions from 1.9.1 to 1.9.2 (#6856)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-07 11:07:43 +01:00
Víctor Fernández Poyatos 9b5f676f50 feat(findings): Require date filters for findings endpoints (#6800) 2025-02-07 13:54:55 +05:45
Pranay Girase 88cfc0fa7e fix(typo): typos in Dashboard and Report in HTML (#6847) 2025-02-06 10:42:31 -05:00
Prowler BotandMrCloudSec 665bfa2f13 chore(regions_update): Changes in regions for AWS services (#6848)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-06 08:46:32 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b89b1a64f4 chore(deps): bump trufflesecurity/trufflehog from 3.88.4 to 3.88.5 (#6844)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 18:02:42 -05:00
Sergio Garcia 9ba657c261 fix(kms): handle error in DescribeKey function (#6839) 2025-02-05 14:03:31 -05:00
Mario Rodriguez LopezandMrCloudSec bce958b8e6 feat(entra): add new check entra_thirdparty_integrated_apps_not_allowed (#6357)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-05 12:45:48 -05:00
Daniel Barranquero 914012de2b fix(cloudfront): fix false positive in s3 origins (#6823) 2025-02-05 12:39:49 -05:00
Ogonna IwunzeandMrCloudSec 8d1c476aed feat(kms): add kms_cmk_not_multi_region AWS check (#6794)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-05 11:20:29 -05:00
Gary Mclean 567c729e9e fix(findings) Spelling mistakes correction (#6822) 2025-02-05 10:26:50 -05:00
Kay Agahd 3f03dd20e4 fix(aws) wording of report.status_extended in awslambda_function_not_publicly_accessible (#6824) 2025-02-05 10:23:52 -05:00
Daniel BarranqueroandMrCloudSec 1c778354da fix(directoryservice): handle ClientException (#6781)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-05 10:22:32 -05:00
Prowler BotandMrCloudSec 3a149fa459 chore(regions_update): Changes in regions for AWS services (#6821)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-05 09:19:56 -05:00
Mario Rodriguez LopezandMrCloudSec f3b121950d feat(entra): add new entra service for Microsoft365 (#6326)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 19:47:14 -05:00
Mario Rodriguez LopezandMrCloudSec 43c13b7ba1 feat(microsoft365): add new check admincenter_settings_password_never_expire (#6023)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 17:24:11 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 9447b33800 chore(deps): bump kubernetes from 31.0.0 to 32.0.0 (#6678)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 17:22:51 -05:00
Hugo Pereira BritoandMrCloudSec 2934752eeb fix(elasticache): InvalidReplicationGroupStateFault error (#6815)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 14:28:31 -05:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MrCloudSec
dd6d8c71fd chore(deps-dev): bump moto from 5.0.27 to 5.0.28 (#6804)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 12:58:48 -05:00
Pablo Lara 80267c389b style(forms): improve spacing consistency (#6814) 2025-02-04 13:20:24 +01:00
Pablo Lara acfbaf75d5 chore(forms): improvements to the sign-in and sign-up forms (#6813) 2025-02-04 12:46:07 +01:00
Pedro Martín 5f54377407 chore(aws_audit_manager_control_tower_guardrails): add checks to reqs (#6699) 2025-02-03 14:59:08 -05:00
Drew Kerrigan 552aa64741 docs(): add description of changed and new delta values to prowler app tutorial (#6801) 2025-02-03 20:51:03 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d64f611f51 chore(deps): bump pytz from 2024.2 to 2025.1 (#6765)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 12:48:18 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> a96cc92d77 chore(deps-dev): bump mkdocs-material from 9.5.50 to 9.6.2 (#6799)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 11:37:02 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3858cccc41 chore(deps-dev): bump pylint from 3.3.3 to 3.3.4 (#6721)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 10:32:42 -05:00
Pedro MartínandSergio Garcia 072828512a fix(cis_1.5_aws): add checks to needed reqs (#6695)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-03 10:32:20 -05:00
Pedro MartínandSergio Garcia a73ffe5642 fix(cis_1.4_aws): add checks to needed reqs (#6696)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-03 10:32:10 -05:00
Pablo Lara 8e784a5b6d feat(scans): show scan details right after launch (#6791) 2025-02-03 16:08:47 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 1b6f9332f1 chore(deps): bump trufflesecurity/trufflehog from 3.88.2 to 3.88.4 (#6760)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 09:35:53 -05:00
secretcod3r db8b472729 fix(gcp): fix wrong provider value in check (#6691) 2025-02-03 09:29:08 -05:00
Pedro Martín 867b371522 fix(cis_2.0_aws): add checks to needed reqs (#6694) 2025-02-03 09:28:04 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> c0d7c9fc7d chore(deps): bump google-api-python-client from 2.159.0 to 2.160.0 (#6720)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 09:27:17 -05:00
Pablo Lara bb4685cf90 fix(findings): remove default status filtering (#6784) 2025-02-03 15:20:18 +01:00
Pablo Lara 6a95426749 fix(findings): order findings by inserted_at DESC (#6782) 2025-02-03 11:51:07 +01:00
Víctor Fernández Poyatos ef6af8e84d feat(schedules): Rework daily schedule to always show the next scan (#6700) 2025-02-03 11:08:27 +01:00
Víctor Fernández Poyatos 763130f253 fix(celery): Kill celery worker process after every task to release memory (#6761) 2025-01-31 19:30:08 +05:45
Hugo Pereira Brito 1256c040e9 fix: microsoft365 mutelist (#6724) 2025-01-31 12:32:39 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 18b7b48a99 chore(deps): bump microsoft-kiota-abstractions from 1.6.8 to 1.9.1 (#6734)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-31 10:07:17 +01:00
Pepe Fagoaga 627c11503f fix(db_event): Handle other events (#6754) 2025-01-30 21:46:43 +05:45
Víctor Fernández Poyatos 712ba84f06 feat(scans): Optimize read queries during scans (#6753) 2025-01-30 20:51:12 +05:45
Pepe Fagoaga 5186e029b3 fix(set_report_color): Add more details to error (#6751) 2025-01-30 20:48:51 +05:45
Pablo Lara 5bfaedf903 fix: Enable hot reloading when using Docker Compose for UI (#6750) 2025-01-30 14:05:39 +01:00
Víctor Fernández Poyatos 5061da6897 feat(findings): Improve /findings/metadata performance (#6748) 2025-01-30 13:31:43 +01:00
Pepe Fagoaga c159a28016 fix(neptune): correct service name (#6743) 2025-01-30 17:16:18 +05:45
Pepe Fagoaga 82a1b1c921 fix(finding): raise when generating invalid findings (#6738) 2025-01-30 15:59:38 +05:45
Pepe Fagoaga bf2210d0f4 fix(acm): Key Error DomainName (#6739) 2025-01-30 15:54:31 +05:45
Kay AgahdandPepe Fagoaga 8f0772cb94 fix(aws): iam_user_with_temporary_credentials resource in OCSF (#6697)
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
2025-01-30 15:28:21 +05:45
Pepe Fagoaga 5b57079ecd fix(sns): Add region to subscriptions (#6731) 2025-01-30 14:38:21 +05:45
Matt Johnson 350d759517 chore: Update Google Analytics ID across all docs.prowler.com sites. (#6730) 2025-01-30 12:47:01 +05:45
Pablo Lara edd793c9f5 fix(scans): change label for next scan (#6725) 2025-01-29 10:46:49 +01:00
Víctor Fernández Poyatos 545c2dc685 fix(migrations): Use indexes instead of constraints to define an index (#6722) 2025-01-29 14:24:04 +05:45
Víctor Fernández Poyatos 84955c066c revert: Update Django DB manager to use psycopg3 and connection pooling (#6717) 2025-01-28 22:15:01 +05:45
Víctor Fernández Poyatos 06dd03b170 fix(scan-summaries): Improve efficiency on providers overview (#6716) 2025-01-28 21:56:29 +05:45
Pedro Martín 47bc2ed2dc fix(defender): add field to SecurityContacts (#6693) 2025-01-28 15:52:56 +01:00
Pablo Lara 44281afc54 fix(scans): filters and sorting for scan table (#6713) 2025-01-28 13:26:31 +01:00
Víctor Fernández Poyatos 4d2859d145 fix(scans, findings): Improve API performance ordering by inserted_at instead of id (#6711) 2025-01-28 16:41:58 +05:45
Pablo Lara 45d44a1669 fix: fixed bug when opening finding details while a scan is in progress (#6708) 2025-01-28 06:58:18 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ddd83b340e chore(deps): bump uuid from 10.0.0 to 11.0.5 in /ui (#6516)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 13:39:42 +01:00
ccdb54d7c3 feat(m365): add Microsoft 365 provider (#5902)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-24 13:14:17 -05:00
Rubén De la Torre Vico bcc246d950 fix(cloudsql): add trusted client certificates case for cloudsql_instance_ssl_connections (#6682) 2025-01-24 10:42:45 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 62139e252a chore(deps): bump azure-mgmt-web from 7.3.1 to 8.0.0 (#6680)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 12:40:11 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 86950c3a0a chore(deps): bump msgraph-sdk from 1.17.0 to 1.18.0 (#6679)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 10:47:09 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f4865ef68d chore(deps): bump azure-storage-blob from 12.24.0 to 12.24.1 (#6666)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 09:44:16 +01:00
Pepe Fagoaga ea7209e7ae chore: bump for next minor (#6672) 2025-01-23 13:13:08 -05:00
Hugo Pereira Brito 998c551cf3 fix(cloudwatch): NoneType object is not iterable (#6671) 2025-01-23 12:27:07 -05:00
e6f29b0116 docs: update # of checks, services, frameworks and categories (#6528)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-23 11:11:03 -05:00
Pepe Fagoaga eb90bb39dc chore(api): Bump to v1.3.0 (#6670) 2025-01-23 21:25:29 +05:45
Pepe Fagoaga ad189b35ad chore(scan): Remove ._findings (#6667) 2025-01-23 20:43:02 +05:45
Pablo Lara 7d2989a233 chore: adjust DateWithTime component height when used with InfoField (#6669) 2025-01-23 15:18:24 +01:00
Pablo Lara 862137ae7d chore(scans): improve scan details (#6665) 2025-01-23 13:20:41 +01:00
Pedro MartínandPepe Fagoaga c86e082d9a feat(detect-secrets): get secrets plugins from config.yaml (#6544)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-23 17:18:19 +05:45
Sergio GarciaandRubén De la Torre Vico 80fe048f97 feat(resource metadata): add resource metadata to JSON OCSF (#6592)
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-01-23 16:06:30 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f2bffb3ce7 chore(deps): bump azure-mgmt-containerservice from 33.0.0 to 34.0.0 (#6630)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-22 16:37:07 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> cbe2f9eef8 chore(deps): bump azure-mgmt-compute from 33.1.0 to 34.0.0 (#6628)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-22 20:00:56 +01:00
Pepe Fagoaga 688f41f570 fix(templates): Customize principals and add validation (#6655) 2025-01-22 21:47:57 +05:45
Anton RubetsandMrCloudSec a29197637e chore(helm): Add prowler helm support (#6580)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-22 10:55:26 -05:00
Prowler BotandMrCloudSec 7a2712a37f chore(regions_update): Changes in regions for AWS services (#6652)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-22 09:30:03 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 189f5cfd8c chore(deps): bump boto3 from 1.35.94 to 1.35.99 (#6651)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-22 09:29:41 -05:00
Kay Agahd e509480892 fix: add detector and line number of potential secret (#6654) 2025-01-22 20:13:23 +05:45
Pepe Fagoaga 7f7955351a chore(pre-commit): poetry checks for API and SDK (#6658) 2025-01-22 20:05:26 +05:45
Pepe Fagoaga 46f1db21a8 chore(api): Use prowler from master (#6657) 2025-01-22 20:05:02 +05:45
Pablo Lara fbe7bc6951 feat(providers): show the cloud formation and terraform template links on the form (#6660) 2025-01-22 14:49:38 +01:00
Pablo Lara f658507847 feat(providers): make external id field mandatory in the aws role secret form (#6656) 2025-01-22 12:45:31 +01:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MrCloudSec
374078683b chore(deps-dev): bump moto from 5.0.16 to 5.0.27 (#6632)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-21 13:56:06 -05:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MrCloudSec
114c4e0886 chore(deps): bump botocore from 1.35.94 to 1.35.99 (#6520)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-21 09:17:18 -05:00
Pablo Lara 67c62766d4 fix(filters): fix dynamic filters (#6642) 2025-01-21 13:33:27 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3f2947158d chore(deps): bump prowler from 5.1.1 to 5.1.4 in /api (#6641)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 14:27:59 +05:45
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 278a7cb356 chore(deps-dev): bump mkdocs-material from 9.5.49 to 9.5.50 (#6631)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 18:31:44 -05:00
Rubén De la Torre Vico 890158a79c fix(OCSF): fix OCSF output when timestamp is UNIX format (#6606) 2025-01-20 17:11:28 -05:00
Rubén De la Torre Vico 4dc1602b77 fix: update Azure CIS with existing App checks (#6611) 2025-01-20 15:12:00 -05:00
Kay Agahd bbba0abac9 fix(aws): list tags for DocumentDB clusters (#6605) 2025-01-20 15:10:58 -05:00
Prowler BotandMrCloudSec d04fd807c6 chore(regions_update): Changes in regions for AWS services (#6599)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-20 15:09:35 -05:00
Pablo Lara 3456df4cf1 fix(snippet-id): improve provider ID readability in tables (#6615) 2025-01-20 17:23:19 +01:00
Pablo Lara f56aaa791e chore(RBAC): add permission's info (#6612) 2025-01-20 16:14:48 +01:00
Adrián Jesús Peña Rodríguez 465a758770 fix(rbac): remove invalid required permission (#6608) 2025-01-20 15:21:52 +01:00
Pablo Lara 0f7c0c1b2c fix(RBAC): tweaks for edit role form (#6609) 2025-01-20 14:09:16 +01:00
Adrián Jesús Peña Rodríguez bf8d10b6f6 feat(api): restrict the deletion of users, only the user of the request can be deleted (#6607) 2025-01-20 13:26:47 +01:00
Pablo Lara 20d04553d6 fix(RBAC): restore manage_account permission for roles (#6602) 2025-01-20 11:35:29 +01:00
Daniel Barranquero b56d62e3c4 fix(sqs): fix flaky test (#6593) 2025-01-17 11:48:39 -05:00
Hugo Pereira Brito 9a332dcba1 chore(services): delete all comment headers (#6585) 2025-01-17 08:21:28 -05:00
Hugo Pereira Brito 166d9f8823 fix(apigatewayv2): managed exception NotFoundException (#6576) 2025-01-17 08:17:51 -05:00
Prowler BotandMrCloudSec 42f5eed75f chore(regions_update): Changes in regions for AWS services (#6577)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-17 08:17:00 -05:00
Rubén De la Torre Vico 01a7db18dd fix: add missing Check_Report_Azure parameters (#6583) 2025-01-17 08:16:43 -05:00
Pablo Lara d4507465a3 fix(providers): update the label and placeholder based on the cloud provider (#6581) 2025-01-17 12:28:38 +01:00
Pablo Lara 3ac92ed10a fix(findings): remove filter delta_in applied by default (#6578) 2025-01-17 11:03:12 +01:00
Pablo Lara 43c76ca85c feat(findings): add first seen in findings details (#6575) 2025-01-17 10:19:10 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 54d87fa96a chore(deps): bump prowler from 5.0.2 to 5.1.1 in /api (#6573)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-17 13:26:07 +05:45
Daniel Barranquero f041f17268 fix(gcp): fix flaky tests from dns service (#6569) 2025-01-16 14:49:25 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 31c80a6967 chore(deps): bump msgraph-sdk from 1.16.0 to 1.17.0 (#6547)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 12:55:30 -05:00
Rubén De la Torre VicoandSergio Garcia 783ce136f4 feat(network): extract Network resource metadata automated (#6555)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-16 12:41:02 -05:00
Rubén De la Torre VicoandSergio Garcia f829145781 feat(storage): extract Storage resource metadata automated (#6563)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-16 11:44:43 -05:00
Rubén De la Torre Vico 389337f8cd feat(vm): extract VM resource metadata automated (#6564) 2025-01-16 11:16:02 -05:00
Pedro Martín a0713c2d66 fix(cis): add subsections if needed (#6559) 2025-01-16 11:10:54 -05:00
Rubén De la Torre Vico f94d3cbce4 feat(sqlserver): extract SQL Server resource metadata automated (#6562) 2025-01-16 10:47:21 -05:00
Daniel BarranqueroandMrCloudSec 8d8994b468 feat(aws): include resource metadata to remaining checks (#6551)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-16 10:44:14 -05:00
Rubén De la Torre Vico 784a9097a5 feat(postgresql): extract PostgreSQL resource metadata automated (#6560) 2025-01-16 10:37:55 -05:00
Pedro Martín b9601626e3 fix(detect_secrets): refactor logic for detect-secrets (#6537) 2025-01-16 21:15:44 +05:45
Rubén De la Torre Vico dc80b011f2 feat(policy): extract Policy resource metadata automated (#6558) 2025-01-16 10:29:28 -05:00
Rubén De la Torre VicoandSergio Garcia ee7d32d460 feat(entra): extract Entra resource metadata automated (#6542)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-16 10:24:53 -05:00
Rubén De la Torre VicoandSergio Garcia 43fd9ee94e feat(monitor): extract monitor resource metadata automated (#6554)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-16 10:16:19 -05:00
Víctor Fernández Poyatos 8821a91f3f feat(db): Update Django DB manager to use psycopg3 and connection pooling (#6541) 2025-01-16 15:29:02 +01:00
Rubén De la Torre Vico 98d9256f92 feat(mysql): extract MySQL resource metadata automated (#6556) 2025-01-16 09:24:06 -05:00
Rubén De la Torre Vico b35495eaa7 feat(keyvault): extract KeyVault resource metadata automated (#6553) 2025-01-16 09:17:36 -05:00
Rubén De la Torre Vico 74d6b614b3 feat(iam): extract IAM resource metadata automated (#6552) 2025-01-16 09:05:23 -05:00
Sergio Garciaandpedrooot dd63c16a74 fix(gcp): iterate through service projects (#6549)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-01-16 08:52:52 -05:00
Pablo Lara 4280266a96 fix(dep): address compatibility issues (#6543) 2025-01-16 14:28:49 +01:00
Hugo Pereira BritoandMrCloudSec b1f02098ff feat(aws): include resource metadata in services from r* to s* (#6536)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-15 18:10:53 -05:00
Pedro MartínandMrCloudSec 95189b574a feat(gcp): add resource metadata to report (#6500)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-15 18:09:35 -05:00
Hugo Pereira BritoandSergio Garcia c5d23503bf feat(aws): include resource metadata in services from a* to b* (#6504)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-15 18:03:37 -05:00
Daniel Barranquero 77950f6069 chore(aws): add resource metadata to services from t to w (#6546) 2025-01-15 17:22:08 -05:00
Daniel Barranquero ec5f2b3753 chore(aws): add resource metadata to services from f to o (#6545) 2025-01-15 17:15:50 -05:00
Rubén De la Torre Vico 9e7104fb7f feat(defender): extract Defender resource metadata in automated way (#6538) 2025-01-15 12:14:24 -05:00
Rubén De la Torre Vico 6b3b6ca45e feat(appinsights): extract App Insights resource metadata in automated way (#6540) 2025-01-15 11:45:23 -05:00
Hugo Pereira Brito 20b8b0b24e feat: add resource metadata to emr_cluster_account_public_block_enabled (#6539) 2025-01-15 11:44:51 -05:00
Sergio Garcia 4e11540458 feat(kubernetes): add resource metadata to report (#6479) 2025-01-15 11:36:09 -05:00
Hugo Pereira BritoandSergio Garcia ee87f2676d feat(aws): include resource metadata in services from d* to e* (#6532)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-15 10:05:04 -05:00
Daniel Barranquero 74a90aab98 feat(aws): add resource metadata to all services starting with c (#6493) 2025-01-15 09:04:19 -05:00
Rubén De la Torre Vico 48ff9a5100 feat(cosmosdb): extract CosmosDB resource metadata in automated way (#6533) 2025-01-15 08:51:48 -05:00
Rubén De la Torre Vico 3dfd578ee5 feat(containerregistry): extract Container Registry resource metadata in automated way (#6530) 2025-01-15 08:51:16 -05:00
Rubén De la Torre Vico 0db46cdc81 feat(azure-app): extract Web App resource metadata in automated way (#6529) 2025-01-15 08:48:36 -05:00
Prowler BotandMrCloudSec fdac58d031 chore(regions_update): Changes in regions for AWS services (#6526)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-15 08:46:35 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> df9d4ce856 chore(deps): bump google-api-python-client from 2.158.0 to 2.159.0 (#6521)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-15 08:33:47 -05:00
Pedro Martín e6ae4e97e8 docs(readme): update pr template to add check for readme (#6531) 2025-01-15 12:12:45 +01:00
Adrián Jesús Peña Rodríguez 10a4c28922 feat(finding): add first_seen attribute (#6460) 2025-01-15 11:25:41 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 8a828c6e51 chore(deps): bump django from 5.1.4 to 5.1.5 in /api (#6519)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-15 10:52:11 +01:00
Víctor Fernández Poyatos d7b40905ff feat(findings): Add resource_tag filters for findings endpoint (#6527) 2025-01-15 10:30:36 +01:00
Adrián Jesús Peña Rodríguez f9a3b5f3cd feat(provider-secret): make existing external_id field mandatory (#6510) 2025-01-15 10:14:44 +01:00
Pablo Lara b73b89242f feat(filters): add resource type filter for findings (#6524) 2025-01-15 08:40:53 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 23a0f6e8de chore(deps-dev): bump eslint-config-prettier from 9.1.0 to 10.0.1 in /ui (#6518)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-15 06:55:25 +01:00
Pedro MartínandSergio Garcia 87967abc3f feat(kubernetes): add CIS 1.10 compliance (#6508)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-14 14:16:00 -05:00
Rubén De la Torre Vico ce60c286dc feat(aks): use Check_Report_Azure constructor properly in AKS checks (#6509) 2025-01-14 14:14:02 -05:00
Pepe Fagoaga 90fd9b0eb8 chore(version): set next minor (#6511) 2025-01-14 14:06:24 -05:00
ca262a6797 chore(regions_update): Changes in regions for AWS services (#6495)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-14 12:43:44 -05:00
Rubén De la Torre Vico c056d39775 feat(aisearch): use Check_Report_Azure constructor properly in AISearch checks (#6506) 2025-01-14 12:37:01 -05:00
johannes-engler-mw 1c4426ea4b fix(Azure TDE): add filter for master DB (#6351) 2025-01-14 12:34:52 -05:00
Pedro Martín 36520bd7a1 feat(azure): add CIS 3.0 for Azure (#5226) 2025-01-14 12:07:22 -05:00
Pepe Fagoaga badf0ace76 feat(prowler-role): Add templates to deploy it in AWS (#6499) 2025-01-14 12:04:20 -05:00
Rubén De la Torre Vico f1f61249e0 feat(azure): include resource metadata in Check_Report_Azure (#6505) 2025-01-14 11:32:40 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> b371cac18c chore(deps): bump jinja2 from 3.1.4 to 3.1.5 (#6457)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 10:03:45 -05:00
Víctor Fernández Poyatos 1846535d8d feat(findings): add /findings/metadata to retrieve dynamic filters information (#6503) 2025-01-14 15:30:03 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d7d9118b9b chore(deps-dev): bump bandit from 1.8.0 to 1.8.2 (#6485)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 08:49:37 -05:00
1655 changed files with 166184 additions and 27799 deletions
+19 -38
View File
@@ -6,11 +6,17 @@
PROWLER_UI_VERSION="stable"
AUTH_URL=http://localhost:3000
API_BASE_URL=http://prowler-api:8080/api/v1
NEXT_PUBLIC_API_BASE_URL=${API_BASE_URL}
NEXT_PUBLIC_API_DOCS_URL=http://prowler-api:8080/api/v1/docs
AUTH_TRUST_HOST=true
UI_PORT=3000
# Temp URL for feeds need to use actual
RSS_FEED_URL=https://prowler.com/blog/rss
# openssl rand -base64 32
AUTH_SECRET="N/c6mnaS5+SWq81+819OrzQZlmx1Vxtp/orjttJSmw8="
# Google Tag Manager ID
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=""
#### Prowler API Configuration ####
PROWLER_API_VERSION="stable"
@@ -79,55 +85,21 @@ DJANGO_CACHE_MAX_AGE=3600
DJANGO_STALE_WHILE_REVALIDATE=60
DJANGO_MANAGE_DB_PARTITIONS=True
# openssl genrsa -out private.pem 2048
DJANGO_TOKEN_SIGNING_KEY="-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDs4e+kt7SnUJek
6V5r9zMGzXCoU5qnChfPiqu+BgANyawz+MyVZPs6RCRfeo6tlCknPQtOziyXYM2I
7X+qckmuzsjqp8+u+o1mw3VvUuJew5k2SQLPYwsiTzuFNVJEOgRo3hywGiGwS2iv
/5nh2QAl7fq2qLqZEXQa5+/xJlQggS1CYxOJgggvLyra50QZlBvPve/AxKJ/EV/Q
irWTZU5lLNI8sH2iZR05vQeBsxZ0dCnGMT+vGl+cGkqrvzQzKsYbDmabMcfTYhYi
78fpv6A4uharJFHayypYBjE39PwhMyyeycrNXlpm1jpq+03HgmDuDMHydk1tNwuT
nEC7m7iNAgMBAAECggEAA2m48nJcJbn9SVi8bclMwKkWmbJErOnyEGEy2sTK3Of+
NWx9BB0FmqAPNxn0ss8K7cANKOhDD7ZLF9E2MO4/HgfoMKtUzHRbM7MWvtEepldi
nnvcUMEgULD8Dk4HnqiIVjt3BdmGiTv46OpBnRWrkSBV56pUL+7msZmMZTjUZvh2
ZWv0+I3gtDIjo2Zo/FiwDV7CfwRjJarRpYUj/0YyuSA4FuOUYl41WAX1I301FKMH
xo3jiAYi1s7IneJ16OtPpOA34Wg5F6ebm/UO0uNe+iD4kCXKaZmxYQPh5tfB0Qa3
qj1T7GNpFNyvtG7VVdauhkb8iu8X/wl6PCwbg0RCKQKBgQD9HfpnpH0lDlHMRw9K
X7Vby/1fSYy1BQtlXFEIPTN/btJ/asGxLmAVwJ2HAPXWlrfSjVAH7CtVmzN7v8oj
HeIHfeSgoWEu1syvnv2AMaYSo03UjFFlfc/GUxF7DUScRIhcJUPCP8jkAROz9nFv
DByNjUL17Q9r43DmDiRsy0IFqQKBgQDvlJ9Uhl+Sp7gRgKYwa/IG0+I4AduAM+Gz
Dxbm52QrMGMTjaJFLmLHBUZ/ot+pge7tZZGws8YR8ufpyMJbMqPjxhIvRRa/p1Tf
E3TQPW93FMsHUvxAgY3MV5MzXFPhlNAKb+akP/RcXUhetGAuZKLubtDCWa55ZQuL
wj2OS+niRQKBgE7K8zUqNi6/22S8xhy/2GPgB1qPObbsABUofK0U6CAGLo6te+gc
6Jo84IyzFtQbDNQFW2Fr+j1m18rw9AqkdcUhQndiZS9AfG07D+zFB86LeWHt4DS4
ymIRX8Kvaak/iDcu/n3Mf0vCrhB6aetImObTj4GgrwlFvtJOmrYnO8EpAoGAIXXP
Xt25gWD9OyyNiVu6HKwA/zN7NYeJcRmdaDhO7B1A6R0x2Zml4AfjlbXoqOLlvLAf
zd79vcoAC82nH1eOPiSOq51plPDI0LMF8IN0CtyTkn1Lj7LIXA6rF1RAvtOqzppc
SvpHpZK9pcRpXnFdtBE0BMDDtl6fYzCIqlP94UUCgYEAnhXbAQMF7LQifEm34Dx8
BizRMOKcqJGPvbO2+Iyt50O5X6onU2ITzSV1QHtOvAazu+B1aG9pEuBFDQ+ASxEu
L9ruJElkOkb/o45TSF6KCsHd55ReTZ8AqnRjf5R+lyzPqTZCXXb8KTcRvWT4zQa3
VxyT2PnaSqEcexWUy4+UXoQ=
-----END PRIVATE KEY-----"
DJANGO_TOKEN_SIGNING_KEY=""
# openssl rsa -in private.pem -pubout -out public.pem
DJANGO_TOKEN_VERIFYING_KEY="-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7OHvpLe0p1CXpOlea/cz
Bs1wqFOapwoXz4qrvgYADcmsM/jMlWT7OkQkX3qOrZQpJz0LTs4sl2DNiO1/qnJJ
rs7I6qfPrvqNZsN1b1LiXsOZNkkCz2MLIk87hTVSRDoEaN4csBohsEtor/+Z4dkA
Je36tqi6mRF0Gufv8SZUIIEtQmMTiYIILy8q2udEGZQbz73vwMSifxFf0Iq1k2VO
ZSzSPLB9omUdOb0HgbMWdHQpxjE/rxpfnBpKq780MyrGGw5mmzHH02IWIu/H6b+g
OLoWqyRR2ssqWAYxN/T8ITMsnsnKzV5aZtY6avtNx4Jg7gzB8nZNbTcLk5xAu5u4
jQIDAQAB
-----END PUBLIC KEY-----"
DJANGO_TOKEN_VERIFYING_KEY=""
# openssl rand -base64 32
DJANGO_SECRETS_ENCRYPTION_KEY="oE/ltOhp/n1TdbHjVmzcjDPLcLA41CVI/4Rk+UB5ESc="
DJANGO_BROKER_VISIBILITY_TIMEOUT=86400
DJANGO_SENTRY_DSN=
DJANGO_THROTTLE_TOKEN_OBTAIN=50/minute
# Sentry settings
SENTRY_ENVIRONMENT=local
SENTRY_RELEASE=local
#### Prowler release version ####
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.5.1
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.10.0
# Social login credentials
SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google"
@@ -137,3 +109,12 @@ SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET=""
SOCIAL_GITHUB_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/github"
SOCIAL_GITHUB_OAUTH_CLIENT_ID=""
SOCIAL_GITHUB_OAUTH_CLIENT_SECRET=""
# Single Sign-On (SSO)
SAML_SSO_CALLBACK_URL="${AUTH_URL}/api/auth/callback/saml"
# Lighthouse tracing
LANGSMITH_TRACING=false
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY=""
LANGCHAIN_PROJECT=""
+25
View File
@@ -22,11 +22,26 @@ provider/kubernetes:
- any-glob-to-any-file: "prowler/providers/kubernetes/**"
- any-glob-to-any-file: "tests/providers/kubernetes/**"
provider/m365:
- changed-files:
- any-glob-to-any-file: "prowler/providers/m365/**"
- any-glob-to-any-file: "tests/providers/m365/**"
provider/github:
- changed-files:
- any-glob-to-any-file: "prowler/providers/github/**"
- any-glob-to-any-file: "tests/providers/github/**"
provider/iac:
- changed-files:
- any-glob-to-any-file: "prowler/providers/iac/**"
- any-glob-to-any-file: "tests/providers/iac/**"
provider/mongodbatlas:
- changed-files:
- any-glob-to-any-file: "prowler/providers/mongodbatlas/**"
- any-glob-to-any-file: "tests/providers/mongodbatlas/**"
github_actions:
- changed-files:
- any-glob-to-any-file: ".github/workflows/*"
@@ -42,11 +57,13 @@ mutelist:
- any-glob-to-any-file: "prowler/providers/azure/lib/mutelist/**"
- any-glob-to-any-file: "prowler/providers/gcp/lib/mutelist/**"
- any-glob-to-any-file: "prowler/providers/kubernetes/lib/mutelist/**"
- any-glob-to-any-file: "prowler/providers/mongodbatlas/lib/mutelist/**"
- any-glob-to-any-file: "tests/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/aws/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/azure/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/gcp/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/kubernetes/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/mongodbatlas/lib/mutelist/**"
integration/s3:
- changed-files:
@@ -93,6 +110,10 @@ component/ui:
- changed-files:
- any-glob-to-any-file: "ui/**"
component/mcp-server:
- changed-files:
- any-glob-to-any-file: "mcp_server/**"
compliance:
- changed-files:
- any-glob-to-any-file: "prowler/compliance/**"
@@ -102,3 +123,7 @@ compliance:
review-django-migrations:
- changed-files:
- any-glob-to-any-file: "api/src/backend/api/migrations/**"
metadata-review:
- changed-files:
- any-glob-to-any-file: "**/*.metadata.json"
+5
View File
@@ -8,6 +8,10 @@ If fixes an issue please add it with `Fix #XXXX`
Please include a summary of the change and which issue is fixed. List any dependencies that are required for this change.
### Steps to review
Please add a detailed description of how to review this PR.
### Checklist
- Are there new checks included in this PR? Yes / No
@@ -16,6 +20,7 @@ Please include a summary of the change and which issue is fixed. List any depend
- [ ] Review if code is being documented following this specification https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings
- [ ] Review if backport is needed.
- [ ] Review if is needed to change the [Readme.md](https://github.com/prowler-cloud/prowler/blob/master/README.md)
- [ ] Ensure new entries are added to [CHANGELOG.md](https://github.com/prowler-cloud/prowler/blob/master/prowler/CHANGELOG.md), if applicable.
#### API
- [ ] Verify if API specs need to be regenerated.
@@ -6,6 +6,7 @@ on:
- "master"
paths:
- "api/**"
- "prowler/**"
- ".github/workflows/api-build-lint-push-containers.yml"
# Uncomment the code below to test this action on PRs
@@ -76,12 +77,12 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Build and push container image (latest)
# Comment the following line for testing
if: github.event_name == 'push'
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ env.WORKING_DIRECTORY }}
# Set push: false for testing
@@ -94,7 +95,7 @@ jobs:
- name: Build and push container image (release)
if: github.event_name == 'release'
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ env.WORKING_DIRECTORY }}
push: true
+2 -2
View File
@@ -48,12 +48,12 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/api-codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
category: "/language:${{matrix.language}}"
+48 -12
View File
@@ -13,6 +13,7 @@ on:
- "master"
- "v5.*"
paths:
- ".github/workflows/api-pull-request.yml"
- "api/**"
env:
@@ -28,6 +29,10 @@ env:
VALKEY_DB: 0
API_WORKING_DIR: ./api
IMAGE_NAME: prowler-api
IGNORE_FILES: |
api/docs/**
api/README.md
api/CHANGELOG.md
jobs:
test:
@@ -77,13 +82,10 @@ jobs:
id: are-non-ignored-files-changed
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: api/**
files_ignore: |
api/.github/**
api/docs/**
api/permissions/**
api/README.md
api/mkdocs.yml
files: |
api/**
.github/workflows/api-pull-request.yml
files_ignore: ${{ env.IGNORE_FILES }}
- name: Replace @master with current branch in pyproject.toml
working-directory: ./api
@@ -100,7 +102,24 @@ jobs:
python -m pip install --upgrade pip
pipx install poetry==2.1.1
- name: Update poetry.lock after the branch name change
- name: Update SDK's poetry.lock resolved_reference to latest commit - Only for push events to `master`
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' && github.event_name == 'push'
run: |
# Get the latest commit hash from the prowler-cloud/prowler repository
LATEST_COMMIT=$(curl -s "https://api.github.com/repos/prowler-cloud/prowler/commits/master" | jq -r '.sha')
echo "Latest commit hash: $LATEST_COMMIT"
# Update the resolved_reference specifically for prowler-cloud/prowler repository
sed -i '/url = "https:\/\/github\.com\/prowler-cloud\/prowler\.git"/,/resolved_reference = / {
s/resolved_reference = "[a-f0-9]\{40\}"/resolved_reference = "'"$LATEST_COMMIT"'"/
}' poetry.lock
# Verify the change was made
echo "Updated resolved_reference:"
grep -A2 -B2 "resolved_reference" poetry.lock
- name: Update poetry.lock
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
@@ -113,6 +132,12 @@ jobs:
python-version: ${{ matrix.python-version }}
cache: "poetry"
- name: Install system dependencies for xmlsec
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
sudo apt-get update
sudo apt-get install -y libxml2-dev libxmlsec1-dev libxmlsec1-openssl pkg-config
- name: Install dependencies
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
@@ -158,8 +183,10 @@ jobs:
- name: Safety
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
# 76352, 76353, 77323 come from SDK, but they cannot upgrade it yet. It does not affect API
# TODO: Botocore needs urllib3 1.X so we need to ignore these vulnerabilities 77744,77745. Remove this once we upgrade to urllib3 2.X
run: |
poetry run safety check --ignore 70612,66963,74429,77119
poetry run safety check --ignore 70612,66963,74429,76352,76353,77323,77744,77745
- name: Vulture
working-directory: ./api
@@ -181,7 +208,7 @@ jobs:
- name: Upload coverage reports to Codecov
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
@@ -190,10 +217,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Test if changes are in not ignored paths
id: are-non-ignored-files-changed
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: api/**
files_ignore: ${{ env.IGNORE_FILES }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Build Container
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ env.API_WORKING_DIR }}
push: false
@@ -7,6 +7,7 @@ on:
- 'v3'
paths:
- 'docs/**'
- '.github/workflows/build-documentation-on-pr.yml'
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
@@ -16,9 +17,20 @@ jobs:
name: Documentation Link
runs-on: ubuntu-latest
steps:
- name: Leave PR comment with the Prowler Documentation URI
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
- name: Find existing documentation comment
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
id: find-comment
with:
issue-number: ${{ env.PR_NUMBER }}
comment-author: 'github-actions[bot]'
body-includes: '<!-- prowler-docs-link -->'
- name: Create or update PR comment with the Prowler Documentation URI
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ env.PR_NUMBER }}
body: |
<!-- prowler-docs-link -->
You can check the documentation for this PR here -> [Prowler Documentation](https://prowler-prowler-docs--${{ env.PR_NUMBER }}.com.readthedocs.build/projects/prowler-open-source/en/${{ env.PR_NUMBER }}/)
edit-mode: replace
@@ -0,0 +1,67 @@
name: Prowler - Create Backport Label
on:
release:
types: [published]
jobs:
create_label:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
steps:
- name: Create backport label
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
OWNER_REPO: ${{ github.repository }}
run: |
VERSION_ONLY=${RELEASE_TAG#v} # Remove 'v' prefix if present (e.g., v3.2.0 -> 3.2.0)
# Check if it's a minor version (X.Y.0)
if [[ "$VERSION_ONLY" =~ ^[0-9]+\.[0-9]+\.0$ ]]; then
echo "Release ${RELEASE_TAG} (version ${VERSION_ONLY}) is a minor version. Proceeding to create backport label."
TWO_DIGIT_VERSION=${VERSION_ONLY%.0} # Extract X.Y from X.Y.0 (e.g., 5.6 from 5.6.0)
FINAL_LABEL_NAME="backport-to-v${TWO_DIGIT_VERSION}"
FINAL_DESCRIPTION="Backport PR to the v${TWO_DIGIT_VERSION} branch"
echo "Effective label name will be: ${FINAL_LABEL_NAME}"
echo "Effective description will be: ${FINAL_DESCRIPTION}"
# Check if the label already exists
STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${GITHUB_TOKEN}" "https://api.github.com/repos/${OWNER_REPO}/labels/${FINAL_LABEL_NAME}")
if [ "${STATUS_CODE}" -eq 200 ]; then
echo "Label '${FINAL_LABEL_NAME}' already exists."
elif [ "${STATUS_CODE}" -eq 404 ]; then
echo "Label '${FINAL_LABEL_NAME}' does not exist. Creating it..."
# Prepare JSON data payload
JSON_DATA=$(printf '{"name":"%s","description":"%s","color":"B60205"}' "${FINAL_LABEL_NAME}" "${FINAL_DESCRIPTION}")
CREATE_STATUS_CODE=$(curl -s -o /tmp/curl_create_response.json -w "%{http_code}" -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
--data "${JSON_DATA}" \
"https://api.github.com/repos/${OWNER_REPO}/labels")
CREATE_RESPONSE_BODY=$(cat /tmp/curl_create_response.json)
rm -f /tmp/curl_create_response.json
if [ "$CREATE_STATUS_CODE" -eq 201 ]; then
echo "Label '${FINAL_LABEL_NAME}' created successfully."
else
echo "Error creating label '${FINAL_LABEL_NAME}'. Status: $CREATE_STATUS_CODE"
echo "Response: $CREATE_RESPONSE_BODY"
exit 1
fi
else
echo "Error checking for label '${FINAL_LABEL_NAME}'. HTTP Status: ${STATUS_CODE}"
exit 1
fi
else
echo "Release ${RELEASE_TAG} (version ${VERSION_ONLY}) is not a minor version. Skipping backport label creation."
exit 0
fi
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@b06f6d72a3791308bb7ba59c2b8cb7a083bd17e4 # v3.88.26
uses: trufflesecurity/trufflehog@a05cf0859455b5b16317ee22d809887a4043cdf0 # v3.90.2
with:
path: ./
base: ${{ github.event.repository.default_branch }}
+168
View File
@@ -0,0 +1,168 @@
name: Prowler - PR Conflict Checker
on:
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- "master"
- "v5.*"
pull_request_target:
types:
- opened
- synchronize
- reopened
branches:
- "master"
- "v5.*"
jobs:
conflict-checker:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: |
**
- name: Check for conflict markers
id: conflict-check
run: |
echo "Checking for conflict markers in changed files..."
CONFLICT_FILES=""
HAS_CONFLICTS=false
# Check each changed file for conflict markers
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
if [ -f "$file" ]; then
echo "Checking file: $file"
# Look for conflict markers
if grep -l "^<<<<<<<\|^=======\|^>>>>>>>" "$file" 2>/dev/null; then
echo "Conflict markers found in: $file"
CONFLICT_FILES="$CONFLICT_FILES$file "
HAS_CONFLICTS=true
fi
fi
done
if [ "$HAS_CONFLICTS" = true ]; then
echo "has_conflicts=true" >> $GITHUB_OUTPUT
echo "conflict_files=$CONFLICT_FILES" >> $GITHUB_OUTPUT
echo "Conflict markers detected in files: $CONFLICT_FILES"
else
echo "has_conflicts=false" >> $GITHUB_OUTPUT
echo "No conflict markers found in changed files"
fi
- name: Add conflict label
if: steps.conflict-check.outputs.has_conflicts == 'true'
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
script: |
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const hasConflictLabel = labels.some(label => label.name === 'has-conflicts');
if (!hasConflictLabel) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['has-conflicts']
});
console.log('Added has-conflicts label');
} else {
console.log('has-conflicts label already exists');
}
- name: Remove conflict label
if: steps.conflict-check.outputs.has_conflicts == 'false'
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
script: |
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'has-conflicts'
});
console.log('Removed has-conflicts label');
} catch (error) {
if (error.status === 404) {
console.log('has-conflicts label was not present');
} else {
throw error;
}
}
- name: Find existing conflict comment
if: steps.conflict-check.outputs.has_conflicts == 'true'
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-regex: '(⚠️ \*\*Conflict Markers Detected\*\*|✅ \*\*Conflict Markers Resolved\*\*)'
- name: Create or update conflict comment
if: steps.conflict-check.outputs.has_conflicts == 'true'
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
edit-mode: replace
body: |
⚠️ **Conflict Markers Detected**
This pull request contains unresolved conflict markers in the following files:
```
${{ steps.conflict-check.outputs.conflict_files }}
```
Please resolve these conflicts by:
1. Locating the conflict markers: `<<<<<<<`, `=======`, and `>>>>>>>`
2. Manually editing the files to resolve the conflicts
3. Removing all conflict markers
4. Committing and pushing the changes
- name: Find existing conflict comment when resolved
if: steps.conflict-check.outputs.has_conflicts == 'false'
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
id: find-resolved-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-regex: '(⚠️ \*\*Conflict Markers Detected\*\*|✅ \*\*Conflict Markers Resolved\*\*)'
- name: Update comment when conflicts resolved
if: steps.conflict-check.outputs.has_conflicts == 'false' && steps.find-resolved-comment.outputs.comment-id != ''
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
comment-id: ${{ steps.find-resolved-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
edit-mode: replace
body: |
✅ **Conflict Markers Resolved**
All conflict markers have been successfully resolved in this pull request.
@@ -0,0 +1,300 @@
name: Prowler - Release Preparation
run-name: Prowler Release Preparation for ${{ inputs.prowler_version }}
on:
workflow_dispatch:
inputs:
prowler_version:
description: 'Prowler version to release (e.g., 5.9.0)'
required: true
type: string
env:
PROWLER_VERSION: ${{ github.event.inputs.prowler_version }}
jobs:
prepare-release:
if: github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'
- name: Install Poetry
run: |
python3 -m pip install --user poetry
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Configure Git
run: |
git config --global user.name "prowler-bot"
git config --global user.email "179230569+prowler-bot@users.noreply.github.com"
- name: Parse version and determine branch
run: |
# Validate version format (reusing pattern from sdk-bump-version.yml)
if [[ $PROWLER_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
MAJOR_VERSION=${BASH_REMATCH[1]}
MINOR_VERSION=${BASH_REMATCH[2]}
PATCH_VERSION=${BASH_REMATCH[3]}
# Export version components to environment
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> "${GITHUB_ENV}"
echo "MINOR_VERSION=${MINOR_VERSION}" >> "${GITHUB_ENV}"
echo "PATCH_VERSION=${PATCH_VERSION}" >> "${GITHUB_ENV}"
# Determine branch name (format: v5.9)
BRANCH_NAME="v${MAJOR_VERSION}.${MINOR_VERSION}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_ENV}"
# Calculate UI version (1.X.X format - matches Prowler minor version)
UI_VERSION="1.${MINOR_VERSION}.${PATCH_VERSION}"
echo "UI_VERSION=${UI_VERSION}" >> "${GITHUB_ENV}"
# Calculate API version (1.X.X format - one minor version ahead)
API_MINOR_VERSION=$((MINOR_VERSION + 1))
API_VERSION="1.${API_MINOR_VERSION}.${PATCH_VERSION}"
echo "API_VERSION=${API_VERSION}" >> "${GITHUB_ENV}"
echo "Prowler version: $PROWLER_VERSION"
echo "Branch name: $BRANCH_NAME"
echo "UI version: $UI_VERSION"
echo "API version: $API_VERSION"
echo "Is minor release: $([ $PATCH_VERSION -eq 0 ] && echo 'true' || echo 'false')"
else
echo "Invalid version syntax: '$PROWLER_VERSION' (must be N.N.N)" >&2
exit 1
fi
- name: Checkout existing branch for patch release
if: ${{ env.PATCH_VERSION != '0' }}
run: |
echo "Patch release detected, checking out existing branch $BRANCH_NAME..."
if git show-ref --verify --quiet "refs/heads/$BRANCH_NAME"; then
echo "Branch $BRANCH_NAME exists locally, checking out..."
git checkout "$BRANCH_NAME"
elif git show-ref --verify --quiet "refs/remotes/origin/$BRANCH_NAME"; then
echo "Branch $BRANCH_NAME exists remotely, checking out..."
git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
else
echo "ERROR: Branch $BRANCH_NAME should exist for patch release $PROWLER_VERSION"
exit 1
fi
- name: Verify version in pyproject.toml
run: |
CURRENT_VERSION=$(grep '^version = ' pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]')
PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]')
if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then
echo "ERROR: Version mismatch in pyproject.toml (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')"
exit 1
fi
echo "✓ pyproject.toml version: $CURRENT_VERSION"
- name: Verify version in prowler/config/config.py
run: |
CURRENT_VERSION=$(grep '^prowler_version = ' prowler/config/config.py | sed -E 's/prowler_version = "([^"]+)"/\1/' | tr -d '[:space:]')
PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]')
if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then
echo "ERROR: Version mismatch in prowler/config/config.py (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')"
exit 1
fi
echo "✓ prowler/config/config.py version: $CURRENT_VERSION"
- name: Verify version in api/pyproject.toml
run: |
CURRENT_API_VERSION=$(grep '^version = ' api/pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]')
API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]')
if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then
echo "ERROR: API version mismatch in api/pyproject.toml (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')"
exit 1
fi
echo "✓ api/pyproject.toml version: $CURRENT_API_VERSION"
- name: Verify prowler dependency in api/pyproject.toml
if: ${{ env.PATCH_VERSION != '0' }}
run: |
CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]')
if [ "$CURRENT_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then
echo "ERROR: Prowler dependency mismatch in api/pyproject.toml (expected: '$BRANCH_NAME_TRIMMED', found: '$CURRENT_PROWLER_REF')"
exit 1
fi
echo "✓ api/pyproject.toml prowler dependency: $CURRENT_PROWLER_REF"
- name: Verify version in api/src/backend/api/v1/views.py
run: |
CURRENT_API_VERSION=$(grep 'spectacular_settings.VERSION = ' api/src/backend/api/v1/views.py | sed -E 's/.*spectacular_settings.VERSION = "([^"]+)".*/\1/' | tr -d '[:space:]')
API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]')
if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then
echo "ERROR: API version mismatch in views.py (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')"
exit 1
fi
echo "✓ api/src/backend/api/v1/views.py version: $CURRENT_API_VERSION"
- name: Checkout existing release branch for minor release
if: ${{ env.PATCH_VERSION == '0' }}
run: |
echo "Minor release detected (patch = 0), checking out existing branch $BRANCH_NAME..."
if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH_NAME"; then
echo "Branch $BRANCH_NAME exists remotely, checking out..."
git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
else
echo "ERROR: Branch $BRANCH_NAME should exist for minor release $PROWLER_VERSION. Please create it manually first."
exit 1
fi
- name: Prepare prowler dependency update for minor release
if: ${{ env.PATCH_VERSION == '0' }}
run: |
CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]')
# Create a temporary branch for the PR
TEMP_BRANCH="update-api-dependency-$BRANCH_NAME_TRIMMED-$(date +%s)"
echo "TEMP_BRANCH=$TEMP_BRANCH" >> $GITHUB_ENV
# Switch back to master and create temp branch
git checkout master
git checkout -b "$TEMP_BRANCH"
# Minor release: update the dependency to use the release branch
echo "Updating prowler dependency from '$CURRENT_PROWLER_REF' to '$BRANCH_NAME_TRIMMED'"
sed -i "s|prowler @ git+https://github.com/prowler-cloud/prowler.git@[^\"]*\"|prowler @ git+https://github.com/prowler-cloud/prowler.git@$BRANCH_NAME_TRIMMED\"|" api/pyproject.toml
# Verify the change was made
UPDATED_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
if [ "$UPDATED_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then
echo "ERROR: Failed to update prowler dependency in api/pyproject.toml"
exit 1
fi
# Update poetry lock file
echo "Updating poetry.lock file..."
cd api
poetry lock
cd ..
# Commit and push the temporary branch
git add api/pyproject.toml api/poetry.lock
git commit -m "chore(api): update prowler dependency to $BRANCH_NAME_TRIMMED for release $PROWLER_VERSION"
git push origin "$TEMP_BRANCH"
echo "✓ Prepared prowler dependency update to: $UPDATED_PROWLER_REF"
- name: Create Pull Request against release branch
if: ${{ env.PATCH_VERSION == '0' }}
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
branch: ${{ env.TEMP_BRANCH }}
base: ${{ env.BRANCH_NAME }}
title: "chore(api): Update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}"
body: |
### Description
Updates the API prowler dependency for release ${{ env.PROWLER_VERSION }}.
**Changes:**
- Updates `api/pyproject.toml` prowler dependency from `@master` to `@${{ env.BRANCH_NAME }}`
- Updates `api/poetry.lock` file with resolved dependencies
This PR should be merged into the `${{ env.BRANCH_NAME }}` release branch.
### License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
labels: |
component/api
no-changelog
- name: Extract changelog entries
run: |
set -e
# Function to extract changelog for a specific version
extract_changelog() {
local file="$1"
local version="$2"
local output_file="$3"
if [ ! -f "$file" ]; then
echo "Warning: $file not found, skipping..."
touch "$output_file"
return
fi
# Extract changelog section for this version
awk -v version="$version" '
/^## \[v?'"$version"'\]/ { found=1; next }
found && /^## \[v?[0-9]+\.[0-9]+\.[0-9]+\]/ { found=0 }
found && !/^## \[v?'"$version"'\]/ { print }
' "$file" > "$output_file"
# Remove --- separators
sed -i '/^---$/d' "$output_file"
# Remove trailing empty lines
sed -i '/^$/d' "$output_file"
}
# Extract changelogs
echo "Extracting changelog entries..."
extract_changelog "prowler/CHANGELOG.md" "$PROWLER_VERSION" "prowler_changelog.md"
extract_changelog "api/CHANGELOG.md" "$API_VERSION" "api_changelog.md"
extract_changelog "ui/CHANGELOG.md" "$UI_VERSION" "ui_changelog.md"
# Combine changelogs in order: UI, API, SDK
> combined_changelog.md
if [ -s "ui_changelog.md" ]; then
echo "## UI" >> combined_changelog.md
echo "" >> combined_changelog.md
cat ui_changelog.md >> combined_changelog.md
echo "" >> combined_changelog.md
fi
if [ -s "api_changelog.md" ]; then
echo "## API" >> combined_changelog.md
echo "" >> combined_changelog.md
cat api_changelog.md >> combined_changelog.md
echo "" >> combined_changelog.md
fi
if [ -s "prowler_changelog.md" ]; then
echo "## SDK" >> combined_changelog.md
echo "" >> combined_changelog.md
cat prowler_changelog.md >> combined_changelog.md
echo "" >> combined_changelog.md
fi
echo "Combined changelog preview:"
cat combined_changelog.md
- name: Create draft release
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
with:
tag_name: ${{ env.PROWLER_VERSION }}
name: Prowler ${{ env.PROWLER_VERSION }}
body_path: combined_changelog.md
draft: true
target_commitish: ${{ env.PATCH_VERSION == '0' && 'master' || env.BRANCH_NAME }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Clean up temporary files
run: |
rm -f prowler_changelog.md api_changelog.md ui_changelog.md combined_changelog.md
@@ -1,4 +1,4 @@
name: Check Changelog
name: Prowler - Check Changelog
on:
pull_request:
@@ -13,7 +13,7 @@ jobs:
contents: read
pull-requests: write
env:
MONITORED_FOLDERS: "api ui prowler"
MONITORED_FOLDERS: "api ui prowler dashboard"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -55,29 +55,20 @@ jobs:
comment-author: 'github-actions[bot]'
body-includes: '<!-- changelog-check -->'
- name: Comment on PR if changelog is missing
if: github.event.pull_request.head.repo.full_name == github.repository && steps.check_folders.outputs.missing_changelogs != ''
- name: Update PR comment with changelog status
if: github.event.pull_request.head.repo.full_name == github.repository
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
issue-number: ${{ github.event.pull_request.number }}
comment-id: ${{ steps.find_comment.outputs.comment-id }}
edit-mode: replace
body: |
<!-- changelog-check -->
⚠️ **Changes detected in the following folders without a corresponding update to the `CHANGELOG.md`:**
${{ steps.check_folders.outputs.missing_changelogs != '' && format('⚠️ **Changes detected in the following folders without a corresponding update to the `CHANGELOG.md`:**
${{ steps.check_folders.outputs.missing_changelogs }}
{0}
Please add an entry to the corresponding `CHANGELOG.md` file to maintain a clear history of changes.
- name: Comment on PR if all changelogs are present
if: github.event.pull_request.head.repo.full_name == github.repository && steps.check_folders.outputs.missing_changelogs == ''
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
issue-number: ${{ github.event.pull_request.number }}
comment-id: ${{ steps.find_comment.outputs.comment-id }}
body: |
<!-- changelog-check -->
✅ All necessary `CHANGELOG.md` files have been updated. Great job! 🎉
Please add an entry to the corresponding `CHANGELOG.md` file to maintain a clear history of changes.', steps.check_folders.outputs.missing_changelogs) || '✅ All necessary `CHANGELOG.md` files have been updated. Great job! 🎉' }}
- name: Fail if changelog is missing
if: steps.check_folders.outputs.missing_changelogs != ''
+10 -9
View File
@@ -18,7 +18,7 @@ jobs:
- name: Set short git commit SHA
id: vars
run: |
shortSha=$(git rev-parse --short ${{ github.sha }})
shortSha=$(git rev-parse --short ${{ github.event.pull_request.merge_commit_sha }})
echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV
- name: Trigger pull request
@@ -27,11 +27,12 @@ jobs:
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
repository: ${{ secrets.CLOUD_DISPATCH }}
event-type: prowler-pull-request-merged
client-payload: '{
"PROWLER_COMMIT_SHA": "${{ github.sha }}",
"PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}",
"PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}",
"PROWLER_PR_LABELS": ${{ toJson(github.event.pull_request.labels.*.name) }},
"PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }},
"PROWLER_PR_URL":${{ toJson(github.event.pull_request.html_url) }}
}'
client-payload: |
{
"PROWLER_COMMIT_SHA": "${{ github.event.pull_request.merge_commit_sha }}",
"PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}",
"PROWLER_PR_TITLE": ${{ toJson(github.event.pull_request.title) }},
"PROWLER_PR_LABELS": ${{ toJson(github.event.pull_request.labels.*.name) }},
"PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }},
"PROWLER_PR_URL": ${{ toJson(github.event.pull_request.html_url) }}
}
@@ -123,11 +123,11 @@ jobs:
AWS_REGION: ${{ env.AWS_REGION }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Build and push container image (latest)
if: github.event_name == 'push'
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
push: true
tags: |
@@ -140,7 +140,7 @@ jobs:
- name: Build and push container image (release)
if: github.event_name == 'release'
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
# Use local context to get changes
# https://github.com/docker/build-push-action#path-context
@@ -157,6 +157,22 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
# - name: Push README to Docker Hub (toniblyx)
# uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2
# with:
# username: ${{ secrets.DOCKERHUB_USERNAME }}
# password: ${{ secrets.DOCKERHUB_TOKEN }}
# repository: ${{ env.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}
# readme-filepath: ./README.md
#
# - name: Push README to Docker Hub (prowlercloud)
# uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2
# with:
# username: ${{ secrets.DOCKERHUB_USERNAME }}
# password: ${{ secrets.DOCKERHUB_TOKEN }}
# repository: ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}
# readme-filepath: ./README.md
dispatch-action:
needs: container-build-push
runs-on: ubuntu-latest
+2 -1
View File
@@ -12,7 +12,6 @@ env:
jobs:
bump-version:
name: Bump Version
if: github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -97,6 +96,7 @@ jobs:
commit-message: "chore(release): Bump version to v${{ env.BUMP_VERSION_TO }}"
branch: "version-bump-to-v${{ env.BUMP_VERSION_TO }}"
title: "chore(release): Bump version to v${{ env.BUMP_VERSION_TO }}"
labels: no-changelog
body: |
### Description
@@ -135,6 +135,7 @@ jobs:
commit-message: "chore(release): Bump version to v${{ env.PATCH_VERSION_TO }}"
branch: "version-bump-to-v${{ env.PATCH_VERSION_TO }}"
title: "chore(release): Bump version to v${{ env.PATCH_VERSION_TO }}"
labels: no-changelog
body: |
### Description
+2 -2
View File
@@ -56,12 +56,12 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/sdk-codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
category: "/language:${{matrix.language}}"
+46 -9
View File
@@ -102,8 +102,15 @@ jobs:
run: |
poetry run vulture --exclude "contrib,api,ui" --min-confidence 100 .
- name: Dockerfile - Check if Dockerfile has changed
id: dockerfile-changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: |
Dockerfile
- name: Hadolint
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
if: steps.dockerfile-changed-files.outputs.any_changed == 'true'
run: |
/tmp/hadolint Dockerfile --ignore=DL3013
@@ -115,7 +122,7 @@ jobs:
files: |
./prowler/providers/aws/**
./tests/providers/aws/**
.poetry.lock
./poetry.lock
- name: AWS - Test
if: steps.aws-changed-files.outputs.any_changed == 'true'
@@ -130,7 +137,7 @@ jobs:
files: |
./prowler/providers/azure/**
./tests/providers/azure/**
.poetry.lock
./poetry.lock
- name: Azure - Test
if: steps.azure-changed-files.outputs.any_changed == 'true'
@@ -145,7 +152,7 @@ jobs:
files: |
./prowler/providers/gcp/**
./tests/providers/gcp/**
.poetry.lock
./poetry.lock
- name: GCP - Test
if: steps.gcp-changed-files.outputs.any_changed == 'true'
@@ -160,7 +167,7 @@ jobs:
files: |
./prowler/providers/kubernetes/**
./tests/providers/kubernetes/**
.poetry.lock
./poetry.lock
- name: Kubernetes - Test
if: steps.kubernetes-changed-files.outputs.any_changed == 'true'
@@ -175,7 +182,7 @@ jobs:
files: |
./prowler/providers/github/**
./tests/providers/github/**
.poetry.lock
./poetry.lock
- name: GitHub - Test
if: steps.github-changed-files.outputs.any_changed == 'true'
@@ -190,7 +197,7 @@ jobs:
files: |
./prowler/providers/nhn/**
./tests/providers/nhn/**
.poetry.lock
./poetry.lock
- name: NHN - Test
if: steps.nhn-changed-files.outputs.any_changed == 'true'
@@ -205,13 +212,43 @@ jobs:
files: |
./prowler/providers/m365/**
./tests/providers/m365/**
.poetry.lock
./poetry.lock
- name: M365 - Test
if: steps.m365-changed-files.outputs.any_changed == 'true'
run: |
poetry run pytest -n auto --cov=./prowler/providers/m365 --cov-report=xml:m365_coverage.xml tests/providers/m365
# Test IaC
- name: IaC - Check if any file has changed
id: iac-changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: |
./prowler/providers/iac/**
./tests/providers/iac/**
./poetry.lock
- name: IaC - Test
if: steps.iac-changed-files.outputs.any_changed == 'true'
run: |
poetry run pytest -n auto --cov=./prowler/providers/iac --cov-report=xml:iac_coverage.xml tests/providers/iac
# Test MongoDB Atlas
- name: MongoDB Atlas - Check if any file has changed
id: mongodb-atlas-changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: |
./prowler/providers/mongodbatlas/**
./tests/providers/mongodbatlas/**
.poetry.lock
- name: MongoDB Atlas - Test
if: steps.mongodb-atlas-changed-files.outputs.any_changed == 'true'
run: |
poetry run pytest -n auto --cov=./prowler/providers/mongodbatlas --cov-report=xml:mongodb_atlas_coverage.xml tests/providers/mongodbatlas
# Common Tests
- name: Lib - Test
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
@@ -226,7 +263,7 @@ jobs:
# Codecov
- name: Upload coverage reports to Codecov
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
@@ -38,7 +38,7 @@ jobs:
pip install boto3
- name: Configure AWS Credentials -- DEV
uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0
uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
with:
aws-region: ${{ env.AWS_REGION_DEV }}
role-to-assume: ${{ secrets.DEV_IAM_ROLE_ARN }}
@@ -56,7 +56,7 @@ jobs:
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
commit-message: "feat(regions_update): Update regions for AWS services"
branch: "aws-services-regions-updated-${{ github.sha }}"
labels: "status/waiting-for-revision, severity/low, provider/aws"
labels: "status/waiting-for-revision, severity/low, provider/aws, no-changelog"
title: "chore(regions_update): Changes in regions for AWS services"
body: |
### Description
@@ -30,6 +30,7 @@ env:
# Container Registries
PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-ui
NEXT_PUBLIC_API_BASE_URL: http://prowler-api:8080/api/v1
jobs:
repository-check:
@@ -76,16 +77,17 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Build and push container image (latest)
# Comment the following line for testing
if: github.event_name == 'push'
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ env.WORKING_DIRECTORY }}
build-args: |
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=${{ env.SHORT_SHA }}
NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
# Set push: false for testing
push: true
tags: |
@@ -96,11 +98,12 @@ jobs:
- name: Build and push container image (release)
if: github.event_name == 'release'
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ env.WORKING_DIRECTORY }}
build-args: |
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${{ env.RELEASE_TAG }}
NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
push: true
tags: |
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }}
+2 -2
View File
@@ -48,12 +48,12 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/ui-codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
category: "/language:${{matrix.language}}"
+100
View File
@@ -0,0 +1,100 @@
name: UI - E2E Tests
on:
pull_request:
branches:
- master
- "v5.*"
paths:
- '.github/workflows/ui-e2e-tests.yml'
- 'ui/**'
jobs:
e2e-tests:
if: github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
env:
AUTH_SECRET: 'fallback-ci-secret-for-testing'
AUTH_TRUST_HOST: true
NEXTAUTH_URL: 'http://localhost:3000'
NEXT_PUBLIC_API_BASE_URL: 'http://localhost:8080/api/v1'
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Fix API data directory permissions
run: docker run --rm -v $(pwd)/_data/api:/data alpine chown -R 1000:1000 /data
- name: Start API services
run: |
# Override docker-compose image tag to use latest instead of stable
# This overrides any PROWLER_API_VERSION set in .env file
export PROWLER_API_VERSION=latest
echo "Using PROWLER_API_VERSION=${PROWLER_API_VERSION}"
docker compose up -d api worker worker-beat
- name: Wait for API to be ready
run: |
echo "Waiting for prowler-api..."
timeout=150 # 5 minutes max
elapsed=0
while [ $elapsed -lt $timeout ]; do
if curl -s ${NEXT_PUBLIC_API_BASE_URL}/docs >/dev/null 2>&1; then
echo "Prowler API is ready!"
exit 0
fi
echo "Waiting for prowler-api... (${elapsed}s elapsed)"
sleep 5
elapsed=$((elapsed + 5))
done
echo "Timeout waiting for prowler-api to start"
exit 1
- name: Load database fixtures for E2E tests
run: |
docker compose exec -T api sh -c '
echo "Loading all fixtures from api/fixtures/dev/..."
for fixture in api/fixtures/dev/*.json; do
if [ -f "$fixture" ]; then
echo "Loading $fixture"
poetry run python manage.py loaddata "$fixture" --database admin
fi
done
echo "All database fixtures loaded successfully!"
'
- name: Setup Node.js environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20.x'
cache: 'npm'
cache-dependency-path: './ui/package-lock.json'
- name: Install UI dependencies
working-directory: ./ui
run: npm ci
- name: Build UI application
working-directory: ./ui
run: npm run build
- name: Cache Playwright browsers
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('ui/package-lock.json') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright browsers
working-directory: ./ui
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npm run test:e2e:install
- name: Run E2E tests
working-directory: ./ui
run: npm run test:e2e
- name: Upload test reports
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: failure()
with:
name: playwright-report
path: ui/playwright-report/
retention-days: 30
- name: Cleanup services
if: always()
run: |
echo "Shutting down services..."
docker compose down -v || true
echo "Cleanup completed"
+6 -3
View File
@@ -34,23 +34,26 @@ jobs:
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: './ui/package-lock.json'
- name: Install dependencies
working-directory: ./ui
run: npm install
run: npm ci
- name: Run Healthcheck
working-directory: ./ui
run: npm run healthcheck
- name: Build the application
working-directory: ./ui
run: npm run build
test-container-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Build Container
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ env.UI_WORKING_DIR }}
# Always build using `prod` target
+21
View File
@@ -44,6 +44,16 @@ junit-reports/
# Cursor files
.cursorignore
.cursor/
# RooCode files
.roo/
.rooignore
.roomodes
# Cline files
.cline/
.clineignore
# Terraform
.terraform*
@@ -53,6 +63,7 @@ junit-reports/
# .env
ui/.env*
api/.env*
mcp_server/.env*
.env.local
# Coverage
@@ -65,3 +76,13 @@ node_modules
# Persistent data
_data/
# Claude
CLAUDE.md
# LLM's (Until we have a standard one)
AGENTS.md
# MCP Server
mcp_server/prowler_mcp_server/prowler_app/server.py
mcp_server/prowler_mcp_server/prowler_app/utils/schema.yaml
+2 -1
View File
@@ -115,7 +115,8 @@ repos:
- id: safety
name: safety
description: "Safety is a tool that checks your installed dependencies for known security vulnerabilities"
entry: bash -c 'safety check --ignore 70612,66963,74429'
# TODO: Botocore needs urllib3 1.X so we need to ignore these vulnerabilities 77744,77745. Remove this once we upgrade to urllib3 2.X
entry: bash -c 'safety check --ignore 70612,66963,74429,76352,76353,77744,77745'
language: system
- id: vulture
+3 -6
View File
@@ -1,4 +1,4 @@
FROM python:3.12.10-slim-bookworm AS build
FROM python:3.12.11-slim-bookworm AS build
LABEL maintainer="https://github.com/prowler-cloud/prowler"
LABEL org.opencontainers.image.source="https://github.com/prowler-cloud/prowler"
@@ -6,7 +6,8 @@ LABEL org.opencontainers.image.source="https://github.com/prowler-cloud/prowler"
ARG POWERSHELL_VERSION=7.5.0
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends wget libicu72 \
RUN apt-get update && apt-get install -y --no-install-recommends \
wget libicu72 libunwind8 libssl3 libcurl4 ca-certificates apt-transport-https gnupg \
&& rm -rf /var/lib/apt/lists/*
# Install PowerShell
@@ -46,10 +47,6 @@ ENV PATH="${HOME}/.local/bin:${PATH}"
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir poetry
# By default poetry does not compile Python source files to bytecode during installation.
# This speeds up the installation process, but the first execution may take a little more
# time because Python then compiles source files to bytecode automatically. If you want to
# compile source files to bytecode during installation, you can use the --compile option
RUN poetry install --compile && \
rm -rf ~/.cache/pip
+42 -55
View File
@@ -3,7 +3,7 @@
<img align="center" src="https://github.com/prowler-cloud/prowler/blob/master/docs/img/prowler-logo-white.png#gh-dark-mode-only" width="50%" height="50%">
</p>
<p align="center">
<b><i>Prowler Open Source</b> is as dynamic and adaptable as the environment it secures. It is trusted by the industry leaders to uphold the highest standards in security.
<b><i>Prowler</b> is the Open Cloud Security platform trusted by thousands to automate security and compliance in any cloud environment. With hundreds of ready-to-use checks and compliance frameworks, Prowler delivers real-time, customizable monitoring and seamless integrations, making cloud security simple, scalable, and cost-effective for organizations of any size.
</p>
<p align="center">
<b>Learn more at <a href="https://prowler.com">prowler.com</i></b>
@@ -19,19 +19,16 @@
<a href="https://goto.prowler.com/slack"><img alt="Slack Shield" src="https://img.shields.io/badge/slack-prowler-brightgreen.svg?logo=slack"></a>
<a href="https://pypi.org/project/prowler/"><img alt="Python Version" src="https://img.shields.io/pypi/v/prowler.svg"></a>
<a href="https://pypi.python.org/pypi/prowler/"><img alt="Python Version" src="https://img.shields.io/pypi/pyversions/prowler.svg"></a>
<a href="https://pypistats.org/packages/prowler"><img alt="PyPI Prowler Downloads" src="https://img.shields.io/pypi/dw/prowler.svg?label=prowler%20downloads"></a>
<a href="https://pypistats.org/packages/prowler"><img alt="PyPI Downloads" src="https://img.shields.io/pypi/dw/prowler.svg?label=downloads"></a>
<a href="https://hub.docker.com/r/toniblyx/prowler"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/toniblyx/prowler"></a>
<a href="https://hub.docker.com/r/toniblyx/prowler"><img alt="Docker" src="https://img.shields.io/docker/cloud/build/toniblyx/prowler"></a>
<a href="https://hub.docker.com/r/toniblyx/prowler"><img alt="Docker" src="https://img.shields.io/docker/image-size/toniblyx/prowler"></a>
<a href="https://gallery.ecr.aws/prowler-cloud/prowler"><img width="120" height=19" alt="AWS ECR Gallery" src="https://user-images.githubusercontent.com/3985464/151531396-b6535a68-c907-44eb-95a1-a09508178616.png"></a>
<a href="https://codecov.io/gh/prowler-cloud/prowler"><img src="https://codecov.io/gh/prowler-cloud/prowler/graph/badge.svg?token=OflBGsdpDl"/></a>
</p>
<p align="center">
<a href="https://github.com/prowler-cloud/prowler"><img alt="Repo size" src="https://img.shields.io/github/repo-size/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler/issues"><img alt="Issues" src="https://img.shields.io/github/issues/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler/releases"><img alt="Version" src="https://img.shields.io/github/v/release/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler/releases"><img alt="Version" src="https://img.shields.io/github/v/release/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler/releases"><img alt="Version" src="https://img.shields.io/github/release-date/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler"><img alt="Contributors" src="https://img.shields.io/github/contributors-anon/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler/issues"><img alt="Issues" src="https://img.shields.io/github/issues/prowler-cloud/prowler"></a>
<a href="https://github.com/prowler-cloud/prowler"><img alt="License" src="https://img.shields.io/github/license/prowler-cloud/prowler"></a>
<a href="https://twitter.com/ToniBlyx"><img alt="Twitter" src="https://img.shields.io/twitter/follow/toniblyx?style=social"></a>
<a href="https://twitter.com/prowlercloud"><img alt="Twitter" src="https://img.shields.io/twitter/follow/prowlercloud?style=social"></a>
@@ -55,15 +52,11 @@ Prowler includes hundreds of built-in controls to ensure compliance with standar
- **National Security Standards:** ENS (Spanish National Security Scheme)
- **Custom Security Frameworks:** Tailored to your needs
## Prowler CLI and Prowler Cloud
Prowler offers a Command Line Interface (CLI), known as Prowler Open Source, and an additional service built on top of it, called <a href="https://prowler.com">Prowler Cloud</a>.
## Prowler App
Prowler App is a web-based application that simplifies running Prowler across your cloud provider accounts. It provides a user-friendly interface to visualize the results and streamline your security assessments.
![Prowler App](docs/img/overview.png)
![Prowler App](docs/products/img/overview.png)
>For more details, refer to the [Prowler App Documentation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-app-installation)
@@ -80,27 +73,41 @@ prowler <provider>
```console
prowler dashboard
```
![Prowler Dashboard](docs/img/dashboard.png)
![Prowler Dashboard](docs/products/img/dashboard.png)
# Prowler at a Glance
> [!Tip]
> For the most accurate and up-to-date information about checks, services, frameworks, and categories, visit [**Prowler Hub**](https://hub.prowler.com).
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) |
|---|---|---|---|---|
| AWS | 564 | 82 | 34 | 10 |
| GCP | 79 | 13 | 7 | 3 |
| Azure | 140 | 18 | 8 | 3 |
| Kubernetes | 83 | 7 | 4 | 7 |
| GitHub | 3 | 2 | 1 | 0 |
| M365 | 44 | 2 | 2 | 0 |
| NHN (Unofficial) | 6 | 2 | 1 | 0 |
> Use the following commands to list Prowler's available checks, services, compliance frameworks, and categories: `prowler <provider> --list-checks`, `prowler <provider> --list-services`, `prowler <provider> --list-compliance` and `prowler <provider> --list-categories`.
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | Support | Stage | Interface |
|---|---|---|---|---|---|---|---|
| AWS | 576 | 82 | 36 | 10 | Official | Stable | UI, API, CLI |
| GCP | 79 | 13 | 10 | 3 | Official | Stable | UI, API, CLI |
| Azure | 162 | 19 | 11 | 4 | Official | Stable | UI, API, CLI |
| Kubernetes | 83 | 7 | 5 | 7 | Official | Stable | UI, API, CLI |
| GitHub | 17 | 2 | 1 | 0 | Official | Stable | UI, API, CLI |
| M365 | 70 | 7 | 3 | 2 | Official | Stable | UI, API, CLI |
| IaC | [See `trivy` docs.](https://trivy.dev/latest/docs/coverage/iac/) | N/A | N/A | N/A | Official | Beta | CLI |
| MongoDB Atlas | 10 | 3 | 0 | 0 | Official | Beta | CLI |
| NHN | 6 | 2 | 1 | 0 | Unofficial | Beta | CLI |
> [!Note]
> The numbers in the table are updated periodically.
> [!Note]
> Use the following commands to list Prowler's available checks, services, compliance frameworks, and categories:
> - `prowler <provider> --list-checks`
> - `prowler <provider> --list-services`
> - `prowler <provider> --list-compliance`
> - `prowler <provider> --list-categories`
# 💻 Installation
## Prowler App
Installing Prowler App
Prowler App offers flexible installation methods tailored to various environments:
> For detailed instructions on using Prowler App, refer to the [Prowler App Usage Guide](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app/).
@@ -130,6 +137,14 @@ If your workstation's architecture is incompatible, you can resolve this by:
> Once configured, access the Prowler App at http://localhost:3000. Sign up using your email and password to get started.
### Common Issues with Docker Pull Installation
> [!Note]
If you want to use AWS role assumption (e.g., with the "Connect assuming IAM Role" option), you may need to mount your local `.aws` directory into the container as a volume (e.g., `- "${HOME}/.aws:/home/prowler/.aws:ro"`). There are several ways to configure credentials for Docker containers. See the [Troubleshooting](./docs/troubleshooting.md) section for more details and examples.
You can find more information in the [Troubleshooting](./docs/troubleshooting.md) section.
### From GitHub
**Requirements**
@@ -225,7 +240,7 @@ The following versions of Prowler CLI are available, depending on your requireme
The container images are available here:
- Prowler CLI:
- [DockerHub](https://hub.docker.com/r/toniblyx/prowler/tags)
- [DockerHub](https://hub.docker.com/r/prowlercloud/prowler/tags)
- [AWS Public ECR](https://gallery.ecr.aws/prowler-cloud/prowler)
- Prowler App:
- [DockerHub - Prowler UI](https://hub.docker.com/r/prowlercloud/prowler-ui/tags)
@@ -260,7 +275,7 @@ python prowler-cli.py -v
- **Prowler API**: A backend service, developed with Django REST Framework, responsible for running Prowler scans and storing the generated results.
- **Prowler SDK**: A Python SDK designed to extend the functionality of the Prowler CLI for advanced capabilities.
![Prowler App Architecture](docs/img/prowler-app-architecture.png)
![Prowler App Architecture](docs/products/img/prowler-app-architecture.png)
## Prowler CLI
@@ -286,40 +301,12 @@ And many more environments.
![Architecture](docs/img/architecture.png)
# Deprecations from v3
## General
- `Allowlist` now is called `Mutelist`.
- The `--quiet` option has been deprecated. Use the `--status` flag to filter findings based on their status: PASS, FAIL, or MANUAL.
- All findings with an `INFO` status have been reclassified as `MANUAL`.
- The CSV output format is standardized across all providers.
**Deprecated Output Formats**
The following formats are now deprecated:
- Native JSON has been replaced with JSON in [OCSF] v1.1.0 format, which is standardized across all providers (https://schema.ocsf.io/).
## AWS
**AWS Flag Deprecation**
The flag --sts-endpoint-region has been deprecated due to the adoption of AWS STS regional tokens.
**Sending FAIL Results to AWS Security Hub**
- To send only FAILS to AWS Security Hub, use one of the following options: `--send-sh-only-fails` or `--security-hub --status FAIL`.
# 📖 Documentation
**Documentation Resources**
For installation instructions, usage details, tutorials, and the Developer Guide, visit https://docs.prowler.com/
# 📃 License
**Prowler License Information**
Prowler is licensed under the Apache License 2.0, as indicated in each file within the repository. Obtaining a Copy of the License
Prowler is licensed under the Apache License 2.0.
A copy of the License is available at <http://www.apache.org/licenses/LICENSE-2.0>
+57 -15
View File
@@ -1,23 +1,65 @@
# Security Policy
# Security
## Software Security
As an **AWS Partner** and we have passed the [AWS Foundation Technical Review (FTR)](https://aws.amazon.com/partners/foundational-technical-review/) and we use the following tools and automation to make sure our code is secure and dependencies up-to-dated:
## Reporting Vulnerabilities
- `bandit` for code security review.
- `safety` and `dependabot` for dependencies.
- `hadolint` and `dockle` for our containers security.
- `snyk` in Docker Hub.
- `clair` in Amazon ECR.
- `vulture`, `flake8`, `black` and `pylint` for formatting and best practices.
At Prowler, we consider the security of our open source software and systems a top priority. But no matter how much effort we put into system security, there can still be vulnerabilities present.
## Reporting a Vulnerability
If you discover a vulnerability, we would like to know about it so we can take steps to address it as quickly as possible. We would like to ask you to help us better protect our users, our clients and our systems.
If you would like to report a vulnerability or have a security concern regarding Prowler Open Source or ProwlerPro service, please submit the information by contacting to https://support.prowler.com.
When reporting vulnerabilities, please consider (1) attack scenario / exploitability, and (2) the security impact of the bug. The following issues are considered out of scope:
The information you share with ProwlerPro as part of this process is kept confidential within ProwlerPro. We will only share this information with a third party if the vulnerability you report is found to affect a third-party product, in which case we will share this information with the third-party product's author or manufacturer. Otherwise, we will only share this information as permitted by you.
- Social engineering support or attacks requiring social engineering.
- Clickjacking on pages with no sensitive actions.
- Cross-Site Request Forgery (CSRF) on unauthenticated forms or forms with no sensitive actions.
- Attacks requiring Man-In-The-Middle (MITM) or physical access to a user's device.
- Previously known vulnerable libraries without a working Proof of Concept (PoC).
- Comma Separated Values (CSV) injection without demonstrating a vulnerability.
- Missing best practices in SSL/TLS configuration.
- Any activity that could lead to the disruption of service (DoS).
- Rate limiting or brute force issues on non-authentication endpoints.
- Missing best practices in Content Security Policy (CSP).
- Missing HttpOnly or Secure flags on cookies.
- Configuration of or missing security headers.
- Missing email best practices, such as invalid, incomplete, or missing SPF/DKIM/DMARC records.
- Vulnerabilities only affecting users of outdated or unpatched browsers (less than two stable versions behind).
- Software version disclosure, banner identification issues, or descriptive error messages.
- Tabnabbing.
- Issues that require unlikely user interaction.
- Improper logout functionality and improper session timeout.
- CORS misconfiguration without an exploitation scenario.
- Broken link hijacking.
- Automated scanning results (e.g., sqlmap, Burp active scanner) that have not been manually verified.
- Content spoofing and text injection issues without a clear attack vector.
- Email spoofing without exploiting security flaws.
- Dead links or broken links.
- User enumeration.
We will review the submitted report, and assign it a tracking number. We will then respond to you, acknowledging receipt of the report, and outline the next steps in the process.
Testing guidelines:
- Do not run automated scanners on other customer projects. Running automated scanners can run up costs for our users. Aggressively configured scanners might inadvertently disrupt services, exploit vulnerabilities, lead to system instability or breaches and violate Terms of Service from our upstream providers. Our own security systems won't be able to distinguish hostile reconnaissance from whitehat research. If you wish to run an automated scanner, notify us at support@prowler.com and only run it on your own Prowler app project. Do NOT attack Prowler in usage of other customers.
- Do not take advantage of the vulnerability or problem you have discovered, for example by downloading more data than necessary to demonstrate the vulnerability or deleting or modifying other people's data.
You will receive a non-automated response to your initial contact within 24 hours, confirming receipt of your reported vulnerability.
Reporting guidelines:
- File a report through our Support Desk at https://support.prowler.com
- If it is about a lack of a security functionality, please file a feature request instead at https://github.com/prowler-cloud/prowler/issues
- Do provide sufficient information to reproduce the problem, so we will be able to resolve it as quickly as possible.
- If you have further questions and want direct interaction with the Prowler team, please contact us at via our Community Slack at goto.prowler.com/slack.
We will coordinate public notification of any validated vulnerability with you. Where possible, we prefer that our respective public disclosures be posted simultaneously.
Disclosure guidelines:
- In order to protect our users and customers, do not reveal the problem to others until we have researched, addressed and informed our affected customers.
- If you want to publicly share your research about Prowler at a conference, in a blog or any other public forum, you should share a draft with us for review and approval at least 30 days prior to the publication date. Please note that the following should not be included:
- Data regarding any Prowler user or customer projects.
- Prowler customers' data.
- Information about Prowler employees, contractors or partners.
What we promise:
- We will respond to your report within 5 business days with our evaluation of the report and an expected resolution date.
- If you have followed the instructions above, we will not take any legal action against you in regard to the report.
- We will handle your report with strict confidentiality, and not pass on your personal details to third parties without your permission.
- We will keep you informed of the progress towards resolving the problem.
- In the public information concerning the problem reported, we will give your name as the discoverer of the problem (unless you desire otherwise).
We strive to resolve all problems as quickly as possible, and we would like to play an active role in the ultimate publication on the problem after it is resolved.
---
For more information about our security policies, please refer to our [Security](https://docs.prowler.com/projects/prowler-open-source/en/latest/security/) section in our documentation.
+2
View File
@@ -19,6 +19,8 @@ DJANGO_REFRESH_TOKEN_LIFETIME=1440
DJANGO_CACHE_MAX_AGE=3600
DJANGO_STALE_WHILE_REVALIDATE=60
DJANGO_SECRETS_ENCRYPTION_KEY=""
# Throttle, two options: Empty means no throttle; or if desired use one in DRF format: https://www.django-rest-framework.org/api-guide/throttling/#setting-the-throttling-policy
DJANGO_THROTTLE_TOKEN_OBTAIN=50/minute
# Decide whether to allow Django manage database table partitions
DJANGO_MANAGE_DB_PARTITIONS=[True|False]
DJANGO_CELERY_DEADLOCK_ATTEMPTS=5
-168
View File
@@ -1,168 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.pyc
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
/_data/
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
*.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
# VSCode
.vscode/
-91
View File
@@ -1,91 +0,0 @@
repos:
## GENERAL
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-merge-conflict
- id: check-yaml
args: ["--unsafe"]
- id: check-json
- id: end-of-file-fixer
- id: trailing-whitespace
- id: no-commit-to-branch
- id: pretty-format-json
args: ["--autofix", "--no-sort-keys", "--no-ensure-ascii"]
exclude: 'src/backend/api/fixtures/dev/.*\.json$'
## TOML
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.13.0
hooks:
- id: pretty-format-toml
args: [--autofix]
files: pyproject.toml
## BASH
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.10.0
hooks:
- id: shellcheck
exclude: contrib
## PYTHON
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.5.0
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/python-poetry/poetry
rev: 1.8.0
hooks:
- id: poetry-check
args: ["--directory=src"]
- id: poetry-lock
args: ["--no-update", "--directory=src"]
- repo: https://github.com/hadolint/hadolint
rev: v2.13.0-beta
hooks:
- id: hadolint
args: ["--ignore=DL3013", "Dockerfile"]
- repo: local
hooks:
- id: pylint
name: pylint
entry: bash -c 'poetry run pylint --disable=W,C,R,E -j 0 -rn -sn src/'
language: system
files: '.*\.py'
- id: trufflehog
name: TruffleHog
description: Detect secrets in your data.
entry: bash -c 'trufflehog --no-update git file://. --only-verified --fail'
# For running trufflehog in docker, use the following entry instead:
# entry: bash -c 'docker run -v "$(pwd):/workdir" -i --rm trufflesecurity/trufflehog:latest git file:///workdir --only-verified --fail'
language: system
stages: ["commit", "push"]
- id: bandit
name: bandit
description: "Bandit is a tool for finding common security issues in Python code"
entry: bash -c 'poetry run bandit -q -lll -x '*_test.py,./contrib/,./.venv/' -r .'
language: system
files: '.*\.py'
- id: safety
name: safety
description: "Safety is a tool that checks your installed dependencies for known security vulnerabilities"
entry: bash -c 'poetry run safety check --ignore 70612,66963,74429,77119'
language: system
- id: vulture
name: vulture
description: "Vulture finds unused code in Python programs."
entry: bash -c 'poetry run vulture --exclude "contrib,.venv,tests,conftest.py" --min-confidence 100 .'
language: system
files: '.*\.py'
+161 -41
View File
@@ -2,6 +2,131 @@
All notable changes to the **Prowler API** are documented in this file.
## [1.14.0] (Prowler UNRELEASED)
### Added
- Default JWT keys are generated and stored if they are missing from configuration [(#8655)](https://github.com/prowler-cloud/prowler/pull/8655)
- `compliance_name` for each compliance [(#7920)](https://github.com/prowler-cloud/prowler/pull/7920)
### Changed
- Now the MANAGE_ACCOUNT permission is required to modify or read user permissions instead of MANAGE_USERS [(#8281)](https://github.com/prowler-cloud/prowler/pull/8281)
- Now at least one user with MANAGE_ACCOUNT permission is required in the tenant [(#8729)](https://github.com/prowler-cloud/prowler/pull/8729)
---
## [1.13.1] (Prowler 5.12.2)
### Changed
- Renamed compliance overview task queue to `compliance` [(#8755)](https://github.com/prowler-cloud/prowler/pull/8755)
### Security
- Django updated to the latest 5.1 security release, 5.1.12, due to [problems](https://www.djangoproject.com/weblog/2025/sep/03/security-releases/) with potential SQL injection in FilteredRelation column aliases [(#8693)](https://github.com/prowler-cloud/prowler/pull/8693)
---
## [1.13.0] (Prowler 5.12.0)
### Added
- Integration with JIRA, enabling sending findings to a JIRA project [(#8622)](https://github.com/prowler-cloud/prowler/pull/8622), [(#8637)](https://github.com/prowler-cloud/prowler/pull/8637)
- `GET /overviews/findings_severity` now supports `filter[status]` and `filter[status__in]` to aggregate by specific statuses (`FAIL`, `PASS`)[(#8186)](https://github.com/prowler-cloud/prowler/pull/8186)
- Throttling options for `/api/v1/tokens` using the `DJANGO_THROTTLE_TOKEN_OBTAIN` environment variable [(#8647)](https://github.com/prowler-cloud/prowler/pull/8647)
---
## [1.12.0] (Prowler 5.11.0)
### Added
- Lighthouse support for OpenAI GPT-5 [(#8527)](https://github.com/prowler-cloud/prowler/pull/8527)
- Integration with Amazon Security Hub, enabling sending findings to Security Hub [(#8365)](https://github.com/prowler-cloud/prowler/pull/8365)
- Generate ASFF output for AWS providers with SecurityHub integration enabled [(#8569)](https://github.com/prowler-cloud/prowler/pull/8569)
### Fixed
- GitHub provider always scans user instead of organization when using provider UID [(#8587)](https://github.com/prowler-cloud/prowler/pull/8587)
---
## [1.11.0] (Prowler 5.10.0)
### Added
- Github provider support [(#8271)](https://github.com/prowler-cloud/prowler/pull/8271)
- Integration with Amazon S3, enabling storage and retrieval of scan data via S3 buckets [(#8056)](https://github.com/prowler-cloud/prowler/pull/8056)
### Fixed
- Avoid sending errors to Sentry in M365 provider when user authentication fails [(#8420)](https://github.com/prowler-cloud/prowler/pull/8420)
---
## [1.10.2] (Prowler v5.9.2)
### Changed
- Optimized queries for resources views [(#8336)](https://github.com/prowler-cloud/prowler/pull/8336)
---
## [v1.10.1] (Prowler v5.9.1)
### Fixed
- Calculate failed findings during scans to prevent heavy database queries [(#8322)](https://github.com/prowler-cloud/prowler/pull/8322)
---
## [v1.10.0] (Prowler v5.9.0)
### Added
- SSO with SAML support [(#8175)](https://github.com/prowler-cloud/prowler/pull/8175)
- `GET /resources/metadata`, `GET /resources/metadata/latest` and `GET /resources/latest` to expose resource metadata and latest scan results [(#8112)](https://github.com/prowler-cloud/prowler/pull/8112)
### Changed
- `/processors` endpoints to post-process findings. Currently, only the Mutelist processor is supported to allow to mute findings.
- Optimized the underlying queries for resources endpoints [(#8112)](https://github.com/prowler-cloud/prowler/pull/8112)
- Optimized include parameters for resources view [(#8229)](https://github.com/prowler-cloud/prowler/pull/8229)
- Optimized overview background tasks [(#8300)](https://github.com/prowler-cloud/prowler/pull/8300)
### Fixed
- Search filter for findings and resources [(#8112)](https://github.com/prowler-cloud/prowler/pull/8112)
- RBAC is now applied to `GET /overviews/providers` [(#8277)](https://github.com/prowler-cloud/prowler/pull/8277)
### Changed
- `POST /schedules/daily` returns a `409 CONFLICT` if already created [(#8258)](https://github.com/prowler-cloud/prowler/pull/8258)
### Security
- Enhanced password validation to enforce 12+ character passwords with special characters, uppercase, lowercase, and numbers [(#8225)](https://github.com/prowler-cloud/prowler/pull/8225)
---
## [v1.9.1] (Prowler v5.8.1)
### Added
- Custom exception for provider connection errors during scans [(#8234)](https://github.com/prowler-cloud/prowler/pull/8234)
### Changed
- Summary and overview tasks now use a dedicated queue and no longer propagate errors to compliance tasks [(#8214)](https://github.com/prowler-cloud/prowler/pull/8214)
### Fixed
- Scan with no resources will not trigger legacy code for findings metadata [(#8183)](https://github.com/prowler-cloud/prowler/pull/8183)
- Invitation email comparison case-insensitive [(#8206)](https://github.com/prowler-cloud/prowler/pull/8206)
### Removed
- Validation of the provider's secret type during updates [(#8197)](https://github.com/prowler-cloud/prowler/pull/8197)
---
## [v1.9.0] (Prowler v5.8.0)
### Added
- Support GCP Service Account key [(#7824)](https://github.com/prowler-cloud/prowler/pull/7824)
- `GET /compliance-overviews` endpoints to retrieve compliance metadata and specific requirements statuses [(#7877)](https://github.com/prowler-cloud/prowler/pull/7877)
- Lighthouse configuration support [(#7848)](https://github.com/prowler-cloud/prowler/pull/7848)
### Changed
- Reworked `GET /compliance-overviews` to return proper requirement metrics [(#7877)](https://github.com/prowler-cloud/prowler/pull/7877)
- Optional `user` and `password` for M365 provider [(#7992)](https://github.com/prowler-cloud/prowler/pull/7992)
### Fixed
- Scheduled scans are no longer deleted when their daily schedule run is disabled [(#8082)](https://github.com/prowler-cloud/prowler/pull/8082)
---
## [v1.8.5] (Prowler v5.7.5)
### Fixed
@@ -13,51 +138,50 @@ All notable changes to the **Prowler API** are documented in this file.
## [v1.8.4] (Prowler v5.7.4)
### Removed
- Reverted RLS transaction handling and DB custom backend [(#7994)](https://github.com/prowler-cloud/prowler/pull/7994).
- Reverted RLS transaction handling and DB custom backend [(#7994)](https://github.com/prowler-cloud/prowler/pull/7994)
---
## [v1.8.3] (Prowler v5.7.3)
### Added
- Database backend to handle already closed connections [(#7935)](https://github.com/prowler-cloud/prowler/pull/7935).
- Database backend to handle already closed connections [(#7935)](https://github.com/prowler-cloud/prowler/pull/7935)
### Changed
- Renamed field encrypted_password to password for M365 provider [(#7784)](https://github.com/prowler-cloud/prowler/pull/7784)
### Fixed
- Fixed transaction persistence with RLS operations [(#7916)](https://github.com/prowler-cloud/prowler/pull/7916).
- Reverted the change `get_with_retry` to use the original `get` method for retrieving tasks [(#7932)](https://github.com/prowler-cloud/prowler/pull/7932).
- Fixed the connection status verification before launching a scan [(#7831)](https://github.com/prowler-cloud/prowler/pull/7831)
- Transaction persistence with RLS operations [(#7916)](https://github.com/prowler-cloud/prowler/pull/7916)
- Reverted the change `get_with_retry` to use the original `get` method for retrieving tasks [(#7932)](https://github.com/prowler-cloud/prowler/pull/7932)
---
## [v1.8.2] (Prowler v5.7.2)
### Fixed
- Fixed task lookup to use task_kwargs instead of task_args for scan report resolution. [(#7830)](https://github.com/prowler-cloud/prowler/pull/7830)
- Fixed Kubernetes UID validation to allow valid context names [(#7871)](https://github.com/prowler-cloud/prowler/pull/7871)
- Fixed the connection status verification before launching a scan [(#7831)](https://github.com/prowler-cloud/prowler/pull/7831)
- Fixed a race condition when creating background tasks [(#7876)](https://github.com/prowler-cloud/prowler/pull/7876).
- Fixed an error when modifying or retrieving tenants due to missing user UUID in transaction context [(#7890)](https://github.com/prowler-cloud/prowler/pull/7890).
- Task lookup to use task_kwargs instead of task_args for scan report resolution [(#7830)](https://github.com/prowler-cloud/prowler/pull/7830)
- Kubernetes UID validation to allow valid context names [(#7871)](https://github.com/prowler-cloud/prowler/pull/7871)
- Connection status verification before launching a scan [(#7831)](https://github.com/prowler-cloud/prowler/pull/7831)
- Race condition when creating background tasks [(#7876)](https://github.com/prowler-cloud/prowler/pull/7876)
- Error when modifying or retrieving tenants due to missing user UUID in transaction context [(#7890)](https://github.com/prowler-cloud/prowler/pull/7890)
---
## [v1.8.1] (Prowler v5.7.1)
### Fixed
- Added database index to improve performance on finding lookup [(#7800)](https://github.com/prowler-cloud/prowler/pull/7800).
- Added database index to improve performance on finding lookup [(#7800)](https://github.com/prowler-cloud/prowler/pull/7800)
---
## [v1.8.0] (Prowler v5.7.0)
### Added
- Added huge improvements to `/findings/metadata` and resource related filters for findings [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
- Added improvements to `/overviews` endpoints [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
- Added new queue to perform backfill background tasks [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
- Added new endpoints to retrieve latest findings and metadata [(#7743)](https://github.com/prowler-cloud/prowler/pull/7743).
- Added export support for Prowler ThreatScore in M365 [(7783)](https://github.com/prowler-cloud/prowler/pull/7783)
- Huge improvements to `/findings/metadata` and resource related filters for findings [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690)
- Improvements to `/overviews` endpoints [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690)
- Queue to perform backfill background tasks [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690)
- New endpoints to retrieve latest findings and metadata [(#7743)](https://github.com/prowler-cloud/prowler/pull/7743)
- Export support for Prowler ThreatScore in M365 [(7783)](https://github.com/prowler-cloud/prowler/pull/7783)
---
@@ -65,9 +189,9 @@ All notable changes to the **Prowler API** are documented in this file.
### Added
- Added M365 as a new provider [(#7563)](https://github.com/prowler-cloud/prowler/pull/7563).
- Added a `compliance/` folder and ZIPexport functionality for all compliance reports.[(#7653)](https://github.com/prowler-cloud/prowler/pull/7653).
- Added a new API endpoint to fetch and download any specific compliance file by name [(#7653)](https://github.com/prowler-cloud/prowler/pull/7653).
- M365 as a new provider [(#7563)](https://github.com/prowler-cloud/prowler/pull/7563)
- `compliance/` folder and ZIPexport functionality for all compliance reports [(#7653)](https://github.com/prowler-cloud/prowler/pull/7653)
- API endpoint to fetch and download any specific compliance file by name [(#7653)](https://github.com/prowler-cloud/prowler/pull/7653)
---
@@ -75,46 +199,42 @@ All notable changes to the **Prowler API** are documented in this file.
### Added
- Support for developing new integrations [(#7167)](https://github.com/prowler-cloud/prowler/pull/7167).
- HTTP Security Headers [(#7289)](https://github.com/prowler-cloud/prowler/pull/7289).
- New endpoint to get the compliance overviews metadata [(#7333)](https://github.com/prowler-cloud/prowler/pull/7333).
- Support for muted findings [(#7378)](https://github.com/prowler-cloud/prowler/pull/7378).
- Added missing fields to API findings and resources [(#7318)](https://github.com/prowler-cloud/prowler/pull/7318).
- Support for developing new integrations [(#7167)](https://github.com/prowler-cloud/prowler/pull/7167)
- HTTP Security Headers [(#7289)](https://github.com/prowler-cloud/prowler/pull/7289)
- New endpoint to get the compliance overviews metadata [(#7333)](https://github.com/prowler-cloud/prowler/pull/7333)
- Support for muted findings [(#7378)](https://github.com/prowler-cloud/prowler/pull/7378)
- Missing fields to API findings and resources [(#7318)](https://github.com/prowler-cloud/prowler/pull/7318)
---
## [v1.5.4] (Prowler v5.4.4)
### Fixed
- Fixed a bug with periodic tasks when trying to delete a provider ([#7466])(https://github.com/prowler-cloud/prowler/pull/7466).
- Bug with periodic tasks when trying to delete a provider [(#7466)](https://github.com/prowler-cloud/prowler/pull/7466)
---
## [v1.5.3] (Prowler v5.4.3)
### Fixed
- Added duplicated scheduled scans handling ([#7401])(https://github.com/prowler-cloud/prowler/pull/7401).
- Added environment variable to configure the deletion task batch size ([#7423])(https://github.com/prowler-cloud/prowler/pull/7423).
- Duplicated scheduled scans handling [(#7401)](https://github.com/prowler-cloud/prowler/pull/7401)
- Environment variable to configure the deletion task batch size [(#7423)](https://github.com/prowler-cloud/prowler/pull/7423)
---
## [v1.5.2] (Prowler v5.4.2)
### Changed
- Refactored deletion logic and implemented retry mechanism for deletion tasks [(#7349)](https://github.com/prowler-cloud/prowler/pull/7349).
- Refactored deletion logic and implemented retry mechanism for deletion tasks [(#7349)](https://github.com/prowler-cloud/prowler/pull/7349)
---
## [v1.5.1] (Prowler v5.4.1)
### Fixed
- Added a handled response in case local files are missing [(#7183)](https://github.com/prowler-cloud/prowler/pull/7183).
- Fixed a race condition when deleting export files after the S3 upload [(#7172)](https://github.com/prowler-cloud/prowler/pull/7172).
- Handled exception when a provider has no secret in test connection [(#7283)](https://github.com/prowler-cloud/prowler/pull/7283).
### Added
- Support for developing new integrations [(#7167)](https://github.com/prowler-cloud/prowler/pull/7167).
- Handle response in case local files are missing [(#7183)](https://github.com/prowler-cloud/prowler/pull/7183)
- Race condition when deleting export files after the S3 upload [(#7172)](https://github.com/prowler-cloud/prowler/pull/7172)
- Handle exception when a provider has no secret in test connection [(#7283)](https://github.com/prowler-cloud/prowler/pull/7283)
---
@@ -122,20 +242,20 @@ All notable changes to the **Prowler API** are documented in this file.
### Added
- Social login integration with Google and GitHub [(#6906)](https://github.com/prowler-cloud/prowler/pull/6906)
- Add API scan report system, now all scans launched from the API will generate a compressed file with the report in OCSF, CSV and HTML formats [(#6878)](https://github.com/prowler-cloud/prowler/pull/6878).
- API scan report system, now all scans launched from the API will generate a compressed file with the report in OCSF, CSV and HTML formats [(#6878)](https://github.com/prowler-cloud/prowler/pull/6878)
- Configurable Sentry integration [(#6874)](https://github.com/prowler-cloud/prowler/pull/6874)
### Changed
- Optimized `GET /findings` endpoint to improve response time and size [(#7019)](https://github.com/prowler-cloud/prowler/pull/7019).
- Optimized `GET /findings` endpoint to improve response time and size [(#7019)](https://github.com/prowler-cloud/prowler/pull/7019)
---
## [v1.4.0] (Prowler v5.3.0)
### Changed
- Daily scheduled scan instances are now created beforehand with `SCHEDULED` state [(#6700)](https://github.com/prowler-cloud/prowler/pull/6700).
- Findings endpoints now require at least one date filter [(#6800)](https://github.com/prowler-cloud/prowler/pull/6800).
- Findings metadata endpoint received a performance improvement [(#6863)](https://github.com/prowler-cloud/prowler/pull/6863).
- Increased the allowed length of the provider UID for Kubernetes providers [(#6869)](https://github.com/prowler-cloud/prowler/pull/6869).
- Daily scheduled scan instances are now created beforehand with `SCHEDULED` state [(#6700)](https://github.com/prowler-cloud/prowler/pull/6700)
- Findings endpoints now require at least one date filter [(#6800)](https://github.com/prowler-cloud/prowler/pull/6800)
- Findings metadata endpoint received a performance improvement [(#6863)](https://github.com/prowler-cloud/prowler/pull/6863)
- Increased the allowed length of the provider UID for Kubernetes providers [(#6869)](https://github.com/prowler-cloud/prowler/pull/6869)
---
+19 -5
View File
@@ -6,7 +6,19 @@ ARG POWERSHELL_VERSION=7.5.0
ENV POWERSHELL_VERSION=${POWERSHELL_VERSION}
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends wget libicu72 \
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
libicu72 \
gcc \
g++ \
make \
libxml2-dev \
libxmlsec1-dev \
libxmlsec1-openssl \
pkg-config \
libtool \
libxslt1-dev \
python3-dev \
&& rm -rf /var/lib/apt/lists/*
# Install PowerShell
@@ -32,23 +44,25 @@ USER prowler
WORKDIR /home/prowler
# Ensure output directory exists
RUN mkdir -p /tmp/prowler_api_output
COPY pyproject.toml ./
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir poetry
COPY src/backend/ ./backend/
ENV PATH="/home/prowler/.local/bin:$PATH"
# Add `--no-root` to avoid installing the current project as a package
RUN poetry install --no-root && \
rm -rf ~/.cache/pip
COPY docker-entrypoint.sh ./docker-entrypoint.sh
RUN poetry run python "$(poetry env info --path)/src/prowler/prowler/providers/m365/lib/powershell/m365_powershell.py"
COPY src/backend/ ./backend/
COPY docker-entrypoint.sh ./docker-entrypoint.sh
WORKDIR /home/prowler/backend
# Development image
+5 -1
View File
@@ -20,6 +20,10 @@ Valkey exposes a Redis 7.2 compliant API. Any service that exposes the Redis API
Under the root path of the project, you can find a file called `.env.example`. This file shows all the environment variables that the project uses. You *must* create a new file called `.env` and set the values for the variables.
If you don't set `DJANGO_TOKEN_SIGNING_KEY` or `DJANGO_TOKEN_VERIFYING_KEY`, the API will generate them at `~/.config/prowler-api/` with `0600` and `0644` permissions; back up these files to persist identity across redeploys.
**Important:** When using the production Docker Compose profile (`docker compose --profile prod`), you **must** set both `DJANGO_TOKEN_SIGNING_KEY` and `DJANGO_TOKEN_VERIFYING_KEY` in your `.env` file, as automatic key generation is not available in this deployment mode.
## Local deployment
Keep in mind if you export the `.env` file to use it with local deployment that you will have to do it within the context of the Poetry interpreter, not before. Otherwise, variables will not be loaded properly.
@@ -257,7 +261,7 @@ cd src/backend
python manage.py loaddata api/fixtures/0_dev_users.json --database admin
```
> The default credentials are `dev@prowler.com:thisisapassword123` or `dev2@prowler.com:thisisapassword123`
> The default credentials are `dev@prowler.com:Thisisapassword123@` or `dev2@prowler.com:Thisisapassword123@`
## Run tests
-125
View File
@@ -1,125 +0,0 @@
services:
api:
build:
dockerfile: Dockerfile
image: prowler-api
env_file:
- path: ./.env
required: false
ports:
- "${DJANGO_PORT:-8000}:${DJANGO_PORT:-8000}"
profiles:
- prod
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
entrypoint:
- "../docker-entrypoint.sh"
- "prod"
api-dev:
build:
dockerfile: Dockerfile
target: dev
image: prowler-api-dev
environment:
- DJANGO_SETTINGS_MODULE=config.django.devel
- DJANGO_LOGGING_FORMATTER=human_readable
env_file:
- path: ./.env
required: false
ports:
- "${DJANGO_PORT:-8080}:${DJANGO_PORT:-8080}"
volumes:
- "./src/backend:/home/prowler/backend"
- "./pyproject.toml:/home/prowler/pyproject.toml"
profiles:
- dev
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
entrypoint:
- "../docker-entrypoint.sh"
- "dev"
postgres:
image: postgres:16.3-alpine
ports:
- "${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}"
hostname: "postgres-db"
volumes:
- ./_data/postgres:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${POSTGRES_ADMIN_USER:-prowler}
- POSTGRES_PASSWORD=${POSTGRES_ADMIN_PASSWORD:-S3cret}
- POSTGRES_DB=${POSTGRES_DB:-prowler_db}
env_file:
- path: ./.env
required: false
healthcheck:
test: ["CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_ADMIN_USER:-prowler} -d ${POSTGRES_DB:-prowler_db}'"]
interval: 5s
timeout: 5s
retries: 5
valkey:
image: valkey/valkey:7-alpine3.19
ports:
- "${VALKEY_PORT:-6379}:6379"
hostname: "valkey"
volumes:
- ./_data/valkey:/data
env_file:
- path: ./.env
required: false
healthcheck:
test: ["CMD-SHELL", "sh -c 'valkey-cli ping'"]
interval: 10s
timeout: 5s
retries: 3
worker:
build:
dockerfile: Dockerfile
image: prowler-worker
environment:
- DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-config.django.production}
env_file:
- path: ./.env
required: false
profiles:
- dev
- prod
depends_on:
valkey:
condition: service_healthy
postgres:
condition: service_healthy
entrypoint:
- "../docker-entrypoint.sh"
- "worker"
worker-beat:
build:
dockerfile: Dockerfile
image: prowler-worker
environment:
- DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-config.django.production}
env_file:
- path: ./.env
required: false
profiles:
- dev
- prod
depends_on:
valkey:
condition: service_healthy
postgres:
condition: service_healthy
entrypoint:
- "../docker-entrypoint.sh"
- "beat"
+5 -1
View File
@@ -3,6 +3,10 @@
apply_migrations() {
echo "Applying database migrations..."
# Fix Inconsistent migration history after adding sites app
poetry run python manage.py check_and_fix_socialaccount_sites_migration --database admin
poetry run python manage.py migrate --database admin
}
@@ -28,7 +32,7 @@ start_prod_server() {
start_worker() {
echo "Starting the worker..."
poetry run python -m celery -A config.celery worker -l "${DJANGO_LOGGING_LEVEL:-info}" -Q celery,scans,scan-reports,deletion,backfill -E --max-tasks-per-child 1
poetry run python -m celery -A config.celery worker -l "${DJANGO_LOGGING_LEVEL:-info}" -Q celery,scans,scan-reports,deletion,backfill,overview,integrations,compliance -E --max-tasks-per-child 1
}
start_worker_beat() {
+1886 -1241
View File
File diff suppressed because it is too large Load Diff
+10 -5
View File
@@ -7,8 +7,8 @@ authors = [{name = "Prowler Engineering", email = "engineering@prowler.com"}]
dependencies = [
"celery[pytest] (>=5.4.0,<6.0.0)",
"dj-rest-auth[with_social,jwt] (==7.0.1)",
"django==5.1.8",
"django-allauth==65.4.1",
"django (==5.1.12)",
"django-allauth[saml] (>=65.8.0,<66.0.0)",
"django-celery-beat (>=2.7.0,<3.0.0)",
"django-celery-results (>=2.5.1,<3.0.0)",
"django-cors-headers==4.4.0",
@@ -23,11 +23,16 @@ dependencies = [
"drf-spectacular==0.27.2",
"drf-spectacular-jsonapi==0.5.1",
"gunicorn==23.0.0",
"prowler @ git+https://github.com/prowler-cloud/prowler.git@v5.7",
"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)",
"uuid6==2024.7.10"
"uuid6==2024.7.10",
"openai (>=1.82.0,<2.0.0)",
"xmlsec==1.3.14",
"h2 (==4.3.0)",
"markdown (>=3.9,<4.0)"
]
description = "Prowler's API (Django/DRF)"
license = "Apache-2.0"
@@ -35,7 +40,7 @@ name = "prowler-api"
package-mode = false
# Needed for the SDK compatibility
requires-python = ">=3.11,<3.13"
version = "1.8.5"
version = "1.14.0"
[project.scripts]
celery = "src.backend.config.settings.celery"
+37 -27
View File
@@ -17,6 +17,8 @@ class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
# Link existing accounts with the same email address
email = sociallogin.account.extra_data.get("email")
if sociallogin.provider.id == "saml":
email = sociallogin.user.email
if email:
existing_user = self.get_user_by_email(email)
if existing_user:
@@ -29,33 +31,41 @@ class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter):
"""
with transaction.atomic(using=MainRouter.admin_db):
user = super().save_user(request, sociallogin, form)
user.save(using=MainRouter.admin_db)
social_account_name = sociallogin.account.extra_data.get("name")
if social_account_name:
user.name = social_account_name
user.save(using=MainRouter.admin_db)
provider = sociallogin.provider.id
extra = sociallogin.account.extra_data
tenant = Tenant.objects.using(MainRouter.admin_db).create(
name=f"{user.email.split('@')[0]} default tenant"
)
with rls_transaction(str(tenant.id)):
Membership.objects.using(MainRouter.admin_db).create(
user=user, tenant=tenant, role=Membership.RoleChoices.OWNER
)
role = Role.objects.using(MainRouter.admin_db).create(
name="admin",
tenant_id=tenant.id,
manage_users=True,
manage_account=True,
manage_billing=True,
manage_providers=True,
manage_integrations=True,
manage_scans=True,
unlimited_visibility=True,
)
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
user=user,
role=role,
tenant_id=tenant.id,
if provider != "saml":
# Handle other providers (e.g., GitHub, Google)
user.save(using=MainRouter.admin_db)
social_account_name = extra.get("name")
if social_account_name:
user.name = social_account_name
user.save(using=MainRouter.admin_db)
tenant = Tenant.objects.using(MainRouter.admin_db).create(
name=f"{user.email.split('@')[0]} default tenant"
)
with rls_transaction(str(tenant.id)):
Membership.objects.using(MainRouter.admin_db).create(
user=user, tenant=tenant, role=Membership.RoleChoices.OWNER
)
role = Role.objects.using(MainRouter.admin_db).create(
name="admin",
tenant_id=tenant.id,
manage_users=True,
manage_account=True,
manage_billing=True,
manage_providers=True,
manage_integrations=True,
manage_scans=True,
unlimited_visibility=True,
)
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
user=user,
role=role,
tenant_id=tenant.id,
)
else:
request.session["saml_user_created"] = str(user.id)
return user
+158
View File
@@ -1,4 +1,28 @@
import logging
import os
from pathlib import Path
import sys
from django.apps import AppConfig
from django.conf import settings
from config.custom_logging import BackendLogger
from config.env import env
logger = logging.getLogger(BackendLogger.API)
SIGNING_KEY_ENV = "DJANGO_TOKEN_SIGNING_KEY"
VERIFYING_KEY_ENV = "DJANGO_TOKEN_VERIFYING_KEY"
PRIVATE_KEY_FILE = "jwt_private.pem"
PUBLIC_KEY_FILE = "jwt_public.pem"
KEYS_DIRECTORY = (
Path.home() / ".config" / "prowler-api"
) # `/home/prowler/.config/prowler-api` inside the container
_keys_initialized = False # Flag to prevent multiple executions within the same process
class ApiConfig(AppConfig):
@@ -9,4 +33,138 @@ class ApiConfig(AppConfig):
from api import signals # noqa: F401
from api.compliance import load_prowler_compliance
# Generate required cryptographic keys if not present, but only if:
# `"manage.py" not in sys.argv`: If an external server (e.g., Gunicorn) is running the app
# `os.environ.get("RUN_MAIN")`: If it's not a Django command or using `runserver`,
# only the main process will do it
if "manage.py" not in sys.argv or os.environ.get("RUN_MAIN"):
self._ensure_crypto_keys()
load_prowler_compliance()
def _ensure_crypto_keys(self):
"""
Orchestrator method that ensures all required cryptographic keys are present.
This method coordinates the generation of:
- RSA key pairs for JWT token signing and verification
Note: During development, Django spawns multiple processes (migrations, fixtures, etc.)
which will each generate their own keys. This is expected behavior and each process
will have consistent keys for its lifetime. In production, set the keys as environment
variables to avoid regeneration.
"""
global _keys_initialized
# Skip key generation if running tests
if hasattr(settings, "TESTING") and settings.TESTING:
return
# Skip if already initialized in this process
if _keys_initialized:
return
# Check if both JWT keys are set; if not, generate them
signing_key = env.str(SIGNING_KEY_ENV, default="").strip()
verifying_key = env.str(VERIFYING_KEY_ENV, default="").strip()
if not signing_key or not verifying_key:
logger.info(
f"Generating JWT RSA key pair. In production, set '{SIGNING_KEY_ENV}' and '{VERIFYING_KEY_ENV}' "
"environment variables."
)
self._ensure_jwt_keys()
# Mark as initialized to prevent future executions in this process
_keys_initialized = True
def _read_key_file(self, file_name):
"""
Utility method to read the contents of a file.
"""
file_path = KEYS_DIRECTORY / file_name
return file_path.read_text().strip() if file_path.is_file() else None
def _write_key_file(self, file_name, content, private=True):
"""
Utility method to write content to a file.
"""
try:
file_path = KEYS_DIRECTORY / file_name
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content)
file_path.chmod(0o600 if private else 0o644)
except Exception as e:
logger.error(
f"Error writing key file '{file_name}': {e}. "
f"Please set '{SIGNING_KEY_ENV}' and '{VERIFYING_KEY_ENV}' manually."
)
raise e
def _ensure_jwt_keys(self):
"""
Generate RSA key pairs for JWT token signing and verification
if they are not already set in environment variables.
"""
# Read existing keys from files if they exist
signing_key = self._read_key_file(PRIVATE_KEY_FILE)
verifying_key = self._read_key_file(PUBLIC_KEY_FILE)
if not signing_key or not verifying_key:
# Generate and store the RSA key pair
signing_key, verifying_key = self._generate_jwt_keys()
self._write_key_file(PRIVATE_KEY_FILE, signing_key, private=True)
self._write_key_file(PUBLIC_KEY_FILE, verifying_key, private=False)
logger.info("JWT keys generated and stored successfully")
else:
logger.info("JWT keys already generated")
# Set environment variables and Django settings
os.environ[SIGNING_KEY_ENV] = signing_key
settings.SIMPLE_JWT["SIGNING_KEY"] = signing_key
os.environ[VERIFYING_KEY_ENV] = verifying_key
settings.SIMPLE_JWT["VERIFYING_KEY"] = verifying_key
def _generate_jwt_keys(self):
"""
Generate and set RSA key pairs for JWT token operations.
"""
try:
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
# Generate RSA key pair
private_key = rsa.generate_private_key( # Future improvement: we could read the next values from env vars
public_exponent=65537,
key_size=2048,
)
# Serialize private key (for signing)
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
).decode("utf-8")
# Serialize public key (for verification)
public_key = private_key.public_key()
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
).decode("utf-8")
logger.debug("JWT RSA key pair generated successfully.")
return private_pem, public_pem
except ImportError as e:
logger.warning(
"The 'cryptography' package is required for automatic JWT key generation."
)
raise e
except Exception as e:
logger.error(
f"Error generating JWT keys: {e}. Please set '{SIGNING_KEY_ENV}' and '{VERIFYING_KEY_ENV}' manually."
)
raise e
+12 -7
View File
@@ -190,10 +190,16 @@ def generate_compliance_overview_template(prowler_compliance: dict):
total_checks = len(requirement.Checks)
checks_dict = {check: None for check in requirement.Checks}
req_status_val = "MANUAL" if total_checks == 0 else "PASS"
# Build requirement dictionary
requirement_dict = {
"name": requirement.Name or requirement.Id,
"description": requirement.Description,
"tactics": getattr(requirement, "Tactics", []),
"subtechniques": getattr(requirement, "SubTechniques", []),
"platforms": getattr(requirement, "Platforms", []),
"technique_url": getattr(requirement, "TechniqueURL", ""),
"attributes": [
dict(attribute) for attribute in requirement.Attributes
],
@@ -204,23 +210,22 @@ def generate_compliance_overview_template(prowler_compliance: dict):
"manual": 0,
"total": total_checks,
},
"status": "PASS",
"status": req_status_val,
}
# Update requirements status
if total_checks == 0:
# Update requirements status counts for the framework
if req_status_val == "MANUAL":
requirements_status["manual"] += 1
elif req_status_val == "PASS":
requirements_status["passed"] += 1
# Add requirement to compliance requirements
compliance_requirements[requirement.Id] = requirement_dict
# Calculate pending requirements
pending_requirements = total_requirements - requirements_status["manual"]
requirements_status["passed"] = pending_requirements
# Build compliance dictionary
compliance_dict = {
"framework": compliance_data.Framework,
"name": compliance_data.Name,
"version": compliance_data.Version,
"provider": provider_type,
"description": compliance_data.Description,
+159 -11
View File
@@ -1,3 +1,4 @@
import re
import secrets
import uuid
from contextlib import contextmanager
@@ -152,6 +153,51 @@ def delete_related_daily_task(provider_id: str):
PeriodicTask.objects.filter(name=task_name).delete()
def create_objects_in_batches(
tenant_id: str, model, objects: list, batch_size: int = 500
):
"""
Bulk-create model instances in repeated, per-tenant RLS transactions.
All chunks execute in their own transaction, so no single transaction
grows too large.
Args:
tenant_id (str): UUID string of the tenant under which to set RLS.
model: Django model class whose `.objects.bulk_create()` will be called.
objects (list): List of model instances (unsaved) to bulk-create.
batch_size (int): Maximum number of objects per bulk_create call.
"""
total = len(objects)
for i in range(0, total, batch_size):
chunk = objects[i : i + batch_size]
with rls_transaction(value=tenant_id, parameter=POSTGRES_TENANT_VAR):
model.objects.bulk_create(chunk, batch_size)
def update_objects_in_batches(
tenant_id: str, model, objects: list, fields: list, batch_size: int = 500
):
"""
Bulk-update model instances in repeated, per-tenant RLS transactions.
All chunks execute in their own transaction, so no single transaction
grows too large.
Args:
tenant_id (str): UUID string of the tenant under which to set RLS.
model: Django model class whose `.objects.bulk_update()` will be called.
objects (list): List of model instances (saved) to bulk-update.
fields (list): List of field names to update.
batch_size (int): Maximum number of objects per bulk_update call.
"""
total = len(objects)
for start in range(0, total, batch_size):
chunk = objects[start : start + batch_size]
with rls_transaction(value=tenant_id, parameter=POSTGRES_TENANT_VAR):
model.objects.bulk_update(chunk, fields, batch_size)
# Postgres Enums
@@ -227,6 +273,72 @@ def register_enum(apps, schema_editor, enum_class): # noqa: F841
register_adapter(enum_class, enum_adapter)
def _should_create_index_on_partition(
partition_name: str, all_partitions: bool = False
) -> bool:
"""
Determine if we should create an index on this partition.
Args:
partition_name: The name of the partition (e.g., "findings_2025_aug", "findings_default")
all_partitions: If True, create on all partitions. If False, only current/future partitions.
Returns:
bool: True if index should be created on this partition, False otherwise.
"""
if all_partitions:
return True
# Extract date from partition name if it follows the pattern
# Partition names look like: findings_2025_aug, findings_2025_jul, etc.
date_pattern = r"(\d{4})_([a-z]{3})$"
match = re.search(date_pattern, partition_name)
if not match:
# If we can't parse the date, include it to be safe (e.g., default partition)
return True
try:
year_str, month_abbr = match.groups()
year = int(year_str)
# Map month abbreviations to numbers
month_map = {
"jan": 1,
"feb": 2,
"mar": 3,
"apr": 4,
"may": 5,
"jun": 6,
"jul": 7,
"aug": 8,
"sep": 9,
"oct": 10,
"nov": 11,
"dec": 12,
}
month = month_map.get(month_abbr.lower())
if month is None:
# Unknown month abbreviation, include it to be safe
return True
partition_date = datetime(year, month, 1, tzinfo=timezone.utc)
# Get current month start
now = datetime.now(timezone.utc)
current_month_start = now.replace(
day=1, hour=0, minute=0, second=0, microsecond=0
)
# Include current month and future partitions
return partition_date >= current_month_start
except (ValueError, TypeError):
# If date parsing fails, include it to be safe
return True
def create_index_on_partitions(
apps, # noqa: F841
schema_editor,
@@ -235,16 +347,39 @@ def create_index_on_partitions(
columns: str,
method: str = "BTREE",
where: str = "",
all_partitions: bool = True,
):
"""
Create an index on every existing partition of `parent_table`.
Create an index on existing partitions of `parent_table`.
Args:
parent_table: The name of the root table (e.g. "findings").
index_name: A short name for the index (will be prefixed per-partition).
columns: The parenthesized column list, e.g. "tenant_id, scan_id, status".
method: The index method—BTREE, GIN, etc. Defaults to BTREE.
where: Optional WHERE clause (without the leading "WHERE"), e.g. "status = 'FAIL'".
method: The index method—BTREE, GIN, etc. Defaults to BTREE.
where: Optional WHERE clause (without the leading "WHERE"), e.g. "status = 'FAIL'".
all_partitions: Whether to create indexes on all partitions or just current/future ones.
Defaults to False (current/future only) to avoid maintenance overhead
on old partitions where the index may not be needed.
Examples:
# Create index only on current and future partitions (recommended for new indexes)
create_index_on_partitions(
apps, schema_editor,
parent_table="findings",
index_name="new_performance_idx",
columns="tenant_id, status, severity",
all_partitions=False # Default behavior
)
# Create index on all partitions (use when migrating existing critical indexes)
create_index_on_partitions(
apps, schema_editor,
parent_table="findings",
index_name="critical_existing_idx",
columns="tenant_id, scan_id",
all_partitions=True
)
"""
with connection.cursor() as cursor:
cursor.execute(
@@ -259,13 +394,14 @@ def create_index_on_partitions(
where_sql = f" WHERE {where}" if where else ""
for partition in partitions:
idx_name = f"{partition.replace('.', '_')}_{index_name}"
sql = (
f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {idx_name} "
f"ON {partition} USING {method} ({columns})"
f"{where_sql};"
)
schema_editor.execute(sql)
if _should_create_index_on_partition(partition, all_partitions):
idx_name = f"{partition.replace('.', '_')}_{index_name}"
sql = (
f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {idx_name} "
f"ON {partition} USING {method} ({columns})"
f"{where_sql};"
)
schema_editor.execute(sql)
def drop_index_on_partitions(
@@ -279,7 +415,7 @@ def drop_index_on_partitions(
Args:
parent_table: The name of the root table (e.g. "findings").
index_name: The same short name used when creating them.
index_name: The same short name used when creating them.
"""
with connection.cursor() as cursor:
cursor.execute(
@@ -416,3 +552,15 @@ class IntegrationTypeEnum(EnumType):
class IntegrationTypeEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("integration_type", *args, **kwargs)
# Postgres enum definition for Processor type
class ProcessorTypeEnum(EnumType):
enum_type_name = "processor_type"
class ProcessorTypeEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("processor_type", *args, **kwargs)
+57 -4
View File
@@ -3,7 +3,7 @@ from rest_framework import status
from rest_framework.exceptions import APIException
from rest_framework_json_api.exceptions import exception_handler
from rest_framework_json_api.serializers import ValidationError
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
class ModelValidationError(ValidationError):
@@ -32,6 +32,36 @@ class InvitationTokenExpiredException(APIException):
default_code = "token_expired"
# Task Management Exceptions (non-HTTP)
class TaskManagementError(Exception):
"""Base exception for task management errors."""
def __init__(self, task=None):
self.task = task
super().__init__()
class TaskFailedException(TaskManagementError):
"""Raised when a task has failed."""
class TaskNotFoundException(TaskManagementError):
"""Raised when a task is not found."""
class TaskInProgressException(TaskManagementError):
"""Raised when a task is running but there's no related Task object to return."""
def __init__(self, task_result=None):
self.task_result = task_result
super().__init__()
# Provider connection errors
class ProviderConnectionError(Exception):
"""Base exception for provider connection errors."""
def custom_exception_handler(exc, context):
if isinstance(exc, django_validation_error):
if hasattr(exc, "error_dict"):
@@ -39,7 +69,30 @@ def custom_exception_handler(exc, context):
else:
exc = ValidationError(detail=exc.messages[0], code=exc.code)
elif isinstance(exc, (TokenError, InvalidToken)):
exc.detail["messages"] = [
message_item["message"] for message_item in exc.detail["messages"]
]
if (
hasattr(exc, "detail")
and isinstance(exc.detail, dict)
and "messages" in exc.detail
):
exc.detail["messages"] = [
message_item["message"] for message_item in exc.detail["messages"]
]
return exception_handler(exc, context)
class ConflictException(APIException):
status_code = status.HTTP_409_CONFLICT
default_detail = "A conflict occurred. The resource already exists."
default_code = "conflict"
def __init__(self, detail=None, code=None, pointer=None):
error_detail = {
"detail": detail or self.default_detail,
"status": self.status_code,
"code": self.default_code,
}
if pointer:
error_detail["source"] = {"pointer": pointer}
super().__init__(detail=[error_detail])
+181 -6
View File
@@ -1,7 +1,8 @@
from datetime import date, datetime, timedelta, timezone
from dateutil.parser import parse
from django.conf import settings
from django.db.models import Q
from django.db.models import F, Q
from django_filters.rest_framework import (
BaseInFilter,
BooleanFilter,
@@ -22,12 +23,14 @@ from api.db_utils import (
StatusEnumField,
)
from api.models import (
ComplianceOverview,
ComplianceRequirementOverview,
Finding,
Integration,
Invitation,
Membership,
OverviewStatusChoices,
PermissionChoices,
Processor,
Provider,
ProviderGroup,
ProviderSecret,
@@ -338,6 +341,8 @@ class ResourceFilter(ProviderRelationshipFilterSet):
tags = CharFilter(method="filter_tag")
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
scan = UUIDFilter(field_name="provider__scan", lookup_expr="exact")
scan__in = UUIDInFilter(field_name="provider__scan", lookup_expr="in")
class Meta:
model = Resource
@@ -352,6 +357,82 @@ class ResourceFilter(ProviderRelationshipFilterSet):
"updated_at": ["gte", "lte"],
}
def filter_queryset(self, queryset):
if not (self.data.get("scan") or self.data.get("scan__in")) and not (
self.data.get("updated_at")
or self.data.get("updated_at__date")
or self.data.get("updated_at__gte")
or self.data.get("updated_at__lte")
):
raise ValidationError(
[
{
"detail": "At least one date filter is required: filter[updated_at], filter[updated_at.gte], "
"or filter[updated_at.lte].",
"status": 400,
"source": {"pointer": "/data/attributes/updated_at"},
"code": "required",
}
]
)
gte_date = (
parse(self.data.get("updated_at__gte")).date()
if self.data.get("updated_at__gte")
else datetime.now(timezone.utc).date()
)
lte_date = (
parse(self.data.get("updated_at__lte")).date()
if self.data.get("updated_at__lte")
else datetime.now(timezone.utc).date()
)
if abs(lte_date - gte_date) > timedelta(
days=settings.FINDINGS_MAX_DAYS_IN_RANGE
):
raise ValidationError(
[
{
"detail": f"The date range cannot exceed {settings.FINDINGS_MAX_DAYS_IN_RANGE} days.",
"status": 400,
"source": {"pointer": "/data/attributes/updated_at"},
"code": "invalid",
}
]
)
return super().filter_queryset(queryset)
def filter_tag_key(self, queryset, name, value):
return queryset.filter(Q(tags__key=value) | Q(tags__key__icontains=value))
def filter_tag_value(self, queryset, name, value):
return queryset.filter(Q(tags__value=value) | Q(tags__value__icontains=value))
def filter_tag(self, queryset, name, value):
# We won't know what the user wants to filter on just based on the value,
# and we don't want to build special filtering logic for every possible
# provider tag spec, so we'll just do a full text search
return queryset.filter(tags__text_search=value)
class LatestResourceFilter(ProviderRelationshipFilterSet):
tag_key = CharFilter(method="filter_tag_key")
tag_value = CharFilter(method="filter_tag_value")
tag = CharFilter(method="filter_tag")
tags = CharFilter(method="filter_tag")
class Meta:
model = Resource
fields = {
"provider": ["exact", "in"],
"uid": ["exact", "icontains"],
"name": ["exact", "icontains"],
"region": ["exact", "icontains", "in"],
"service": ["exact", "icontains", "in"],
"type": ["exact", "icontains", "in"],
}
def filter_tag_key(self, queryset, name, value):
return queryset.filter(Q(tags__key=value) | Q(tags__key__icontains=value))
@@ -637,12 +718,11 @@ class RoleFilter(FilterSet):
class ComplianceOverviewFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
provider_type = ChoiceFilter(choices=Provider.ProviderChoices.choices)
provider_type__in = ChoiceInFilter(choices=Provider.ProviderChoices.choices)
scan_id = UUIDFilter(field_name="scan__id")
scan_id = UUIDFilter(field_name="scan_id")
region = CharFilter(field_name="region")
class Meta:
model = ComplianceOverview
model = ComplianceRequirementOverview
fields = {
"inserted_at": ["date", "gte", "lte"],
"compliance_id": ["exact", "icontains"],
@@ -671,6 +751,72 @@ class ScanSummaryFilter(FilterSet):
}
class ScanSummarySeverityFilter(ScanSummaryFilter):
"""Filter for findings_severity ScanSummary endpoint - includes status filters"""
# Custom status filters - only for severity grouping endpoint
status = ChoiceFilter(method="filter_status", choices=OverviewStatusChoices.choices)
status__in = CharInFilter(method="filter_status_in", lookup_expr="in")
def filter_status(self, queryset, name, value):
# Validate the status value
if value not in [choice[0] for choice in OverviewStatusChoices.choices]:
raise ValidationError(f"Invalid status value: {value}")
# Apply the filter by annotating the queryset with the status field
if value == OverviewStatusChoices.FAIL:
return queryset.annotate(status_count=F("fail"))
elif value == OverviewStatusChoices.PASS:
return queryset.annotate(status_count=F("_pass"))
else:
return queryset.annotate(status_count=F("total"))
def filter_status_in(self, queryset, name, value):
# Validate the status values
valid_statuses = [choice[0] for choice in OverviewStatusChoices.choices]
for status_val in value:
if status_val not in valid_statuses:
raise ValidationError(f"Invalid status value: {status_val}")
# If all statuses or no valid statuses, use total
if (
set(value)
>= {
OverviewStatusChoices.FAIL,
OverviewStatusChoices.PASS,
}
or not value
):
return queryset.annotate(status_count=F("total"))
# Build the sum expression based on status values
sum_expression = None
for status in value:
if status == OverviewStatusChoices.FAIL:
field_expr = F("fail")
elif status == OverviewStatusChoices.PASS:
field_expr = F("_pass")
else:
continue
if sum_expression is None:
sum_expression = field_expr
else:
sum_expression = sum_expression + field_expr
if sum_expression is None:
return queryset.annotate(status_count=F("total"))
return queryset.annotate(status_count=sum_expression)
class Meta:
model = ScanSummary
fields = {
"inserted_at": ["date", "gte", "lte"],
"region": ["exact", "icontains", "in"],
}
class ServiceOverviewFilter(ScanSummaryFilter):
def is_valid(self):
# Check if at least one of the inserted_at filters is present
@@ -705,3 +851,32 @@ class IntegrationFilter(FilterSet):
fields = {
"inserted_at": ["date", "gte", "lte"],
}
class ProcessorFilter(FilterSet):
processor_type = ChoiceFilter(choices=Processor.ProcessorChoices.choices)
processor_type__in = ChoiceInFilter(
choices=Processor.ProcessorChoices.choices,
field_name="processor_type",
lookup_expr="in",
)
class IntegrationJiraFindingsFilter(FilterSet):
# To be expanded as needed
finding_id = UUIDFilter(field_name="id", lookup_expr="exact")
finding_id__in = UUIDInFilter(field_name="id", lookup_expr="in")
class Meta:
model = Finding
fields = {}
def filter_queryset(self, queryset):
# Validate that there is at least one filter provided
if not self.data:
raise ValidationError(
{
"findings": "No finding filters provided. At least one filter is required."
}
)
return super().filter_queryset(queryset)
@@ -3,7 +3,7 @@
"model": "api.user",
"pk": "8b38e2eb-6689-4f1e-a4ba-95b275130200",
"fields": {
"password": "pbkdf2_sha256$720000$vA62S78kog2c2ytycVQdke$Fp35GVLLMyy5fUq3krSL9I02A+ocQ+RVa4S22LIAO5s=",
"password": "pbkdf2_sha256$870000$Z63pGJ7nre48hfcGbk5S0O$rQpKczAmijs96xa+gPVJifpT3Fetb8DOusl5Eq6gxac=",
"last_login": null,
"name": "Devie Prowlerson",
"email": "dev@prowler.com",
@@ -16,7 +16,7 @@
"model": "api.user",
"pk": "b6493a3a-c997-489b-8b99-278bf74de9f6",
"fields": {
"password": "pbkdf2_sha256$720000$vA62S78kog2c2ytycVQdke$Fp35GVLLMyy5fUq3krSL9I02A+ocQ+RVa4S22LIAO5s=",
"password": "pbkdf2_sha256$870000$Z63pGJ7nre48hfcGbk5S0O$rQpKczAmijs96xa+gPVJifpT3Fetb8DOusl5Eq6gxac=",
"last_login": null,
"name": "Devietoo Prowlerson",
"email": "dev2@prowler.com",
@@ -24,5 +24,18 @@
"is_active": true,
"date_joined": "2024-09-18T09:04:20.850Z"
}
},
{
"model": "api.user",
"pk": "6d4f8a91-3c2e-4b5a-8f7d-1e9c5b2a4d6f",
"fields": {
"password": "pbkdf2_sha256$870000$Z63pGJ7nre48hfcGbk5S0O$rQpKczAmijs96xa+gPVJifpT3Fetb8DOusl5Eq6gxac=",
"last_login": null,
"name": "E2E Test User",
"email": "e2e@prowler.com",
"company_name": "Prowler E2E Tests",
"is_active": true,
"date_joined": "2024-01-01T00:00:00.850Z"
}
}
]
@@ -46,5 +46,24 @@
"role": "member",
"date_joined": "2024-09-19T11:03:59.712Z"
}
},
{
"model": "api.tenant",
"pk": "7c8f94a3-e2d1-4b3a-9f87-2c4d5e6f1a2b",
"fields": {
"inserted_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"name": "E2E Test Tenant"
}
},
{
"model": "api.membership",
"pk": "9b1a2c3d-4e5f-6789-abc1-23456789def0",
"fields": {
"user": "6d4f8a91-3c2e-4b5a-8f7d-1e9c5b2a4d6f",
"tenant": "7c8f94a3-e2d1-4b3a-9f87-2c4d5e6f1a2b",
"role": "owner",
"date_joined": "2024-01-01T00:00:00.000Z"
}
}
]
@@ -149,5 +149,32 @@
"user": "8b38e2eb-6689-4f1e-a4ba-95b275130200",
"inserted_at": "2024-11-20T15:36:14.302Z"
}
},
{
"model": "api.role",
"pk": "a5b6c7d8-9e0f-1234-5678-90abcdef1234",
"fields": {
"tenant": "7c8f94a3-e2d1-4b3a-9f87-2c4d5e6f1a2b",
"name": "e2e_admin",
"manage_users": true,
"manage_account": true,
"manage_billing": true,
"manage_providers": true,
"manage_integrations": true,
"manage_scans": true,
"unlimited_visibility": true,
"inserted_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}
},
{
"model": "api.userrolerelationship",
"pk": "f1e2d3c4-b5a6-9876-5432-10fedcba9876",
"fields": {
"tenant": "7c8f94a3-e2d1-4b3a-9f87-2c4d5e6f1a2b",
"role": "a5b6c7d8-9e0f-1234-5678-90abcdef1234",
"user": "6d4f8a91-3c2e-4b5a-8f7d-1e9c5b2a4d6f",
"inserted_at": "2024-01-01T00:00:00.000Z"
}
}
]
File diff suppressed because one or more lines are too long
@@ -0,0 +1,80 @@
from django.contrib.sites.models import Site
from django.core.management.base import BaseCommand
from django.db import DEFAULT_DB_ALIAS, connection, connections, transaction
from django.db.migrations.recorder import MigrationRecorder
def table_exists(table_name):
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_name = %s
)
""",
[table_name],
)
return cursor.fetchone()[0]
class Command(BaseCommand):
help = "Fix migration inconsistency between socialaccount and sites"
def add_arguments(self, parser):
parser.add_argument(
"--database",
default=DEFAULT_DB_ALIAS,
help="Specifies the database to operate on.",
)
def handle(self, *args, **options):
db = options["database"]
connection = connections[db]
recorder = MigrationRecorder(connection)
applied = set(recorder.applied_migrations())
has_social = ("socialaccount", "0001_initial") in applied
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'django_site'
);
"""
)
site_table_exists = cursor.fetchone()[0]
if has_social and not site_table_exists:
self.stdout.write(
f"Detected inconsistency in '{db}'. Creating 'django_site' table manually..."
)
with transaction.atomic(using=db):
with connection.schema_editor() as schema_editor:
schema_editor.create_model(Site)
recorder.record_applied("sites", "0001_initial")
recorder.record_applied("sites", "0002_alter_domain_unique")
self.stdout.write(
"Fixed: 'django_site' table created and migrations registered."
)
# Ensure the relationship table also exists
if not table_exists("socialaccount_socialapp_sites"):
self.stdout.write(
"Detected missing 'socialaccount_socialapp_sites' table. Creating manually..."
)
with connection.schema_editor() as schema_editor:
from allauth.socialaccount.models import SocialApp
schema_editor.create_model(
SocialApp._meta.get_field("sites").remote_field.through
)
self.stdout.write(
"Fixed: 'socialaccount_socialapp_sites' table created."
)
@@ -0,0 +1,14 @@
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("api", "0025_findings_uid_index_parent"),
]
operations = [
migrations.RunSQL(
"ALTER TYPE provider_secret_type ADD VALUE IF NOT EXISTS 'service_account';",
reverse_sql=migrations.RunSQL.noop,
),
]
@@ -0,0 +1,124 @@
# Generated by Django 5.1.8 on 2025-05-21 11:37
import uuid
import django.db.models.deletion
from django.db import migrations, models
import api.db_utils
import api.rls
from api.rls import RowLevelSecurityConstraint
class Migration(migrations.Migration):
dependencies = [
("api", "0026_provider_secret_gcp_service_account"),
]
operations = [
migrations.CreateModel(
name="ComplianceRequirementOverview",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
("compliance_id", models.TextField(blank=False)),
("framework", models.TextField(blank=False)),
("version", models.TextField(blank=True)),
("description", models.TextField(blank=True)),
("region", models.TextField(blank=False)),
("requirement_id", models.TextField(blank=False)),
(
"requirement_status",
api.db_utils.StatusEnumField(
choices=[
("FAIL", "Fail"),
("PASS", "Pass"),
("MANUAL", "Manual"),
]
),
),
("passed_checks", models.IntegerField(default=0)),
("failed_checks", models.IntegerField(default=0)),
("total_checks", models.IntegerField(default=0)),
(
"scan",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="compliance_requirements_overviews",
related_query_name="compliance_requirements_overview",
to="api.scan",
),
),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "compliance_requirements_overviews",
"abstract": False,
"indexes": [
models.Index(
fields=["tenant_id", "scan_id"], name="cro_tenant_scan_idx"
),
models.Index(
fields=["tenant_id", "scan_id", "compliance_id"],
name="cro_scan_comp_idx",
),
models.Index(
fields=["tenant_id", "scan_id", "compliance_id", "region"],
name="cro_scan_comp_reg_idx",
),
models.Index(
fields=[
"tenant_id",
"scan_id",
"compliance_id",
"requirement_id",
],
name="cro_scan_comp_req_idx",
),
models.Index(
fields=[
"tenant_id",
"scan_id",
"compliance_id",
"requirement_id",
"region",
],
name="cro_scan_comp_req_reg_idx",
),
],
"constraints": [
models.UniqueConstraint(
fields=(
"tenant_id",
"scan_id",
"compliance_id",
"requirement_id",
"region",
),
name="unique_tenant_compliance_requirement_overview",
)
],
},
),
migrations.AddConstraint(
model_name="ComplianceRequirementOverview",
constraint=RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_compliancerequirementoverview",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
]
@@ -0,0 +1,29 @@
from functools import partial
from django.db import migrations
from api.db_utils import create_index_on_partitions, drop_index_on_partitions
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0027_compliance_requirement_overviews"),
]
operations = [
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="findings",
index_name="find_tenant_scan_check_idx",
columns="tenant_id, scan_id, check_id",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="findings",
index_name="find_tenant_scan_check_idx",
),
)
]
@@ -0,0 +1,17 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0028_findings_check_index_partitions"),
]
operations = [
migrations.AddIndex(
model_name="finding",
index=models.Index(
fields=["tenant_id", "scan_id", "check_id"],
name="find_tenant_scan_check_idx",
),
),
]
@@ -0,0 +1,107 @@
# Generated by Django 5.1.10 on 2025-06-12 12:45
import uuid
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models
import api.rls
class Migration(migrations.Migration):
dependencies = [
("api", "0029_findings_check_index_parent"),
]
operations = [
migrations.CreateModel(
name="LighthouseConfiguration",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"name",
models.CharField(
help_text="Name of the configuration",
max_length=100,
validators=[django.core.validators.MinLengthValidator(3)],
),
),
(
"api_key",
models.BinaryField(
help_text="Encrypted API key for the LLM service"
),
),
(
"model",
models.CharField(
choices=[
("gpt-4o-2024-11-20", "GPT-4o v2024-11-20"),
("gpt-4o-2024-08-06", "GPT-4o v2024-08-06"),
("gpt-4o-2024-05-13", "GPT-4o v2024-05-13"),
("gpt-4o", "GPT-4o Default"),
("gpt-4o-mini-2024-07-18", "GPT-4o Mini v2024-07-18"),
("gpt-4o-mini", "GPT-4o Mini Default"),
],
default="gpt-4o-2024-08-06",
help_text="Must be one of the supported model names",
max_length=50,
),
),
(
"temperature",
models.FloatField(default=0, help_text="Must be between 0 and 1"),
),
(
"max_tokens",
models.IntegerField(
default=4000, help_text="Must be between 500 and 5000"
),
),
(
"business_context",
models.TextField(
blank=True,
default="",
help_text="Additional business context for this AI model configuration",
),
),
("is_active", models.BooleanField(default=True)),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "lighthouse_configurations",
"abstract": False,
"constraints": [
models.UniqueConstraint(
fields=("tenant_id",),
name="unique_lighthouse_config_per_tenant",
),
],
},
),
migrations.AddConstraint(
model_name="lighthouseconfiguration",
constraint=api.rls.RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_lighthouseconfiguration",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
]
@@ -0,0 +1,24 @@
# Generated by Django 5.1.10 on 2025-06-23 10:04
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0030_lighthouseconfiguration"),
("django_celery_beat", "0019_alter_periodictasks_options"),
]
operations = [
migrations.AlterField(
model_name="scan",
name="scheduler_task",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="django_celery_beat.periodictask",
),
),
]
+150
View File
@@ -0,0 +1,150 @@
# Generated by Django 5.1.10 on 2025-07-02 15:47
import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import api.db_utils
import api.rls
class Migration(migrations.Migration):
dependencies = [
("api", "0031_scan_disable_on_cascade_periodic_tasks"),
]
operations = [
migrations.AlterField(
model_name="integration",
name="integration_type",
field=api.db_utils.IntegrationTypeEnumField(
choices=[
("amazon_s3", "Amazon S3"),
("aws_security_hub", "AWS Security Hub"),
("jira", "JIRA"),
("slack", "Slack"),
]
),
),
migrations.CreateModel(
name="SAMLToken",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("expires_at", models.DateTimeField(editable=False)),
("token", models.JSONField(unique=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"db_table": "saml_tokens",
},
),
migrations.CreateModel(
name="SAMLConfiguration",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
(
"email_domain",
models.CharField(
help_text="Email domain used to identify the tenant, e.g. prowlerdemo.com",
max_length=254,
unique=True,
),
),
(
"metadata_xml",
models.TextField(
help_text="Raw IdP metadata XML to configure SingleSignOnService, certificates, etc."
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "saml_configurations",
},
),
migrations.AddConstraint(
model_name="samlconfiguration",
constraint=api.rls.RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_samlconfiguration",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
migrations.AddConstraint(
model_name="samlconfiguration",
constraint=models.UniqueConstraint(
fields=("tenant",), name="unique_samlconfig_per_tenant"
),
),
migrations.CreateModel(
name="SAMLDomainIndex",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("email_domain", models.CharField(max_length=254, unique=True)),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "saml_domain_index",
},
),
migrations.AddConstraint(
model_name="samldomainindex",
constraint=models.UniqueConstraint(
fields=("email_domain", "tenant"),
name="unique_resources_by_email_domain",
),
),
migrations.AddConstraint(
model_name="samldomainindex",
constraint=api.rls.BaseSecurityConstraint(
name="statements_on_samldomainindex",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
]
@@ -0,0 +1,34 @@
# Generated by Django 5.1.5 on 2025-03-03 15:46
from functools import partial
from django.db import migrations
from api.db_utils import PostgresEnumMigration, ProcessorTypeEnum, register_enum
from api.models import Processor
ProcessorTypeEnumMigration = PostgresEnumMigration(
enum_name="processor_type",
enum_values=tuple(
processor_type[0] for processor_type in Processor.ProcessorChoices.choices
),
)
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0032_saml"),
]
operations = [
migrations.RunPython(
ProcessorTypeEnumMigration.create_enum_type,
reverse_code=ProcessorTypeEnumMigration.drop_enum_type,
),
migrations.RunPython(
partial(register_enum, enum_class=ProcessorTypeEnum),
reverse_code=migrations.RunPython.noop,
),
]
@@ -0,0 +1,88 @@
# Generated by Django 5.1.5 on 2025-03-26 13:04
import uuid
import django.db.models.deletion
from django.db import migrations, models
import api.db_utils
import api.rls
from api.rls import RowLevelSecurityConstraint
class Migration(migrations.Migration):
dependencies = [
("api", "0033_processors_enum"),
]
operations = [
migrations.CreateModel(
name="Processor",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"processor_type",
api.db_utils.ProcessorTypeEnumField(
choices=[("mutelist", "Mutelist")]
),
),
("configuration", models.JSONField(default=dict)),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "processors",
"abstract": False,
"indexes": [
models.Index(
fields=["tenant_id", "id"], name="processor_tenant_id_idx"
),
models.Index(
fields=["tenant_id", "processor_type"],
name="processor_tenant_type_idx",
),
],
},
),
migrations.AddConstraint(
model_name="processor",
constraint=models.UniqueConstraint(
fields=("tenant_id", "processor_type"),
name="unique_processor_types_tenant",
),
),
migrations.AddConstraint(
model_name="processor",
constraint=RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_processor",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
migrations.AddField(
model_name="scan",
name="processor",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="scans",
related_query_name="scan",
to="api.processor",
),
),
]
@@ -0,0 +1,22 @@
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0034_processors"),
]
operations = [
migrations.AddField(
model_name="finding",
name="muted_reason",
field=models.TextField(
blank=True,
max_length=500,
null=True,
validators=[django.core.validators.MinLengthValidator(3)],
),
),
]
@@ -0,0 +1,30 @@
from functools import partial
from django.db import migrations
from api.db_utils import create_index_on_partitions, drop_index_on_partitions
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0035_finding_muted_reason"),
]
operations = [
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="resource_finding_mappings",
index_name="rfm_tenant_finding_idx",
columns="tenant_id, finding_id",
method="BTREE",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="resource_finding_mappings",
index_name="rfm_tenant_finding_idx",
),
),
]
@@ -0,0 +1,17 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0036_rfm_tenant_finding_index_partitions"),
]
operations = [
migrations.AddIndex(
model_name="resourcefindingmapping",
index=models.Index(
fields=["tenant_id", "finding_id"],
name="rfm_tenant_finding_idx",
),
),
]
@@ -0,0 +1,15 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0037_rfm_tenant_finding_index_parent"),
]
operations = [
migrations.AddField(
model_name="resource",
name="failed_findings_count",
field=models.IntegerField(default=0),
)
]
@@ -0,0 +1,20 @@
from django.contrib.postgres.operations import AddIndexConcurrently
from django.db import migrations, models
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0038_resource_failed_findings_count"),
]
operations = [
AddIndexConcurrently(
model_name="resource",
index=models.Index(
fields=["tenant_id", "-failed_findings_count", "id"],
name="resources_failed_findings_idx",
),
),
]
@@ -0,0 +1,30 @@
from functools import partial
from django.db import migrations
from api.db_utils import create_index_on_partitions, drop_index_on_partitions
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0039_resource_resources_failed_findings_idx"),
]
operations = [
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="resource_finding_mappings",
index_name="rfm_tenant_resource_idx",
columns="tenant_id, resource_id",
method="BTREE",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="resource_finding_mappings",
index_name="rfm_tenant_resource_idx",
),
),
]
@@ -0,0 +1,17 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0040_rfm_tenant_resource_index_partitions"),
]
operations = [
migrations.AddIndex(
model_name="resourcefindingmapping",
index=models.Index(
fields=["tenant_id", "resource_id"],
name="rfm_tenant_resource_idx",
),
),
]
@@ -0,0 +1,23 @@
from django.contrib.postgres.operations import AddIndexConcurrently
from django.db import migrations, models
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0041_rfm_tenant_resource_parent_partitions"),
("django_celery_beat", "0019_alter_periodictasks_options"),
]
operations = [
AddIndexConcurrently(
model_name="scan",
index=models.Index(
condition=models.Q(("state", "completed")),
fields=["tenant_id", "provider_id", "-inserted_at"],
include=("id",),
name="scans_prov_ins_desc_idx",
),
),
]
@@ -0,0 +1,33 @@
# Generated by Django 5.1.7 on 2025-07-09 14:44
from django.db import migrations
import api.db_utils
class Migration(migrations.Migration):
dependencies = [
("api", "0042_scan_scans_prov_ins_desc_idx"),
]
operations = [
migrations.AlterField(
model_name="provider",
name="provider",
field=api.db_utils.ProviderEnumField(
choices=[
("aws", "AWS"),
("azure", "Azure"),
("gcp", "GCP"),
("kubernetes", "Kubernetes"),
("m365", "M365"),
("github", "GitHub"),
],
default="aws",
),
),
migrations.RunSQL(
"ALTER TYPE provider ADD VALUE IF NOT EXISTS 'github';",
reverse_sql=migrations.RunSQL.noop,
),
]
@@ -0,0 +1,19 @@
# Generated by Django 5.1.10 on 2025-07-17 11:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0043_github_provider"),
]
operations = [
migrations.AddConstraint(
model_name="integration",
constraint=models.UniqueConstraint(
fields=("configuration", "tenant"),
name="unique_configuration_per_tenant",
),
),
]
@@ -0,0 +1,17 @@
# Generated by Django 5.1.10 on 2025-07-21 16:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0044_integration_unique_configuration_per_tenant"),
]
operations = [
migrations.AlterField(
model_name="scan",
name="output_location",
field=models.CharField(blank=True, max_length=4096, null=True),
),
]
@@ -0,0 +1,33 @@
# Generated by Django 5.1.10 on 2025-08-20 09:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0045_alter_scan_output_location"),
]
operations = [
migrations.AlterField(
model_name="lighthouseconfiguration",
name="model",
field=models.CharField(
choices=[
("gpt-4o-2024-11-20", "GPT-4o v2024-11-20"),
("gpt-4o-2024-08-06", "GPT-4o v2024-08-06"),
("gpt-4o-2024-05-13", "GPT-4o v2024-05-13"),
("gpt-4o", "GPT-4o Default"),
("gpt-4o-mini-2024-07-18", "GPT-4o Mini v2024-07-18"),
("gpt-4o-mini", "GPT-4o Mini Default"),
("gpt-5-2025-08-07", "GPT-5 v2025-08-07"),
("gpt-5", "GPT-5 Default"),
("gpt-5-mini-2025-08-07", "GPT-5 Mini v2025-08-07"),
("gpt-5-mini", "GPT-5 Mini Default"),
],
default="gpt-4o-2024-08-06",
help_text="Must be one of the supported model names",
max_length=50,
),
),
]
@@ -0,0 +1,16 @@
# Generated by Django 5.1.10 on 2025-08-20 08:24
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("api", "0046_lighthouse_gpt5"),
]
operations = [
migrations.RemoveConstraint(
model_name="integration",
name="unique_configuration_per_tenant",
),
]
+603 -21
View File
@@ -1,13 +1,21 @@
import json
import logging
import re
import xml.etree.ElementTree as ET
from datetime import datetime, timedelta, timezone
from uuid import UUID, uuid4
from cryptography.fernet import Fernet
from allauth.socialaccount.models import SocialApp
from config.custom_logging import BackendLogger
from config.settings.social_login import SOCIALACCOUNT_PROVIDERS
from cryptography.fernet import Fernet, InvalidToken
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import SearchVector, SearchVectorField
from django.contrib.sites.models import Site
from django.core.exceptions import ValidationError
from django.core.validators import MinLengthValidator
from django.db import models
from django.db.models import Q
@@ -19,12 +27,14 @@ from psqlextra.models import PostgresPartitionedModel
from psqlextra.types import PostgresPartitioningMethod
from uuid6 import uuid7
from api.db_router import MainRouter
from api.db_utils import (
CustomUserManager,
FindingDeltaEnumField,
IntegrationTypeEnumField,
InvitationStateEnumField,
MemberRoleEnumField,
ProcessorTypeEnumField,
ProviderEnumField,
ProviderSecretTypeEnumField,
ScanTriggerEnumField,
@@ -49,6 +59,8 @@ fernet = Fernet(settings.SECRETS_ENCRYPTION_KEY.encode())
# Convert Prowler Severity enum to Django TextChoices
SeverityChoices = enum_to_choices(Severity)
logger = logging.getLogger(BackendLogger.API)
class StatusChoices(models.TextChoices):
"""
@@ -62,6 +74,15 @@ class StatusChoices(models.TextChoices):
MANUAL = "MANUAL", _("Manual")
class OverviewStatusChoices(models.TextChoices):
"""
Status filters allowed in overview/severity endpoints.
"""
FAIL = "FAIL", _("Fail")
PASS = "PASS", _("Pass")
class StateChoices(models.TextChoices):
AVAILABLE = "available", _("Available")
SCHEDULED = "scheduled", _("Scheduled")
@@ -193,6 +214,7 @@ class Provider(RowLevelSecurityProtectedModel):
GCP = "gcp", _("GCP")
KUBERNETES = "kubernetes", _("Kubernetes")
M365 = "m365", _("M365")
GITHUB = "github", _("GitHub")
@staticmethod
def validate_aws_uid(value):
@@ -253,6 +275,16 @@ class Provider(RowLevelSecurityProtectedModel):
pointer="/data/attributes/uid",
)
@staticmethod
def validate_github_uid(value):
if not re.match(r"^[a-zA-Z0-9][a-zA-Z0-9-]{0,38}$", value):
raise ModelValidationError(
detail="GitHub provider ID must be a valid GitHub username or organization name (1-39 characters, "
"starting with alphanumeric, containing only alphanumeric characters and hyphens).",
code="github-uid",
pointer="/data/attributes/uid",
)
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
@@ -398,20 +430,6 @@ class Scan(RowLevelSecurityProtectedModel):
name = models.CharField(
blank=True, null=True, max_length=100, validators=[MinLengthValidator(3)]
)
provider = models.ForeignKey(
Provider,
on_delete=models.CASCADE,
related_name="scans",
related_query_name="scan",
)
task = models.ForeignKey(
Task,
on_delete=models.CASCADE,
related_name="scans",
related_query_name="scan",
null=True,
blank=True,
)
trigger = ScanTriggerEnumField(
choices=TriggerChoices.choices,
)
@@ -427,11 +445,31 @@ class Scan(RowLevelSecurityProtectedModel):
completed_at = models.DateTimeField(null=True, blank=True)
next_scan_at = models.DateTimeField(null=True, blank=True)
scheduler_task = models.ForeignKey(
PeriodicTask, on_delete=models.CASCADE, null=True, blank=True
PeriodicTask, on_delete=models.SET_NULL, null=True, blank=True
)
output_location = models.CharField(blank=True, null=True, max_length=4096)
provider = models.ForeignKey(
Provider,
on_delete=models.CASCADE,
related_name="scans",
related_query_name="scan",
)
task = models.ForeignKey(
Task,
on_delete=models.CASCADE,
related_name="scans",
related_query_name="scan",
null=True,
blank=True,
)
processor = models.ForeignKey(
"Processor",
on_delete=models.SET_NULL,
related_name="scans",
related_query_name="scan",
null=True,
blank=True,
)
output_location = models.CharField(blank=True, null=True, max_length=200)
# TODO: mutelist foreign key
class Meta(RowLevelSecurityProtectedModel.Meta):
db_table = "scans"
@@ -458,6 +496,13 @@ class Scan(RowLevelSecurityProtectedModel):
condition=Q(state=StateChoices.COMPLETED),
name="scans_prov_state_ins_desc_idx",
),
# TODO This might replace `scans_prov_state_ins_desc_idx` completely. Review usage
models.Index(
fields=["tenant_id", "provider_id", "-inserted_at"],
condition=Q(state=StateChoices.COMPLETED),
include=["id"],
name="scans_prov_ins_desc_idx",
),
]
class JSONAPIMeta:
@@ -543,6 +588,8 @@ class Resource(RowLevelSecurityProtectedModel):
details = models.TextField(blank=True, null=True)
partition = models.TextField(blank=True, null=True)
failed_findings_count = models.IntegerField(default=0)
# Relationships
tags = models.ManyToManyField(
ResourceTag,
@@ -589,6 +636,10 @@ class Resource(RowLevelSecurityProtectedModel):
fields=["tenant_id", "provider_id"],
name="resources_tenant_provider_idx",
),
models.Index(
fields=["tenant_id", "-failed_findings_count", "id"],
name="resources_failed_findings_idx",
),
]
constraints = [
@@ -687,6 +738,9 @@ class Finding(PostgresPartitionedModel, RowLevelSecurityProtectedModel):
check_id = models.CharField(max_length=100, blank=False, null=False)
check_metadata = models.JSONField(default=dict, null=False)
muted = models.BooleanField(default=False, null=False)
muted_reason = models.TextField(
blank=True, null=True, validators=[MinLengthValidator(3)], max_length=500
)
compliance = models.JSONField(default=dict, null=True, blank=True)
# Denormalize resource data for performance
@@ -762,6 +816,10 @@ class Finding(PostgresPartitionedModel, RowLevelSecurityProtectedModel):
GinIndex(fields=["resource_services"], name="gin_find_service_idx"),
GinIndex(fields=["resource_regions"], name="gin_find_region_idx"),
GinIndex(fields=["resource_types"], name="gin_find_rtype_idx"),
models.Index(
fields=["tenant_id", "scan_id", "check_id"],
name="find_tenant_scan_check_idx",
),
]
class JSONAPIMeta:
@@ -824,6 +882,16 @@ class ResourceFindingMapping(PostgresPartitionedModel, RowLevelSecurityProtected
# - tenant_id
# - id
indexes = [
models.Index(
fields=["tenant_id", "finding_id"],
name="rfm_tenant_finding_idx",
),
models.Index(
fields=["tenant_id", "resource_id"],
name="rfm_tenant_resource_idx",
),
]
constraints = [
models.UniqueConstraint(
fields=("tenant_id", "resource_id", "finding_id"),
@@ -850,6 +918,7 @@ class ProviderSecret(RowLevelSecurityProtectedModel):
class TypeChoices(models.TextChoices):
STATIC = "static", _("Key-value pairs")
ROLE = "role", _("Role assumption")
SERVICE_ACCOUNT = "service_account", _("GCP Service Account Key")
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
@@ -927,6 +996,11 @@ class Invitation(RowLevelSecurityProtectedModel):
null=True,
)
def save(self, *args, **kwargs):
if self.email:
self.email = self.email.strip().lower()
super().save(*args, **kwargs)
class Meta(RowLevelSecurityProtectedModel.Meta):
db_table = "invitations"
@@ -1142,6 +1216,78 @@ class ComplianceOverview(RowLevelSecurityProtectedModel):
resource_name = "compliance-overviews"
class ComplianceRequirementOverview(RowLevelSecurityProtectedModel):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
compliance_id = models.TextField(blank=False)
framework = models.TextField(blank=False)
version = models.TextField(blank=True)
description = models.TextField(blank=True)
region = models.TextField(blank=False)
requirement_id = models.TextField(blank=False)
requirement_status = StatusEnumField(choices=StatusChoices)
passed_checks = models.IntegerField(default=0)
failed_checks = models.IntegerField(default=0)
total_checks = models.IntegerField(default=0)
scan = models.ForeignKey(
Scan,
on_delete=models.CASCADE,
related_name="compliance_requirements_overviews",
related_query_name="compliance_requirements_overview",
)
class Meta(RowLevelSecurityProtectedModel.Meta):
db_table = "compliance_requirements_overviews"
constraints = [
models.UniqueConstraint(
fields=(
"tenant_id",
"scan_id",
"compliance_id",
"requirement_id",
"region",
),
name="unique_tenant_compliance_requirement_overview",
),
RowLevelSecurityConstraint(
field="tenant_id",
name="rls_on_%(class)s",
statements=["SELECT", "INSERT", "DELETE"],
),
]
indexes = [
models.Index(fields=["tenant_id", "scan_id"], name="cro_tenant_scan_idx"),
models.Index(
fields=["tenant_id", "scan_id", "compliance_id"],
name="cro_scan_comp_idx",
),
models.Index(
fields=["tenant_id", "scan_id", "compliance_id", "region"],
name="cro_scan_comp_reg_idx",
),
models.Index(
fields=["tenant_id", "scan_id", "compliance_id", "requirement_id"],
name="cro_scan_comp_req_idx",
),
models.Index(
fields=[
"tenant_id",
"scan_id",
"compliance_id",
"requirement_id",
"region",
],
name="cro_scan_comp_req_reg_idx",
),
]
class JSONAPIMeta:
resource_name = "compliance-requirements-overviews"
class ScanSummary(RowLevelSecurityProtectedModel):
objects = ActiveProviderManager()
all_objects = models.Manager()
@@ -1209,8 +1355,7 @@ class ScanSummary(RowLevelSecurityProtectedModel):
class Integration(RowLevelSecurityProtectedModel):
class IntegrationChoices(models.TextChoices):
S3 = "amazon_s3", _("Amazon S3")
SAML = "saml", _("SAML")
AMAZON_S3 = "amazon_s3", _("Amazon S3")
AWS_SECURITY_HUB = "aws_security_hub", _("AWS Security Hub")
JIRA = "jira", _("JIRA")
SLACK = "slack", _("Slack")
@@ -1284,6 +1429,273 @@ class IntegrationProviderRelationship(RowLevelSecurityProtectedModel):
]
class SAMLToken(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
expires_at = models.DateTimeField(editable=False)
token = models.JSONField(unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = "saml_tokens"
def save(self, *args, **kwargs):
if not self.expires_at:
self.expires_at = datetime.now(timezone.utc) + timedelta(seconds=15)
super().save(*args, **kwargs)
def is_expired(self) -> bool:
return datetime.now(timezone.utc) >= self.expires_at
class SAMLDomainIndex(models.Model):
"""
Public index of SAML domains. No RLS. Used for fast lookup in SAML login flow.
"""
email_domain = models.CharField(max_length=254, unique=True)
tenant = models.ForeignKey("Tenant", on_delete=models.CASCADE)
class Meta:
db_table = "saml_domain_index"
constraints = [
models.UniqueConstraint(
fields=("email_domain", "tenant"),
name="unique_resources_by_email_domain",
),
BaseSecurityConstraint(
name="statements_on_%(class)s",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
]
class SAMLConfiguration(RowLevelSecurityProtectedModel):
"""
Stores per-tenant SAML settings, including email domain and IdP metadata.
Automatically syncs to a SocialApp instance on save.
Note:
This model exists to provide a tenant-aware abstraction over SAML configuration.
It supports row-level security, custom validation, and metadata parsing, enabling
Prowler to expose a clean API and admin interface for managing SAML integrations.
Although Django Allauth uses the SocialApp model to store provider configuration,
it is not designed for multi-tenant use. SocialApp lacks support for tenant scoping,
email domain mapping, and structured metadata handling.
By managing SAMLConfiguration separately, we ensure:
- Strong isolation between tenants via RLS.
- Ownership of raw IdP metadata and its validation.
- An explicit link between SAML config and business-level identifiers (e.g. email domain).
- Programmatic transformation into the SocialApp format used by Allauth.
In short, this model acts as a secure and user-friendly layer over Allauth's lower-level primitives.
"""
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
email_domain = models.CharField(
max_length=254,
unique=True,
help_text="Email domain used to identify the tenant, e.g. prowlerdemo.com",
)
metadata_xml = models.TextField(
help_text="Raw IdP metadata XML to configure SingleSignOnService, certificates, etc."
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class JSONAPIMeta:
resource_name = "saml-configurations"
class Meta:
db_table = "saml_configurations"
constraints = [
RowLevelSecurityConstraint(
field="tenant_id",
name="rls_on_%(class)s",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
# 1 config per tenant
models.UniqueConstraint(
fields=["tenant"],
name="unique_samlconfig_per_tenant",
),
]
def clean(self, old_email_domain=None, is_create=False):
# Domain must not contain @
if "@" in self.email_domain:
raise ValidationError({"email_domain": "Domain must not contain @"})
# Enforce at most one config per tenant
qs = SAMLConfiguration.objects.filter(tenant=self.tenant)
# Exclude ourselves in case of update
if self.pk:
qs = qs.exclude(pk=self.pk)
if qs.exists():
raise ValidationError(
{"tenant": "A SAML configuration already exists for this tenant."}
)
# The email domain must be unique in the entire system
qs = SAMLConfiguration.objects.using(MainRouter.admin_db).filter(
email_domain__iexact=self.email_domain
)
if qs.exists() and old_email_domain != self.email_domain:
raise ValidationError(
{"tenant": "There is a problem with your email domain."}
)
# The entityID must be unique in the system
idp_settings = self._parsed_metadata
entity_id = idp_settings.get("entity_id")
if entity_id:
# Find any SocialApp with this entityID
q = SocialApp.objects.filter(provider="saml", provider_id=entity_id)
# If updating, exclude our own SocialApp from the check
if not is_create:
q = q.exclude(client_id=old_email_domain)
else:
q = q.exclude(client_id=self.email_domain)
if q.exists():
raise ValidationError(
{"metadata_xml": "There is a problem with your metadata."}
)
def save(self, *args, **kwargs):
self.email_domain = self.email_domain.strip().lower()
is_create = not SAMLConfiguration.objects.filter(pk=self.pk).exists()
if not is_create:
old = SAMLConfiguration.objects.get(pk=self.pk)
old_email_domain = old.email_domain
old_metadata_xml = old.metadata_xml
else:
old_email_domain = None
old_metadata_xml = None
self._parsed_metadata = self._parse_metadata()
self.clean(old_email_domain, is_create)
super().save(*args, **kwargs)
if is_create or (
old_email_domain != self.email_domain
or old_metadata_xml != self.metadata_xml
):
self._sync_social_app(old_email_domain)
# Sync the public index
if not is_create and old_email_domain and old_email_domain != self.email_domain:
SAMLDomainIndex.objects.filter(email_domain=old_email_domain).delete()
# Create/update the new domain index
SAMLDomainIndex.objects.update_or_create(
email_domain=self.email_domain, defaults={"tenant": self.tenant}
)
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
SocialApp.objects.filter(provider="saml", client_id=self.email_domain).delete()
SAMLDomainIndex.objects.filter(email_domain=self.email_domain).delete()
def _parse_metadata(self):
"""
Parse the raw IdP metadata XML and extract:
- entity_id
- sso_url
- slo_url (may be None)
- x509cert (required)
"""
ns = {
"md": "urn:oasis:names:tc:SAML:2.0:metadata",
"ds": "http://www.w3.org/2000/09/xmldsig#",
}
try:
root = ET.fromstring(self.metadata_xml)
except ET.ParseError as e:
raise ValidationError({"metadata_xml": f"Invalid XML: {e}"})
# Entity ID
entity_id = root.attrib.get("entityID")
if not entity_id:
raise ValidationError({"metadata_xml": "Missing entityID in metadata."})
# SSO endpoint (must exist)
sso = root.find(".//md:IDPSSODescriptor/md:SingleSignOnService", ns)
if sso is None or "Location" not in sso.attrib:
raise ValidationError(
{"metadata_xml": "Missing SingleSignOnService in metadata."}
)
sso_url = sso.attrib["Location"]
# SLO endpoint (optional)
slo = root.find(".//md:IDPSSODescriptor/md:SingleLogoutService", ns)
slo_url = slo.attrib.get("Location") if slo is not None else None
# X.509 certificate (required)
cert = root.find(
'.//md:KeyDescriptor[@use="signing"]/ds:KeyInfo/ds:X509Data/ds:X509Certificate',
ns,
)
if cert is None or not cert.text or not cert.text.strip():
raise ValidationError(
{
"metadata_xml": 'Metadata must include a <ds:X509Certificate> under <KeyDescriptor use="signing">.'
}
)
x509cert = cert.text.strip()
return {
"entity_id": entity_id,
"sso_url": sso_url,
"slo_url": slo_url,
"x509cert": x509cert,
}
def _sync_social_app(self, previous_email_domain=None):
"""
Create or update the corresponding SocialApp based on email_domain.
If the domain changed, update the matching SocialApp.
"""
settings_dict = SOCIALACCOUNT_PROVIDERS["saml"].copy()
settings_dict["idp"] = self._parsed_metadata
current_site = Site.objects.get(id=settings.SITE_ID)
social_app_qs = SocialApp.objects.filter(
provider="saml", client_id=previous_email_domain or self.email_domain
)
client_id = self.email_domain[:191]
name = f"SAML-{self.email_domain}"[:40]
if social_app_qs.exists():
social_app = social_app_qs.first()
social_app.client_id = client_id
social_app.name = name
social_app.settings = settings_dict
social_app.provider_id = self._parsed_metadata["entity_id"]
social_app.save()
social_app.sites.set([current_site])
else:
social_app = SocialApp.objects.create(
provider="saml",
client_id=client_id,
name=name,
settings=settings_dict,
provider_id=self._parsed_metadata["entity_id"],
)
social_app.sites.set([current_site])
class ResourceScanSummary(RowLevelSecurityProtectedModel):
scan_id = models.UUIDField(default=uuid7, db_index=True)
resource_id = models.UUIDField(default=uuid4, db_index=True)
@@ -1331,3 +1743,173 @@ class ResourceScanSummary(RowLevelSecurityProtectedModel):
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
]
class LighthouseConfiguration(RowLevelSecurityProtectedModel):
"""
Stores configuration and API keys for LLM services.
"""
class ModelChoices(models.TextChoices):
GPT_4O_2024_11_20 = "gpt-4o-2024-11-20", _("GPT-4o v2024-11-20")
GPT_4O_2024_08_06 = "gpt-4o-2024-08-06", _("GPT-4o v2024-08-06")
GPT_4O_2024_05_13 = "gpt-4o-2024-05-13", _("GPT-4o v2024-05-13")
GPT_4O = "gpt-4o", _("GPT-4o Default")
GPT_4O_MINI_2024_07_18 = "gpt-4o-mini-2024-07-18", _("GPT-4o Mini v2024-07-18")
GPT_4O_MINI = "gpt-4o-mini", _("GPT-4o Mini Default")
GPT_5_2025_08_07 = "gpt-5-2025-08-07", _("GPT-5 v2025-08-07")
GPT_5 = "gpt-5", _("GPT-5 Default")
GPT_5_MINI_2025_08_07 = "gpt-5-mini-2025-08-07", _("GPT-5 Mini v2025-08-07")
GPT_5_MINI = "gpt-5-mini", _("GPT-5 Mini Default")
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
name = models.CharField(
max_length=100,
validators=[MinLengthValidator(3)],
blank=False,
null=False,
help_text="Name of the configuration",
)
api_key = models.BinaryField(
blank=False, null=False, help_text="Encrypted API key for the LLM service"
)
model = models.CharField(
max_length=50,
choices=ModelChoices.choices,
blank=False,
null=False,
default=ModelChoices.GPT_4O_2024_08_06,
help_text="Must be one of the supported model names",
)
temperature = models.FloatField(default=0, help_text="Must be between 0 and 1")
max_tokens = models.IntegerField(
default=4000, help_text="Must be between 500 and 5000"
)
business_context = models.TextField(
blank=True,
null=False,
default="",
help_text="Additional business context for this AI model configuration",
)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
def clean(self):
super().clean()
# Validate temperature
if not 0 <= self.temperature <= 1:
raise ModelValidationError(
detail="Temperature must be between 0 and 1",
code="invalid_temperature",
pointer="/data/attributes/temperature",
)
# Validate max_tokens
if not 500 <= self.max_tokens <= 5000:
raise ModelValidationError(
detail="Max tokens must be between 500 and 5000",
code="invalid_max_tokens",
pointer="/data/attributes/max_tokens",
)
@property
def api_key_decoded(self):
"""Return the decrypted API key, or None if unavailable or invalid."""
if not self.api_key:
return None
try:
decrypted_key = fernet.decrypt(bytes(self.api_key))
return decrypted_key.decode()
except InvalidToken:
logger.warning("Invalid token while decrypting API key.")
except Exception as e:
logger.exception("Unexpected error while decrypting API key: %s", e)
@api_key_decoded.setter
def api_key_decoded(self, value):
"""Store the encrypted API key."""
if not value:
raise ModelValidationError(
detail="API key is required",
code="invalid_api_key",
pointer="/data/attributes/api_key",
)
# Validate OpenAI API key format
openai_key_pattern = r"^sk-[\w-]+T3BlbkFJ[\w-]+$"
if not re.match(openai_key_pattern, value):
raise ModelValidationError(
detail="Invalid OpenAI API key format.",
code="invalid_api_key",
pointer="/data/attributes/api_key",
)
self.api_key = fernet.encrypt(value.encode())
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
class Meta(RowLevelSecurityProtectedModel.Meta):
db_table = "lighthouse_configurations"
constraints = [
RowLevelSecurityConstraint(
field="tenant_id",
name="rls_on_%(class)s",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
# Add unique constraint for name within a tenant
models.UniqueConstraint(
fields=["tenant_id"], name="unique_lighthouse_config_per_tenant"
),
]
class JSONAPIMeta:
resource_name = "lighthouse-configurations"
class Processor(RowLevelSecurityProtectedModel):
class ProcessorChoices(models.TextChoices):
MUTELIST = "mutelist", _("Mutelist")
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
processor_type = ProcessorTypeEnumField(choices=ProcessorChoices.choices)
configuration = models.JSONField(default=dict)
class Meta(RowLevelSecurityProtectedModel.Meta):
db_table = "processors"
constraints = [
models.UniqueConstraint(
fields=("tenant_id", "processor_type"),
name="unique_processor_types_tenant",
),
RowLevelSecurityConstraint(
field="tenant_id",
name="rls_on_%(class)s",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
]
indexes = [
models.Index(
fields=["tenant_id", "id"],
name="processor_tenant_id_idx",
),
models.Index(
fields=["tenant_id", "processor_type"],
name="processor_tenant_type_idx",
),
]
class JSONAPIMeta:
resource_name = "processors"
+1 -1
View File
@@ -1,4 +1,4 @@
from rest_framework_json_api.pagination import JsonApiPageNumberPagination
from drf_spectacular_jsonapi.schemas.pagination import JsonApiPageNumberPagination
class ComplianceOverviewPagination(JsonApiPageNumberPagination):
+95
View File
@@ -0,0 +1,95 @@
def _pick_task_response_component(components):
schemas = components.get("schemas", {}) or {}
for candidate in ("TaskResponse",):
if candidate in schemas:
return candidate
return None
def _extract_task_example_from_components(components):
schemas = components.get("schemas", {}) or {}
candidate = "TaskResponse"
doc = schemas.get(candidate)
if isinstance(doc, dict) and "example" in doc:
return doc["example"]
res = schemas.get(candidate)
if isinstance(res, dict) and "example" in res:
example = res["example"]
return example if "data" in example else {"data": example}
# Fallback
return {
"data": {
"type": "tasks",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"attributes": {
"inserted_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"name": "string",
"state": "available",
"result": None,
"task_args": None,
"metadata": None,
},
}
}
def attach_task_202_examples(result, generator, request, public): # noqa: F841
if not isinstance(result, dict):
return result
components = result.get("components", {}) or {}
task_resp_component = _pick_task_response_component(components)
task_example = _extract_task_example_from_components(components)
paths = result.get("paths", {}) or {}
for path_item in paths.values():
if not isinstance(path_item, dict):
continue
for method_obj in path_item.values():
if not isinstance(method_obj, dict):
continue
responses = method_obj.get("responses", {}) or {}
resp_202 = responses.get("202")
if not isinstance(resp_202, dict):
continue
content = resp_202.get("content", {}) or {}
jsonapi = content.get("application/vnd.api+json")
if not isinstance(jsonapi, dict):
continue
# Inject example if missing
if "examples" not in jsonapi and "example" not in jsonapi:
jsonapi["examples"] = {
"Task queued": {
"summary": "Task queued",
"value": task_example,
}
}
# Rewrite schema $ref if needed
if task_resp_component:
schema = jsonapi.get("schema")
must_replace = False
if not isinstance(schema, dict):
must_replace = True
else:
ref = schema.get("$ref")
if not ref:
must_replace = True
else:
current = ref.split("/")[-1]
if current != task_resp_component:
must_replace = True
if must_replace:
jsonapi["schema"] = {
"$ref": f"#/components/schemas/{task_resp_component}"
}
return result
File diff suppressed because it is too large Load Diff
@@ -11,7 +11,7 @@ def test_basic_authentication():
client = APIClient()
test_user = "test_email@prowler.com"
test_password = "test_password"
test_password = "Test_password@1"
# Check that a 401 is returned when no basic authentication is provided
no_auth_response = client.get(reverse("provider-list"))
@@ -108,7 +108,7 @@ def test_user_me_when_inviting_users(create_test_user, tenants_fixture, roles_fi
user1_email = "user1@testing.com"
user2_email = "user2@testing.com"
password = "thisisapassword123"
password = "Thisisapassword123@"
user1_response = client.post(
reverse("user-list"),
@@ -187,7 +187,7 @@ class TestTokenSwitchTenant:
client = APIClient()
test_user = "test_email@prowler.com"
test_password = "test_password"
test_password = "Test_password1@"
# Check that we can create a new user without any kind of authentication
user_creation_response = client.post(
@@ -17,7 +17,7 @@ def test_delete_provider_without_executing_task(
client = APIClient()
test_user = "test_email@prowler.com"
test_password = "test_password"
test_password = "Test_password1@"
prowler_task = tasks_fixture[0]
task_mock = Mock()
@@ -0,0 +1,77 @@
from unittest.mock import MagicMock, patch
import pytest
from allauth.socialaccount.models import SocialLogin
from django.contrib.auth import get_user_model
from api.adapters import ProwlerSocialAccountAdapter
User = get_user_model()
@pytest.mark.django_db
class TestProwlerSocialAccountAdapter:
def test_get_user_by_email_returns_user(self, create_test_user):
adapter = ProwlerSocialAccountAdapter()
user = adapter.get_user_by_email(create_test_user.email)
assert user == create_test_user
def test_get_user_by_email_returns_none_for_unknown_email(self):
adapter = ProwlerSocialAccountAdapter()
assert adapter.get_user_by_email("notfound@example.com") is None
def test_pre_social_login_links_existing_user(self, create_test_user, rf):
adapter = ProwlerSocialAccountAdapter()
sociallogin = MagicMock(spec=SocialLogin)
sociallogin.account = MagicMock()
sociallogin.provider = MagicMock()
sociallogin.provider.id = "saml"
sociallogin.account.extra_data = {}
sociallogin.user = create_test_user
sociallogin.connect = MagicMock()
adapter.pre_social_login(rf.get("/"), sociallogin)
call_args = sociallogin.connect.call_args
assert call_args is not None
called_request, called_user = call_args[0]
assert called_request.path == "/"
assert called_user.email == create_test_user.email
def test_pre_social_login_no_link_if_email_missing(self, rf):
adapter = ProwlerSocialAccountAdapter()
sociallogin = MagicMock(spec=SocialLogin)
sociallogin.account = MagicMock()
sociallogin.provider = MagicMock()
sociallogin.user = MagicMock()
sociallogin.provider.id = "saml"
sociallogin.account.extra_data = {}
sociallogin.connect = MagicMock()
adapter.pre_social_login(rf.get("/"), sociallogin)
sociallogin.connect.assert_not_called()
def test_save_user_saml_sets_session_flag(self, rf):
adapter = ProwlerSocialAccountAdapter()
request = rf.get("/")
request.session = {}
sociallogin = MagicMock(spec=SocialLogin)
sociallogin.provider = MagicMock()
sociallogin.provider.id = "saml"
sociallogin.account = MagicMock()
sociallogin.account.extra_data = {}
mock_user = MagicMock()
mock_user.id = 123
with patch("api.adapters.super") as mock_super:
with patch("api.adapters.transaction"):
with patch("api.adapters.MainRouter"):
mock_super.return_value.save_user.return_value = mock_user
adapter.save_user(request, sociallogin)
assert request.session["saml_user_created"] == "123"
+152
View File
@@ -0,0 +1,152 @@
import os
from pathlib import Path
from unittest.mock import MagicMock
import pytest
from django.conf import settings
import api.apps as api_apps_module
from api.apps import (
ApiConfig,
PRIVATE_KEY_FILE,
PUBLIC_KEY_FILE,
SIGNING_KEY_ENV,
VERIFYING_KEY_ENV,
)
@pytest.fixture(autouse=True)
def reset_keys_initialized(monkeypatch):
"""Ensure per-test clean state for the module-level guard flag."""
monkeypatch.setattr(api_apps_module, "_keys_initialized", False, raising=False)
def _stub_keys():
return (
"""-----BEGIN PRIVATE KEY-----\nPRIVATE\n-----END PRIVATE KEY-----\n""",
"""-----BEGIN PUBLIC KEY-----\nPUBLIC\n-----END PUBLIC KEY-----\n""",
)
def test_generate_jwt_keys_when_missing(monkeypatch, tmp_path):
# Arrange: isolate FS, env, and settings; force generation path
monkeypatch.setattr(
api_apps_module, "KEYS_DIRECTORY", Path(tmp_path), raising=False
)
monkeypatch.delenv(SIGNING_KEY_ENV, raising=False)
monkeypatch.delenv(VERIFYING_KEY_ENV, raising=False)
# Work on a copy of SIMPLE_JWT to avoid mutating the global settings dict for other tests
monkeypatch.setattr(
settings, "SIMPLE_JWT", settings.SIMPLE_JWT.copy(), raising=False
)
monkeypatch.setattr(settings, "TESTING", False, raising=False)
# Avoid dependency on the cryptography package
monkeypatch.setattr(ApiConfig, "_generate_jwt_keys", staticmethod(_stub_keys))
config = ApiConfig("api", api_apps_module)
# Act
config._ensure_crypto_keys()
# Assert: files created with expected content
priv_path = Path(tmp_path) / PRIVATE_KEY_FILE
pub_path = Path(tmp_path) / PUBLIC_KEY_FILE
assert priv_path.is_file()
assert pub_path.is_file()
assert priv_path.read_text() == _stub_keys()[0]
assert pub_path.read_text() == _stub_keys()[1]
# Env vars and Django settings updated
assert os.environ[SIGNING_KEY_ENV] == _stub_keys()[0]
assert os.environ[VERIFYING_KEY_ENV] == _stub_keys()[1]
assert settings.SIMPLE_JWT["SIGNING_KEY"] == _stub_keys()[0]
assert settings.SIMPLE_JWT["VERIFYING_KEY"] == _stub_keys()[1]
def test_ensure_crypto_keys_are_idempotent_within_process(monkeypatch, tmp_path):
# Arrange
monkeypatch.setattr(
api_apps_module, "KEYS_DIRECTORY", Path(tmp_path), raising=False
)
monkeypatch.delenv(SIGNING_KEY_ENV, raising=False)
monkeypatch.delenv(VERIFYING_KEY_ENV, raising=False)
monkeypatch.setattr(
settings, "SIMPLE_JWT", settings.SIMPLE_JWT.copy(), raising=False
)
monkeypatch.setattr(settings, "TESTING", False, raising=False)
mock_generate = MagicMock(side_effect=_stub_keys)
monkeypatch.setattr(ApiConfig, "_generate_jwt_keys", staticmethod(mock_generate))
config = ApiConfig("api", api_apps_module)
# Act: first call should generate, second should be a no-op (guard flag)
config._ensure_crypto_keys()
config._ensure_crypto_keys()
# Assert: generation occurred exactly once
assert mock_generate.call_count == 1
def test_ensure_jwt_keys_uses_existing_files(monkeypatch, tmp_path):
# Arrange: pre-create key files
monkeypatch.setattr(
api_apps_module, "KEYS_DIRECTORY", Path(tmp_path), raising=False
)
monkeypatch.setattr(
settings, "SIMPLE_JWT", settings.SIMPLE_JWT.copy(), raising=False
)
existing_private, existing_public = _stub_keys()
(Path(tmp_path) / PRIVATE_KEY_FILE).write_text(existing_private)
(Path(tmp_path) / PUBLIC_KEY_FILE).write_text(existing_public)
# If generation were called, fail the test
def _fail_generate():
raise AssertionError("_generate_jwt_keys should not be called when files exist")
monkeypatch.setattr(ApiConfig, "_generate_jwt_keys", staticmethod(_fail_generate))
config = ApiConfig("api", api_apps_module)
# Act: call the lower-level method directly to set env/settings from files
config._ensure_jwt_keys()
# Assert
# _read_key_file() strips trailing newlines; environment/settings should reflect stripped content
assert os.environ[SIGNING_KEY_ENV] == existing_private.strip()
assert os.environ[VERIFYING_KEY_ENV] == existing_public.strip()
assert settings.SIMPLE_JWT["SIGNING_KEY"] == existing_private.strip()
assert settings.SIMPLE_JWT["VERIFYING_KEY"] == existing_public.strip()
def test_ensure_crypto_keys_skips_when_env_vars(monkeypatch, tmp_path):
# Arrange: put values in env so the orchestrator doesn't generate
monkeypatch.setattr(
api_apps_module, "KEYS_DIRECTORY", Path(tmp_path), raising=False
)
monkeypatch.setenv(SIGNING_KEY_ENV, "ENV-PRIVATE")
monkeypatch.setenv(VERIFYING_KEY_ENV, "ENV-PUBLIC")
monkeypatch.setattr(
settings, "SIMPLE_JWT", settings.SIMPLE_JWT.copy(), raising=False
)
monkeypatch.setattr(settings, "TESTING", False, raising=False)
called = {"ensure": False}
def _track_call():
called["ensure"] = True
return _stub_keys()
monkeypatch.setattr(ApiConfig, "_generate_jwt_keys", staticmethod(_track_call))
config = ApiConfig("api", api_apps_module)
# Act
config._ensure_crypto_keys()
# Assert: orchestrator did not trigger generation when env present
assert called["ensure"] is False
+24 -6
View File
@@ -1,12 +1,12 @@
from unittest.mock import patch, MagicMock
from unittest.mock import MagicMock, patch
from api.compliance import (
generate_compliance_overview_template,
generate_scan_compliance,
get_prowler_provider_checks,
get_prowler_provider_compliance,
load_prowler_compliance,
load_prowler_checks,
generate_scan_compliance,
generate_compliance_overview_template,
load_prowler_compliance,
)
from api.models import Provider
@@ -69,7 +69,7 @@ class TestCompliance:
load_prowler_compliance()
from api.compliance import PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE, PROWLER_CHECKS
from api.compliance import PROWLER_CHECKS, PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE
assert PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE == {
"template_key": "template_value"
@@ -218,6 +218,10 @@ class TestCompliance:
Description="Description of requirement 1",
Attributes=[],
Checks=["check1", "check2"],
Tactics=["tactic1"],
SubTechniques=["subtechnique1"],
Platforms=["platform1"],
TechniqueURL="https://example.com",
)
requirement2 = MagicMock(
Id="requirement2",
@@ -225,12 +229,17 @@ class TestCompliance:
Description="Description of requirement 2",
Attributes=[],
Checks=[],
Tactics=[],
SubTechniques=[],
Platforms=[],
TechniqueURL="",
)
compliance1 = MagicMock(
Requirements=[requirement1, requirement2],
Framework="Framework 1",
Version="1.0",
Description="Description of compliance1",
Name="Compliance 1",
)
prowler_compliance = {"aws": {"compliance1": compliance1}}
@@ -240,6 +249,7 @@ class TestCompliance:
"aws": {
"compliance1": {
"framework": "Framework 1",
"name": "Compliance 1",
"version": "1.0",
"provider": "aws",
"description": "Description of compliance1",
@@ -247,6 +257,10 @@ class TestCompliance:
"requirement1": {
"name": "Requirement 1",
"description": "Description of requirement 1",
"tactics": ["tactic1"],
"subtechniques": ["subtechnique1"],
"platforms": ["platform1"],
"technique_url": "https://example.com",
"attributes": [],
"checks": {"check1": None, "check2": None},
"checks_status": {
@@ -260,6 +274,10 @@ class TestCompliance:
"requirement2": {
"name": "Requirement 2",
"description": "Description of requirement 2",
"tactics": [],
"subtechniques": [],
"platforms": [],
"technique_url": "",
"attributes": [],
"checks": {},
"checks_status": {
@@ -268,7 +286,7 @@ class TestCompliance:
"manual": 0,
"total": 0,
},
"status": "PASS",
"status": "MANUAL",
},
},
"requirements_status": {
+175
View File
@@ -3,12 +3,17 @@ from enum import Enum
from unittest.mock import patch
import pytest
from django.conf import settings
from freezegun import freeze_time
from api.db_utils import (
_should_create_index_on_partition,
batch_delete,
create_objects_in_batches,
enum_to_choices,
generate_random_token,
one_week_from_now,
update_objects_in_batches,
)
from api.models import Provider
@@ -138,3 +143,173 @@ class TestBatchDelete:
)
assert Provider.objects.all().count() == 0
assert summary == {"api.Provider": create_test_providers}
class TestShouldCreateIndexOnPartition:
@freeze_time("2025-05-15 00:00:00Z")
@pytest.mark.parametrize(
"partition_name, all_partitions, expected",
[
("any_name", True, True),
("findings_default", True, True),
("findings_2022_jan", True, True),
("foo_bar", False, True),
("findings_2025_MAY", False, True),
("findings_2025_may", False, True),
("findings_2025_jun", False, True),
("findings_2025_apr", False, False),
("findings_2025_xyz", False, True),
],
)
def test_partition_inclusion_logic(self, partition_name, all_partitions, expected):
assert (
_should_create_index_on_partition(partition_name, all_partitions)
is expected
)
@freeze_time("2025-05-15 00:00:00Z")
def test_invalid_date_components(self):
# even if regex matches but int conversion fails, we fallback True
# (e.g. year too big, month number parse error)
bad_name = "findings_99999_jan"
assert _should_create_index_on_partition(bad_name, False) is True
bad_name2 = "findings_2025_abc"
# abc not in month_map → fallback True
assert _should_create_index_on_partition(bad_name2, False) is True
@pytest.mark.django_db
class TestCreateObjectsInBatches:
@pytest.fixture
def tenant(self, tenants_fixture):
return tenants_fixture[0]
def make_provider_instances(self, tenant, count):
"""
Return a list of `count` unsaved Provider instances for the given tenant.
"""
base_uid = 1000
return [
Provider(
tenant=tenant,
uid=str(base_uid + i),
provider=Provider.ProviderChoices.AWS,
)
for i in range(count)
]
def test_exact_multiple_of_batch(self, tenant):
total = 6
batch_size = 3
objs = self.make_provider_instances(tenant, total)
create_objects_in_batches(str(tenant.id), Provider, objs, batch_size=batch_size)
qs = Provider.objects.filter(tenant=tenant)
assert qs.count() == total
def test_non_multiple_of_batch(self, tenant):
total = 7
batch_size = 3
objs = self.make_provider_instances(tenant, total)
create_objects_in_batches(str(tenant.id), Provider, objs, batch_size=batch_size)
qs = Provider.objects.filter(tenant=tenant)
assert qs.count() == total
def test_batch_size_default(self, tenant):
default_size = settings.DJANGO_DELETION_BATCH_SIZE
total = default_size + 2
objs = self.make_provider_instances(tenant, total)
create_objects_in_batches(str(tenant.id), Provider, objs)
qs = Provider.objects.filter(tenant=tenant)
assert qs.count() == total
@pytest.mark.django_db
class TestUpdateObjectsInBatches:
@pytest.fixture
def tenant(self, tenants_fixture):
return tenants_fixture[0]
def make_provider_instances(self, tenant, count):
"""
Return a list of `count` unsaved Provider instances for the given tenant.
"""
base_uid = 2000
return [
Provider(
tenant=tenant,
uid=str(base_uid + i),
provider=Provider.ProviderChoices.AWS,
)
for i in range(count)
]
def test_exact_multiple_of_batch(self, tenant):
total = 6
batch_size = 3
objs = self.make_provider_instances(tenant, total)
create_objects_in_batches(str(tenant.id), Provider, objs, batch_size=batch_size)
# Fetch them back, mutate the `uid` field, then update in batches
providers = list(Provider.objects.filter(tenant=tenant))
for p in providers:
p.uid = f"{p.uid}_upd"
update_objects_in_batches(
tenant_id=str(tenant.id),
model=Provider,
objects=providers,
fields=["uid"],
batch_size=batch_size,
)
qs = Provider.objects.filter(tenant=tenant, uid__endswith="_upd")
assert qs.count() == total
def test_non_multiple_of_batch(self, tenant):
total = 7
batch_size = 3
objs = self.make_provider_instances(tenant, total)
create_objects_in_batches(str(tenant.id), Provider, objs, batch_size=batch_size)
providers = list(Provider.objects.filter(tenant=tenant))
for p in providers:
p.uid = f"{p.uid}_upd"
update_objects_in_batches(
tenant_id=str(tenant.id),
model=Provider,
objects=providers,
fields=["uid"],
batch_size=batch_size,
)
qs = Provider.objects.filter(tenant=tenant, uid__endswith="_upd")
assert qs.count() == total
def test_batch_size_default(self, tenant):
default_size = settings.DJANGO_DELETION_BATCH_SIZE
total = default_size + 2
objs = self.make_provider_instances(tenant, total)
create_objects_in_batches(str(tenant.id), Provider, objs)
providers = list(Provider.objects.filter(tenant=tenant))
for p in providers:
p.uid = f"{p.uid}_upd"
# Update without specifying batch_size (uses default)
update_objects_in_batches(
tenant_id=str(tenant.id),
model=Provider,
objects=providers,
fields=["uid"],
)
qs = Provider.objects.filter(tenant=tenant, uid__endswith="_upd")
assert qs.count() == total
+379
View File
@@ -0,0 +1,379 @@
import json
from uuid import uuid4
import pytest
from django_celery_results.models import TaskResult
from rest_framework import status
from rest_framework.response import Response
from api.exceptions import (
TaskFailedException,
TaskInProgressException,
TaskNotFoundException,
)
from api.models import Task, User
from api.rls import Tenant
from api.v1.mixins import PaginateByPkMixin, TaskManagementMixin
@pytest.mark.django_db
class TestPaginateByPkMixin:
@pytest.fixture
def tenant(self):
return Tenant.objects.create(name="Test Tenant")
@pytest.fixture
def users(self, tenant):
# Create 5 users with proper email field
users = []
for i in range(5):
user = User.objects.create(email=f"user{i}@example.com", name=f"User {i}")
users.append(user)
return users
class DummyView(PaginateByPkMixin):
def __init__(self, page):
self._page = page
def paginate_queryset(self, qs):
return self._page
def get_serializer(self, queryset, many):
class S:
def __init__(self, data):
# serialize to list of ids
self.data = [obj.id for obj in data] if many else queryset.id
return S(queryset)
def get_paginated_response(self, data):
return Response({"results": data}, status=status.HTTP_200_OK)
def test_no_pagination(self, users):
base_qs = User.objects.all().order_by("id")
view = self.DummyView(page=None)
resp = view.paginate_by_pk(
request=None, base_queryset=base_qs, manager=User.objects
)
# since no pagination, should return all ids in order
expected = [u.id for u in base_qs]
assert isinstance(resp, Response)
assert resp.data == expected
def test_with_pagination(self, users):
base_qs = User.objects.all().order_by("id")
# simulate paging to first 2 ids
page = [base_qs[1].id, base_qs[3].id]
view = self.DummyView(page=page)
resp = view.paginate_by_pk(
request=None, base_queryset=base_qs, manager=User.objects
)
# should fetch only those two users, in the same order as page
assert resp.status_code == status.HTTP_200_OK
assert resp.data == {"results": page}
@pytest.mark.django_db
class TestTaskManagementMixin:
class DummyView(TaskManagementMixin):
pass
@pytest.fixture
def tenant(self):
return Tenant.objects.create(name="Test Tenant")
@pytest.fixture(autouse=True)
def cleanup(self):
Task.objects.all().delete()
TaskResult.objects.all().delete()
def test_no_task_and_no_taskresult_raises_not_found(self):
view = self.DummyView()
with pytest.raises(TaskNotFoundException):
view.check_task_status("task_xyz", {"foo": "bar"})
def test_no_task_and_no_taskresult_returns_none_when_not_raising(self):
view = self.DummyView()
result = view.check_task_status(
"task_xyz", {"foo": "bar"}, raise_on_not_found=False
)
assert result is None
def test_taskresult_pending_raises_in_progress(self):
task_kwargs = {"foo": "bar"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_xyz",
task_kwargs=json.dumps(task_kwargs),
status="PENDING",
)
view = self.DummyView()
with pytest.raises(TaskInProgressException) as excinfo:
view.check_task_status("task_xyz", task_kwargs, raise_on_not_found=False)
assert hasattr(excinfo.value, "task_result")
assert excinfo.value.task_result == tr
def test_taskresult_started_raises_in_progress(self):
task_kwargs = {"foo": "bar"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_xyz",
task_kwargs=json.dumps(task_kwargs),
status="STARTED",
)
view = self.DummyView()
with pytest.raises(TaskInProgressException) as excinfo:
view.check_task_status("task_xyz", task_kwargs, raise_on_not_found=False)
assert hasattr(excinfo.value, "task_result")
assert excinfo.value.task_result == tr
def test_taskresult_progress_raises_in_progress(self):
task_kwargs = {"foo": "bar"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_xyz",
task_kwargs=json.dumps(task_kwargs),
status="PROGRESS",
)
view = self.DummyView()
with pytest.raises(TaskInProgressException) as excinfo:
view.check_task_status("task_xyz", task_kwargs, raise_on_not_found=False)
assert hasattr(excinfo.value, "task_result")
assert excinfo.value.task_result == tr
def test_taskresult_failure_raises_failed(self):
task_kwargs = {"a": 1}
TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_fail",
task_kwargs=json.dumps(task_kwargs),
status="FAILURE",
)
view = self.DummyView()
with pytest.raises(TaskFailedException):
view.check_task_status("task_fail", task_kwargs, raise_on_not_found=False)
def test_taskresult_failure_returns_none_when_not_raising(self):
task_kwargs = {"a": 1}
TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_fail",
task_kwargs=json.dumps(task_kwargs),
status="FAILURE",
)
view = self.DummyView()
result = view.check_task_status(
"task_fail", task_kwargs, raise_on_failed=False, raise_on_not_found=False
)
assert result is None
def test_taskresult_success_returns_none(self):
task_kwargs = {"x": 2}
TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_ok",
task_kwargs=json.dumps(task_kwargs),
status="SUCCESS",
)
view = self.DummyView()
# should not raise, and returns None
assert (
view.check_task_status("task_ok", task_kwargs, raise_on_not_found=False)
is None
)
def test_taskresult_revoked_returns_none(self):
task_kwargs = {"x": 2}
TaskResult.objects.create(
task_id=str(uuid4()),
task_name="task_revoked",
task_kwargs=json.dumps(task_kwargs),
status="REVOKED",
)
view = self.DummyView()
# should not raise, and returns None
assert (
view.check_task_status(
"task_revoked", task_kwargs, raise_on_not_found=False
)
is None
)
def test_task_with_failed_status_raises_failed(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="FAILURE",
)
task = Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
with pytest.raises(TaskFailedException) as excinfo:
view.check_task_status("scan_task", task_kwargs)
# Check that the exception contains the expected task
assert hasattr(excinfo.value, "task")
assert excinfo.value.task == task
def test_task_with_cancelled_status_raises_failed(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="REVOKED",
)
task = Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
with pytest.raises(TaskFailedException) as excinfo:
view.check_task_status("scan_task", task_kwargs)
# Check that the exception contains the expected task
assert hasattr(excinfo.value, "task")
assert excinfo.value.task == task
def test_task_with_failed_status_returns_task_when_not_raising(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="FAILURE",
)
task = Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.check_task_status("scan_task", task_kwargs, raise_on_failed=False)
assert result == task
def test_task_with_completed_status_returns_none(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="SUCCESS",
)
Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.check_task_status("scan_task", task_kwargs)
assert result is None
def test_task_with_executing_status_returns_task(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="STARTED",
)
task = Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.check_task_status("scan_task", task_kwargs)
assert result is not None
assert result.pk == task.pk
def test_task_with_pending_status_returns_task(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="PENDING",
)
task = Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.check_task_status("scan_task", task_kwargs)
assert result is not None
assert result.pk == task.pk
def test_get_task_response_if_running_returns_none_for_completed_task(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="SUCCESS",
)
Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.get_task_response_if_running("scan_task", task_kwargs)
assert result is None
def test_get_task_response_if_running_returns_none_for_no_task(self):
view = self.DummyView()
result = view.get_task_response_if_running(
"nonexistent", {"foo": "bar"}, raise_on_not_found=False
)
assert result is None
def test_get_task_response_if_running_returns_202_for_executing_task(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="STARTED",
)
task = Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.get_task_response_if_running("scan_task", task_kwargs)
assert isinstance(result, Response)
assert result.status_code == status.HTTP_202_ACCEPTED
assert "Content-Location" in result.headers
# The response should contain the serialized task data
assert result.data is not None
assert "id" in result.data
assert str(result.data["id"]) == str(task.id)
def test_get_task_response_if_running_returns_none_for_available_task(self, tenant):
task_kwargs = {"provider_id": "test"}
tr = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs),
status="PENDING",
)
Task.objects.create(tenant=tenant, task_runner_task=tr)
view = self.DummyView()
result = view.get_task_response_if_running("scan_task", task_kwargs)
# PENDING maps to AVAILABLE, which is not EXECUTING, so should return None
assert result is None
def test_kwargs_filtering_works_correctly(self, tenant):
# Create tasks with different kwargs
task_kwargs_1 = {"provider_id": "test1", "scan_type": "full"}
task_kwargs_2 = {"provider_id": "test2", "scan_type": "quick"}
tr1 = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs_1),
status="STARTED",
)
tr2 = TaskResult.objects.create(
task_id=str(uuid4()),
task_name="scan_task",
task_kwargs=json.dumps(task_kwargs_2),
status="STARTED",
)
task1 = Task.objects.create(tenant=tenant, task_runner_task=tr1)
task2 = Task.objects.create(tenant=tenant, task_runner_task=tr2)
view = self.DummyView()
# Should find task1 when searching for its kwargs
result1 = view.check_task_status("scan_task", {"provider_id": "test1"})
assert result1 is not None
assert result1.pk == task1.pk
# Should find task2 when searching for its kwargs
result2 = view.check_task_status("scan_task", {"provider_id": "test2"})
assert result2 is not None
assert result2.pk == task2.pk
# Should not find anything when searching for non-existent kwargs
result3 = view.check_task_status(
"scan_task", {"provider_id": "test3"}, raise_on_not_found=False
)
assert result3 is None
+205 -1
View File
@@ -1,6 +1,9 @@
import pytest
from allauth.socialaccount.models import SocialApp
from django.core.exceptions import ValidationError
from api.models import Resource, ResourceTag
from api.db_router import MainRouter
from api.models import Resource, ResourceTag, SAMLConfiguration, SAMLDomainIndex
@pytest.mark.django_db
@@ -120,3 +123,204 @@ class TestResourceModel:
# compliance={},
# )
# assert Finding.objects.filter(uid=long_uid).exists()
@pytest.mark.django_db
class TestSAMLConfigurationModel:
VALID_METADATA = """<?xml version='1.0' encoding='UTF-8'?>
<md:EntityDescriptor entityID='TEST' xmlns:md='urn:oasis:names:tc:SAML:2.0:metadata'>
<md:IDPSSODescriptor WantAuthnRequestsSigned='false' protocolSupportEnumeration='urn:oasis:names:tc:SAML:2.0:protocol'>
<md:KeyDescriptor use='signing'>
<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:X509Data>
<ds:X509Certificate>FAKECERTDATA</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleSignOnService Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' Location='https://idp.test/sso'/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
"""
def test_creates_valid_configuration(self, tenants_fixture):
tenant = tenants_fixture[0]
config = SAMLConfiguration.objects.using(MainRouter.admin_db).create(
email_domain="ssoexample.com",
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant,
)
assert config.email_domain == "ssoexample.com"
assert SocialApp.objects.filter(client_id="ssoexample.com").exists()
def test_email_domain_with_at_symbol_fails(self, tenants_fixture):
tenant = tenants_fixture[0]
config = SAMLConfiguration(
email_domain="invalid@domain.com",
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant,
)
with pytest.raises(ValidationError) as exc_info:
config.clean()
errors = exc_info.value.message_dict
assert "email_domain" in errors
assert "Domain must not contain @" in errors["email_domain"][0]
def test_duplicate_email_domain_fails(self, tenants_fixture):
tenant1, tenant2, *_ = tenants_fixture
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
email_domain="duplicate.com",
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant1,
)
config = SAMLConfiguration(
email_domain="duplicate.com",
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant2,
)
with pytest.raises(ValidationError) as exc_info:
config.clean()
errors = exc_info.value.message_dict
assert "tenant" in errors
assert "There is a problem with your email domain." in errors["tenant"][0]
def test_duplicate_tenant_config_fails(self, tenants_fixture):
tenant = tenants_fixture[0]
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
email_domain="unique1.com",
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant,
)
config = SAMLConfiguration(
email_domain="unique2.com",
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant,
)
with pytest.raises(ValidationError) as exc_info:
config.clean()
errors = exc_info.value.message_dict
assert "tenant" in errors
assert (
"A SAML configuration already exists for this tenant."
in errors["tenant"][0]
)
def test_invalid_metadata_xml_fails(self, tenants_fixture):
tenant = tenants_fixture[0]
config = SAMLConfiguration(
email_domain="brokenxml.com",
metadata_xml="<bad<xml>",
tenant=tenant,
)
with pytest.raises(ValidationError) as exc_info:
config._parse_metadata()
errors = exc_info.value.message_dict
assert "metadata_xml" in errors
assert "Invalid XML" in errors["metadata_xml"][0]
assert "not well-formed" in errors["metadata_xml"][0]
def test_metadata_missing_sso_fails(self, tenants_fixture):
tenant = tenants_fixture[0]
xml = """<md:EntityDescriptor entityID="x" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:IDPSSODescriptor></md:IDPSSODescriptor>
</md:EntityDescriptor>"""
config = SAMLConfiguration(
email_domain="nosso.com",
metadata_xml=xml,
tenant=tenant,
)
with pytest.raises(ValidationError) as exc_info:
config._parse_metadata()
errors = exc_info.value.message_dict
assert "metadata_xml" in errors
assert "Missing SingleSignOnService" in errors["metadata_xml"][0]
def test_metadata_missing_certificate_fails(self, tenants_fixture):
tenant = tenants_fixture[0]
xml = """<md:EntityDescriptor entityID="x" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:IDPSSODescriptor>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://example.com/sso"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>"""
config = SAMLConfiguration(
email_domain="nocert.com",
metadata_xml=xml,
tenant=tenant,
)
with pytest.raises(ValidationError) as exc_info:
config._parse_metadata()
errors = exc_info.value.message_dict
assert "metadata_xml" in errors
assert "X509Certificate" in errors["metadata_xml"][0]
def test_deletes_saml_configuration_and_related_objects(self, tenants_fixture):
tenant = tenants_fixture[0]
email_domain = "deleteme.com"
# Create the configuration
config = SAMLConfiguration.objects.using(MainRouter.admin_db).create(
email_domain=email_domain,
metadata_xml=TestSAMLConfigurationModel.VALID_METADATA,
tenant=tenant,
)
# Verify that the SocialApp and SAMLDomainIndex exist
assert SocialApp.objects.filter(client_id=email_domain).exists()
assert (
SAMLDomainIndex.objects.using(MainRouter.admin_db)
.filter(email_domain=email_domain)
.exists()
)
# Delete the configuration
config.delete()
# Verify that the configuration and its related objects are deleted
assert (
not SAMLConfiguration.objects.using(MainRouter.admin_db)
.filter(pk=config.pk)
.exists()
)
assert not SocialApp.objects.filter(client_id=email_domain).exists()
assert (
not SAMLDomainIndex.objects.using(MainRouter.admin_db)
.filter(email_domain=email_domain)
.exists()
)
def test_duplicate_entity_id_fails_on_creation(self, tenants_fixture):
tenant1, tenant2, *_ = tenants_fixture
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
email_domain="first.com",
metadata_xml=self.VALID_METADATA,
tenant=tenant1,
)
config = SAMLConfiguration(
email_domain="second.com",
metadata_xml=self.VALID_METADATA,
tenant=tenant2,
)
with pytest.raises(ValidationError) as exc_info:
config.save()
errors = exc_info.value.message_dict
assert "metadata_xml" in errors
assert "There is a problem with your metadata." in errors["metadata_xml"][0]
+424 -3
View File
@@ -1,6 +1,8 @@
import json
from unittest.mock import ANY, Mock, patch
import pytest
from conftest import TODAY
from django.urls import reverse
from rest_framework import status
@@ -60,7 +62,7 @@ class TestUserViewSet:
def test_create_user_with_all_permissions(self, authenticated_client_rbac):
valid_user_payload = {
"name": "test",
"password": "newpassword123",
"password": "Newpassword123@",
"email": "new_user@test.com",
}
response = authenticated_client_rbac.post(
@@ -74,7 +76,7 @@ class TestUserViewSet:
):
valid_user_payload = {
"name": "test",
"password": "newpassword123",
"password": "Newpassword123@",
"email": "new_user@test.com",
}
response = authenticated_client_no_permissions_rbac.post(
@@ -150,6 +152,221 @@ class TestUserViewSet:
assert response.status_code == status.HTTP_200_OK
assert response.json()["data"]["attributes"]["email"] == "rbac_limited@rbac.com"
def test_me_shows_own_roles_and_memberships_without_manage_account(
self, authenticated_client_no_permissions_rbac
):
response = authenticated_client_no_permissions_rbac.get(reverse("user-me"))
assert response.status_code == status.HTTP_200_OK
rels = response.json()["data"]["relationships"]
# Self should see own roles and memberships even without manage_account
assert isinstance(rels["roles"]["data"], list)
assert rels["memberships"]["meta"]["count"] == 1
def test_me_shows_roles_and_memberships_with_manage_account(
self, authenticated_client_rbac
):
response = authenticated_client_rbac.get(reverse("user-me"))
assert response.status_code == status.HTTP_200_OK
rels = response.json()["data"]["relationships"]
# Roles should have data when manage_account is True
assert len(rels["roles"]["data"]) > 0
# Memberships should be present and count > 0
assert rels["memberships"]["meta"]["count"] > 0
def test_me_include_roles_and_memberships_included_block(
self, authenticated_client_rbac
):
# Request current user info including roles and memberships
response = authenticated_client_rbac.get(
reverse("user-me"), {"include": "roles,memberships"}
)
assert response.status_code == status.HTTP_200_OK
payload = response.json()
# Included must contain memberships corresponding to relationships data
rel_memberships = payload["data"]["relationships"]["memberships"]
ids_in_relationship = {item["id"] for item in rel_memberships["data"]}
included = payload["included"]
included_membership_ids = {
item["id"] for item in included if item["type"] == "memberships"
}
# If there are memberships in relationships, they must be present in included
if ids_in_relationship:
assert ids_in_relationship.issubset(included_membership_ids)
else:
# At minimum, included should contain the user's membership when requested
# (count should align with meta count)
assert rel_memberships["meta"]["count"] == len(included_membership_ids)
def test_list_users_with_manage_account_only_forbidden(
self, authenticated_client_rbac_manage_account
):
response = authenticated_client_rbac_manage_account.get(reverse("user-list"))
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_retrieve_other_user_with_manage_account_only_forbidden(
self, authenticated_client_rbac_manage_account, create_test_user
):
response = authenticated_client_rbac_manage_account.get(
reverse("user-detail", kwargs={"pk": create_test_user.id})
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_list_users_with_manage_users_only_hides_relationships(
self, authenticated_client_rbac_manage_users_only
):
# Ensure there is at least one other user in the same tenant
mu_user = authenticated_client_rbac_manage_users_only.user
mu_membership = Membership.objects.filter(user=mu_user).first()
tenant = mu_membership.tenant
other_user = User.objects.create_user(
name="other_in_tenant",
email="other_in_tenant@rbac.com",
password="Password123@",
)
Membership.objects.create(user=other_user, tenant=tenant)
response = authenticated_client_rbac_manage_users_only.get(reverse("user-list"))
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert isinstance(data, list)
current_user_id = str(mu_user.id)
assert any(item["id"] == current_user_id for item in data)
for item in data:
rels = item["relationships"]
if item["id"] == current_user_id:
# Self should see own relationships
assert isinstance(rels["roles"]["data"], list)
assert rels["memberships"]["meta"].get("count", 0) >= 1
else:
# Others should be hidden without manage_account
assert rels["roles"]["data"] == []
assert rels["memberships"]["data"] == []
assert rels["memberships"]["meta"]["count"] == 0
def test_include_roles_hidden_without_manage_account(
self, authenticated_client_rbac_manage_users_only
):
# Arrange: ensure another user in the same tenant with its own role
mu_user = authenticated_client_rbac_manage_users_only.user
mu_membership = Membership.objects.filter(user=mu_user).first()
tenant = mu_membership.tenant
other_user = User.objects.create_user(
name="other_in_tenant_inc",
email="other_in_tenant_inc@rbac.com",
password="Password123@",
)
Membership.objects.create(user=other_user, tenant=tenant)
other_role = Role.objects.create(
name="other_inc_role",
tenant_id=tenant.id,
manage_users=False,
manage_account=False,
)
UserRoleRelationship.objects.create(
user=other_user, role=other_role, tenant_id=tenant.id
)
response = authenticated_client_rbac_manage_users_only.get(
reverse("user-list"), {"include": "roles"}
)
assert response.status_code == status.HTTP_200_OK
payload = response.json()
# Assert: included must not contain the other user's role
included = payload.get("included", [])
included_role_ids = {
item["id"] for item in included if item.get("type") == "roles"
}
assert str(other_role.id) not in included_role_ids
# Relationships for other user should be empty
for item in payload["data"]:
if item["id"] == str(other_user.id):
rels = item["relationships"]
assert rels["roles"]["data"] == []
def test_include_roles_visible_with_manage_account(
self, authenticated_client_rbac, tenants_fixture
):
# Arrange: another user in tenant[0] with its role
tenant = tenants_fixture[0]
other_user = User.objects.create_user(
name="other_with_role",
email="other_with_role@rbac.com",
password="Password123@",
)
Membership.objects.create(user=other_user, tenant=tenant)
other_role = Role.objects.create(
name="other_visible_role",
tenant_id=tenant.id,
manage_users=False,
manage_account=False,
)
UserRoleRelationship.objects.create(
user=other_user, role=other_role, tenant_id=tenant.id
)
response = authenticated_client_rbac.get(
reverse("user-list"), {"include": "roles"}
)
assert response.status_code == status.HTTP_200_OK
payload = response.json()
# Assert: included must contain the other user's role
included = payload.get("included", [])
included_role_ids = {
item["id"] for item in included if item.get("type") == "roles"
}
assert str(other_role.id) in included_role_ids
def test_retrieve_user_with_manage_users_only_hides_relationships(
self, authenticated_client_rbac_manage_users_only
):
# Create a target user in the same tenant to ensure visibility
mu_user = authenticated_client_rbac_manage_users_only.user
mu_membership = Membership.objects.filter(user=mu_user).first()
tenant = mu_membership.tenant
target_user = User.objects.create_user(
name="target_same_tenant",
email="target_same_tenant@rbac.com",
password="Password123@",
)
Membership.objects.create(user=target_user, tenant=tenant)
response = authenticated_client_rbac_manage_users_only.get(
reverse("user-detail", kwargs={"pk": target_user.id})
)
assert response.status_code == status.HTTP_200_OK
rels = response.json()["data"]["relationships"]
assert rels["roles"]["data"] == []
assert rels["memberships"]["data"] == []
assert rels["memberships"]["meta"]["count"] == 0
def test_list_users_with_all_permissions_shows_relationships(
self, authenticated_client_rbac
):
response = authenticated_client_rbac.get(reverse("user-list"))
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert isinstance(data, list)
rels = data[0]["relationships"]
assert len(rels["roles"]["data"]) >= 0
assert rels["memberships"]["meta"]["count"] >= 0
@pytest.mark.django_db
class TestProviderViewSet:
@@ -321,7 +538,7 @@ class TestProviderViewSet:
@pytest.mark.django_db
class TestLimitedVisibility:
TEST_EMAIL = "rbac@rbac.com"
TEST_PASSWORD = "thisisapassword123"
TEST_PASSWORD = "Thisisapassword123@"
@pytest.fixture
def limited_admin_user(
@@ -409,3 +626,207 @@ class TestLimitedVisibility:
assert (
response.json()["data"]["relationships"]["providers"]["meta"]["count"] == 1
)
def test_overviews_providers(
self,
authenticated_client_rbac_limited,
scan_summaries_fixture,
providers_fixture,
):
# By default, the associated provider is the one which has the overview data
response = authenticated_client_rbac_limited.get(reverse("overview-providers"))
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["data"]) > 0
# Changing the provider visibility, no data should be returned
# Only the associated provider to that group is changed
new_provider = providers_fixture[1]
ProviderGroupMembership.objects.all().update(provider=new_provider)
response = authenticated_client_rbac_limited.get(reverse("overview-providers"))
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["data"]) == 0
@pytest.mark.parametrize(
"endpoint_name",
[
"findings",
"findings_severity",
],
)
def test_overviews_findings(
self,
endpoint_name,
authenticated_client_rbac_limited,
scan_summaries_fixture,
providers_fixture,
):
# By default, the associated provider is the one which has the overview data
response = authenticated_client_rbac_limited.get(
reverse(f"overview-{endpoint_name}")
)
assert response.status_code == status.HTTP_200_OK
values = response.json()["data"]["attributes"].values()
assert any(value > 0 for value in values)
# Changing the provider visibility, no data should be returned
# Only the associated provider to that group is changed
new_provider = providers_fixture[1]
ProviderGroupMembership.objects.all().update(provider=new_provider)
response = authenticated_client_rbac_limited.get(
reverse(f"overview-{endpoint_name}")
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]["attributes"].values()
assert all(value == 0 for value in data)
def test_overviews_services(
self,
authenticated_client_rbac_limited,
scan_summaries_fixture,
providers_fixture,
):
# By default, the associated provider is the one which has the overview data
response = authenticated_client_rbac_limited.get(
reverse("overview-services"), {"filter[inserted_at]": TODAY}
)
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["data"]) > 0
# Changing the provider visibility, no data should be returned
# Only the associated provider to that group is changed
new_provider = providers_fixture[1]
ProviderGroupMembership.objects.all().update(provider=new_provider)
response = authenticated_client_rbac_limited.get(
reverse("overview-services"), {"filter[inserted_at]": TODAY}
)
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["data"]) == 0
@pytest.mark.django_db
class TestRolePermissions:
def test_role_create_with_manage_account_only_allowed(
self, authenticated_client_rbac_manage_account
):
data = {
"data": {
"type": "roles",
"attributes": {
"name": "Role Manage Account Only",
"manage_users": "false",
"manage_account": "true",
"manage_providers": "false",
"manage_scans": "false",
"unlimited_visibility": "false",
},
"relationships": {"provider_groups": {"data": []}},
}
}
response = authenticated_client_rbac_manage_account.post(
reverse("role-list"),
data=json.dumps(data),
content_type="application/vnd.api+json",
)
assert response.status_code == status.HTTP_201_CREATED
def test_role_create_with_manage_users_only_forbidden(
self, authenticated_client_rbac_manage_users_only
):
data = {
"data": {
"type": "roles",
"attributes": {
"name": "Role Manage Users Only",
"manage_users": "true",
"manage_account": "false",
"manage_providers": "false",
"manage_scans": "false",
"unlimited_visibility": "false",
},
"relationships": {"provider_groups": {"data": []}},
}
}
response = authenticated_client_rbac_manage_users_only.post(
reverse("role-list"),
data=json.dumps(data),
content_type="application/vnd.api+json",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@pytest.mark.django_db
class TestUserRoleLinkPermissions:
def test_link_user_roles_with_manage_account_only_allowed(
self, authenticated_client_rbac_manage_account
):
# Arrange: create a second user in the same tenant as the manage_account user
ma_user = authenticated_client_rbac_manage_account.user
ma_membership = Membership.objects.filter(user=ma_user).first()
tenant = ma_membership.tenant
user2 = User.objects.create_user(
name="target_user",
email="target_user_ma@rbac.com",
password="Password123@",
)
Membership.objects.create(user=user2, tenant=tenant)
# Create a role in the same tenant
role = Role.objects.create(
name="linkable_role",
tenant_id=tenant.id,
manage_users=False,
manage_account=False,
)
data = {"data": [{"type": "roles", "id": str(role.id)}]}
# Act
response = authenticated_client_rbac_manage_account.post(
reverse("user-roles-relationship", kwargs={"pk": user2.id}),
data=data,
content_type="application/vnd.api+json",
)
# Assert
assert response.status_code == status.HTTP_204_NO_CONTENT
def test_link_user_roles_with_manage_users_only_forbidden(
self, authenticated_client_rbac_manage_users_only
):
mu_user = authenticated_client_rbac_manage_users_only.user
mu_membership = Membership.objects.filter(user=mu_user).first()
tenant = mu_membership.tenant
user2 = User.objects.create_user(
name="target_user2",
email="target_user_mu@rbac.com",
password="Password123@",
)
Membership.objects.create(user=user2, tenant=tenant)
role = Role.objects.create(
name="linkable_role_mu",
tenant_id=tenant.id,
manage_users=False,
manage_account=False,
)
data = {"data": [{"type": "roles", "id": str(role.id)}]}
response = authenticated_client_rbac_manage_users_only.post(
reverse("user-roles-relationship", kwargs={"pk": user2.id}),
data=data,
content_type="application/vnd.api+json",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -0,0 +1,100 @@
import pytest
from rest_framework.exceptions import ValidationError
from api.v1.serializer_utils.integrations import S3ConfigSerializer
class TestS3ConfigSerializer:
"""Test cases for S3ConfigSerializer validation."""
def test_validate_output_directory_valid_paths(self):
"""Test that valid output directory paths are accepted."""
serializer = S3ConfigSerializer()
# Test normal paths
assert serializer.validate_output_directory("test") == "test"
assert serializer.validate_output_directory("test/folder") == "test/folder"
assert serializer.validate_output_directory("my-folder_123") == "my-folder_123"
# Test paths with leading slashes (should be normalized)
assert serializer.validate_output_directory("/test") == "test"
assert serializer.validate_output_directory("/test/folder") == "test/folder"
# Test paths with excessive slashes (should be normalized)
assert serializer.validate_output_directory("///test") == "test"
assert serializer.validate_output_directory("///////test") == "test"
assert serializer.validate_output_directory("test//folder") == "test/folder"
assert serializer.validate_output_directory("test///folder") == "test/folder"
def test_validate_output_directory_empty_values(self):
"""Test that empty values raise validation errors."""
serializer = S3ConfigSerializer()
with pytest.raises(
ValidationError, match="Output directory cannot be empty or just"
):
serializer.validate_output_directory(".")
with pytest.raises(
ValidationError, match="Output directory cannot be empty or just"
):
serializer.validate_output_directory("/")
def test_validate_output_directory_invalid_characters(self):
"""Test that invalid characters are rejected."""
serializer = S3ConfigSerializer()
invalid_chars = ["<", ">", ":", '"', "|", "?", "*"]
for char in invalid_chars:
with pytest.raises(
ValidationError, match="Output directory contains invalid characters"
):
serializer.validate_output_directory(f"test{char}folder")
def test_validate_output_directory_too_long(self):
"""Test that paths that are too long are rejected."""
serializer = S3ConfigSerializer()
# Create a path longer than 900 characters
long_path = "a" * 901
with pytest.raises(ValidationError, match="Output directory path is too long"):
serializer.validate_output_directory(long_path)
def test_validate_output_directory_edge_cases(self):
"""Test edge cases for output directory validation."""
serializer = S3ConfigSerializer()
# Test path at the limit (900 characters)
path_at_limit = "a" * 900
assert serializer.validate_output_directory(path_at_limit) == path_at_limit
# Test complex normalization
assert serializer.validate_output_directory("//test/../folder//") == "folder"
assert serializer.validate_output_directory("/test/./folder/") == "test/folder"
def test_s3_config_serializer_full_validation(self):
"""Test the full S3ConfigSerializer with valid data."""
data = {
"bucket_name": "my-test-bucket",
"output_directory": "///////test", # This should be normalized
}
serializer = S3ConfigSerializer(data=data)
assert serializer.is_valid()
validated_data = serializer.validated_data
assert validated_data["bucket_name"] == "my-test-bucket"
assert validated_data["output_directory"] == "test" # Normalized
def test_s3_config_serializer_invalid_data(self):
"""Test the full S3ConfigSerializer with invalid data."""
data = {
"bucket_name": "my-test-bucket",
"output_directory": "test<invalid", # Contains invalid character
}
serializer = S3ConfigSerializer(data=data)
assert not serializer.is_valid()
assert "output_directory" in serializer.errors
+322 -5
View File
@@ -6,16 +6,18 @@ from rest_framework.exceptions import NotFound, ValidationError
from api.db_router import MainRouter
from api.exceptions import InvitationTokenExpiredException
from api.models import Invitation, Provider
from api.models import Integration, Invitation, Provider
from api.utils import (
get_prowler_provider_kwargs,
initialize_prowler_provider,
merge_dicts,
prowler_integration_connection_test,
prowler_provider_connection_test,
return_prowler_provider,
validate_invitation,
)
from prowler.providers.aws.aws_provider import AwsProvider
from prowler.providers.aws.lib.security_hub.security_hub import SecurityHubConnection
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.gcp.gcp_provider import GcpProvider
from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider
@@ -131,6 +133,21 @@ class TestInitializeProwlerProvider:
initialize_prowler_provider(provider)
mock_return_prowler_provider.return_value.assert_called_once_with(key="value")
@patch("api.utils.return_prowler_provider")
def test_initialize_prowler_provider_with_mutelist(
self, mock_return_prowler_provider
):
provider = MagicMock()
provider.secret.secret = {"key": "value"}
mutelist_processor = MagicMock()
mutelist_processor.configuration = {"Mutelist": {"key": "value"}}
mock_return_prowler_provider.return_value = MagicMock()
initialize_prowler_provider(provider, mutelist_processor)
mock_return_prowler_provider.return_value.assert_called_once_with(
key="value", mutelist_content={"key": "value"}
)
class TestProwlerProviderConnectionTest:
@patch("api.utils.return_prowler_provider")
@@ -182,6 +199,10 @@ class TestGetProwlerProviderKwargs:
Provider.ProviderChoices.M365.value,
{},
),
(
Provider.ProviderChoices.GITHUB.value,
{"organizations": ["provider_uid"]},
),
],
)
def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs):
@@ -200,6 +221,25 @@ class TestGetProwlerProviderKwargs:
expected_result = {**secret_dict, **expected_extra_kwargs}
assert result == expected_result
def test_get_prowler_provider_kwargs_with_mutelist(self):
provider_uid = "provider_uid"
secret_dict = {"key": "value"}
secret_mock = MagicMock()
secret_mock.secret = secret_dict
mutelist_processor = MagicMock()
mutelist_processor.configuration = {"Mutelist": {"key": "value"}}
provider = MagicMock()
provider.provider = Provider.ProviderChoices.AWS.value
provider.secret = secret_mock
provider.uid = provider_uid
result = get_prowler_provider_kwargs(provider, mutelist_processor)
expected_result = {**secret_dict, "mutelist_content": {"key": "value"}}
assert result == expected_result
def test_get_prowler_provider_kwargs_unsupported_provider(self):
# Setup
provider_uid = "provider_uid"
@@ -254,7 +294,7 @@ class TestValidateInvitation:
assert result == invitation
mock_db.get.assert_called_once_with(
token="VALID_TOKEN", email="user@example.com"
token="VALID_TOKEN", email__iexact="user@example.com"
)
def test_invitation_not_found_raises_validation_error(self):
@@ -269,7 +309,7 @@ class TestValidateInvitation:
"invitation_token": "Invalid invitation code."
}
mock_db.get.assert_called_once_with(
token="INVALID_TOKEN", email="user@example.com"
token="INVALID_TOKEN", email__iexact="user@example.com"
)
def test_invitation_not_found_raises_not_found(self):
@@ -284,7 +324,7 @@ class TestValidateInvitation:
assert exc_info.value.detail == "Invitation is not valid."
mock_db.get.assert_called_once_with(
token="INVALID_TOKEN", email="user@example.com"
token="INVALID_TOKEN", email__iexact="user@example.com"
)
def test_invitation_expired(self, invitation):
@@ -332,5 +372,282 @@ class TestValidateInvitation:
"invitation_token": "Invalid invitation code."
}
mock_db.get.assert_called_once_with(
token="VALID_TOKEN", email="different@example.com"
token="VALID_TOKEN", email__iexact="different@example.com"
)
def test_valid_invitation_uppercase_email(self):
"""Test that validate_invitation works with case-insensitive email lookup."""
uppercase_email = "USER@example.com"
invitation = MagicMock(spec=Invitation)
invitation.token = "VALID_TOKEN"
invitation.email = uppercase_email
invitation.expires_at = datetime.now(timezone.utc) + timedelta(days=1)
invitation.state = Invitation.State.PENDING
invitation.tenant = MagicMock()
with patch("api.utils.Invitation.objects.using") as mock_using:
mock_db = mock_using.return_value
mock_db.get.return_value = invitation
result = validate_invitation("VALID_TOKEN", "user@example.com")
assert result == invitation
mock_db.get.assert_called_once_with(
token="VALID_TOKEN", email__iexact="user@example.com"
)
class TestProwlerIntegrationConnectionTest:
"""Test prowler_integration_connection_test function for SecurityHub regions reset."""
@patch("api.utils.SecurityHub")
def test_security_hub_connection_failure_resets_regions(
self, mock_security_hub_class
):
"""Test that SecurityHub connection failure resets regions to empty dict."""
# Create integration with existing regions configuration
integration = MagicMock()
integration.integration_type = Integration.IntegrationChoices.AWS_SECURITY_HUB
integration.credentials = {
"aws_access_key_id": "test_key",
"aws_secret_access_key": "test_secret",
}
integration.configuration = {
"send_only_fails": True,
"regions": {
"us-east-1": True,
"us-west-2": True,
"eu-west-1": False,
"ap-south-1": False,
},
}
# Mock provider relationship
mock_provider = MagicMock()
mock_provider.uid = "123456789012"
mock_relationship = MagicMock()
mock_relationship.provider = mock_provider
integration.integrationproviderrelationship_set.first.return_value = (
mock_relationship
)
# Mock failed SecurityHub connection
mock_connection = SecurityHubConnection(
is_connected=False,
error=Exception("SecurityHub testing"),
enabled_regions=set(),
disabled_regions=set(),
)
mock_security_hub_class.test_connection.return_value = mock_connection
# Call the function
result = prowler_integration_connection_test(integration)
# Assertions
assert result.is_connected is False
assert str(result.error) == "SecurityHub testing"
# Verify regions were completely reset to empty dict
assert integration.configuration["regions"] == {}
# Verify save was called to persist the change
integration.save.assert_called_once()
# Verify test_connection was called with correct parameters
mock_security_hub_class.test_connection.assert_called_once_with(
aws_account_id="123456789012",
raise_on_exception=False,
aws_access_key_id="test_key",
aws_secret_access_key="test_secret",
)
@patch("api.utils.SecurityHub")
def test_security_hub_connection_success_saves_regions(
self, mock_security_hub_class
):
"""Test that successful SecurityHub connection saves regions correctly."""
integration = MagicMock()
integration.integration_type = Integration.IntegrationChoices.AWS_SECURITY_HUB
integration.credentials = {
"aws_access_key_id": "valid_key",
"aws_secret_access_key": "valid_secret",
}
integration.configuration = {"send_only_fails": False}
# Mock provider relationship
mock_provider = MagicMock()
mock_provider.uid = "123456789012"
mock_relationship = MagicMock()
mock_relationship.provider = mock_provider
integration.integrationproviderrelationship_set.first.return_value = (
mock_relationship
)
# Mock successful SecurityHub connection with regions
mock_connection = SecurityHubConnection(
is_connected=True,
error=None,
enabled_regions={"us-east-1", "eu-west-1"},
disabled_regions={"ap-south-1"},
)
mock_security_hub_class.test_connection.return_value = mock_connection
result = prowler_integration_connection_test(integration)
assert result.is_connected is True
# Verify regions were saved correctly
assert integration.configuration["regions"]["us-east-1"] is True
assert integration.configuration["regions"]["eu-west-1"] is True
assert integration.configuration["regions"]["ap-south-1"] is False
integration.save.assert_called_once()
@patch("api.utils.rls_transaction")
@patch("api.utils.Jira")
def test_jira_connection_success_basic_auth(
self, mock_jira_class, mock_rls_transaction
):
integration = MagicMock()
integration.integration_type = Integration.IntegrationChoices.JIRA
integration.tenant_id = "test-tenant-id"
integration.credentials = {
"user_mail": "test@example.com",
"api_token": "test_api_token",
"domain": "example.atlassian.net",
}
integration.configuration = {}
# Mock successful JIRA connection with projects
mock_connection = MagicMock()
mock_connection.is_connected = True
mock_connection.error = None
mock_connection.projects = {"PROJ1": "Project 1", "PROJ2": "Project 2"}
mock_jira_class.test_connection.return_value = mock_connection
# Mock rls_transaction context manager
mock_rls_transaction.return_value.__enter__ = MagicMock()
mock_rls_transaction.return_value.__exit__ = MagicMock()
result = prowler_integration_connection_test(integration)
assert result.is_connected is True
assert result.error is None
# Verify JIRA connection was called with correct parameters including domain from credentials
mock_jira_class.test_connection.assert_called_once_with(
user_mail="test@example.com",
api_token="test_api_token",
domain="example.atlassian.net",
raise_on_exception=False,
)
# Verify rls_transaction was called with correct tenant_id
mock_rls_transaction.assert_called_once_with("test-tenant-id")
# Verify projects were saved to integration configuration
assert integration.configuration["projects"] == {
"PROJ1": "Project 1",
"PROJ2": "Project 2",
}
# Verify integration.save() was called
integration.save.assert_called_once()
@patch("api.utils.rls_transaction")
@patch("api.utils.Jira")
def test_jira_connection_failure_invalid_credentials(
self, mock_jira_class, mock_rls_transaction
):
integration = MagicMock()
integration.integration_type = Integration.IntegrationChoices.JIRA
integration.tenant_id = "test-tenant-id"
integration.credentials = {
"user_mail": "invalid@example.com",
"api_token": "invalid_token",
"domain": "invalid.atlassian.net",
}
integration.configuration = {}
# Mock failed JIRA connection
mock_connection = MagicMock()
mock_connection.is_connected = False
mock_connection.error = Exception("Authentication failed: Invalid credentials")
mock_connection.projects = {} # Empty projects when connection fails
mock_jira_class.test_connection.return_value = mock_connection
# Mock rls_transaction context manager
mock_rls_transaction.return_value.__enter__ = MagicMock()
mock_rls_transaction.return_value.__exit__ = MagicMock()
result = prowler_integration_connection_test(integration)
assert result.is_connected is False
assert "Authentication failed: Invalid credentials" in str(result.error)
# Verify JIRA connection was called with correct parameters
mock_jira_class.test_connection.assert_called_once_with(
user_mail="invalid@example.com",
api_token="invalid_token",
domain="invalid.atlassian.net",
raise_on_exception=False,
)
# Verify rls_transaction was called even on failure
mock_rls_transaction.assert_called_once_with("test-tenant-id")
# Verify empty projects dict was saved to integration configuration
assert integration.configuration["projects"] == {}
# Verify integration.save() was called even on connection failure
integration.save.assert_called_once()
@patch("api.utils.rls_transaction")
@patch("api.utils.Jira")
def test_jira_connection_projects_update_with_existing_configuration(
self, mock_jira_class, mock_rls_transaction
):
"""Test that projects are properly updated when integration already has configuration data"""
integration = MagicMock()
integration.integration_type = Integration.IntegrationChoices.JIRA
integration.tenant_id = "test-tenant-id"
integration.credentials = {
"user_mail": "test@example.com",
"api_token": "test_api_token",
"domain": "example.atlassian.net",
}
integration.configuration = {
"issue_types": ["Task"], # Existing configuration
"projects": {"OLD_PROJ": "Old Project"}, # Will be overwritten
}
# Mock successful JIRA connection with new projects
mock_connection = MagicMock()
mock_connection.is_connected = True
mock_connection.error = None
mock_connection.projects = {
"NEW_PROJ1": "New Project 1",
"NEW_PROJ2": "New Project 2",
}
mock_jira_class.test_connection.return_value = mock_connection
# Mock rls_transaction context manager
mock_rls_transaction.return_value.__enter__ = MagicMock()
mock_rls_transaction.return_value.__exit__ = MagicMock()
result = prowler_integration_connection_test(integration)
assert result.is_connected is True
assert result.error is None
# Verify projects were updated (old projects replaced with new ones)
assert integration.configuration["projects"] == {
"NEW_PROJ1": "New Project 1",
"NEW_PROJ2": "New Project 2",
}
# Verify other configuration fields were preserved
assert integration.configuration["issue_types"] == ["Task"]
# Verify integration.save() was called
integration.save.assert_called_once()
File diff suppressed because it is too large Load Diff
+132 -9
View File
@@ -6,13 +6,18 @@ from django.db.models import Subquery
from rest_framework.exceptions import NotFound, ValidationError
from api.db_router import MainRouter
from api.db_utils import rls_transaction
from api.exceptions import InvitationTokenExpiredException
from api.models import Invitation, Provider, Resource
from api.models import Integration, Invitation, Processor, Provider, Resource
from api.v1.serializers import FindingMetadataSerializer
from prowler.lib.outputs.jira.jira import Jira, JiraBasicAuthError
from prowler.providers.aws.aws_provider import AwsProvider
from prowler.providers.aws.lib.s3.s3 import S3
from prowler.providers.aws.lib.security_hub.security_hub import SecurityHub
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.common.models import Connection
from prowler.providers.gcp.gcp_provider import GcpProvider
from prowler.providers.github.github_provider import GithubProvider
from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider
from prowler.providers.m365.m365_provider import M365Provider
@@ -55,14 +60,21 @@ def merge_dicts(default_dict: dict, replacement_dict: dict) -> dict:
def return_prowler_provider(
provider: Provider,
) -> [AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider]:
) -> [
AwsProvider
| AzureProvider
| GcpProvider
| GithubProvider
| KubernetesProvider
| M365Provider
]:
"""Return the Prowler provider class based on the given provider type.
Args:
provider (Provider): The provider object containing the provider type and associated secrets.
Returns:
AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider: The corresponding provider class.
AwsProvider | AzureProvider | GcpProvider | GithubProvider | KubernetesProvider | M365Provider: The corresponding provider class.
Raises:
ValueError: If the provider type specified in `provider.provider` is not supported.
@@ -78,16 +90,21 @@ def return_prowler_provider(
prowler_provider = KubernetesProvider
case Provider.ProviderChoices.M365.value:
prowler_provider = M365Provider
case Provider.ProviderChoices.GITHUB.value:
prowler_provider = GithubProvider
case _:
raise ValueError(f"Provider type {provider.provider} not supported")
return prowler_provider
def get_prowler_provider_kwargs(provider: Provider) -> dict:
def get_prowler_provider_kwargs(
provider: Provider, mutelist_processor: Processor | None = None
) -> dict:
"""Get the Prowler provider kwargs based on the given provider type.
Args:
provider (Provider): The provider object containing the provider type and associated secret.
mutelist_processor (Processor): The mutelist processor object containing the mutelist configuration.
Returns:
dict: The provider kwargs for the corresponding provider class.
@@ -105,24 +122,45 @@ def get_prowler_provider_kwargs(provider: Provider) -> dict:
}
elif provider.provider == Provider.ProviderChoices.KUBERNETES.value:
prowler_provider_kwargs = {**prowler_provider_kwargs, "context": provider.uid}
elif provider.provider == Provider.ProviderChoices.GITHUB.value:
if provider.uid:
prowler_provider_kwargs = {
**prowler_provider_kwargs,
"organizations": [provider.uid],
}
if mutelist_processor:
mutelist_content = mutelist_processor.configuration.get("Mutelist", {})
if mutelist_content:
prowler_provider_kwargs["mutelist_content"] = mutelist_content
return prowler_provider_kwargs
def initialize_prowler_provider(
provider: Provider,
) -> AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider:
mutelist_processor: Processor | None = None,
) -> (
AwsProvider
| AzureProvider
| GcpProvider
| GithubProvider
| KubernetesProvider
| M365Provider
):
"""Initialize a Prowler provider instance based on the given provider type.
Args:
provider (Provider): The provider object containing the provider type and associated secrets.
mutelist_processor (Processor): The mutelist processor object containing the mutelist configuration.
Returns:
AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider: An instance of the corresponding provider class
(`AwsProvider`, `AzureProvider`, `GcpProvider`, `KubernetesProvider` or `M365Provider`) initialized with the
AwsProvider | AzureProvider | GcpProvider | GithubProvider | KubernetesProvider | M365Provider: An instance of the corresponding provider class
(`AwsProvider`, `AzureProvider`, `GcpProvider`, `GithubProvider`, `KubernetesProvider` or `M365Provider`) initialized with the
provider's secrets.
"""
prowler_provider = return_prowler_provider(provider)
prowler_provider_kwargs = get_prowler_provider_kwargs(provider)
prowler_provider_kwargs = get_prowler_provider_kwargs(provider, mutelist_processor)
return prowler_provider(**prowler_provider_kwargs)
@@ -147,6 +185,77 @@ def prowler_provider_connection_test(provider: Provider) -> Connection:
)
def prowler_integration_connection_test(integration: Integration) -> Connection:
"""Test the connection to a Prowler integration based on the given integration type.
Args:
integration (Integration): The integration object containing the integration type and associated credentials.
Returns:
Connection: A connection object representing the result of the connection test for the specified integration.
"""
if integration.integration_type == Integration.IntegrationChoices.AMAZON_S3:
return S3.test_connection(
**integration.credentials,
bucket_name=integration.configuration["bucket_name"],
raise_on_exception=False,
)
# TODO: It is possible that we can unify the connection test for all integrations, but need refactoring
# to avoid code duplication. Actually the AWS integrations are similar, so SecurityHub and S3 can be unified
# making some changes in the SDK.
elif (
integration.integration_type == Integration.IntegrationChoices.AWS_SECURITY_HUB
):
# Get the provider associated with this integration
provider_relationship = integration.integrationproviderrelationship_set.first()
if not provider_relationship:
return Connection(
is_connected=False, error="No provider associated with this integration"
)
credentials = (
integration.credentials
if integration.credentials
else provider_relationship.provider.secret.secret
)
connection = SecurityHub.test_connection(
aws_account_id=provider_relationship.provider.uid,
raise_on_exception=False,
**credentials,
)
# Only save regions if connection is successful
if connection.is_connected:
regions_status = {r: True for r in connection.enabled_regions}
regions_status.update({r: False for r in connection.disabled_regions})
# Save regions information in the integration configuration
integration.configuration["regions"] = regions_status
integration.save()
else:
# Reset regions information if connection fails
integration.configuration["regions"] = {}
integration.save()
return connection
elif integration.integration_type == Integration.IntegrationChoices.JIRA:
jira_connection = Jira.test_connection(
**integration.credentials,
raise_on_exception=False,
)
project_keys = jira_connection.projects if jira_connection.is_connected else {}
with rls_transaction(str(integration.tenant_id)):
integration.configuration["projects"] = project_keys
integration.save()
return jira_connection
elif integration.integration_type == Integration.IntegrationChoices.SLACK:
pass
else:
raise ValueError(
f"Integration type {integration.integration_type} not supported"
)
def validate_invitation(
invitation_token: str, email: str, raise_not_found=False
) -> Invitation:
@@ -187,7 +296,7 @@ def validate_invitation(
# Admin DB connector is used to bypass RLS protection since the invitation belongs to a tenant the user
# is not a member of yet
invitation = Invitation.objects.using(MainRouter.admin_db).get(
token=invitation_token, email=email
token=invitation_token, email__iexact=email
)
except Invitation.DoesNotExist:
if raise_not_found:
@@ -238,3 +347,17 @@ def get_findings_metadata_no_aggregations(tenant_id: str, filtered_queryset):
serializer.is_valid(raise_exception=True)
return serializer.data
def initialize_prowler_integration(integration: Integration) -> Jira:
# TODO Refactor other integrations to use this function
if integration.integration_type == Integration.IntegrationChoices.JIRA:
try:
return Jira(**integration.credentials)
except JiraBasicAuthError as jira_auth_error:
with rls_transaction(str(integration.tenant_id)):
integration.configuration["projects"] = {}
integration.connected = False
integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
integration.save()
raise jira_auth_error
+203 -2
View File
@@ -1,5 +1,16 @@
from django.urls import reverse
from django_celery_results.models import TaskResult
from rest_framework import status
from rest_framework.response import Response
from api.exceptions import (
TaskFailedException,
TaskInProgressException,
TaskNotFoundException,
)
from api.models import StateChoices, Task
from api.v1.serializers import TaskSerializer
class PaginateByPkMixin:
"""
@@ -13,21 +24,211 @@ class PaginateByPkMixin:
request, # noqa: F841
base_queryset,
manager,
select_related: list[str] | None = None,
prefetch_related: list[str] | None = None,
select_related: list | None = None,
prefetch_related: list | None = None,
) -> Response:
"""
Paginate a queryset by primary key.
This method is useful when you want to paginate a queryset that has been
filtered or annotated in a way that would be lost if you used the default
pagination method.
"""
pk_list = base_queryset.values_list("id", flat=True)
page = self.paginate_queryset(pk_list)
if page is None:
return Response(self.get_serializer(base_queryset, many=True).data)
queryset = manager.filter(id__in=page)
if select_related:
queryset = queryset.select_related(*select_related)
if prefetch_related:
queryset = queryset.prefetch_related(*prefetch_related)
# Optimize tags loading, if applicable
if hasattr(self, "_optimize_tags_loading"):
queryset = self._optimize_tags_loading(queryset)
queryset = sorted(queryset, key=lambda obj: page.index(obj.id))
serialized = self.get_serializer(queryset, many=True).data
return self.get_paginated_response(serialized)
class TaskManagementMixin:
"""
Mixin to manage task status checking.
This mixin provides functionality to check if a task with specific parameters
is running, completed, failed, or doesn't exist. It returns the task when running
and raises specific exceptions for failed/not found scenarios that can be handled
at the view level.
"""
def check_task_status(
self,
task_name: str,
task_kwargs: dict,
raise_on_failed: bool = True,
raise_on_not_found: bool = True,
) -> Task | None:
"""
Check the status of a task with given name and kwargs.
This method first checks for a related Task object, and if not found,
checks TaskResult directly. If a TaskResult is found and running but
there's no related Task, it raises TaskInProgressException.
Args:
task_name (str): The name of the task to check
task_kwargs (dict): The kwargs to match against the task
raise_on_failed (bool): Whether to raise exception if task failed
raise_on_not_found (bool): Whether to raise exception if task not found
Returns:
Task | None: The task instance if found (regardless of state), None if not found and raise_on_not_found=False
Raises:
TaskFailedException: If task failed and raise_on_failed=True
TaskNotFoundException: If task not found and raise_on_not_found=True
TaskInProgressException: If task is running but no related Task object exists
"""
# First, try to find a Task object with related TaskResult
try:
# Build the filter for task kwargs
task_filter = {
"task_runner_task__task_name": task_name,
}
# Add kwargs filters - we need to check if the task kwargs contain our parameters
for key, value in task_kwargs.items():
task_filter["task_runner_task__task_kwargs__contains"] = str(value)
task = (
Task.objects.filter(**task_filter)
.select_related("task_runner_task")
.order_by("-inserted_at")
.first()
)
if task:
# Get task state using the same logic as TaskSerializer
task_state_mapping = {
"PENDING": StateChoices.AVAILABLE,
"STARTED": StateChoices.EXECUTING,
"PROGRESS": StateChoices.EXECUTING,
"SUCCESS": StateChoices.COMPLETED,
"FAILURE": StateChoices.FAILED,
"REVOKED": StateChoices.CANCELLED,
}
celery_status = (
task.task_runner_task.status if task.task_runner_task else None
)
task_state = task_state_mapping.get(
celery_status or "", StateChoices.AVAILABLE
)
# Check task state and raise exceptions accordingly
if task_state in (StateChoices.FAILED, StateChoices.CANCELLED):
if raise_on_failed:
raise TaskFailedException(task=task)
return task
elif task_state == StateChoices.COMPLETED:
return None
return task
except Task.DoesNotExist:
pass
# If no Task found, check TaskResult directly
try:
# Build the filter for TaskResult
task_result_filter = {
"task_name": task_name,
}
# Add kwargs filters - check if the task kwargs contain our parameters
for key, value in task_kwargs.items():
task_result_filter["task_kwargs__contains"] = str(value)
task_result = (
TaskResult.objects.filter(**task_result_filter)
.order_by("-date_created")
.first()
)
if task_result:
# Check if the TaskResult indicates a running task
if task_result.status in ["PENDING", "STARTED", "PROGRESS"]:
# Task is running but no related Task object exists
raise TaskInProgressException(task_result=task_result)
elif task_result.status == "FAILURE":
if raise_on_failed:
raise TaskFailedException(task=None)
# For other statuses (SUCCESS, REVOKED), we don't have a Task to return,
# so we treat it as not found
except TaskResult.DoesNotExist:
pass
# No task found at all
if raise_on_not_found:
raise TaskNotFoundException()
return None
def get_task_response_if_running(
self,
task_name: str,
task_kwargs: dict,
raise_on_failed: bool = True,
raise_on_not_found: bool = True,
) -> Response | None:
"""
Get a 202 response with task details if the task is currently running.
This method is useful for endpoints that should return task status when
a background task is in progress, similar to the compliance overview endpoints.
Args:
task_name (str): The name of the task to check
task_kwargs (dict): The kwargs to match against the task
Returns:
Response | None: 202 response with task details if running, None otherwise
"""
task = self.check_task_status(
task_name=task_name,
task_kwargs=task_kwargs,
raise_on_failed=raise_on_failed,
raise_on_not_found=raise_on_not_found,
)
if not task:
return None
# Get task state
task_state_mapping = {
"PENDING": StateChoices.AVAILABLE,
"STARTED": StateChoices.EXECUTING,
"PROGRESS": StateChoices.EXECUTING,
"SUCCESS": StateChoices.COMPLETED,
"FAILURE": StateChoices.FAILED,
"REVOKED": StateChoices.CANCELLED,
}
celery_status = task.task_runner_task.status if task.task_runner_task else None
task_state = task_state_mapping.get(celery_status or "", StateChoices.AVAILABLE)
if task_state == StateChoices.EXECUTING:
self.response_serializer_class = TaskSerializer
serializer = TaskSerializer(task)
return Response(
data=serializer.data,
status=status.HTTP_202_ACCEPTED,
headers={
"Content-Location": reverse("task-detail", kwargs={"pk": task.id})
},
)
@@ -0,0 +1,23 @@
import yaml
from rest_framework_json_api import serializers
from rest_framework_json_api.serializers import ValidationError
class BaseValidateSerializer(serializers.Serializer):
def validate(self, data):
if hasattr(self, "initial_data"):
initial_data = set(self.initial_data.keys()) - {"id", "type"}
unknown_keys = initial_data - set(self.fields.keys())
if unknown_keys:
raise ValidationError(f"Invalid fields: {unknown_keys}")
return data
class YamlOrJsonField(serializers.JSONField):
def to_internal_value(self, data):
if isinstance(data, str):
try:
data = yaml.safe_load(data)
except yaml.YAMLError as exc:
raise serializers.ValidationError("Invalid YAML format") from exc
return super().to_internal_value(data)
@@ -1,24 +1,78 @@
import os
import re
from drf_spectacular.utils import extend_schema_field
from rest_framework_json_api import serializers
from rest_framework_json_api.serializers import ValidationError
class BaseValidateSerializer(serializers.Serializer):
def validate(self, data):
if hasattr(self, "initial_data"):
initial_data = set(self.initial_data.keys()) - {"id", "type"}
unknown_keys = initial_data - set(self.fields.keys())
if unknown_keys:
raise ValidationError(f"Invalid fields: {unknown_keys}")
return data
# Integrations
from api.v1.serializer_utils.base import BaseValidateSerializer
class S3ConfigSerializer(BaseValidateSerializer):
bucket_name = serializers.CharField()
output_directory = serializers.CharField()
output_directory = serializers.CharField(allow_blank=True)
def validate_output_directory(self, value):
"""
Validate the output_directory field to ensure it's a properly formatted path.
Prevents paths with excessive slashes like "///////test".
If empty, sets a default value.
"""
# If empty or None, set default value
if not value:
return "output"
# Normalize the path to remove excessive slashes
normalized_path = os.path.normpath(value)
# Remove leading slashes for S3 paths
if normalized_path.startswith("/"):
normalized_path = normalized_path.lstrip("/")
# Check for invalid characters or patterns
if re.search(r'[<>:"|?*]', normalized_path):
raise serializers.ValidationError(
'Output directory contains invalid characters. Avoid: < > : " | ? *'
)
# Check for empty path after normalization
if not normalized_path or normalized_path == ".":
raise serializers.ValidationError(
"Output directory cannot be empty or just '.' or '/'."
)
# Check for paths that are too long (S3 key limit is 1024 characters, leave some room for filename)
if len(normalized_path) > 900:
raise serializers.ValidationError(
"Output directory path is too long (max 900 characters)."
)
return normalized_path
class Meta:
resource_name = "integrations"
class SecurityHubConfigSerializer(BaseValidateSerializer):
send_only_fails = serializers.BooleanField(default=False)
archive_previous_findings = serializers.BooleanField(default=False)
regions = serializers.DictField(default=dict, read_only=True)
def to_internal_value(self, data):
validated_data = super().to_internal_value(data)
# Always initialize regions as empty dict
validated_data["regions"] = {}
return validated_data
class Meta:
resource_name = "integrations"
class JiraConfigSerializer(BaseValidateSerializer):
domain = serializers.CharField(read_only=True)
issue_types = serializers.ListField(
read_only=True, child=serializers.CharField(), default=["Task"]
)
projects = serializers.DictField(read_only=True)
class Meta:
resource_name = "integrations"
@@ -39,6 +93,15 @@ class AWSCredentialSerializer(BaseValidateSerializer):
resource_name = "integrations"
class JiraCredentialSerializer(BaseValidateSerializer):
user_mail = serializers.EmailField(required=True)
api_token = serializers.CharField(required=True)
domain = serializers.CharField(required=True)
class Meta:
resource_name = "integrations"
@extend_schema_field(
{
"oneOf": [
@@ -90,6 +153,27 @@ class AWSCredentialSerializer(BaseValidateSerializer):
},
},
},
{
"type": "object",
"title": "JIRA Credentials",
"properties": {
"user_mail": {
"type": "string",
"format": "email",
"description": "The email address of the JIRA user account.",
},
"api_token": {
"type": "string",
"description": "The API token for authentication with JIRA. This can be generated from your "
"Atlassian account settings.",
},
"domain": {
"type": "string",
"description": "The JIRA domain/instance URL (e.g., 'your-domain.atlassian.net').",
},
},
"required": ["user_mail", "api_token", "domain"],
},
]
}
)
@@ -110,10 +194,40 @@ class IntegrationCredentialField(serializers.JSONField):
},
"output_directory": {
"type": "string",
"description": "The directory path within the bucket where files will be saved.",
"description": "The directory path within the bucket where files will be saved. Optional - "
'defaults to "output" if not provided. Path will be normalized to remove '
'excessive slashes and invalid characters are not allowed (< > : " | ? *). '
"Maximum length is 900 characters.",
"maxLength": 900,
"pattern": '^[^<>:"|?*]+$',
"default": "output",
},
},
"required": ["bucket_name", "output_directory"],
"required": ["bucket_name"],
},
{
"type": "object",
"title": "AWS Security Hub",
"properties": {
"send_only_fails": {
"type": "boolean",
"default": False,
"description": "If true, only findings with status 'FAIL' will be sent to Security Hub.",
},
"archive_previous_findings": {
"type": "boolean",
"default": False,
"description": "If true, archives findings that are not present in the current execution.",
},
},
},
{
"type": "object",
"title": "JIRA",
"description": "JIRA integration does not accept any configuration in the payload. Leave it as an "
"empty JSON object (`{}`).",
"properties": {},
"additionalProperties": False,
},
]
}
@@ -0,0 +1,21 @@
from drf_spectacular.utils import extend_schema_field
from api.v1.serializer_utils.base import YamlOrJsonField
from prowler.lib.mutelist.mutelist import mutelist_schema
@extend_schema_field(
{
"oneOf": [
{
"type": "object",
"title": "Mutelist",
"properties": {"Mutelist": mutelist_schema},
"additionalProperties": False,
},
]
}
)
class ProcessorConfigField(YamlOrJsonField):
pass
@@ -154,6 +154,17 @@ from rest_framework_json_api import serializers
},
"required": ["client_id", "client_secret", "refresh_token"],
},
{
"type": "object",
"title": "GCP Service Account Key",
"properties": {
"service_account_key": {
"type": "object",
"description": "The service account key for GCP.",
}
},
"required": ["service_account_key"],
},
{
"type": "object",
"title": "Kubernetes Static Credentials",
@@ -165,6 +176,43 @@ from rest_framework_json_api import serializers
},
"required": ["kubeconfig_content"],
},
{
"type": "object",
"title": "GitHub Personal Access Token",
"properties": {
"personal_access_token": {
"type": "string",
"description": "GitHub personal access token for authentication.",
}
},
"required": ["personal_access_token"],
},
{
"type": "object",
"title": "GitHub OAuth App Token",
"properties": {
"oauth_app_token": {
"type": "string",
"description": "GitHub OAuth App token for authentication.",
}
},
"required": ["oauth_app_token"],
},
{
"type": "object",
"title": "GitHub App Credentials",
"properties": {
"github_app_id": {
"type": "integer",
"description": "GitHub App ID for authentication.",
},
"github_app_key": {
"type": "string",
"description": "Path to the GitHub App private key file.",
},
},
"required": ["github_app_id", "github_app_key"],
},
]
}
)
File diff suppressed because it is too large Load Diff
+54
View File
@@ -1,20 +1,25 @@
from allauth.socialaccount.providers.saml.views import ACSView, MetadataView, SLSView
from django.urls import include, path
from drf_spectacular.views import SpectacularRedocView
from rest_framework_nested import routers
from api.v1.views import (
ComplianceOverviewViewSet,
CustomSAMLLoginView,
CustomTokenObtainView,
CustomTokenRefreshView,
CustomTokenSwitchTenantView,
FindingViewSet,
GithubSocialLoginView,
GoogleSocialLoginView,
IntegrationJiraViewSet,
IntegrationViewSet,
InvitationAcceptViewSet,
InvitationViewSet,
LighthouseConfigViewSet,
MembershipViewSet,
OverviewViewSet,
ProcessorViewSet,
ProviderGroupProvidersRelationshipView,
ProviderGroupViewSet,
ProviderSecretViewSet,
@@ -22,10 +27,14 @@ from api.v1.views import (
ResourceViewSet,
RoleProviderGroupRelationshipView,
RoleViewSet,
SAMLConfigurationViewSet,
SAMLInitiateAPIView,
SAMLTokenValidateView,
ScanViewSet,
ScheduleViewSet,
SchemaView,
TaskViewSet,
TenantFinishACSView,
TenantMembersViewSet,
TenantViewSet,
UserRoleRelationshipView,
@@ -49,6 +58,13 @@ router.register(
router.register(r"overviews", OverviewViewSet, basename="overview")
router.register(r"schedules", ScheduleViewSet, basename="schedule")
router.register(r"integrations", IntegrationViewSet, basename="integration")
router.register(r"processors", ProcessorViewSet, basename="processor")
router.register(r"saml-config", SAMLConfigurationViewSet, basename="saml-config")
router.register(
r"lighthouse-configurations",
LighthouseConfigViewSet,
basename="lighthouseconfiguration",
)
tenants_router = routers.NestedSimpleRouter(router, r"tenants", lookup="tenant")
tenants_router.register(
@@ -58,6 +74,13 @@ tenants_router.register(
users_router = routers.NestedSimpleRouter(router, r"users", lookup="user")
users_router.register(r"memberships", MembershipViewSet, basename="user-membership")
integrations_router = routers.NestedSimpleRouter(
router, r"integrations", lookup="integration"
)
integrations_router.register(
r"jira", IntegrationJiraViewSet, basename="integration-jira"
)
urlpatterns = [
path("tokens", CustomTokenObtainView.as_view(), name="token-obtain"),
path("tokens/refresh", CustomTokenRefreshView.as_view(), name="token-refresh"),
@@ -112,11 +135,42 @@ urlpatterns = [
),
name="provider_group-providers-relationship",
),
# API endpoint to start SAML SSO flow
path(
"auth/saml/initiate/", SAMLInitiateAPIView.as_view(), name="api_saml_initiate"
),
path(
"accounts/saml/<organization_slug>/login/",
CustomSAMLLoginView.as_view(),
name="saml_login",
),
path(
"accounts/saml/<organization_slug>/acs/",
ACSView.as_view(),
name="saml_acs",
),
path(
"accounts/saml/<organization_slug>/acs/finish/",
TenantFinishACSView.as_view(),
name="saml_finish_acs",
),
path(
"accounts/saml/<organization_slug>/sls/",
SLSView.as_view(),
name="saml_sls",
),
path(
"accounts/saml/<organization_slug>/metadata/",
MetadataView.as_view(),
name="saml_metadata",
),
path("tokens/saml", SAMLTokenValidateView.as_view(), name="token-saml"),
path("tokens/google", GoogleSocialLoginView.as_view(), name="token-google"),
path("tokens/github", GithubSocialLoginView.as_view(), name="token-github"),
path("", include(router.urls)),
path("", include(tenants_router.urls)),
path("", include(users_router.urls)),
path("", include(integrations_router.urls)),
path("schema", SchemaView.as_view(), name="schema"),
path("docs", SpectacularRedocView.as_view(url_name="schema"), name="docs"),
]
File diff suppressed because it is too large Load Diff
+88
View File
@@ -1,3 +1,5 @@
import string
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
@@ -20,3 +22,89 @@ class MaximumLengthValidator:
return _(
f"Your password must contain no more than {self.max_length} characters."
)
class SpecialCharactersValidator:
def __init__(self, special_characters=None, min_special_characters=1):
# Use string.punctuation if no custom characters provided
self.special_characters = special_characters or string.punctuation
self.min_special_characters = min_special_characters
def validate(self, password, user=None):
if (
sum(1 for char in password if char in self.special_characters)
< self.min_special_characters
):
raise ValidationError(
_("This password must contain at least one special character."),
code="password_no_special_characters",
params={
"special_characters": self.special_characters,
"min_special_characters": self.min_special_characters,
},
)
def get_help_text(self):
return _(
f"Your password must contain at least one special character from: {self.special_characters}"
)
class UppercaseValidator:
def __init__(self, min_uppercase=1):
self.min_uppercase = min_uppercase
def validate(self, password, user=None):
if sum(1 for char in password if char.isupper()) < self.min_uppercase:
raise ValidationError(
_(
"This password must contain at least %(min_uppercase)d uppercase letter."
),
code="password_no_uppercase_letters",
params={"min_uppercase": self.min_uppercase},
)
def get_help_text(self):
return _(
f"Your password must contain at least {self.min_uppercase} uppercase letter."
)
class LowercaseValidator:
def __init__(self, min_lowercase=1):
self.min_lowercase = min_lowercase
def validate(self, password, user=None):
if sum(1 for char in password if char.islower()) < self.min_lowercase:
raise ValidationError(
_(
"This password must contain at least %(min_lowercase)d lowercase letter."
),
code="password_no_lowercase_letters",
params={"min_lowercase": self.min_lowercase},
)
def get_help_text(self):
return _(
f"Your password must contain at least {self.min_lowercase} lowercase letter."
)
class NumericValidator:
def __init__(self, min_numeric=1):
self.min_numeric = min_numeric
def validate(self, password, user=None):
if sum(1 for char in password if char.isdigit()) < self.min_numeric:
raise ValidationError(
_(
"This password must contain at least %(min_numeric)d numeric character."
),
code="password_no_numeric_characters",
params={"min_numeric": self.min_numeric},
)
def get_help_text(self):
return _(
f"Your password must contain at least {self.min_numeric} numeric character."
)
+7
View File
@@ -1,6 +1,13 @@
import warnings
from celery import Celery, Task
from config.env import env
# Suppress specific warnings from django-rest-auth: https://github.com/iMerica/dj-rest-auth/issues/684
warnings.filterwarnings(
"ignore", category=UserWarning, module="dj_rest_auth.registration.serializers"
)
BROKER_VISIBILITY_TIMEOUT = env.int("DJANGO_BROKER_VISIBILITY_TIMEOUT", default=86400)
celery_app = Celery("tasks")
+45 -1
View File
@@ -10,6 +10,8 @@ from config.settings.social_login import * # noqa
SECRET_KEY = env("SECRET_KEY", default="secret")
DEBUG = env.bool("DJANGO_DEBUG", default=False)
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
USE_X_FORWARDED_HOST = True
# Application definition
@@ -26,16 +28,19 @@ INSTALLED_APPS = [
"rest_framework",
"corsheaders",
"drf_spectacular",
"drf_spectacular_jsonapi",
"django_guid",
"rest_framework_json_api",
"django_celery_results",
"django_celery_beat",
"rest_framework_simplejwt.token_blacklist",
"allauth",
"django.contrib.sites",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
"allauth.socialaccount.providers.github",
"allauth.socialaccount.providers.saml",
"dj_rest_auth.registration",
"rest_framework.authtoken",
]
@@ -103,6 +108,13 @@ REST_FRAMEWORK = {
),
"TEST_REQUEST_DEFAULT_FORMAT": "vnd.api+json",
"JSON_API_UNIFORM_EXCEPTIONS": True,
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.ScopedRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {
"token-obtain": env("DJANGO_THROTTLE_TOKEN_OBTAIN", default=None),
"dj_rest_auth": None,
},
}
SPECTACULAR_SETTINGS = {
@@ -111,6 +123,9 @@ SPECTACULAR_SETTINGS = {
"PREPROCESSING_HOOKS": [
"drf_spectacular_jsonapi.hooks.fix_nested_path_parameters",
],
"POSTPROCESSING_HOOKS": [
"api.schema_hooks.attach_task_202_examples",
],
"TITLE": "API Reference - Prowler",
}
@@ -154,6 +169,30 @@ AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
{
"NAME": "api.validators.SpecialCharactersValidator",
"OPTIONS": {
"min_special_characters": 1,
},
},
{
"NAME": "api.validators.UppercaseValidator",
"OPTIONS": {
"min_uppercase": 1,
},
},
{
"NAME": "api.validators.LowercaseValidator",
"OPTIONS": {
"min_lowercase": 1,
},
},
{
"NAME": "api.validators.NumericValidator",
"OPTIONS": {
"min_numeric": 1,
},
},
]
SIMPLE_JWT = {
@@ -238,8 +277,13 @@ DJANGO_OUTPUT_S3_AWS_SECRET_ACCESS_KEY = env.str(
DJANGO_OUTPUT_S3_AWS_SESSION_TOKEN = env.str("DJANGO_OUTPUT_S3_AWS_SESSION_TOKEN", "")
DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION = env.str("DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION", "")
DJANGO_DELETION_BATCH_SIZE = env.int("DJANGO_DELETION_BATCH_SIZE", 5000)
# HTTP Security Headers
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
DJANGO_DELETION_BATCH_SIZE = env.int("DJANGO_DELETION_BATCH_SIZE", 5000)
# SAML requirement
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
+9 -3
View File
@@ -4,6 +4,7 @@ from config.env import env
IGNORED_EXCEPTIONS = [
# Provider is not connected due to credentials errors
"is not connected",
"ProviderConnectionError",
# Authentication Errors from AWS
"InvalidToken",
"AccessDeniedException",
@@ -16,7 +17,7 @@ IGNORED_EXCEPTIONS = [
"InternalServerErrorException",
"AccessDenied",
"No Shodan API Key", # Shodan Check
"RequestLimitExceeded", # For now we don't want to log the RequestLimitExceeded errors
"RequestLimitExceeded", # For now, we don't want to log the RequestLimitExceeded errors
"ThrottlingException",
"Rate exceeded",
"SubscriptionRequiredException",
@@ -42,7 +43,9 @@ IGNORED_EXCEPTIONS = [
"AWSAccessKeyIDInvalidError",
"AWSSessionTokenExpiredError",
"EndpointConnectionError", # AWS Service is not available in a region
"Pool is closed", # The following comes from urllib3: eu-west-1 -- HTTPClientError[126]: An HTTP Client raised an unhandled exception: AWSHTTPSConnectionPool(host='hostname.s3.eu-west-1.amazonaws.com', port=443): Pool is closed.
# The following comes from urllib3: eu-west-1 -- HTTPClientError[126]: An HTTP Client raised an
# unhandled exception: AWSHTTPSConnectionPool(host='hostname.s3.eu-west-1.amazonaws.com', port=443): Pool is closed.
"Pool is closed",
# Authentication Errors from GCP
"ClientAuthenticationError",
"AuthorizationFailed",
@@ -66,12 +69,15 @@ IGNORED_EXCEPTIONS = [
"AzureClientIdAndClientSecretNotBelongingToTenantIdError",
"AzureHTTPResponseError",
"Error with credentials provided",
# PowerShell Errors in User Authentication
"Microsoft Teams User Auth connection failed: Please check your permissions and try again.",
"Exchange Online User Auth connection failed: Please check your permissions and try again.",
]
def before_send(event, hint):
"""
before_send handles the Sentry events in order to sent them or not
before_send handles the Sentry events in order to send them or not
"""
# Ignore logs with the ignored_exceptions
# https://docs.python.org/3/library/logging.html#logrecord-objects
@@ -11,8 +11,7 @@ GITHUB_OAUTH_CALLBACK_URL = env("SOCIAL_GITHUB_OAUTH_CALLBACK_URL", default="")
# Allauth settings
ACCOUNT_LOGIN_METHODS = {"email"} # Use Email / Password authentication
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
ACCOUNT_EMAIL_VERIFICATION = "none" # Do not require email confirmation
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
REST_AUTH = {
@@ -25,6 +24,20 @@ SOCIALACCOUNT_EMAIL_AUTHENTICATION = True
# Connect local account and social account if local account with that email address already exists
SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT = True
SOCIALACCOUNT_ADAPTER = "api.adapters.ProwlerSocialAccountAdapter"
# def inline(pem: str) -> str:
# return "".join(
# line.strip()
# for line in pem.splitlines()
# if "CERTIFICATE" not in line and "KEY" not in line
# )
# # SAML keys (TODO: Validate certificates)
# SAML_PUBLIC_CERT = inline(env("SAML_PUBLIC_CERT", default=""))
# SAML_PRIVATE_KEY = inline(env("SAML_PRIVATE_KEY", default=""))
SOCIALACCOUNT_PROVIDERS = {
"google": {
"APP": {
@@ -50,4 +63,20 @@ SOCIALACCOUNT_PROVIDERS = {
"read:org",
],
},
"saml": {
"use_nameid_for_email": True,
"sp": {
"entity_id": "urn:prowler.com:sp",
},
"advanced": {
# TODO: Validate certificates
# "x509cert": SAML_PUBLIC_CERT,
# "private_key": SAML_PRIVATE_KEY,
# "authn_request_signed": True,
# "want_message_signed": True,
# "want_assertion_signed": True,
"reject_idp_initiated_sso": False,
"name_id_format": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
},
},
}

Some files were not shown because too many files have changed in this diff Show More