Compare commits

...

1224 Commits
4.6.0 ... v5.4

Author SHA1 Message Date
Pepe Fagoaga
f347080dbd chore(release): bump for 5.4.5 (#7475) 2025-04-08 13:14:51 -04:00
Prowler Bot
2cc8363697 fix: handle errors in AWS, Azure, and GCP (#7471)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-08 19:03:42 +05:45
Prowler Bot
154467e7c8 fix(provider): disable periodic task on views before deleting (#7470)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-04-08 15:50:39 +05:45
Prowler Bot
16c71f3c04 fix(soc2_aws): update compliance and remove some requirements (#7455)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-04-07 16:53:52 -04:00
Prowler Bot
849707166a fix(gcp): handle logic for empty project names (#7450)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-07 15:21:54 -04:00
Prowler Bot
59513d777c fix(aws): add resource arn for transit gateways (#7448)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-07 13:38:28 -04:00
Prowler Bot
f52929673d fix(gcp): ignore redirect balancers and add regional ones (#7449)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-07 12:43:45 -04:00
Prowler Bot
611681488d fix(defender): add default resource name in contacts (#7441)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-04 11:49:58 -04:00
Prowler Bot
9630f23585 fix(aws): solve multiple errors (#7440)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-04 10:47:08 -04:00
Prowler Bot
23cfd91708 fix(azure): remove resource_name inside the Check_Report (#7430)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-04-03 12:34:53 -04:00
Prowler Bot
0c44f28bf7 fix(gcp): make logging sink check at project level (#7428)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-03 11:34:03 -04:00
Pepe Fagoaga
09c529d810 chore(release): bump for 5.4.4 (#7427) 2025-04-03 10:19:07 -04:00
Prowler Bot
5be859d86c chore(deletion): Add environment variable for batch size (#7426)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-04-03 15:42:22 +05:45
Prowler Bot
5340008c8f chore(sentry): ignore exception when aws service not available in a region (#7398)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-04-03 13:01:14 +05:45
Prowler Bot
a5aa4c30d7 fix(scans): Handle duplicated scan tasks (#7409)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-04-03 13:00:58 +05:45
Prowler Bot
56d0c2fbea fix(resources): add the correct id and names for resources (#7414)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-01 22:24:33 +02:00
Prowler Bot
6b7ef199e0 fix(report): log as error when Resource ID or Name do not exist (#7412)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-04-01 21:23:16 +02:00
Prowler Bot
933c5063ee fix(redshift): validation error for Cluster.multi_az (#7400)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-03-31 14:51:49 +02:00
Prowler Bot
72a998a692 fix(rds): hundle Certificate rds-ca-2019 not found (#7392)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-03-27 12:04:19 +01:00
Prowler Bot
a4d1e3bb69 fix(stepfunctions): Nonetype object has no attribute level (#7389)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-27 11:09:17 +01:00
Prowler Bot
2a8b04cced fix(fms): resource metadata could not be converted to dict (#7388)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-03-27 09:13:16 +01:00
Prowler Bot
cfc02186d4 fix(vm): handle Nonetype is not iterable for extensions (#7377)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-26 00:31:57 +01:00
Prowler Bot
7e432a3b69 fix(s3): handle None S3 account public access block (#7376)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-25 17:55:54 +01:00
Prowler Bot
fed8de314f fix(storagegateway): describe smb/nfs share per region (#7375)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-25 16:56:25 +01:00
Prowler Bot
ce23c4b5aa fix(network): handle Nonetype is not iterable for security groups (#7372)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-25 15:53:55 +01:00
Prowler Bot
33e99ef628 fix(vm): handle NoneType accessing security_profile (#7373)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-25 14:43:49 +01:00
Prowler Bot
72761a6ef6 fix(iam): handle none SAML Providers (#7371)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-25 11:18:10 +01:00
Prowler Bot
2a4fdff827 fix(iam): handle UnboundLocalError cannot access local variable 'report' (#7370)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-03-25 10:20:49 +01:00
Pepe Fagoaga
8e264313bc chore(release): bump for 5.4.3 2025-03-24 18:08:59 +01:00
Víctor Fernández Poyatos
21654b0bc0 chore: bump API version (#7355) 2025-03-24 20:20:52 +05:45
Prowler Bot
7fa57ba3e2 ref(providers): Refactor provider deletion functions (#7351)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-03-24 19:43:39 +05:45
Prowler Bot
ea9b6bb191 chore(awslambda): update obsolete lambda runtimes (#7345)
Co-authored-by: Jonny <106528116+jonathanbro@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-24 13:18:05 +01:00
Prowler Bot
95acb7b0c8 chore(next): Remove x-powered-by header (#7347)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-03-24 16:44:50 +05:45
Prowler Bot
d23edfa337 chore: upgrade Next.js to 14.2.25 to fix auth middleware vulnerability (#7340)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-03-24 09:52:42 +01:00
Pepe Fagoaga
40678a5863 chore(release): bump for 5.4.2 (#7328) 2025-03-20 18:49:13 +01:00
Prowler Bot
23aded92a3 chore(api): Update CHANGELOG (#7327)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-03-20 15:24:16 +05:45
Prowler Bot
6e56d3862d fix(scan_id): Read the ID from the Scan object (#7326)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-03-20 15:22:57 +05:45
Prowler Bot
d95fccd163 fix(gcp): make provider id mandatory in test_connection (#7315)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-03-19 20:38:37 +05:45
Prowler Bot
7ddf860a55 fix: add a handled response in case local files are missing (#7227)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-03-19 11:58:25 +01:00
Prowler Bot
3f41c75a45 fix(route53): solve false positive in route53_public_hosted_zones_cloudwatch_logging_enabled (#7293)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-03-19 13:39:56 +05:45
Prowler Bot
04b6dbf639 fix(microsoft365): typo Microsoft365NotTenantIdButClientIdAndClienSecretError (#7258)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-03-19 13:38:08 +05:45
Prowler Bot
ff4d16deb5 fix(scan): add compliance info inside finding (#7247)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-03-19 13:37:16 +05:45
Prowler Bot
562921cd5e fix(test-connection): Handle provider without secret (#7290)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-03-19 13:36:38 +05:45
Prowler Bot
8f061e4fed fix(exports): change the way to remove the local export files after s3 upload (#7224)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-03-17 17:30:57 +05:45
Prowler Bot
3fb86d754a fix(cloudwatch): handle None metric alarms (#7207)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-12 16:18:44 +01:00
Prowler Bot
7874707310 chore(sentry): ignore new exceptions in Sentry (#7189)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-12 11:35:32 +01:00
Prowler Bot
1c934e37c7 chore(sentry): ignore expected errors in GCP API (#7186)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-11 17:27:07 +01:00
Prowler Bot
8459cff16d fix(ens): remove and change duplicated ids (#7180)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-03-11 12:46:31 +01:00
Prowler Bot
57ae096395 fix(azure): correct check title for SQL Server Unrestricted (#7160)
Co-authored-by: Gary Mclean <gary.mclean@krrv.io>
2025-03-07 19:22:35 +01:00
Prowler Bot
200185de25 fix(metadata): match type with check results (#7155)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-07 18:16:32 +01:00
Prowler Bot
f8447b0f79 fix(metadata): typo in ec2_securitygroup_allow_wide_open_public_ipv4 (#7158)
Co-authored-by: ryan-stavella <71134114+ryan-stavella@users.noreply.github.com>
2025-03-07 16:32:36 +01:00
Prowler Bot
19289bbe20 fix(aws): ecs_task_definitions_no_environment_secrets.metadata.json (#7153)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-03-07 15:27:59 +01:00
César Arroba
b5b371fa0c chore: increase release to 5.4.1 (#7144)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-07 14:20:28 +01:00
Prowler Bot
939a623cec fix: tweaks for compliance cards (#7148)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-03-07 11:40:55 +01:00
Víctor Fernández Poyatos
926f449ae6 fix(overviews): manage overview exceptions and use batch_size with bulk (#7140) 2025-03-06 15:39:51 +01:00
César Arroba
646668c6ae chore(ui-gha): delete double quotes on prowler version (#7139) 2025-03-06 15:39:40 +01:00
Prowler Bot
8e6b92792b fix(groups): display uid if alias is missing (#7138)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-03-06 14:41:57 +01:00
Prowler Bot
65c081ce38 fix(credentials): adjust helper links to fit width (#7134)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-03-06 13:01:10 +01:00
Pepe Fagoaga
5600131d6a revert(findings): change uid from varchar to text (#7132) 2025-03-06 11:43:07 +01:00
César Arroba
dbd271980f chore(ui-gha): add version prefix (#7125) 2025-03-05 16:34:42 +01:00
Víctor Fernández Poyatos
ff532a899e fix(reports): Fix task kwargs and result (#7124) 2025-03-05 16:34:36 +01:00
César Arroba
0c9675ec70 chore(ui): add prowler version on build (#7120) 2025-03-05 16:34:26 +01:00
Pablo Lara
d45eda2b2b feat(compliance): new compliance selector (#7118) 2025-03-05 16:34:07 +01:00
dependabot[bot]
0abcf80d19 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-05 16:33:35 +01:00
Pablo Lara
c0e10fd395 chore(ui): update label from 'Select a scan job' to 'Select a cloud p… (#7107) 2025-03-05 16:32:20 +01:00
Pepe Fagoaga
a80e9b26a8 chore(api): Use Prowler from v5.4 (#7092) 2025-03-03 22:30:58 +05:45
Sergio Garcia
2a9cd57fb8 fix(deps): update vulnerable cryptography dependency (#6993) 2025-03-03 17:38:23 +01:00
Prowler Bot
a0ad1a5f49 chore(deps): bump cryptography from 43.0.1 to 44.0.1 in /api (#7003)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-03-03 17:21:15 +01:00
César Arroba
dff22dd166 Revert "chore(api): update prowler version to 5.4 (#7091)"
This reverts commit 58138810b9.
2025-03-03 17:11:20 +01:00
César Arroba
58138810b9 chore(api): update prowler version to 5.4 (#7091)
Co-authored-by: Prowler Bot <bot@prowler.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-03-03 17:08:45 +01:00
Víctor Fernández Poyatos
1ecc272fe4 chore: update changelog 2025-03-03 16:27:05 +01:00
Pablo Lara
b784167006 fix(roles): show the correct error message (#7089) 2025-03-03 15:50:28 +01:00
Pablo Lara
cf0ec8dea0 fix: bug with create role and unlimited visibility checkbox (#7088) 2025-03-03 15:50:23 +01:00
Sergio Garcia
96cae5e961 feat(aws): add fixers for threat detection checks (#7085) 2025-03-03 15:50:18 +01:00
Pablo Lara
a48e5cb15f feat(version): add prowler version to the sidebar (#7086) 2025-03-03 15:50:14 +01:00
Pablo Lara
5a9ff007e0 chore: Update the latest table findings with the most recent changes (#7084) 2025-03-03 15:50:06 +01:00
Prowler Bot
24c45f894c chore(regions_update): Changes in regions for AWS services (#7034)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 15:47:09 +01:00
dependabot[bot]
5d03c85629 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-03-03 15:46:15 +01:00
Pablo Lara
41dc397a7a feat(sidebar): sidebar with new functionalities (#7018) 2025-03-03 15:01:38 +01:00
Prowler Bot
237a9adce9 chore(regions_update): Changes in regions for AWS services (#7067)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 15:01:29 +01:00
Sergio Garcia
a06167f1c2 fix(threat detection): run single threat detection check (#7065) 2025-03-03 15:01:21 +01:00
Pepe Fagoaga
a7d58c40dd refactor(stats): Use Finding instead of Check_Report (#7053)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-03-03 15:01:12 +01:00
Pepe Fagoaga
e260c46389 chore(examples): Scan AWS (#7064) 2025-03-03 15:01:02 +01:00
Sergio Garcia
115169a596 chore(gcp): enhance GCP APIs logic (#7046) 2025-03-03 15:00:49 +01:00
dependabot[bot]
5b19173c1d 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-03-03 15:00:40 +01:00
Daniel Barranquero
d3dd1644e6 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-03-03 15:00:29 +01:00
Pedro Martín
8ff0c59964 feat(docs): add info related with sts assume role and regions (#7062) 2025-03-03 15:00:19 +01:00
Daniel Barranquero
285939c389 fix(azure): handle account not supporting Blob (#7060) 2025-03-03 15:00:04 +01:00
Sergio Garcia
a62ae8af51 fix(ecs): ensure unique finding id in ECS checks (#7059) 2025-03-03 14:59:56 +01:00
Prowler Bot
5d78b9e439 chore(regions_update): Changes in regions for AWS services (#7056)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:59:45 +01:00
Hugo Pereira Brito
1056c270ca feat(microsoft365): add new check entra_policy_ensure_default_user_cannot_create_tenants (#6918)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-03 14:59:35 +01:00
Pablo Lara
eeef6600b7 feat(exports): download scan exports (#7006) 2025-03-03 14:59:14 +01:00
Pepe Fagoaga
e142f17abe fix(env): UI version must be stable (#7055) 2025-03-03 14:58:45 +01:00
Víctor Fernández Poyatos
a65d858dac fix(migrations): Fix migration dependency order (#7051) 2025-03-03 14:58:32 +01:00
Víctor Fernández Poyatos
6235a1ba41 feat(labeler): apply label on migration changes (#7052) 2025-03-03 14:58:22 +01:00
Pepe Fagoaga
05007d03ee fix(findings): change uid from varchar to text (#7048) 2025-03-03 14:58:13 +01:00
Víctor Fernández Poyatos
102d099947 feat(findings): Add Django management command to populate database with dummy data (#7049) 2025-03-03 14:58:03 +01:00
Adrián Jesús Peña Rodríguez
3194675a5c feat(export): add API export system (#6878) 2025-03-03 14:57:40 +01:00
dependabot[bot]
14e6e4aa68 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-03-03 14:57:22 +01:00
Pedro Martín
b24c3665b5 feat(aws): add ISO 27001 2022 compliance framework (#7035)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-03-03 14:56:31 +01:00
Prowler Bot
1f60878867 chore(regions_update): Changes in regions for AWS services (#7015)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:54:16 +01:00
dependabot[bot]
2dd18662d8 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-03-03 14:54:02 +01:00
Hugo Pereira Brito
175360dbe6 refactor(microsoft365): CheckReportMicrosoft365 and resource metadata (#6952) 2025-03-03 14:53:42 +01:00
Víctor Fernández Poyatos
80e24b971f feat(findings): Optimize findings endpoint (#7019) 2025-03-03 14:53:22 +01:00
Pepe Fagoaga
78877c470a chore(action): Conventional Commit Check (#7033) 2025-03-03 14:53:08 +01:00
dependabot[bot]
9c9b100359 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-03-03 14:52:51 +01:00
Pedro Martín
10f3232294 feat(outputs): add sample outputs (#6945) 2025-03-03 14:52:37 +01:00
Pedro Martín
a2e5f70f36 fix(cis): show report table on the CLI (#6979) 2025-03-03 14:52:23 +01:00
Pedro Martín
8d8b31c757 feat(azure): add PCI DSS 4.0 (#6982) 2025-03-03 14:52:03 +01:00
Pedro Martín
cba1e718b9 feat(kubernetes): add PCI DSS 4.0 (#7013) 2025-03-03 14:51:42 +01:00
Pedro Martín
6c3c37fc26 feat(dashboard): take the latest finding uid by timestamp (#6987) 2025-03-03 14:51:29 +01:00
Víctor Fernández Poyatos
b610cacd0c feat(tasks): add deletion queue for deletion tasks (#7022) 2025-03-03 14:51:14 +01:00
Pedro Martín
027a5705cb feat(gcp): add PCI DSS 4.0 (#7010) 2025-03-03 14:51:00 +01:00
Prowler Bot
b7fbfb4360 chore(regions_update): Changes in regions for AWS services (#7011)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:50:41 +01:00
dependabot[bot]
5acf0a7e3d 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-03-03 14:50:26 +01:00
Raj Chowdhury
3a25e86e30 fix(typo): solve typo in dashboard.md (#7009) 2025-03-03 14:50:06 +01:00
dependabot[bot]
50f1592eb3 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-03-03 14:49:46 +01:00
César Arroba
0f2927cb88 feat(api): setup sentry for OSS API (#6874) 2025-03-03 14:49:32 +01:00
Pablo Lara
b4e1434052 chore(users): renaming the account now triggers a re-render in the sidebar (#7005) 2025-03-03 14:49:16 +01:00
dependabot[bot]
43710783f9 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-03-03 14:49:04 +01:00
dependabot[bot]
16f767e7b9 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-03-03 14:48:41 +01:00
Hugo Pereira Brito
42818217a0 docs(tutorials): update all deprecated poetry shell references (#7002) 2025-03-03 14:44:50 +01:00
Prowler Bot
13405594b2 chore(regions_update): Changes in regions for AWS services (#6998)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:44:33 +01:00
Pedro Martín
b5a3852334 chore(github): add compliance to PR labeler (#6996) 2025-03-03 14:44:16 +01:00
Hugo Pereira Brito
181ff1acb3 docs(installation): add warning for poetry shell deprecation in README (#6983) 2025-03-03 14:43:35 +01:00
Pablo Lara
91e59a3279 chore(findings): add 'Status Extended' attribute to finding details (#6997) 2025-03-03 14:43:20 +01:00
Pedro Martín
b3fad1a765 feat(aws): add PCI DSS 4.0 (#6949) 2025-03-03 14:42:41 +01:00
dependabot[bot]
6f90927a79 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-03-03 14:42:24 +01:00
dependabot[bot]
0bb4a9a3e9 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-03-03 14:42:10 +01:00
Pablo Lara
80d9cde60b feat(scans): update the progress for executing scans (#6972) 2025-03-03 14:41:39 +01:00
César Arroba
11196c2f83 chore(gha): trigger API or UI deployment when push to master (#6946) 2025-03-03 14:41:21 +01:00
Prowler Bot
55a0d0a1b5 chore(regions_update): Changes in regions for AWS services (#6978) 2025-03-03 14:41:06 +01:00
Pedro Martín
4e5e1d7bd4 feat(aws): add compliance CIS 4.0 (#6937) 2025-03-03 14:40:17 +01:00
dependabot[bot]
06a0a434ab 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-03-03 14:39:58 +01:00
Pepe Fagoaga
153833fc55 fix(ocsf): Adapt for 1.4.0 (#6971) 2025-03-03 14:38:57 +01:00
Prowler Bot
fc4877975f chore(regions_update): Changes in regions for AWS services (#6968)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:38:21 +01:00
dependabot[bot]
0797efd4fd 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-03-03 14:38:07 +01:00
Prowler Bot
fbec99a0b7 chore(regions_update): Changes in regions for AWS services (#6944)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:37:28 +01:00
dependabot[bot]
b2cb1de95e 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-03-03 14:37:06 +01:00
dependabot[bot]
190c2316d7 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-03-03 14:36:16 +01:00
César Arroba
f6c352281a fix(gha): fix short sha step (#6939) 2025-03-03 14:36:00 +01:00
César Arroba
66dfe89936 chore(gha): add tag for api and ui images on push to master (#6920) 2025-03-03 14:35:41 +01:00
dependabot[bot]
8b3942ca49 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-03-03 14:35:06 +01:00
dependabot[bot]
9d35213bd5 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-03-03 14:34:13 +01:00
Víctor Fernández Poyatos
3e586e615d feat(social-login): Add social login integration for Google and Github OAuth providers (#6906) 2025-03-03 14:33:12 +01:00
Sergio Garcia
a4f950e093 chore(docs): external K8s cluster Prowler App credentials (#6921) 2025-03-03 14:32:30 +01:00
Pedro Martín
7c2441f6ff fix(gcp): remove typos on CIS 3.0 (#6917) 2025-03-03 14:31:48 +01:00
dependabot[bot]
0a92af3eb2 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-03-03 14:31:25 +01:00
César Arroba
666f3a0e20 fix(gha): fix test build containers on pull requests actions (#6909) 2025-03-03 14:30:35 +01:00
dependabot[bot]
06ef98b5cc 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-03-03 14:29:39 +01:00
Prowler Bot
79125bdd40 chore(regions_update): Changes in regions for AWS services (#6900)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-03-03 14:28:42 +01:00
César Arroba
e8e8b085ac chore(api): test build container image on pull request (#6850) 2025-03-03 14:28:24 +01:00
César Arroba
c9b81d003a chore(ui): test build container image on pull request (#6849) 2025-03-03 14:27:33 +01:00
Pepe Fagoaga
23fa3c1e38 chore(version): Update version to 5.4.0 (#6894) 2025-03-03 14:26:51 +01:00
dependabot[bot]
03fbd0baca 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-03-03 14:24:50 +01:00
dependabot[bot]
d4fe24ef47 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-03-03 13:05:51 +01:00
Prowler Bot
9c5220ee98 fix(elasticache): improve logic in elasticache_redis_cluster_backup_enabled (#7045)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-26 12:12:44 +01:00
Prowler Bot
6491bce5a6 fix(azure): migrate resource models to avoid using SDK defaults (#7043)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-02-26 10:49:33 +01:00
Prowler Bot
ca375dd79c chore(iam): enhance iam_role_cross_service_confused_deputy_prevention recommendation (#7041)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-26 08:35:26 +01:00
Prowler Bot
e807573b54 fix(soc2_aws): remove duplicated checks (#6999)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-20 17:26:50 +05:30
Prowler Bot
c0f4c9743f fix(deps): update vulnerable cryptography dependency (#6994)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-20 16:04:14 +05:30
Prowler Bot
5974d0b5da fix(report): remove invalid resources in report (#6984)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-20 11:05:58 +05:30
Prowler Bot
6244a8a5f7 fix(roles): handle empty response in deleteRole and ensure revalidation (#6977)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-02-19 09:06:56 +01:00
Prowler Bot
5b9dae4529 test(cloudfront): add name retrieval test for cloudfront bucket domains (#6975)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-19 09:12:17 +05:30
Prowler Bot
a424374c44 fix(cloudfront): Incorrect bucket name retrievement (#6967)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-19 08:08:31 +05:30
Prowler Bot
b7fc2542e8 fix(gcp): Correct false positive when sslMode=ENCRYPTED_ONLY in CloudSQL (#6942)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-02-14 16:36:26 -05:00
Prowler Bot
83a1598a1e fix(issue pages): apply sorting by default in issue pages (#6935)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-02-14 10:35:49 +01:00
Prowler Bot
b22b56a06b fix(gcp): handle DNS Managed Zone with no DNSSEC (#6928)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-13 14:50:05 -05:00
Prowler Bot
5020e4713c fix(aws): codebuild service threw KeyError for projects type CODEPIPELINE (#6930)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-02-13 13:53:05 -05:00
Prowler Bot
ee534a740e fix(aws): SNS threw IndexError if SubscriptionArn is PendingConfirmation (#6923)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-02-13 10:35:19 -05:00
Prowler Bot
48cb45b7a8 fix(aws): handle AccessDenied when retrieving resource policy (#6912)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-12 19:15:51 -05:00
Prowler Bot
91b74822e9 fix(kms): Amazon KMS API call error handling (#6904)
Co-authored-by: Ogonna Iwunze <1915636+wunzeco@users.noreply.github.com>
2025-02-12 11:08:47 -05:00
Pepe Fagoaga
287eef5085 chore(version): Update version to 5.3.1 (#6895) 2025-02-12 16:39:09 +05:45
Mario Rodriguez Lopez
45d359c84a 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 17:18:43 +01:00
Pablo Lara
6049e5d4e8 chore: Update prowler api version (#6877)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-02-10 17:39:08 +05:45
Víctor Fernández Poyatos
dfd377f89e chore(api): Update changelog and specs (#6876) 2025-02-10 12:25:04 +01:00
Víctor Fernández Poyatos
37e6c52c14 chore: Add needed steps for API in PR template (#6875) 2025-02-10 12:24:51 +01:00
Pepe Fagoaga
d6a7f4d88f fix(kubernetes): Change UID validation (#6869)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-10 11:24:34 +01:00
Pepe Fagoaga
239cda0a90 chore: Rename dashboard table latest findings (#6873)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-02-10 11:24:27 +01:00
dependabot[bot]
4a821e425b 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-10 11:24:21 +01:00
Sergio Garcia
e1a2f0c204 docs(eks): add documentation about EKS onboarding (#6853)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-02-10 11:24:16 +01:00
Prowler Bot
c70860c733 chore(regions_update): Changes in regions for AWS services (#6858)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-10 11:24:09 +01:00
Víctor Fernández Poyatos
05e71e033f feat(findings): Use ArrayAgg and subqueries on metadata endpoint (#6863)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-02-10 11:24:03 +01:00
Pablo Lara
5164ec2eb9 feat: implement new functionality with inserted_at__gte in findings a… (#6864) 2025-02-10 11:23:58 +01:00
Víctor Fernández Poyatos
be18dac4f9 docs: Add details about user creation in Prowler app (#6862) 2025-02-10 11:23:52 +01:00
dependabot[bot]
bb126c242f 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-10 11:23:47 +01:00
Víctor Fernández Poyatos
e27780a856 feat(findings): Require date filters for findings endpoints (#6800) 2025-02-10 11:23:41 +01:00
Pranay Girase
196ec51751 fix(typo): typos in Dashboard and Report in HTML (#6847) 2025-02-10 11:23:33 +01:00
Prowler Bot
86abf9e64c chore(regions_update): Changes in regions for AWS services (#6848)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-10 11:23:28 +01:00
dependabot[bot]
9d8be578e3 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-10 11:23:19 +01:00
Mario Rodriguez Lopez
b3aa800082 feat(entra): add new check entra_thirdparty_integrated_apps_not_allowed (#6357)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-10 11:23:13 +01:00
Ogonna Iwunze
501674a778 feat(kms): add kms_cmk_not_multi_region AWS check (#6794)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-10 11:23:01 +01:00
Prowler Bot
5ff6ae79d8 chore(regions_update): Changes in regions for AWS services (#6821)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-02-10 11:21:08 +01:00
Mario Rodriguez Lopez
e518a869ab feat(entra): add new entra service for Microsoft365 (#6326)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-10 11:20:58 +01:00
Mario Rodriguez Lopez
43927a62f3 feat(microsoft365): add new check admincenter_settings_password_never_expire (#6023)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-10 11:20:52 +01:00
dependabot[bot]
335980c8d8 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-10 11:20:42 +01:00
Pablo Lara
ca3ee378db style(forms): improve spacing consistency (#6814) 2025-02-10 11:17:11 +01:00
Pablo Lara
c05bc1068a chore(forms): improvements to the sign-in and sign-up forms (#6813) 2025-02-10 11:17:03 +01:00
Drew Kerrigan
2e3164636d docs(): add description of changed and new delta values to prowler app tutorial (#6801) 2025-02-10 11:16:56 +01:00
dependabot[bot]
c34e07fc40 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-10 11:16:50 +01:00
dependabot[bot]
6022122a61 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-10 11:16:44 +01:00
dependabot[bot]
f65f5e4b46 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-10 11:16:37 +01:00
Pablo Lara
dee17733a0 feat(scans): show scan details right after launch (#6791) 2025-02-10 11:16:30 +01:00
dependabot[bot]
cddda1e64e 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-10 11:16:23 +01:00
dependabot[bot]
f7b873db03 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-10 11:16:17 +01:00
Víctor Fernández Poyatos
792bc70d0a feat(schedules): Rework daily schedule to always show the next scan (#6700) 2025-02-10 11:16:11 +01:00
Hugo Pereira Brito
185491b061 fix: microsoft365 mutelist (#6724) 2025-02-10 11:16:05 +01:00
dependabot[bot]
3af8a43480 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-02-10 11:15:57 +01:00
Pablo Lara
fd78406b29 fix: Enable hot reloading when using Docker Compose for UI (#6750) 2025-02-10 11:15:49 +01:00
Matt Johnson
4758b258a3 chore: Update Google Analytics ID across all docs.prowler.com sites. (#6730) 2025-02-10 11:15:41 +01:00
dependabot[bot]
015e2b3b88 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-02-10 11:15:33 +01:00
Mario Rodriguez Lopez
e184c9cb61 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-02-10 11:15:24 +01:00
dependabot[bot]
9004a01183 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-02-10 11:15:18 +01:00
dependabot[bot]
dd65ba3d9e 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-02-10 11:15:08 +01:00
dependabot[bot]
bba616a18f 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-02-10 11:14:33 +01:00
Pepe Fagoaga
aa0f8d2981 chore: bump for next minor (#6672) 2025-02-10 11:13:42 +01:00
Paolo Frigo
2511d6ffa9 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-02-10 11:12:02 +01:00
Prowler Bot
27329457be fix(dashboard): adjust the bar chart display (#6868)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-07 11:04:23 -05:00
Prowler Bot
7189f3d526 fix(aws): key error for detect-secrets (#6865)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-02-07 10:04:54 -05:00
Prowler Bot
58e7589c9d fix(kms): handle error in DescribeKey function (#6842)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-05 15:27:43 -05:00
Prowler Bot
d60f4b5ded fix(cloudfront): fix false positive in s3 origins (#6838)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-02-05 13:36:49 -05:00
Prowler Bot
4c2ec094f6 fix(findings): Spelling mistakes correction (#6834)
Co-authored-by: Gary Mclean <gary.mclean@krrv.io>
2025-02-05 11:53:17 -05:00
Prowler Bot
395ecaff5b fix(directoryservice): handle ClientException (#6828)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-02-05 11:20:13 -05:00
Prowler Bot
c39506ef7d fix(aws) wording of report.status_extended in awslambda_function_not_publicly_accessible (#6831)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-02-05 11:18:27 -05:00
Prowler Bot
eb90d479e2 chore(aws_audit_manager_control_tower_guardrails): add checks to reqs (#6803)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 19:47:04 -05:00
Prowler Bot
b92a73f5ea fix(elasticache): InvalidReplicationGroupStateFault error (#6820)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-04 16:08:26 -05:00
Prowler Bot
ad121f3059 chore(deps-dev): bump moto from 5.0.27 to 5.0.28 (#6817)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 14:25:04 -05:00
Pepe Fagoaga
70e4c5a44e chore: bump for next patch (#6764) 2025-02-03 15:25:23 -05:00
Prowler Bot
b5a46b7b59 fix(cis_1.5_aws): add checks to needed reqs (#6798)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-03 11:37:53 -05:00
Prowler Bot
f1a97cd166 fix(cis_1.4_aws): add checks to needed reqs (#6796)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-03 11:37:39 -05:00
Prowler Bot
0774508093 fix(cis_2.0_aws): add checks to needed reqs (#6787)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-03 11:37:24 -05:00
Prowler Bot
0664ce6b94 fix(gcp): fix wrong provider value in check (#6789)
Co-authored-by: secretcod3r <101349794+secretcod3r@users.noreply.github.com>
2025-02-03 10:32:53 -05:00
Prowler Bot
407c779c52 fix(findings): remove default status filtering (#6785)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-02-03 15:25:11 +01:00
Prowler Bot
c60f13f23f fix(findings): order findings by inserted_at DESC (#6783)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-02-03 11:57:45 +01:00
Prowler Bot
37d912ef01 fix(celery): Kill celery worker process after every task to release memory (#6763)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-31 19:37:34 +05:45
Pepe Fagoaga
d3de89c017 chore: bump for next patch (#6762) 2025-01-31 19:34:54 +05:45
Prowler Bot
cb22af25c6 fix(db_event): Handle other events (#6757)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-30 21:48:42 +05:45
Prowler Bot
a534b94495 fix(set_report_color): Add more details to error (#6755)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-30 21:46:34 +05:45
Prowler Bot
6262b4ff0b feat(scans): Optimize read queries during scans (#6756)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-30 20:56:11 +05:45
Prowler Bot
84ecd7ab2c feat(findings): Improve /findings/metadata performance (#6749)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-30 18:39:25 +05:45
Prowler Bot
1a5428445a fix(neptune): correct service name (#6747)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-30 17:52:00 +05:45
Prowler Bot
ac8e991ca0 fix(aws): iam_user_with_temporary_credentials resource in OCSF (#6741)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-01-30 17:17:20 +05:45
Prowler Bot
83a0331472 fix(acm): Key Error DomainName (#6744)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-30 17:17:05 +05:45
Prowler Bot
cce31e2971 fix(finding): raise when generating invalid findings (#6745)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-30 17:16:50 +05:45
Prowler Bot
0adf7d6e77 fix(sns): Add region to subscriptions (#6740)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-30 15:46:55 +05:45
Pepe Fagoaga
295f8b557e chore: bump for next patch (#6727) 2025-01-29 20:00:47 +05:45
Prowler Bot
bb2c5c3161 fix(scans): change label for next scan (#6726)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-29 10:49:35 +01:00
Prowler Bot
0018f36a36 fix(migrations): Use indexes instead of constraints to define an index (#6723)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-29 14:29:03 +05:45
Prowler Bot
857de84f49 fix(defender): add field to SecurityContacts (#6715)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-01-29 13:53:14 +05:45
Prowler Bot
9630f2242a revert: Update Django DB manager to use psycopg3 and connection pooling (#6719)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-28 22:33:32 +05:45
Prowler Bot
1fe125867c fix(scan-summaries): Improve efficiency on providers overview (#6718)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-28 22:15:22 +05:45
Prowler Bot
0737893240 fix(scans): filters and sorting for scan table (#6714)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-28 13:29:39 +01:00
Prowler Bot
282fe3d348 fix(scans, findings): Improve API performance ordering by inserted_at instead of id (#6712)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-28 17:28:26 +05:45
Prowler Bot
b5d83640ae fix: fixed bug when opening finding details while a scan is in progress (#6709)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-28 07:01:43 +01:00
Prowler Bot
2823d3ad21 fix(cloudsql): add trusted client certificates case for cloudsql_instance_ssl_connections (#6687)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-24 12:19:05 -05:00
Prowler Bot
00b93bfe86 fix(cloudwatch): NoneType object is not iterable (#6677)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-01-23 13:25:02 -05:00
Pepe Fagoaga
84c253d887 chore: bump for next patch (#6673) 2025-01-23 13:13:05 -05:00
Pepe Fagoaga
2ab5a702c9 chore(api): Bump to v1.3.0 (#6670) 2025-01-23 16:40:59 +01:00
Sergio Garcia
11d9cdf24e 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:08:13 +01:00
Rubén De la Torre Vico
b1de41619b fix: add missing Check_Report_Azure parameters (#6583) 2025-01-23 16:07:23 +01:00
Rubén De la Torre Vico
18a4881a51 feat(network): extract Network resource metadata automated (#6555)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-23 16:06:44 +01:00
Rubén De la Torre Vico
de76a168c0 feat(storage): extract Storage resource metadata automated (#6563)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-23 16:06:40 +01:00
Rubén De la Torre Vico
bcc13a742d feat(vm): extract VM resource metadata automated (#6564) 2025-01-23 16:06:32 +01:00
Rubén De la Torre Vico
23b584f4bf feat(sqlserver): extract SQL Server resource metadata automated (#6562) 2025-01-23 16:06:25 +01:00
Daniel Barranquero
074b7c1ff5 feat(aws): include resource metadata to remaining checks (#6551)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-23 16:06:18 +01:00
Rubén De la Torre Vico
c04e9ed914 feat(postgresql): extract PostgreSQL resource metadata automated (#6560) 2025-01-23 16:06:11 +01:00
Rubén De la Torre Vico
1f1b126e79 feat(policy): extract Policy resource metadata automated (#6558) 2025-01-23 16:06:06 +01:00
Rubén De la Torre Vico
9b0dd80f13 feat(entra): extract Entra resource metadata automated (#6542)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-23 16:06:01 +01:00
Rubén De la Torre Vico
b0807478f2 feat(monitor): extract monitor resource metadata automated (#6554)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-23 16:05:54 +01:00
Rubén De la Torre Vico
11dfa58ecd feat(mysql): extract MySQL resource metadata automated (#6556) 2025-01-23 16:05:48 +01:00
Rubén De la Torre Vico
412f396e0a feat(keyvault): extract KeyVault resource metadata automated (#6553) 2025-01-23 16:05:44 +01:00
Rubén De la Torre Vico
8100d43ff2 feat(iam): extract IAM resource metadata automated (#6552) 2025-01-23 16:05:38 +01:00
Sergio Garcia
bc96acef48 fix(gcp): iterate through service projects (#6549)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2025-01-23 16:05:24 +01:00
Hugo Pereira Brito
6e9876b61a feat(aws): include resource metadata in services from r* to s* (#6536)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-23 16:05:17 +01:00
Pedro Martín
32253ca4f7 feat(gcp): add resource metadata to report (#6500)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-23 16:05:08 +01:00
Hugo Pereira Brito
4c6be5e283 feat(aws): include resource metadata in services from a* to b* (#6504)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-23 16:05:03 +01:00
Daniel Barranquero
69178fd7bd chore(aws): add resource metadata to services from t to w (#6546) 2025-01-23 16:04:49 +01:00
Daniel Barranquero
cd4432c14b chore(aws): add resource metadata to services from f to o (#6545) 2025-01-23 16:04:40 +01:00
Rubén De la Torre Vico
0e47172aec feat(defender): extract Defender resource metadata in automated way (#6538) 2025-01-23 16:04:30 +01:00
Rubén De la Torre Vico
efe18ae8b2 feat(appinsights): extract App Insights resource metadata in automated way (#6540) 2025-01-23 16:04:18 +01:00
Hugo Pereira Brito
d5e13df4fe feat: add resource metadata to emr_cluster_account_public_block_enabled (#6539) 2025-01-23 16:04:13 +01:00
Sergio Garcia
b0e84d74f2 feat(kubernetes): add resource metadata to report (#6479) 2025-01-23 16:04:05 +01:00
Hugo Pereira Brito
28526b591c feat(aws): include resource metadata in services from d* to e* (#6532)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-23 16:03:59 +01:00
Daniel Barranquero
51e6a6edb1 feat(aws): add resource metadata to all services starting with c (#6493) 2025-01-23 16:03:50 +01:00
Rubén De la Torre Vico
c1b132a29e feat(cosmosdb): extract CosmosDB resource metadata in automated way (#6533) 2025-01-23 16:03:43 +01:00
Rubén De la Torre Vico
e2530e7d57 feat(containerregistry): extract Container Registry resource metadata in automated way (#6530) 2025-01-23 16:03:37 +01:00
Rubén De la Torre Vico
f2fcb1599b feat(azure-app): extract Web App resource metadata in automated way (#6529) 2025-01-23 16:03:32 +01:00
Rubén De la Torre Vico
160eafa0c9 feat(aks): use Check_Report_Azure constructor properly in AKS checks (#6509) 2025-01-23 16:03:17 +01:00
Rubén De la Torre Vico
c2bc0f1368 feat(aisearch): use Check_Report_Azure constructor properly in AISearch checks (#6506) 2025-01-23 16:03:10 +01:00
Rubén De la Torre Vico
27d27fff81 feat(azure): include resource metadata in Check_Report_Azure (#6505) 2025-01-23 16:02:00 +01:00
Pepe Fagoaga
66e8f0ce18 chore(scan): Remove ._findings (#6667) 2025-01-23 15:58:37 +01:00
Pedro Martín
0ceae8361b feat(kubernetes): add CIS 1.10 compliance (#6508)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
# Conflicts:
#	prowler/compliance/kubernetes/cis_1.10_kubernetes.json
2025-01-23 15:39:40 +01:00
Pedro Martín
5e52fded83 feat(azure): add CIS 3.0 for Azure (#5226)
# Conflicts:
#	prowler/compliance/azure/cis_3.0_azure.json
2025-01-23 15:35:35 +01:00
Pablo Lara
0a7d07b4b6 chore: adjust DateWithTime component height when used with InfoField (#6669) 2025-01-23 15:21:42 +01:00
Pablo Lara
34b5f483d7 chore(scans): improve scan details (#6665) 2025-01-23 14:16:35 +01:00
Pedro Martín
9d04a1bc52 feat(detect-secrets): get secrets plugins from config.yaml (#6544)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-23 14:16:15 +01:00
dependabot[bot]
b25c0aaa00 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-23 14:16:03 +01:00
dependabot[bot]
652b93ea45 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-23 14:15:54 +01:00
Pepe Fagoaga
ccb7726511 fix(templates): Customize principals and add validation (#6655) 2025-01-23 14:15:41 +01:00
Anton Rubets
c514a4e451 chore(helm): Add prowler helm support (#6580)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-23 14:15:33 +01:00
Prowler Bot
d841bd6890 chore(regions_update): Changes in regions for AWS services (#6652)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-23 14:15:24 +01:00
dependabot[bot]
ff54e10ab2 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-23 14:15:03 +01:00
Pepe Fagoaga
718e562741 chore(pre-commit): poetry checks for API and SDK (#6658) 2025-01-23 14:14:10 +01:00
Pablo Lara
ce05e2a939 feat(providers): show the cloud formation and terraform template links on the form (#6660) 2025-01-23 14:13:37 +01:00
Pablo Lara
90831d3084 feat(providers): make external id field mandatory in the aws role secret form (#6656) 2025-01-23 14:13:30 +01:00
dependabot[bot]
2c928dead5 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-23 14:13:23 +01:00
dependabot[bot]
3ffe147664 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-23 14:13:04 +01:00
dependabot[bot]
3373b0f47c 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-23 14:12:52 +01:00
Prowler Bot
b29db04560 chore(regions_update): Changes in regions for AWS services (#6599)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-23 14:12:38 +01:00
Hugo Pereira Brito
f964a0362e chore(services): delete all comment headers (#6585) 2025-01-23 14:11:58 +01:00
Prowler Bot
537b23dfae chore(regions_update): Changes in regions for AWS services (#6577)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-23 14:11:46 +01:00
Pablo Lara
48cf3528b4 feat(findings): add first seen in findings details (#6575) 2025-01-23 14:11:08 +01:00
dependabot[bot]
3c4b9d32c9 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-23 14:09:46 +01:00
Víctor Fernández Poyatos
fd8361ae2c feat(db): Update Django DB manager to use psycopg3 and connection pooling (#6541)
# Conflicts:
#	api/poetry.lock
#	api/pyproject.toml
2025-01-23 14:07:34 +01:00
Prowler Bot
33cadaa932 chore(regions_update): Changes in regions for AWS services (#6526)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-23 14:02:14 +01:00
dependabot[bot]
cc126eb8b4 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-23 14:02:07 +01:00
Pedro Martín
c996b3f6aa docs(readme): update pr template to add check for readme (#6531) 2025-01-23 14:01:53 +01:00
Adrián Jesús Peña Rodríguez
e2b406a300 feat(finding): add first_seen attribute (#6460) 2025-01-23 14:01:46 +01:00
dependabot[bot]
c2c69da603 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>
# Conflicts:
#	api/poetry.lock
2025-01-23 14:01:33 +01:00
Adrián Jesús Peña Rodríguez
4e51348ff2 feat(provider-secret): make existing external_id field mandatory (#6510) 2025-01-23 14:00:42 +01:00
dependabot[bot]
3257b82706 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-23 13:59:26 +01:00
Pepe Fagoaga
c98d764daa chore(version): set next minor (#6511)
# Conflicts:
#	prowler/config/config.py
#	pyproject.toml
2025-01-23 13:57:20 +01:00
Prowler Bot
0448429a9f 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-23 13:56:43 +01:00
Pepe Fagoaga
b948ac6125 feat(prowler-role): Add templates to deploy it in AWS (#6499) 2025-01-23 13:56:28 +01:00
dependabot[bot]
3acc09ea16 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-23 13:56:09 +01:00
dependabot[bot]
82d0d0de9d 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-23 13:56:00 +01:00
Prowler Bot
f9cfc4d087 fix: add detector and line number of potential secret (#6663)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-01-22 10:55:49 -05:00
Pepe Fagoaga
7d68ff455b chore(api): Use prowler from v5.1 (#6659) 2025-01-22 20:04:55 +05:45
Pepe Fagoaga
ddf4881971 chore(version): Update version to 5.1.6 (#6645) 2025-01-21 13:28:44 -05:00
Prowler Bot
9ad4944142 fix(filters): fix dynamic filters (#6643)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-21 13:40:18 +01:00
Prowler Bot
7f33ea76a4 fix(OCSF): fix OCSF output when timestamp is UNIX format (#6627)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-20 18:03:51 -05:00
Prowler Bot
1140c29384 fix(aws): list tags for DocumentDB clusters (#6622)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-01-20 17:22:06 -05:00
Prowler Bot
2441a62f39 fix: update Azure CIS with existing App checks (#6625)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-20 16:27:14 -05:00
Pepe Fagoaga
c26a231fc1 chore(version): Update version to 5.1.5 (#6618) 2025-01-20 15:07:58 -05:00
Prowler Bot
2fb2315037 chore(RBAC): add permission's info (#6617)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-20 17:31:52 +01:00
Prowler Bot
a9e475481a fix(snippet-id): improve provider ID readability in tables (#6616)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-20 17:28:04 +01:00
Prowler Bot
826d7c4dc3 fix(rbac): remove invalid required permission (#6614)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-01-20 17:02:31 +01:00
Prowler Bot
b7f4b37f66 feat(api): restrict the deletion of users, only the user of the request can be deleted (#6613)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
2025-01-20 17:02:21 +01:00
Prowler Bot
193d691bfe fix(RBAC): tweaks for edit role form (#6610)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-20 14:12:43 +01:00
Prowler Bot
a359bc581c fix(RBAC): restore manage_account permission for roles (#6603)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-20 11:53:08 +01:00
Prowler Bot
9a28ff025a fix(sqs): fix flaky test (#6595)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-01-17 12:40:11 -05:00
Prowler Bot
f1c7050700 fix(apigatewayv2): managed exception NotFoundException (#6590)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-01-17 09:27:19 -05:00
Pepe Fagoaga
9391c27b9e chore(version): Update version to 5.1.4 (#6591) 2025-01-17 09:25:35 -05:00
Prowler Bot
4c54de092f feat(findings): Add resource_tag filters for findings endpoint (#6587)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-17 19:01:51 +05:45
Prowler Bot
690c482a43 fix(gcp): fix flaky tests from dns service (#6571)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-01-17 08:15:34 -05:00
Prowler Bot
ad2d857c6f feat(findings): add /findings/metadata to retrieve dynamic filters information (#6586)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-17 18:47:59 +05:45
Pepe Fagoaga
07ee59d2ef chore(version): Update version to 5.1.3 (#6584) 2025-01-17 18:46:08 +05:45
Prowler Bot
bec4617d0a fix(providers): update the label and placeholder based on the cloud provider (#6582)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-17 12:33:25 +01:00
Prowler Bot
94916f8305 fix(findings): remove filter delta_in applied by default (#6579)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-17 11:06:07 +01:00
Prowler Bot
44de651be3 fix(cis): add subsections if needed (#6568)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-01-16 14:49:49 -05:00
Prowler Bot
bdcba9c642 fix(detect_secrets): refactor logic for detect-secrets (#6566)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-01-16 13:07:18 -05:00
Prowler Bot
c172f75f1a fix(dep): address compatibility issues (#6557)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-16 14:35:06 +01:00
Prowler Bot
ec492fa13a feat(filters): add resource type filter for findings (#6525)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
2025-01-15 08:43:49 +01:00
Prowler Bot
702659959c fix(Azure TDE): add filter for master DB (#6514)
Co-authored-by: johannes-engler-mw <132657752+johannes-engler-mw@users.noreply.github.com>
2025-01-14 15:25:27 -05:00
Pepe Fagoaga
fef332a591 chore(version): set next fixes 2025-01-14 18:05:04 +01:00
Pablo Lara
a65ca72177 chore(groups): Enable updating groups without roles or providers (#6498) 2025-01-14 11:16:13 +01:00
Pablo Lara
1108d90768 chore(roles): prevent capitalization of provider groups and roles (#6497) 2025-01-14 10:41:08 +01:00
Adrián Jesús Peña Rodríguez
6715aa351f fix(rbac): block admin role deletion (#6470) 2025-01-14 10:27:41 +01:00
dependabot[bot]
851497eb0a chore(deps): bump @radix-ui/react-slot from 1.1.0 to 1.1.1 in /ui (#6481)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 10:25:14 +01:00
dependabot[bot]
3bb4663e3e chore(deps-dev): bump eslint-plugin-import from 2.29.1 to 2.31.0 in /ui (#6482)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 10:24:31 +01:00
Pablo Lara
6953fcf6b5 chore(rbac): tweaks role permissions (#6496) 2025-01-14 10:23:23 +01:00
Adrián Jesús Peña Rodríguez
ab844eee3f ref(rbac): disable some checks (#6471) 2025-01-14 09:33:15 +01:00
Pedro Martín
708e06aa3b fix(iso27001-2013): add ReqId and ReqDescription in output (#6405) 2025-01-13 13:14:09 -05:00
Prowler Bot
aa8b8bbcae chore(regions_update): Changes in regions for AWS services (#6459)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-13 12:41:11 -05:00
Pablo Lara
0ce1e15c2c styles(invitations): tweak styles for invitation details box (#6475) 2025-01-13 18:32:33 +01:00
Pablo Lara
105a83d946 fix(invitation): correct the URL used to share an invitation (#6472) 2025-01-13 17:27:10 +01:00
Pedro Martín
e9a885a54d feat(compliance): add CIS 3.0 for gcp (#6463) 2025-01-13 10:59:53 -05:00
Pablo Lara
0a8759ee06 chore(manage-groups): tweaks for provider manage groups (#6468) 2025-01-13 16:39:14 +01:00
Prowler Bot
33ec21bbac chore(regions_update): Changes in regions for AWS services (#6458)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-13 10:37:43 -05:00
dependabot[bot]
7c00f65ecc chore(deps): bump @radix-ui/react-toast from 1.2.1 to 1.2.4 in /ui (#6445)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 15:55:56 +01:00
Rubén De la Torre Vico
7777c8f135 fix(vpc): add new principal wildcard verification (#6461) 2025-01-13 09:49:10 -05:00
dependabot[bot]
2386490002 chore(deps-dev): bump openapi-schema-validator from 0.6.2 to 0.6.3 (#6454)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 09:36:31 -05:00
Pepe Fagoaga
b620f12027 chore(rls): Add tenant_id filters in views and improve querysets (#6211)
Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2025-01-13 11:37:40 +01:00
Rubén De la Torre Vico
00722181ad docs(azure): improve tutorials for Prowler App (#6210) 2025-01-13 09:59:58 +01:00
Sergio Garcia
15e888a939 feat(ec2): include resource metadata in Check_Report (#6440) 2025-01-13 13:04:55 +05:45
dependabot[bot]
43fa600f1c chore(deps): bump date-fns from 3.6.0 to 4.1.0 in /ui (#6444)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-11 08:35:18 +01:00
dependabot[bot]
2e4b5399c9 chore(deps): bump lucide-react from 0.417.0 to 0.471.0 in /ui (#6456)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-11 08:34:47 +01:00
Prowler Bot
62cbb442e8 chore(regions_update): Changes in regions for AWS services (#6448)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-10 11:36:43 -05:00
Pedro Martín
b0fe696935 refactor(mutelist): use jsonschema on mutelist (#6264) 2025-01-10 20:04:20 +05:45
Matt Johnson
42dbefbb31 feat: New gen-ai category for all relevant checks. (#6450) 2025-01-10 08:57:20 -05:00
Daniel Barranquero
f3dbe28681 fix(codeartifact): fix flaky tests (#6449) 2025-01-10 18:16:00 +05:45
Pedro Martín
6a5f1a7839 docs(integrations): add integrations docs (#6269) 2025-01-10 17:00:20 +05:45
Pedro Martín
3b70f9fed4 docs(outputs): add custom outputs formats documentation (#6386) 2025-01-10 16:54:50 +05:45
dependabot[bot]
7eb01aaa5c chore(deps-dev): bump safety from 3.2.3 to 3.2.9 in /api (#6431)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 16:31:19 +05:45
dependabot[bot]
1e27e52fba chore(deps-dev): bump vulture from 2.11 to 2.14 in /api (#6426)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 15:14:55 +05:45
dependabot[bot]
16d73619e4 chore(deps): bump boto3 from 1.35.93 to 1.35.94 (#6410)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 19:29:59 -05:00
dependabot[bot]
bc82696f15 chore(deps): bump google-api-python-client from 2.157.0 to 2.158.0 (#6442)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 18:16:23 -05:00
dependabot[bot]
fdb90623fc chore(deps): bump trufflesecurity/trufflehog from 3.88.1 to 3.88.2 (#6446)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 17:52:12 -05:00
Prowler Bot
5fa62a9770 chore(regions_update): Changes in regions for AWS services (#6399)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-09 14:57:30 -05:00
Pablo Lara
8f3df7e45d fix(BC: NextUI): fix BC from NextUI, resolve ESLint warnings and optimize hooks dependencies (#6404) 2025-01-09 17:37:33 +01:00
dependabot[bot]
bb417587ae chore(deps-dev): bump @iconify/react from 5.0.1 to 5.2.0 in /ui (#6421)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 17:05:11 +01:00
dependabot[bot]
6b6e12cea3 chore(deps): bump jinja2 from 3.1.4 to 3.1.5 in /api (#6316)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 20:39:02 +05:45
Pepe Fagoaga
65e70b2ca4 chore(dependabot): Review for API and UI (#6402) 2025-01-09 20:28:26 +05:45
Pepe Fagoaga
94d25f6f6a chore(containers): Build stable for API and UI (#6395) 2025-01-09 20:24:57 +05:45
Sergio Garcia
4bcf036831 fix(iam): handle non existing MFA devices (#6396) 2025-01-09 09:23:05 -05:00
dependabot[bot]
901bc69a7d chore(deps): bump django from 5.1.1 to 5.1.4 in /api (#6376)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 13:36:58 +01:00
Adrián Jesús Peña Rodríguez
465217442b fix(api): change the inserted_at.lte unittest (#6403) 2025-01-09 13:12:55 +01:00
Pablo Lara
e6b40358aa feat(update-credentials): add explanation text for the current behavior (#6400) 2025-01-09 11:13:36 +01:00
Daniel Barranquero
9d48f7286a fix(cloudformation): fix flaky tests (#6398) 2025-01-09 15:30:11 +05:45
Prowler Bot
80311d3837 chore(regions_update): Changes in regions for AWS services (#6390)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-08 12:28:24 -05:00
Pedro Martín
f501149068 fix(pre-commit): add api needed excludes (#6393) 2025-01-08 16:34:55 +01:00
dependabot[bot]
750de62828 chore(deps): bump botocore from 1.35.93 to 1.35.94 (#6388)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-08 10:32:34 -05:00
Pablo Lara
d2f338ceb6 feat(scans): add new component - alert bar 2025-01-08 11:01:52 +01:00
dependabot[bot]
e8d66979b3 chore(deps): bump azure-mgmt-network from 28.0.0 to 28.1.0 (#6296)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 16:09:53 -05:00
Sergio Garcia
b5180389f8 feat(aws): add new check cloudformation_stack_cdktoolkit_bootstrap_version (#6323) 2025-01-07 14:52:55 -05:00
dependabot[bot]
fbd5235e15 chore(deps): bump msgraph-sdk from 1.15.0 to 1.16.0 (#6350)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 13:56:02 -05:00
dependabot[bot]
afd2267c26 chore(deps): bump microsoft-kiota-abstractions from 1.6.7 to 1.6.8 (#6347)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 11:40:57 -05:00
dependabot[bot]
9e798ababd chore(deps): bump google-api-python-client from 2.156.0 to 2.157.0 (#6349)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 10:40:20 -05:00
Prowler Bot
e9f2fc8ee1 chore(regions_update): Changes in regions for AWS services (#6382)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-07 10:11:24 -05:00
dependabot[bot]
12198b4f06 chore(deps): bump boto3 from 1.35.87 to 1.35.93 (#6381)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 09:20:20 -05:00
Adrián Jesús Peña Rodríguez
15fae4d8f8 fix(ci): move poetry deprecated command to new one (#6384) 2025-01-07 12:38:33 +01:00
dependabot[bot]
3de3fed858 chore(deps): bump next from 14.2.12 to 14.2.22 in /ui (#6356)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 12:29:06 +01:00
dependabot[bot]
1bf4255d93 chore(deps): bump cookie and next-auth in /ui (#5880)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2025-01-07 12:03:45 +01:00
dependabot[bot]
b91a132e61 chore(deps): bump azure-mgmt-compute from 33.0.0 to 33.1.0 (#6219)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 12:02:47 +01:00
dependabot[bot]
39302c9e93 chore(deps): bump botocore from 1.35.88 to 1.35.93 (#6373)
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-06 22:59:41 -05:00
dependabot[bot]
65e21c4268 chore(deps): bump trufflesecurity/trufflehog from 3.88.0 to 3.88.1 (#6372)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 18:06:28 -05:00
Rubén De la Torre Vico
3d6a6a9fec fix(aws): add missing sqs service without subservice (#6352) 2025-01-06 12:48:18 -05:00
Rubén De la Torre Vico
d185902c86 docs: add new format CloudFormation for ResourceType in check metadata (#6353)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-06 10:25:00 -05:00
Prowler Bot
8ce4ad83ed chore(regions_update): Changes in regions for AWS services (#6329)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2025-01-06 10:16:57 -05:00
dependabot[bot]
89620a96bc chore(deps): bump botocore from 1.35.87 to 1.35.88 (#6321)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-27 12:21:12 -05:00
dependabot[bot]
f1c008f934 chore(deps-dev): bump coverage from 7.6.9 to 7.6.10 (#6322)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-27 09:59:40 -05:00
dependabot[bot]
4d688c9b47 chore(deps): bump boto3 from 1.35.85 to 1.35.87 (#6320)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 19:01:01 -05:00
dependabot[bot]
db5481cc9c chore(deps-dev): bump pylint from 3.3.2 to 3.3.3 (#6317)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 13:50:20 -05:00
dependabot[bot]
ce9a5e6484 chore(deps): bump botocore from 1.35.85 to 1.35.87 (#6307)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 09:18:02 -05:00
Víctor Fernández Poyatos
550165b42b feat(compliance): generate compliance reports for GCP scans using API (#6318) 2024-12-26 13:31:20 +01:00
Prowler Bot
080551132a chore(regions_update): Changes in regions for AWS services (#6299)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-23 08:35:48 -05:00
dependabot[bot]
0a61848365 chore(deps): bump boto3 from 1.35.83 to 1.35.85 (#6295)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-23 07:41:45 -05:00
dependabot[bot]
fcb9ca7795 chore(deps): bump trufflesecurity/trufflehog from 3.87.2 to 3.88.0 (#6298)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-23 07:41:23 -05:00
Víctor Fernández Poyatos
71c58cee9e fix(migrations): fix django migration order dependency (#6302) 2024-12-23 12:26:00 +01:00
Sergio Garcia
c811b6715d fix(gha): run API and UI tests in correct versions (#6294) 2024-12-23 11:47:51 +01:00
Kay Agahd
231829d8cd fix(aws): disallow child-accounts to overwrite policy for ai_services_opt_out (#6229)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-20 11:04:42 -05:00
dependabot[bot]
dbd2f8becb chore(deps): bump botocore from 1.35.83 to 1.35.85 (#6276)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-20 09:47:05 -05:00
Prowler Bot
cc04e6614e chore(regions_update): Changes in regions for AWS services (#6282)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-20 09:46:55 -05:00
Pablo Lara
a5c5ed614c chore(menu): add API reference link to the sidebar (#6287) 2024-12-20 15:04:29 +01:00
Víctor Fernández Poyatos
ea13241317 fix(users): fix /users/me behavior when having more than 1 users in the same tenant (#6284) 2024-12-20 09:01:23 -05:00
Sergio Garcia
a377a9ff6a chore(gha): solve pypi release github action (#6278) 2024-12-20 08:57:29 -05:00
Víctor Fernández Poyatos
f7e510b333 fix(db-utils): fix batch_delete function (#6283) 2024-12-20 08:55:21 -05:00
Pablo Lara
4472b80f1c chore(findings): remove delta new as filter by default in findings (#6280) 2024-12-20 09:36:01 +01:00
dependabot[bot]
577eb3eec9 chore(deps): bump msgraph-sdk from 1.14.0 to 1.15.0 (#6250)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-20 09:34:46 +01:00
dependabot[bot]
1ed6a1a40f chore(deps): bump trufflesecurity/trufflehog from 3.87.1 to 3.87.2 (#6279)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 17:51:41 -05:00
Sergio Garcia
fe4cd1cddf fix(aws): add missing region to Backup Recovery Point (#6273) 2024-12-19 16:08:22 -05:00
Pablo Lara
6d7a8c8130 feat(roles): RBAC functionality (#6201) 2024-12-19 18:35:10 +01:00
dependabot[bot]
3057aeeacf chore(deps): bump slack-sdk from 3.33.5 to 3.34.0 (#6254)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 12:27:35 -05:00
Sergio Garcia
bb5b63f62f fix(aws): solve None type errors (#6268) 2024-12-19 11:32:33 -05:00
Prowler Bot
58cd944618 chore(regions_update): Changes in regions for AWS services (#6262)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-19 10:05:09 -05:00
Daniel Barranquero
5964b68c86 feat(codeartifact): add new fixer codeartifact_packages_external_public_publishing_disabled_fixer (#6263) 2024-12-19 10:05:01 -05:00
Pepe Fagoaga
c87aaeba04 chore(api): Use prowler ^5.0 (#6266) 2024-12-19 09:40:51 -05:00
dependabot[bot]
6e361005dc chore(deps): bump trufflesecurity/trufflehog from 3.87.0 to 3.87.1 (#6249)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 09:02:44 -05:00
dependabot[bot]
f5ab254bc5 chore(deps): bump microsoft-kiota-abstractions from 1.6.6 to 1.6.7 (#6233)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 09:02:01 -05:00
dependabot[bot]
298392b409 chore(deps): bump google-api-python-client from 2.155.0 to 2.156.0 (#6252)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 11:10:10 +01:00
Twodragon
74a2bf0721 feat(prowler-docker): Run Prowler docker with AWS SSO (#5867)
Co-authored-by: twodragon114 <twodragon114@gmail.com>
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2024-12-19 10:55:15 +01:00
dependabot[bot]
ddc5dc0316 chore(deps): bump boto3 from 1.35.81 to 1.35.83 (#6253)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 09:45:16 +01:00
Pepe Fagoaga
d3af947553 fix(gha): make conditional job for checking the repo (#6255) 2024-12-19 14:19:41 +05:45
Pepe Fagoaga
36bb2509ac docs: add note about platform flag in docker (#6256) 2024-12-19 14:18:16 +05:45
Pepe Fagoaga
e4c2b0c2d3 chore: skip action on .env changes (#6257) 2024-12-19 14:17:56 +05:45
Víctor Fernández Poyatos
ac5260ad43 feat(celery): Add configurable broker visibility timeout setting (#6245) 2024-12-19 00:03:11 +05:45
Adrián Jesús Peña Rodríguez
33857109c9 ref(rbac): enable relationship creation when objects is created (#6238) 2024-12-18 16:45:32 +01:00
Pepe Fagoaga
8cc8f76204 fix(.env): remove comment (#6230) 2024-12-18 20:36:03 +05:45
Pedro Martín
8f3229928e chore(config): set default values for empty config fields (#6225) 2024-12-18 09:48:32 -05:00
Pedro Martín
2551992fd8 fix(docs): change typo from provideruid in k8s (#6239)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-18 09:02:44 -05:00
Prowler Bot
eb1decfce1 chore(regions_update): Changes in regions for AWS services (#6237)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-18 08:51:22 -05:00
Pepe Fagoaga
fd5e7b809f docs: add note about containers arch (#6236) 2024-12-18 11:09:35 +01:00
dependabot[bot]
1ac681226d chore(deps): bump botocore from 1.35.81 to 1.35.83 (#6232)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 18:52:46 -05:00
dependabot[bot]
366940298d chore(deps): bump trufflesecurity/trufflehog from 3.86.1 to 3.87.0 (#6234)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 18:51:32 -05:00
Adrián Jesús Peña Rodríguez
fa400ded7d ref(rbac): improve rbac implementation for views (#6226) 2024-12-17 18:11:48 +01:00
dependabot[bot]
ec9455ff75 chore(deps): bump boto3 from 1.35.80 to 1.35.81 (#6218)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 11:32:30 -05:00
Daniel Barranquero
2183f31ff5 feat(ec2): add new fixers for internet exposed ports (#6223) 2024-12-17 10:04:00 -05:00
Prowler Bot
67257a4212 chore(regions_update): Changes in regions for AWS services (#6222)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-17 10:00:52 -05:00
Pedro Martín
001fa60a11 feat(mutelist): add description field (#6221)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-12-17 15:13:55 +01:00
Víctor Fernández Poyatos
0ec3ed8be7 feat(services): Add GET /overviews/services to API (#6029) 2024-12-17 08:47:44 +01:00
dependabot[bot]
3ed0b8a464 chore(deps-dev): bump mkdocs-material from 9.5.48 to 9.5.49 (#6217)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 08:42:55 +01:00
Pedro Martín
fd610d44c0 refactor(gcp): use always <client>.region for checks (#6206) 2024-12-16 18:21:42 -05:00
Adrián Jesús Peña Rodríguez
b8cc4b4f0f feat(stepfunctions): add stepfunctions service and check stepfunctions_statemachine_logging_enabled (#5466)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-12-16 11:34:02 -05:00
Pedro Martín
396e51c27d feat(gcp): add service account credentials (#6165) 2024-12-16 10:11:32 -05:00
Daniel Barranquero
36e61cb7a2 feat(ec2): add new fixer ec2_ami_public_fixer (#6177) 2024-12-16 10:09:14 -05:00
Daniel Barranquero
78c6484ddb feat(cloudtrail): add new fixer cloudtrail_logs_s3_bucket_is_not_publicly_accessible_fixer (#6174) 2024-12-16 10:05:34 -05:00
Daniel Barranquero
3f1e90a5b3 feat(s3): add new fixer s3_bucket_policy_public_write_access_fixer (#6173) 2024-12-16 10:01:38 -05:00
dependabot[bot]
e1bfec898f chore(deps): bump botocore from 1.35.80 to 1.35.81 (#6199)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 09:57:03 -05:00
dependabot[bot]
b5b816dac9 chore(deps): bump boto3 from 1.35.79 to 1.35.80 (#6198)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 07:51:44 -05:00
Pepe Fagoaga
57854f23b7 chore(rls): rename tenant_transaction to rls_transaction (#6202) 2024-12-16 12:27:55 +01:00
Rubén De la Torre Vico
9d7499b74f fix(azure): custom Prowler Role for Azure assignableScopes (#6149) 2024-12-16 08:34:17 +01:00
dependabot[bot]
5b0b85c0f8 chore(deps): bump actions/setup-node from 3 to 4 (#5893)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 14:57:27 +01:00
Pedro Martín
f7e8df618b chore(labeler): add provider github (#6194) 2024-12-13 09:43:49 -04:00
Adrián Jesús Peña Rodríguez
d00d254c90 feat(api): RBAC system (#6114) 2024-12-13 14:14:40 +01:00
dependabot[bot]
f9fbde6637 chore(deps): bump botocore from 1.35.79 to 1.35.80 (#6172)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 13:20:40 +01:00
Sergio Garcia
7b1a0474db fix(aws): set unique resource IDs (#6152) 2024-12-13 13:00:38 +01:00
Pepe Fagoaga
da4f9b8e5f fix(RLS): enforce config security (#6066) 2024-12-13 12:55:09 +01:00
Pepe Fagoaga
32f69d24b6 fix: dependabot syntax (#6181) 2024-12-13 12:20:43 +01:00
Pepe Fagoaga
d032a61a9e chore(dependabot): Add docker (#6180) 2024-12-13 12:13:53 +01:00
dependabot[bot]
07e0dc2ef5 chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /ui (#5881)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-12-13 08:25:57 +01:00
dependabot[bot]
9e175e8504 chore(deps): bump nanoid from 3.3.7 to 3.3.8 in /ui (#6110)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 07:59:50 +01:00
dependabot[bot]
6b8a434cda chore(deps): bump boto3 from 1.35.78 to 1.35.79 (#6171)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 07:58:58 +01:00
Pepe Fagoaga
554491a642 chore(gha): build and push OSS UI (#6168) 2024-12-12 19:10:44 +01:00
Pedro Martín
dc4e2f3c85 feat(GHA): build containers for API (#6032)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-12-12 19:05:25 +01:00
Daniel Barranquero
7d2c50991b feat(s3): add new fixer s3_bucket_public_access_fixer (#6164)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-12 12:17:41 -04:00
Pedro Martín
83c204e010 fix(rds): add invalid SG to status_extended (#6157) 2024-12-12 11:51:09 -04:00
dependabot[bot]
316eb049dd chore(deps): bump botocore from 1.35.78 to 1.35.79 (#6153)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 11:29:23 -04:00
Daniel Barranquero
be347b2428 feat(ec2): add new check ec2_launch_template_imdsv2_required (#6139)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-12 11:27:20 -04:00
Daniel Barranquero
a90c772827 feat(s3): add new fixer s3_bucket_public_list_acl_fixer (#6166) 2024-12-12 11:16:46 -04:00
Daniel Barranquero
26c70976c0 feat(s3): add new fixer s3_bucket_public_write_acl_fixer (#5855) 2024-12-12 11:10:43 -04:00
dependabot[bot]
657310dc25 chore(deps): bump boto3 from 1.35.77 to 1.35.78 (#6154)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 10:39:22 -04:00
Daniel Barranquero
6e595eaf92 feat(ec2): add new fixer ec2_instance_port_cifs_exposed_to_internet_fixer (#6159) 2024-12-12 09:22:56 -04:00
Prowler Bot
997831e33d chore(regions_update): Changes in regions for AWS services (#6158)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-12 09:10:46 -04:00
dependabot[bot]
5920cdc48f chore(deps): bump trufflesecurity/trufflehog from 3.86.0 to 3.86.1 (#6156)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 09:10:20 -04:00
dependabot[bot]
971e73f9cb chore(deps): bump google-api-python-client from 2.154.0 to 2.155.0 (#6155)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 09:09:51 -04:00
Mads Brouer Lundholm
bd9673c9de fix(aurora): Add default ports to the check of using non default ports (#5821)
Co-authored-by: Mads Rantala Lundholm <mao@bankdata.dk>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-12-11 13:01:45 -04:00
johannes-engler-mw
eded97d735 feat(azure): check for minimal TLS version for Azure SQL server (#5745)
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2024-12-11 16:37:53 +01:00
Daniel Barranquero
fdb1956b0b feat(opensearch): add new fixer opensearch_service_domains_not_publicly_accessible_fixer (#5926) 2024-12-11 11:29:48 -04:00
Daniel Barranquero
a915c04e9e fix(autoscaling): autoscaling_group_launch_configuration_requires_imdsv2 fails if Launch Template is used (#6111)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-11 11:18:30 -04:00
Daniel Barranquero
07178ac69a feat(glacier): add new fixer glacier_vaults_policy_public_access_fixer (#5950) 2024-12-11 11:10:12 -04:00
Daniel Barranquero
9b434d4856 feat(ecr): add new fixer ecr_repositories_not_publicly_accessible_fixer (#5923) 2024-12-11 10:42:11 -04:00
dependabot[bot]
0758e97628 chore(deps): bump botocore from 1.35.77 to 1.35.78 (#6132)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 10:19:37 -04:00
Sergio Garcia
b486007f95 fix(README): show latest release (#6145) 2024-12-11 10:19:06 -04:00
dependabot[bot]
0c0887afef chore(deps): bump trufflesecurity/trufflehog from 3.85.0 to 3.86.0 (#6130)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 09:29:14 -04:00
dependabot[bot]
805ed81031 chore(deps): bump boto3 from 1.35.76 to 1.35.77 (#6131)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 09:26:07 -04:00
Prowler Bot
ec3fddf5b1 chore(regions_update): Changes in regions for AWS services (#6136)
Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com>
2024-12-11 09:25:17 -04:00
Rubén De la Torre Vico
d7b0bc02ba feat(app): add support for TLS 1.3 to Web Apps check (#6004) 2024-12-11 13:14:29 +01:00
Pablo Lara
4d1c8eae8f feat(users): user detail can be edited now properly (#6135) 2024-12-11 10:05:30 +01:00
Sergio Garcia
989ccf4ae3 fix(iam): set unique resource id for each user access key (#6128) 2024-12-11 09:13:49 +01:00
Pedro Martín
9c089756c3 fix(compliance_tables): add correct values for findings (#6122)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-10 15:40:45 -04:00
Hugo Pereira Brito
8d4b0914a8 fix(aws): get firewall manager managed rule groups (#6119) 2024-12-10 15:34:22 -04:00
Hugo Pereira Brito
1ae3f89aab fix(aws): check AWS Owned keys in firehose_stream_encrypted_at_rest (#6108) 2024-12-10 13:42:13 -04:00
Daniel Barranquero
b984f0423a feat(sqs): add new fixer sqs_queues_not_publicly_accessible_fixer (#5911)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-10 12:26:42 -04:00
Sergio Garcia
f2f196cfcd fix(aws): set IAM identity as resource in threat detection (#6048) 2024-12-10 17:03:01 +01:00
dependabot[bot]
6471d936bb chore(deps): bump msgraph-sdk from 1.12.0 to 1.14.0 (#5957)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 11:42:40 -04:00
Adrián Jesús Peña Rodríguez
21bbdccc41 fix(deploy): temporal fix for the alpine-python segmentation fault (#6109) 2024-12-10 16:27:52 +01:00
Sergio Garcia
48946fa4f7 fix(gcp): make sure default project is active (#6097) 2024-12-10 11:06:48 -04:00
dependabot[bot]
9312dda7c2 chore(deps): bump microsoft-kiota-abstractions from 1.6.2 to 1.6.6 (#6038)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 10:37:04 -04:00
dependabot[bot]
e3013329ee chore(deps): bump botocore from 1.35.76 to 1.35.77 (#6098)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 09:26:36 -04:00
Sergio Garcia
38a0d2d740 fix(aws): set same severity for EC2 IMDSv2 checks (#6046) 2024-12-10 08:55:41 +01:00
Mario Rodriguez Lopez
5c2adf1e14 docs(unitesting): Make some fixes to the documentation (#6102) 2024-12-10 08:51:19 +01:00
Daniel Barranquero
7ddd2c04c8 feat(awslambda): add new fixer awslambda_function_not_publicly_accessible_fixer (#5840) 2024-12-09 12:28:42 -04:00
Pepe Fagoaga
9a55632d8e fix(backport): more than one backport tag is allowed (#6090) 2024-12-09 17:19:33 +01:00
dependabot[bot]
f8b4427505 chore(deps-dev): bump vulture from 2.13 to 2.14 (#6068)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 11:10:41 -04:00
Sergio Garcia
f1efc1456d chore(dependabot): change interval of PRs (#6086) 2024-12-09 15:46:28 +01:00
Sergio Garcia
2ea5851b67 docs(api): add commands to run API scheduler (#6085) 2024-12-09 10:34:02 -04:00
dependabot[bot]
a3051bc4e3 chore(deps-dev): bump mkdocs-material from 9.5.47 to 9.5.48 (#6073)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 10:14:08 -04:00
Pepe Fagoaga
d454427b8b fix(backport): remove v from branch prefix (#6081) 2024-12-09 10:13:20 -04:00
Pepe Fagoaga
4b41bd6adf chore(containers): support for v4.6 branch (#6063)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-09 09:23:06 -04:00
Pepe Fagoaga
cdd044d120 chore(dependabot): Update for UI and v4 (#6062) 2024-12-09 09:15:03 -04:00
Pepe Fagoaga
213a793fbc chore(actions): standardize names (#6059) 2024-12-09 09:14:06 -04:00
Pepe Fagoaga
a8a567c588 docs: Prowler SaaS -> Cloud and add missing compliance (#6061) 2024-12-09 09:12:54 -04:00
Pepe Fagoaga
fefe89a1ed fix(backport): Add action to detect labels (#5270) 2024-12-09 09:12:08 -04:00
Sergio Garcia
493fe2d523 docs(env): move warning about env files (#6049) 2024-12-09 11:11:05 +01:00
dependabot[bot]
d8fc830f1d chore(deps): bump boto3 from 1.35.71 to 1.35.76 (#6054)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 10:11:51 +01:00
Pepe Fagoaga
b6c3ba0f0d chore: delete unneeded requirements file (#6056) 2024-12-09 09:07:10 +01:00
dependabot[bot]
32cd39d158 chore(deps-dev): bump coverage from 7.6.8 to 7.6.9 (#6053)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-06 20:29:06 -04:00
dependabot[bot]
203275817f chore(deps-dev): bump pytest from 8.3.3 to 8.3.4 (#5992)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-06 12:53:11 -04:00
dependabot[bot]
c05c3396b5 chore(deps-dev): bump mkdocs-material from 9.5.46 to 9.5.47 (#5988)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-06 11:56:37 -04:00
dependabot[bot]
8f172aec8a chore(deps-dev): bump pylint from 3.3.1 to 3.3.2 (#5993)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-06 11:04:28 -04:00
dependabot[bot]
263a7e2134 chore(deps): bump botocore from 1.35.71 to 1.35.76 (#6037) 2024-12-06 09:41:57 -04:00
dependabot[bot]
a2ea216604 chore(deps): bump slack-sdk from 3.33.4 to 3.33.5 (#6039)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-06 08:44:00 -04:00
dependabot[bot]
77c572f990 chore(deps): bump trufflesecurity/trufflehog from 3.84.1 to 3.85.0 (#6040)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-06 08:38:14 -04:00
Prowler Bot
bb0c346c4d chore(regions_update): Changes in regions for AWS services (#6041)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-12-06 08:38:03 -04:00
Daniel Barranquero
2ce8e1fd21 fix(backup): modify list recovery points call (#5996) 2024-12-06 08:35:29 -04:00
Pepe Fagoaga
ecfd94aeb1 fix(codecov): create components (#6028) 2024-12-05 16:35:56 +01:00
Pedro Martín
eddc672264 chore(version): update prowler version (#6027) 2024-12-05 13:51:13 +01:00
Pedro Martín
8c71a39487 docs(prowler-app): add link to https://api.prowler.com/api/v1/docs (#6016) 2024-12-05 11:01:51 +01:00
Pedro Martín
ff0ac27723 docs(index): update index with images (#6015) 2024-12-05 11:01:42 +01:00
Víctor Fernández Poyatos
ad7134d283 fix(tenant): fix delete tenants behavior (#6013) 2024-12-04 13:57:16 +01:00
Pablo Lara
58723ae52e fix(invitations): remove wrong url (#6005) 2024-12-03 21:08:31 +01:00
Pablo Lara
52723eda6e feat(providers): refactor workflow providers v2 (#6001) 2024-12-03 17:36:24 +01:00
Pepe Fagoaga
4a4636571e chore(actions): prepare for v5 (#6003) 2024-12-03 17:07:35 +01:00
Víctor Fernández Poyatos
32d8da2131 fix(api): cascade deletion and next scan at time (#5999) 2024-12-03 14:59:49 +01:00
Hugo Pereira Brito
bb34a932ff feat(docs): added link from app guide to app installation (#5987) 2024-12-02 12:22:24 -04:00
Sergio Garcia
50796bea7a chore(docs): update screenshots and docs of Prowler App (#5984) 2024-12-02 11:37:00 -04:00
Víctor Fernández Poyatos
d678946044 chore(celery-beat): disable periodic cleanup (#5986) 2024-12-02 12:43:21 +01:00
Pablo Lara
fdafb8b0d3 chore(teaks v5): apply v5 feedback changes (temporarily hide recover password) (#5985) 2024-12-02 12:34:29 +01:00
Pablo Lara
c8b84163c9 chore: apply v5 feedback changes (add link to the graph) (#5983) 2024-12-01 17:57:20 +01:00
Víctor Fernández Poyatos
ab489befe6 feat(provider): add include query parameter for provider_groups (#5974) 2024-12-01 16:57:59 +01:00
Pablo Lara
67f3adbe4c Feature/v5 tweaks UI v4 (#5982) 2024-12-01 16:57:34 +01:00
Pablo Lara
9b018ff885 chore: apply v5 feedback changes (scan page) (#5981) 2024-12-01 15:41:34 +01:00
Pablo Lara
3c2b0a58a1 feat(v5): tweaks UI for v5 release - 2 (#5979) 2024-12-01 15:28:11 +01:00
Víctor Fernández Poyatos
2a13301d35 feat(scan): add state filter for scans endpoints (#5980) 2024-12-01 15:03:28 +01:00
Pedro De Castro
333f74dba0 fix(docs): Docker compose files download (#5977) 2024-12-01 08:44:56 -04:00
Víctor Fernández Poyatos
ffaa267b5e feat(scan, schedule): add next_scan_at field to scans and POST /schedules/daily (#5978) 2024-12-01 09:12:19 +01:00
Sergio Garcia
ff80a47123 feat(docker-compose): add Docker Compose YAMLs and .env (#5909) 2024-11-30 17:21:31 -04:00
Sergio Garcia
17c31c64d9 fix(tests): use datetime.datetime.now() in GCP kms_key_rotation_enabled (#5976) 2024-11-30 16:31:56 -04:00
Víctor Fernández Poyatos
add2134274 fix(overview): retrieve aggregated findings from completed scans (#5975) 2024-11-30 19:25:29 +01:00
Pablo Lara
3547153c0a feat(v5): tweaks UI (#5971) 2024-11-30 18:51:26 +01:00
Adrián Jesús Peña Rodríguez
76b8ac157d feat(dynamic_filters): add dynamic filters system (#5973) 2024-11-30 17:09:38 +01:00
Pedro Martín
e09a04d593 docs(readme): update readme with console instead of bash (#5970) 2024-11-29 12:50:08 -04:00
Sergio Garcia
f6187ee9ca docs(readme): add Prowler App documentation (#5916) 2024-11-29 17:43:32 +01:00
Sergio Garcia
1fbf72cb6b docs(installation): add documentation for Prowler App installation (#5883) 2024-11-29 17:28:14 +01:00
Sergio Garcia
bcb2987f60 docs(architecture): add Prowler App architecture diagram (#5914) 2024-11-29 17:17:00 +01:00
Sergio Garcia
75b6d376c4 docs(usage): add documentation for Prowler App usage (#5885)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-11-29 11:00:36 -04:00
Víctor Fernández Poyatos
9794b5cf27 fix(scan): fix deadlock on resource transactions during concurrent scans (#5968) 2024-11-29 15:41:03 +01:00
Víctor Fernández Poyatos
89a7128236 feat(Provider): add soft deletion for providers and related resources (#5956) 2024-11-29 15:26:14 +01:00
Sergio Garcia
c1d6021a3a fix(k8s): handle Kubernetes kubeconfig content correctly (#5939) 2024-11-29 09:31:52 -04:00
StylusFrost
d5bb5e9287 fix(azure): containerregistry_not_publicly_accesible is not accurate (#5938)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2024-11-29 14:06:55 +01:00
Rubén De la Torre Vico
466ec0e66c fix(rds): add default key value to RDS event (#5961) 2024-11-29 09:01:06 -04:00
Rubén De la Torre Vico
f0ebfcdd69 feat(prowler-policy): add missing permissions (#5962) 2024-11-29 09:00:05 -04:00
dependabot[bot]
fb15329aee chore(deps): bump boto3 from 1.35.70 to 1.35.71 (#5958)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-29 08:56:39 -04:00
Sergio Garcia
c35dc7ea4a fix(api): add EKS ARN to K8s validation (#5963) 2024-11-29 08:55:58 -04:00
Pablo Lara
6dea923866 chore(codebase) Update/UI code base (#5960) 2024-11-29 06:54:38 +01:00
Pedro Martín
bcf1ef1d31 chore(check): remove custom_report_interface (#5955) 2024-11-28 13:06:06 -04:00
dependabot[bot]
9bf3171cfa chore(deps): bump botocore from 1.35.70 to 1.35.71 (#5944)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 11:57:35 -04:00
Prowler Bot
70e327a3c1 chore(regions_update): Changes in regions for AWS services (#5947)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-28 09:11:29 -04:00
dependabot[bot]
af815287ed chore(deps-dev): bump bandit from 1.7.10 to 1.8.0 (#5943)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 09:11:17 -04:00
Pablo Lara
d5187b3099 chore(auth): restore auth file and move the server action to user file (#5951) 2024-11-28 12:55:31 +01:00
Pablo Lara
fd8d34e8bc feat(ui:profile) add profile card (#5948) 2024-11-28 10:39:10 +01:00
Sergio Garcia
4ba1c0259f fix(gcp): use session credentials to check if API is active (#5935) 2024-11-27 14:00:26 -04:00
Sergio Garcia
17a39f3305 fix(aws): exclude threat detection checks if category not present (#5933) 2024-11-27 11:54:59 -04:00
Víctor Fernández Poyatos
b69a0d5137 feat(overviews): Add API overview endpoints for findings and severity (#5910) 2024-11-27 15:51:05 +01:00
Pepe Fagoaga
f576b24fc8 fix(list_by_service): execute lambda if requested (#5930) 2024-11-27 15:32:57 +01:00
dependabot[bot]
f9864eeda0 chore(deps): bump boto3 from 1.35.66 to 1.35.70 (#5929)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-27 10:16:36 -04:00
dependabot[bot]
03db9d3f74 chore(deps): bump botocore from 1.35.69 to 1.35.70 (#5918)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-27 09:07:21 -04:00
Pablo Lara
677e20a1a4 feat(ui:overview) overview findings by status and severity (#5925) 2024-11-27 13:53:16 +01:00
Prowler Bot
4a8150d613 chore(regions_update): Changes in regions for AWS services (#5922)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-27 08:51:19 -04:00
Pablo Lara
afd152c073 feat(ui:cleaning): tweaks for Prowler v5 (#5913) 2024-11-26 16:26:06 +01:00
Pablo Lara
d57db6c39e feat(ui:overview): add new fail findings to date table (#5906) 2024-11-26 16:17:26 +01:00
Pablo Lara
0b2e1f1917 feat: configure codeql for ui repository (#5912) 2024-11-26 16:09:56 +01:00
dependabot[bot]
9a666891fd chore(deps-dev): bump mkdocs-material from 9.5.45 to 9.5.46 (#5894)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 09:45:31 -04:00
Mario Rodriguez Lopez
9c383baff3 fix(ec2): Change ec2_sg_high_risk_ports configurable parameter name (#5904) 2024-11-26 08:24:45 -04:00
Prowler Bot
3e9b4d34bd chore(regions_update): Changes in regions for AWS services (#5905)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-26 08:12:21 -04:00
dependabot[bot]
122ddd3e72 chore(deps-dev): bump coverage from 7.6.7 to 7.6.8 (#5895)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 08:11:40 -04:00
dependabot[bot]
f61d800147 chore(deps): bump actions/checkout from 3 to 4 (#5892)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 08:33:12 +01:00
dependabot[bot]
901806e98b chore(deps): bump codecov/codecov-action from 4 to 5 (#5891)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 08:32:51 +01:00
dependabot[bot]
920d6a8692 chore(deps): bump tj-actions/changed-files from 42 to 45 (#5890)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 08:32:13 +01:00
Sergio Garcia
8eb2fbeb18 chore(version): update Prowler version (#5884) 2024-11-26 08:20:42 +01:00
dependabot[bot]
96e91c4d70 chore(deps): bump botocore from 1.35.66 to 1.35.69 (#5897)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 08:20:16 +01:00
Pedro De Castro
94c6253c70 feat: Merge new components API and UI (#5875) 2024-11-25 18:37:00 +01:00
Pedro De Castro
04d99f1928 chore: Github Actions. Postgres env variables 2024-11-25 18:22:54 +01:00
Pedro De Castro
94a174c405 chore: Github Actions. Postgres env variables 2024-11-25 18:03:18 +01:00
Sergio Garcia
2e26750006 chore(gcp): update docstring of ADC credentials (#5877) 2024-11-25 13:01:42 -04:00
Pedro De Castro
e7e80944e9 chore: Github Actions. Naming and API env variables 2024-11-25 17:57:51 +01:00
Pedro De Castro
ff6c1e4127 chore: Change API license to match current Prowler license 2024-11-25 16:35:32 +01:00
Daniel Barranquero
a67e3f4c58 chore(aws): update fixers docstring (#5874) 2024-11-25 11:16:16 -04:00
Prowler Bot
a4c92ea0ea chore(regions_update): Changes in regions for AWS services (#5873)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-25 10:30:34 -04:00
Pedro De Castro
f4ffb42c91 chore(actions): Fix CodeQL ignore path syntax 2024-11-25 14:32:28 +01:00
Pedro De Castro
0ec9f37d2f chore: Revert changes at the Pull Request template 2024-11-25 14:11:39 +01:00
Pedro De Castro
15f500f91a chore(actions): Update Github Actions according to the new components 2024-11-25 14:02:01 +01:00
Pedro De Castro
5120c1d869 chore(ui): Merge UI repository 2024-11-25 13:18:47 +01:00
Pedro De Castro
725fcf80aa chore(ui): Merge UI repository 2024-11-25 13:15:14 +01:00
Pedro De Castro
6fe8c81312 chore(api): Merge API repository 2024-11-25 13:12:54 +01:00
Pedro De Castro
befcdd3dfa Update and remove MD files preparing repositories merge (#99) 2024-11-25 13:06:04 +01:00
Pedro De Castro
766fcf75cd chore: Update and remove MD files preparing repositories merge (#89) 2024-11-25 12:55:01 +01:00
Pablo Lara
d2a1433ff8 Merge pull request #98 from prowler-cloud/PRWLR-5379-Overview-Page-Provider-Overview
feat(overview): overview page provider overview
2024-11-25 12:15:31 +01:00
Pablo Lara
cfd4339c41 feat: render all providers with or without data 2024-11-25 12:11:27 +01:00
Pablo Lara
365c3fe3ad Merge pull request #97 from prowler-cloud/PRWLR-5450-Providers-Page-Add-Provider-Remove-Start-now
feat(providers) providers page add provider remove start now
2024-11-25 12:00:21 +01:00
Pablo Lara
f8af960909 feat: add graph in overview page with providers overview 2024-11-24 15:22:12 +01:00
Pablo Lara
121b24b7d1 chore: improve filtering component 2024-11-24 13:21:42 +01:00
Pablo Lara
c7b463d61e chore: refresh scan's data with a button 2024-11-24 11:57:29 +01:00
Pablo Lara
520a5fc756 chore: changes for setup provider's workflow 2024-11-24 10:25:30 +01:00
Pablo Lara
f45edc18a9 chore: updating changes with prowler cloud ui 2024-11-24 09:27:18 +01:00
dependabot[bot]
38f0f9a84d chore(deps): bump aiohttp from 3.10.8 to 3.10.11 (#85)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.10.8 to 3.10.11.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.10.8...v3.10.11)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-22 09:43:01 +01:00
Víctor Fernández Poyatos
1c6d42e60d feat(Overview): PRWLR-5433 Add /overviews/providers endpoint (#88)
* feat(Overview): PRWLR-5433 add overviews/providers views and serializers

* test(Overview): PRWLR-5433 add unit tests

* chore(Schema): update API schema

* feat(Overview): PRWLR-5433 order by -findings_failed by default

* test(Tenant): PRWLR-5433 fix unit test
2024-11-21 17:59:21 +01:00
Pablo Lara
6cdfddd2ff Merge pull request #96 from prowler-cloud/PRWLR-5142-Prowler-V-release-final-tweaks-for-Findings-page
Tweaks for findings details and filters
2024-11-20 16:06:19 +01:00
Pablo Lara
a1074f1a81 feat: filters for findings are working 2024-11-20 15:56:21 +01:00
Pablo Lara
a90a3f12e7 fix: fix typo error 2024-11-20 15:46:09 +01:00
Pablo Lara
47d74a7742 fix: fix typo error 2024-11-20 15:45:32 +01:00
Pablo Lara
7fd53c1bc3 feat: tweaks filters 2024-11-20 13:58:45 +01:00
Víctor Fernández Poyatos
ad949632b4 feat(Provider, Scan): PRWLR-5405 Add daily schedule scan for added Providers (#87)
* feat: PRWLR-5405 add django-celery-beat dep

* fix(Scan): PRWLR-5405 fix scan status update in real-time

* feat(Celery-beat): PRWLR-5405 add django-celery-beat resources

* feat(Provider,Beat): PRWLR-5405 add daily scheduled scan for each new provider

* chore(Scan): PRWLR-5405 change default sort parameter

* fix(Migrations): PRWLR-5405 fix meta fields

* test(Tenants): PRWLR-5405 fix integration tests

* chore: fix typo on .env.example
2024-11-20 13:10:45 +01:00
Pablo Lara
ebc96bed06 chore: spacing tweaks 2024-11-20 10:16:56 +01:00
Pablo Lara
c4a3a1e0b5 chore: move filters outside of the table 2024-11-20 10:15:14 +01:00
Pablo Lara
07beb094fb chore:color tweaks 2024-11-20 09:57:31 +01:00
Pablo Lara
280a4df4f2 chore: put in a row the links for remediation 2024-11-20 09:50:47 +01:00
Pablo Lara
ccc2aecbd4 chore: color tweaks 2024-11-20 09:46:04 +01:00
Pablo Lara
a2cc3e913d chore: finding details tweaks 2024-11-20 08:31:29 +01:00
Pablo Lara
b28cfede8c chore: remove container class and style tweaks for status finding badge 2024-11-19 17:36:56 +01:00
Pablo Lara
73c5764495 chore: add new component for finding status and add sorting to the findings table 2024-11-19 13:05:22 +01:00
Pablo Lara
e84fd1fd65 fix: change types because changed in the API specs. 2024-11-19 12:39:35 +01:00
Pablo Lara
776b41e866 Merge pull request #95 from prowler-cloud/PRWLR-5363-Compliance-Overview
Compliance overview - first iteration -
2024-11-18 14:17:08 +01:00
Pablo Lara
985efc67cc feat: first iteration of compliance dashboard is working 2024-11-18 14:05:36 +01:00
Pablo Lara
223073e3df feat: allow compliance data selection by choosing a scan 2024-11-18 09:07:07 +01:00
Pablo Lara
783db5c3dc feat: allow compliance data selection by choosing a scan 2024-11-18 08:21:54 +01:00
Pablo Lara
eb40369c30 chore: render an message if there is no data for compliances 2024-11-18 07:45:19 +01:00
Pablo Lara
e92bbffc53 chore: delete old dummy data for compliances dashboard 2024-11-16 21:13:41 +01:00
Pablo Lara
d1424b3c9c fix: resolve breaking changes caused by updated API specs 2024-11-16 15:57:28 +01:00
Pablo Lara
1d0cc950a1 Merge pull request #94 from prowler-cloud/PRWLR-4887-Invitations-users-integration
Invitations/Users integration page
2024-11-16 15:04:01 +01:00
Pablo Lara
01bc745478 chore: replace 'delete' with 'revoke' in invitations 2024-11-16 12:59:30 +01:00
Pablo Lara
aedc8de964 Merge branch 'main' into PRWLR-4887-Invitations-users-integration 2024-11-16 12:52:11 +01:00
Pablo Lara
3f5f50fe38 chore: add defaultValue prop to the CustomInput component 2024-11-16 12:50:22 +01:00
Pablo Lara
4fd5d868c6 chore: change label for revoke invitations 2024-11-16 12:49:33 +01:00
Pablo Lara
e21386c1d5 chore: Show the error in the after the invitation token field 2024-11-16 12:48:23 +01:00
Víctor Fernández Poyatos
aa8c46d232 feat(ComplianceOverview): PRWLR-5149 Add compliance overview endpoints (#84)
* chore(Fixtures): PRWLR-5149 move development fixtures to dev directory

* feat(Compliance): PRWLR-5149 add compliance templates and basic logic on scans

* chore(Compliance): PRWLR-5149 make default compliance requirements pass if no findings

* feat(Compliance): PRWLR-5149 add model

* feat(Compliance): PRWLR-5149 add serializers

* feat(Compliance): PRWLR-5149 add filters

* feat(Compliance): PRWLR-5149 add views and urls

* feat(Scan): PRWLR-5149 add compliance storing during scans

* chore(Compliance, Scan): PRWLR-5149 refactor for performance

* chore(Compliance): PRWLR-5149 add docstrings

* feat(ComplianceOverview): PRWLR-5149 add new view for summary

* chore: PRWLR-5149 update resource_names on all models to follow JSON:API spec

* feat(ComplianceOverview): PRWLR-5149 add indexes to model for performance

* feat(ComplianceOverview): PRWLR-5149 refactor views to summarize by default

* chore(ComplianceOverview): PRWLR-5149 improve readability

* chore(ComplianceOverview): PRWLR-5149 set default ordering to compliance_id

* feat(Compliance): PRWLR-5149 add check status values count for each requirement

* chore: PRWLR-5149 update API spec

* chore(Provider,Scan): PRWLR-5149 disable scanner_args

* feat(Scan): PRWLR-5149 retrieve all regions from provider when generating compliance

* feat(Scan): PRWLR-5149 improve efficiency on scan task

* chore: PRWLR-5149 update API spec

* test(Compliance): PRWLR-5149 add unit tests

* test(Scan): PRWLR-5149 update scan task unit tests

* fix(ComplianceOverview): PRWLR-5149 fix filter

* test(ComplianceOverview): PRWLR-5149 add unit tests

* chore: PRWLR-5149 update API spec

* feat(Compliance): PRWLR-5149 add manual findings to compliance results

* chore(ComplianceOverview): PRWLR-5149 add fixture

* chore: PRWLR-5149 update poetry lock

* fix(Build): fix dockerfile and resources fixture

* chore(Schema): update API schema
2024-11-15 15:39:27 +01:00
Sergio Garcia
7a57922891 chore(api): ensure correct deployment (#79)
* chore(api): ensure correct deployment

* add hadolint

* chore: revision

* chore: revision

* chore: revision

* chore: revision

* typo
2024-11-14 15:11:53 +01:00
Pablo Lara
58068b34bf feat: invitations are working - first iteration 2024-11-14 11:55:11 +01:00
Pablo Lara
1dc4bd313a feat: invitation workflow is working as expected 2024-11-14 08:08:08 +01:00
Pablo Lara
890bd12e99 feat: workflow to invite an user is working 2024-11-13 18:52:06 +01:00
Adrián Jesús Peña Rodríguez
bf04261af6 feat(provider-groups): PRWLR-4725 add provider-groups system (#82)
* feat(provider-groups): PRWLR-4725 add provider-groups system

* feat(provider-groups): PRWLR-4725 add provider-groups migrations

* feat(provider-groups): PRWLR-4725 improve provider-groups models
2024-11-13 18:17:08 +01:00
Víctor Fernández Poyatos
f3dce4f7a7 fix(User): PRWLR-5356 allow deleting and updating users (#83) 2024-11-13 17:35:56 +01:00
Pablo Lara
29dfd303db feat: adding workflow to send invites to the user 2024-11-13 17:18:32 +01:00
Sergio Garcia
521b3ded9c fix(Dockerfile): ensure correct deployment (#92)
* fix(Dockerfile): ensure correct deployment

* chore(dockerfile): Add NEXT_TELEMETRY_DISABLED=1

---------

Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-11-13 16:15:33 +01:00
Pablo Lara
e4395ddd55 Merge pull request #91 from prowler-cloud/PRWLR-4734-Users-Page-displays-the-users-for-the-current-membership
Users page displays the users for the current membership
2024-11-13 14:41:02 +01:00
Pablo Lara
6d05ad9815 chore: remove unused console log 2024-11-13 14:32:10 +01:00
Pablo Lara
0290b837f2 feat: user table is working as expected 2024-11-13 14:31:33 +01:00
Pablo Lara
833bf0520c chore: remove old files and add new ones related to users 2024-11-13 14:25:31 +01:00
Pablo Lara
239826ce1f chore: remove old files and add new ones related to users 2024-11-13 14:24:44 +01:00
Adrián Jesús Peña Rodríguez
b1547a6d28 fix(migrations): add missing operations (#66)
* fix(migrations): add missing operations

* fix(migrations): remove redundant base_manager_name
2024-11-13 12:08:14 +01:00
Pablo Lara
4603e6b46d chore: invert severity filter list order 2024-11-13 10:07:14 +01:00
Víctor Fernández Poyatos
26050bad5b build(Dockerfile): remove g++ from dockerfile and update prowler (#81) 2024-11-13 09:46:16 +01:00
Pablo Lara
810cc6c2f8 Merge pull request #89 from prowler-cloud/PRWLR-5141-Prowler-V-release-tweaks-scan-page-v3
Tweaks scan page v3
2024-11-13 08:26:48 +01:00
Pablo Lara
8fb6f5b11d chore: add GitHub action to run the build 2024-11-13 08:22:58 +01:00
Pablo Lara
db36cdf379 fix: fix the build, and run prettier 2024-11-13 08:21:13 +01:00
Víctor Fernández Poyatos
3efdfad37d fix(ResourceTagMapping): PRWLR-5271 set CASCADE for resource field (#80) 2024-11-12 15:59:44 +01:00
Pablo Lara
7fc06a2740 Merge pull request #87 from prowler-cloud/PRWLR-5183-test-new-prowler-app
chore(ui): ensure correct deployments
2024-11-12 08:42:02 +01:00
Sergio
65c197d9ae revert package-lock.json 2024-11-11 16:38:43 -05:00
Sergio
a3060ed295 chore(ui): ensure correct deployments 2024-11-11 16:28:46 -05:00
Pablo Lara
2378b01ea9 chore: apply tweaks to scan table 2024-11-11 13:39:37 +01:00
Pablo Lara
60c2c409b0 fix: apply prettier to fix an error coming from main branch 2024-11-11 13:02:03 +01:00
Pablo Lara
1c84ceda2e Merge branch 'main' into PRWLR-5141-Prowler-V-release-tweaks-scan-page-v3 2024-11-11 12:05:09 +01:00
Pablo Lara
1a6f8fc504 Merge pull request #84 from prowler-cloud/dev-company-name
fix(company_name): Getting the value from form. Avoid send empty values
2024-11-11 11:58:48 +01:00
Pedro De Castro
39fbdab93c fix(company_name): Getting the value from form. Avoid send empty values 2024-11-09 19:50:54 +01:00
Pablo Lara
1802caf25f Merge branch 'main' into PRWLR-5141-Prowler-V-release-tweaks-scan-page-v3 2024-11-08 13:27:05 +01:00
Pedro De Castro
7c2cd453eb Finding detail card
Finding detail card
2024-11-08 12:50:24 +01:00
Pedro De Castro
a07a0b05bc feat: services view
feat: services view
2024-11-08 12:48:35 +01:00
Pablo Lara
d0d8de9028 chore: add a default name for scans if it's empty by the user 2024-11-08 11:37:55 +01:00
Pablo Lara
30ed31cebe Merge pull request #82 from prowler-cloud/PRWLR-5141-Prowler-V-release-tweaks-scan-page-v2
Create workflow to launch a scan
2024-11-08 11:21:39 +01:00
Pablo Lara
bec7644798 feat: render the task result in scan details 2024-11-08 11:17:43 +01:00
Pablo Lara
327b4f4bba chore: style tweaks for sheet component 2024-11-08 10:42:31 +01:00
Pablo Lara
39f1796da6 feat: scan details can be shared now in the URL 2024-11-08 10:36:28 +01:00
Pablo Lara
fdb644fc6d chore: WIP 2024-11-08 09:56:58 +01:00
Pablo Lara
df73234234 feat: the new workflow to launch a scan is almost done 2024-11-08 09:41:48 +01:00
Pepe Fagoaga
95dc87a91b chore(partitions): add env to create partitions (#68)
* fix(partitions): Use calendar months

* fix: unit to get partition datetime

* fix: imports

* fix: format

* chore: merge

* fix(partitions): Only allow month as unit

* fix(uuid7_end): default months to 1

* test: fix test_uuid7_end

* test: reset expected dt to start of month

* fix: tests uuid utils

* docs: we only allow months

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-11-08 09:34:32 +01:00
Pablo Lara
5801857883 feat: dynamic provider selector for scan launch 2024-11-08 08:45:27 +01:00
Pablo Lara
1c37b58177 delete: remove old component 2024-11-08 08:11:24 +01:00
Drew Kerrigan
d8d831c2a0 fix(): remove escaped newlines when reading cetificates for JWT signing and verification (#77)
* fix(): remove escaped newlines when reading cetificates for JWT signing and verification

* fix(): updating dev credentials in README
2024-11-07 18:13:51 +01:00
Pablo Lara
260f007e5b chore: adding a select component to choose a provider to launch a scan 2024-11-07 17:02:23 +01:00
Pablo Lara
69528cbe66 Merge pull request #81 from prowler-cloud/PRWLR-5141-Prowler-V-release-tweaks-scan-page
chore: remove unused icon
2024-11-07 10:52:24 +01:00
Pablo Lara
c268e0613c chore: remove unused icon 2024-11-07 10:51:42 +01:00
Pablo Lara
714e96cc6e Merge pull request #80 from prowler-cloud/PRWLR-5141-Prowler-V-release-tweaks-scan-page
Add scan details for demo purposes
2024-11-07 10:38:32 +01:00
Pablo Lara
89dd56a0ff chore: add scan details for demo purposes 2024-11-07 10:32:52 +01:00
Víctor Fernández Poyatos
0271fe5ca0 feat(User): Add GET /users (#76)
* feat(Membership): implement include parameter for users in memberships

* feat(User): refactor userviewset

* chore(Schema): update API schema

* feat(User): add filters
2024-11-07 10:24:00 +01:00
Pedro De Castro
89d7189a0f fix(findings): Add resource id to props 2024-11-07 08:05:16 +01:00
Pedro De Castro
fca3d138c5 feat: Finding detail 2024-11-07 08:01:38 +01:00
Pedro De Castro
354bd90cfa fix: remove ui folder from prev project 2024-11-07 07:14:04 +01:00
Pedro De Castro
c1f86cb502 fix: remove console log and linter errors 2024-11-07 06:38:34 +01:00
Pedro De Castro
fd2fdbe2f9 feat: services view 2024-11-07 06:31:18 +01:00
Pablo Lara
58b5d3cf83 Merge pull request #77 from prowler-cloud/PRWLR-5141-Prowler-V-release-final-touches-for-Launch-Scan-page
Prwlr 5141 prowler v release final touches for launch scan page
2024-11-06 15:57:02 +01:00
Pablo Lara
87fb26d271 chore: twaks for scan page 2024-11-06 15:54:15 +01:00
Pablo Lara
05271bc110 fix: sign-in and sign-up buttons have again loading state 2024-11-06 15:42:23 +01:00
Víctor Fernández Poyatos
6f1aa6a1b1 fix(Finding): PRWLR-5179 Fix finding's scan filters and related UUID utils (#75)
* fix(Finding): PRWLR-5179 fix scan_id filters and related logic

* test(uuid_utils): PRWLR-5179 refactor unit tests

* chore: PRWLR-5179 update API spec
2024-11-06 15:06:29 +01:00
Pablo Lara
c7a8a62cf2 Merge pull request #76 from prowler-cloud/PRWLR-5109-Set-Up-Providers-Credentials-Workflow
Set up providers credentials workflow
2024-11-06 14:33:38 +01:00
Pablo Lara
2448f9b029 chore: build is working as expected 2024-11-06 14:29:10 +01:00
Pablo Lara
e90e10587b chore: remove unused console log 2024-11-06 14:06:14 +01:00
Pablo Lara
b11a33d3da feat: reset credentials for gcp, azure and kubernetes if test connection fail 2024-11-06 13:46:03 +01:00
Pablo Lara
73f7167b63 chore: replace Link component to use it from NextJS and not from NextUI 2024-11-06 11:03:12 +01:00
Pablo Lara
05e3be418d fix: the test connection button from actions in the providers table is working as expected now 2024-11-06 10:55:40 +01:00
Adrián Jesús Peña Rodríguez
b09fd48d61 fix(auth): PRWLR-5180 change user_id to sub (#74) 2024-11-06 10:53:40 +01:00
Pablo Lara
c62ab62bf9 feat: improve custom button and add prop to use it asLink when needed 2024-11-06 09:34:18 +01:00
Pablo Lara
44b0208846 chore: handle API error from test connection 2024-11-06 08:47:56 +01:00
Pablo Lara
e444e39fd0 feat: add helper function to monitor task state during execution 2024-11-06 08:29:39 +01:00
Pablo Lara
76c6065a80 fix: avoid app crashed when there is no data to render 2024-11-06 07:45:57 +01:00
Pablo Lara
f96777bcf9 chore: handle data when executing the request 2024-11-05 16:35:48 +01:00
Pablo Lara
4a3ff78636 feat: aws providers can be added via role 2024-11-05 16:19:07 +01:00
Víctor Fernández Poyatos
4ab119d6c9 feat(Invitation): PRWLR-4722 Add invitations endpoints (#71)
* feat(Invitation): PRWLR-4722 add model and enum

* feat(Invitation): PRWLR-4722 add serializers

* feat(Invitation): PRWLR-4722 add filters

* feat(Invitation): PRWLR-4722 update token field constraints

* feat(Invitation): PRWLR-4722 add serializers

* feat(Invitation): PRWLR-4722 add views, url and custom logic

* feat(Invitation): PRWLR-4722 update unique constraint in model

* feat(Invitation): PRWLR-4722 update serializer validation error messages

* fix(Invitation): PRWLR-4722 fix view logic

* feat(User): PRWLR-4722 add invitation_code query param and logic to create user view

* fix(Invitation): PRWLR-4722 fix invitation creation tenant filter

* chore: PRWLR-4722 add comments

* feat(Invitation): PRWLR-4722 add email filter to view

* fix(Utils): PRWLR-4722 fix datetime functions

* fix(User): PRWLR-4722 fix bug when creating users

* fix(Tests): PRWLR-4722 adapt unit and integration tests

* test(db-utils): PRWLR-4722 add new unit tests

* test(Invitation): PRWLR-4722 add unit tests

* test(Invitation): PRWLR-4722 add unit tests

* fix(Invitation): PRWLR-4722 fix views and serializers

* feat(Invitation): PRWLR-4722 refactor invitation validation and tests

* chore: PRWLR-4722 update API spec

* test(Invitation): PRWLR-4722 add more unit tests

* feat(Invitation): PRWLR-4722 refactor invitation urls

* chore: PRWLR-4722 update API spec
2024-11-05 15:30:53 +01:00
Pablo Lara
f2d207d1d4 fix: fix build error (#73) 2024-11-05 14:43:19 +01:00
Adrián Jesús Peña Rodríguez
4bab3e262c feat(serializers): add role_session_name description (#70)
* feat(serializers): add role_session_name description

* feat(serializers): update spec
2024-11-05 13:27:20 +01:00
Pablo Lara
e0c2720d31 chore: hidden credentials inputs for cloud providers 2024-11-05 07:07:53 +01:00
Víctor Fernández Poyatos
e3ae44d033 fix(Provider): PRWLR-5153 fix provider initialization when testing connection (#69) 2024-11-04 17:20:31 +01:00
Pablo Lara
e04ba94ace chore: Button for Start scan now is working now as the last step in the workflow 2024-11-04 13:37:10 +01:00
Pablo Lara
9a9481a88e chore: set buttons for start scan now or schedule it 2024-11-04 13:21:45 +01:00
Pablo Lara
3609043e4c chore: remove connected param in the last step 2024-11-04 12:53:55 +01:00
Víctor Fernández Poyatos
3de2c47c56 fix(Scan): PRWLR-5145 Update resource storing when performing a scan (#67)
* chore(Resource): PRWLR-5145 remove region from unique constraint

* feat(Resource): PRWLR-5145 update how resources are stored during a scan

* test(Task): PRWLR-5145 add unit tests for scan task resources
2024-11-04 11:05:02 +01:00
Pablo Lara
8ca21bb92e chore: add alias by default if provider alias is empty when add a provider 2024-11-04 07:46:44 +01:00
Pablo Lara
258d18112c feat: add action to getTask and implement the last step in the workflow - launch scan 2024-11-03 11:31:47 +01:00
Pablo Lara
ff9d5442ab chore: update with the last step - workflow component 2024-11-03 10:39:10 +01:00
Pablo Lara
4a3b767002 chore: remove the old test connection component 2024-11-03 10:07:11 +01:00
Pablo Lara
ee2d7ca79e feat: add test connection form 2024-11-02 10:08:00 +01:00
Pablo Lara
89c441ba58 feat: add test connection form 2024-11-02 09:10:30 +01:00
Pablo Lara
c3c775786c feat: add credentials for kubernetes 2024-11-01 09:30:43 +01:00
Pablo Lara
33ae08be65 feat: add credentials for GCP 2024-10-31 18:38:12 +01:00
Pablo Lara
593bce5155 feat: add credentials for AWS and Azure are working nicely 2024-10-31 18:27:28 +01:00
Adrián Jesús Peña Rodríguez
31c035eb52 fix(migrations): PRWLR-4869 add missing error_messages field (#65) 2024-10-31 17:49:14 +01:00
Víctor Fernández Poyatos
fc19fbac68 feat(ProviderSecret): PRWLR-5128 Implement role assumption provider credentials for AWS (#64)
* feat(ProviderSecret): PRWLR-5128 add role assumption logic

* feat(Provider): PRWLR-5128 add static kwargs to Prowler provider initialization

* chore: PRWLR-5128 update API spec

* test(ProviderSecret): PRWLR-5128 add new unit tests

* chore: PRWLR-5128 update API spec
2024-10-31 16:25:20 +01:00
Adrián Jesús Peña Rodríguez
c188028de5 feat(auth): PRWLR-4944 add recommended fields to JWTs (#62)
* feat(auth): PRWLR-4944 add recommended fields to JWTs

* feat(auth): PRWLR-4944 remove extra validations

* feat(auth): PRWLR-4944 fix format
2024-10-31 16:24:23 +01:00
Víctor Fernández Poyatos
43f9a5b1d0 fix(Task): fix serializer to convert None to null when decoding (#63) 2024-10-31 16:21:40 +01:00
Pablo Lara
c81cb04bd0 chore: create separate component for azure credentials 2024-10-31 09:12:31 +01:00
Pablo Lara
d7452238d6 chore: create separate component for aws credentials 2024-10-31 09:08:23 +01:00
Pablo Lara
fb99733a1e chore: add form for azure credentials 2024-10-31 08:51:44 +01:00
Pablo Lara
7c4f34bb6c feat: custom add credentials page 2024-10-31 08:08:20 +01:00
Pablo Lara
9882cd53cf chore: add credentials type to the url if exists 2024-10-31 06:48:58 +01:00
Pablo Lara
052b882195 chore: client validation when select a provider type 2024-10-31 06:41:36 +01:00
Pablo Lara
3a8053c3c6 chore: remove the old form to add providers 2024-10-31 05:53:59 +01:00
Pablo Lara
d0b5992146 feat: redirect on add credentials page if there is no provider associated 2024-10-30 17:30:29 +01:00
Pablo Lara
37343750cd chore: add form for add-credentials-providers 2024-10-30 17:26:34 +01:00
Pablo Lara
f1a951b2e4 chore: add form for add-credentials-providers 2024-10-30 15:01:48 +01:00
Pablo Lara
6783da028c WIP 2024-10-30 09:49:11 +01:00
Pablo Lara
ee7ba35068 WIP 2024-10-30 06:18:21 +01:00
Pablo Lara
886e3aefb0 WIP 2024-10-30 04:09:19 +01:00
Pablo Lara
ccc80d5ce4 WIP 2024-10-30 04:03:51 +01:00
Pablo Lara
e468a91468 WIP 2024-10-30 03:47:07 +01:00
Pepe Fagoaga
01045c973f chore(partitions): add env to create partitions (#61)
* chore(partitions): add env to create partitions

* chore(partitions): rename env to DJANGO_MANAGE_DB_PARTITIONS

* chore(partitions): use True|False as value

* fix: begin comment with uppercase
2024-10-29 16:16:09 +01:00
Pablo Lara
5a8d6087f9 wIP 2024-10-29 16:00:09 +01:00
Pablo Lara
f0c663aca8 feat: add new component - workflow to set up providers 2024-10-29 12:22:03 +01:00
Pablo Lara
0a801d29cd feat: add new component - navigation header 2024-10-29 10:01:46 +01:00
Pablo Lara
52526800f9 feat: add new component - navigation header 2024-10-29 09:52:03 +01:00
Adrián Jesús Peña Rodríguez
98ec0532b2 fix(serializers): PRWLR-4869 hide email address information when it already exists (#60)
* fix(serializers): PRWLR-4869 hide email address information when it already exists

* fix(serializers): PRWLR-4869 fix ruff format error
2024-10-28 15:11:20 +01:00
dependabot[bot]
674a38e80f chore(deps): bump werkzeug from 3.0.4 to 3.0.6 (#59)
Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.4 to 3.0.6.
- [Release notes](https://github.com/pallets/werkzeug/releases)
- [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/werkzeug/compare/3.0.4...3.0.6)

---
updated-dependencies:
- dependency-name: werkzeug
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-28 08:50:45 +01:00
Pablo Lara
753c128357 chore: remove unused console log 2024-10-28 07:45:07 +01:00
Adrián Jesús Peña Rodríguez
a4b16dd1e9 fix(Finding): PRWLR-5098 change the size of the UID field to 300 characters (#58) 2024-10-22 11:58:49 +02:00
Pablo Lara
13ff0e08bb Merge pull request #75 from prowler-cloud/PRWLR-4982-Create-a-finding-component-integrate-with-API
Prwlr 4982 create a finding component integrate with api
2024-10-22 11:09:33 +02:00
Pablo Lara
9a9a6410e1 feat: render findings first iteration 2024-10-22 11:07:00 +02:00
Pablo Lara
af267fede4 chore: WIP 2024-10-21 20:30:26 +02:00
Pablo Lara
cc0923b3c7 chore: update FindingProps to the latest version 2024-10-21 12:02:07 +02:00
Pablo Lara
5f7a3d0bcf chore: update FindingProps to the latest version 2024-10-21 11:55:02 +02:00
Víctor Fernández Poyatos
ed427c1352 chore(Scan, Finding): PRWLR-5056 Adjust finding information storing when performing a scan (#57)
* chore: PRWLR-5056 update Prowler dependency

* feat(Scan): PRWLR-5056 adapt scan task code to sdk breaking changes

* test(Scan): PRWLR-5056 fix unit tests

* chore: PRWLR-5056 update fixtures

* chore: PRWLR-5056 update Prowler dependency
2024-10-18 13:56:07 +02:00
Víctor Fernández Poyatos
a8825c385b feat(User): PRWLR-4988 Make users' email case insensitive (#56)
* feat(User): PRWLR-4988 make User.email case insensitive

* test(User): PRWLR-4988 update unit tests

* feat(User): PRWLR-4988 include email validation in serializer
2024-10-17 19:22:20 +02:00
Víctor Fernández Poyatos
6d69a192f3 fix(Finding, Resource): PRWLR-5057 Fix include query parameter for /findings and /resources (#55)
* fix(Finding, Resource): PRWLR-5057 fix include query parameter

* fix(Finding, Resource): PRWLR-5057 optimize requests

* test(Finding, Resource): PRWLR-5057 add unit tests for include
2024-10-17 18:07:06 +02:00
Pablo Lara
a694b422cf WIP 2024-10-16 18:03:29 +02:00
Víctor Fernández Poyatos
60c75b4814 chore(Finding): PRWLR-5059 Remove default filtering and change default ordering (#54) 2024-10-16 13:41:41 +02:00
Pablo Lara
efd2805602 feat: render finding table 2024-10-16 11:07:57 +02:00
Pablo Lara
b3c905c95a chore: add Findings props type 2024-10-16 07:09:30 +02:00
Pablo Lara
868615fa89 chore: clean finding folder 2024-10-16 07:08:22 +02:00
Pablo Lara
08937a9a66 Merge pull request #74 from prowler-cloud/PRWLR-4883-Integrate-authentication-endpoint-client-validation
Prevent sending default empty string for company name during sign-up
2024-10-16 06:17:12 +02:00
Pablo Lara
ce205dc95d fix: prevent sending default empty string for company name during sign-up 2024-10-16 06:06:37 +02:00
Pablo Lara
53b04879a0 Merge pull request #69 from prowler-cloud/dependabot/pip/django-5.0.9
chore(deps): bump django from 5.0.8 to 5.0.9
2024-10-14 17:46:48 +02:00
Pablo Lara
91e7906a0b Merge pull request #73 from prowler-cloud/PRWLR-4777-Create-Scan-page-integration-scan-endpoint-4
Create scan page integration scan endpoint
2024-10-14 17:43:49 +02:00
Pablo Lara
7f73e26016 fix: showing the error for company name when try to sign up 2024-10-14 17:42:30 +02:00
Pablo Lara
d0b54d1950 feat: detail view for scans has been implemented 2024-10-14 17:30:32 +02:00
Pablo Lara
da9429351f chore: replace disable for isDisable prop 2024-10-14 17:28:22 +02:00
Pablo Lara
c0a9bd14aa feat: integrate Sheet component with ScanDetail view via getScan 2024-10-13 08:56:03 +02:00
Pablo Lara
0585428029 feat: getScan detail view first iteration 2024-10-12 14:19:18 +02:00
Pablo Lara
bfb591977e feat: there is no DELETE method for scans for now 2024-10-12 07:43:27 +02:00
Pablo Lara
1fff7ef1d3 feat: add PATCH method for scans 2024-10-11 16:18:15 +02:00
Víctor Fernández Poyatos
351132fb5b feat(ProviderSecret): PRWLR-4102 Implement /providers/secrets CRUD (#53)
* feat(Credential): PRWLR-4102 add model definition

* feat(Credential): PRWLR-4102 add serializers, views, urls and decorator

* feat(ProviderSecret): PRWLR-4102 rework credentials into provider secrets

* feat(ProviderSecret): PRWLR-4102 rework urls, views, serializers

* feat(Provider, Scan): PRWLR-4102 refactor modules to adapt connection test and scans to secrets

* feat(ProviderSecret): PRWLR-4102 add GCPProviderSecret serializer

* feat(Provider): PRWLR-4102 validate provider_id when testing connection

* chore(Utils): PRWLR-4987 refactor prowler provider functions

* test(Utils): PRWLR-4102 add unit tests

* test(Scan, Provider): PRWLR-4102 fix unit tests

* chore: PRWLR-4102 add docstrings and update prowler version and API spec

* chore(Provider, Scan): PRWLR-4102 update fixtures

* test(ProviderSecret): PRWLR-4102 add unit tests

* chore: PRWLR-4102 optimize imports
2024-10-11 15:49:45 +02:00
Pablo Lara
f29e87f45b feat: Scan on demand can be executed now from the UI 2024-10-11 15:33:03 +02:00
Pablo Lara
69a1468c18 Wrap CustomButton component with React.forwardRef 2024-10-11 06:49:14 +02:00
Pablo Lara
0a8c352194 chore: rename file for scan actions 2024-10-10 16:47:05 +02:00
Pablo Lara
ab29373537 chore: tweak styles snippet id component 2024-10-10 16:39:30 +02:00
Pablo Lara
b304f11b18 chore: tweak styles for entity info short component 2024-10-10 16:37:18 +02:00
Pablo Lara
4cf7a3244f chore: replace icon for check connection component 2024-10-10 15:43:41 +02:00
Pablo Lara
bd46196fd0 chore: replace icon for spnippet id 2024-10-10 15:34:10 +02:00
Pablo Lara
d79e1d6c94 chore: add table for schedule scans 2024-10-10 15:24:50 +02:00
Pablo Lara
5b51653d78 chore: retrieve values for all scans in getScans 2024-10-10 14:02:36 +02:00
Pablo Lara
5246d84599 chore: retrieve values for all scans in getScans 2024-10-10 14:02:21 +02:00
Pablo Lara
9409ea75e5 chore: table for launch scan is added to scan page 2024-10-10 09:17:31 +02:00
Pablo Lara
970cb97f73 chore: table for launch scan is added to scan page 2024-10-10 08:52:36 +02:00
Pablo Lara
a1585142b7 chore: refactor custom filters to be able to have two in the same page 2024-10-09 13:56:56 +02:00
Pablo Lara
ba106ac8f3 Merge pull request #71 from prowler-cloud/PRWLR-4777-Create-Scan-page-integration-scan-endpoint-2
Small style tweaks
2024-10-09 10:13:51 +02:00
Pablo Lara
558d83c957 chore: style tweaks 2024-10-09 10:11:48 +02:00
Pablo Lara
7b38950f3c Merge pull request #70 from prowler-cloud/PRWLR-4777-Create-Scan-page-integration-scan-endpoint
Refactor common components and fix typo errors
2024-10-09 08:18:48 +02:00
Pablo Lara
67333c00b9 chore: add NextUI theme colors in Tailwind config 2024-10-09 08:15:57 +02:00
Pablo Lara
7a6ab5b7c7 refactor: extract common components to reduce code duplication, fix typo 2024-10-09 07:50:56 +02:00
Pablo Lara
a149458593 chore: rename custom components 2024-10-09 06:47:10 +02:00
Pablo Lara
fe27a32dcb chore: change color action 2024-10-09 06:42:38 +02:00
dependabot[bot]
a6095f7aa1 chore(deps): bump django from 5.0.8 to 5.0.9
Bumps [django](https://github.com/django/django) from 5.0.8 to 5.0.9.
- [Commits](https://github.com/django/django/compare/5.0.8...5.0.9)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-08 21:35:13 +00:00
Víctor Fernández Poyatos
8791b7e3f1 feat(Scan, Finding): PRWLR-4987 Adjust findings delta based on previous findings (#52)
* feat(Finding): PRWLR-4987 add uid field to Findings

* feat(Scan): PRWLR-4987 implement logic to calculate Finding delta value

* test(Scan): PRWLR-4987 add unit tests for _create_finding_delta

* chore(Spec): PRWLR-4987 update API spec
2024-10-08 14:43:18 +02:00
Pablo Lara
e843ef6ffc Merge pull request #68 from prowler-cloud/PRWLR-4823-remove-menu-items
Remove menu items
2024-10-08 12:07:55 +02:00
Pablo Lara
b3c2f3a3fc chore: tsx tweaks 2024-10-08 12:05:29 +02:00
Pablo Lara
3d533b56ef chore: rename sidebar component 2024-10-08 11:24:31 +02:00
Pablo Lara
b43832fa8f chore: menu tweaks 2024-10-08 11:23:52 +02:00
Pablo Lara
a5332b31f1 Merge pull request #67 from prowler-cloud/PRWLR-4823-remove-menu-items
Remove menu items
2024-10-08 10:02:58 +02:00
Pablo Lara
fa604af6ea chore: styling tweaks for custom box 2024-10-08 10:01:43 +02:00
Pablo Lara
dbb0d506af chore: menu item tweaks 2024-10-08 09:58:44 +02:00
Pablo Lara
785bdb5bb3 Merge pull request #65 from prowler-cloud/PRWLR-4883-Integrate-authentication-endpoint-OSS
Integrate authentication endpoint oss
2024-10-08 09:30:44 +02:00
Pablo Lara
343754061a Merge pull request #66 from prowler-cloud/PRWLR-4883-Integrate-authentication-endpoint-OSS-bg-2
Styling signIn and signUp pages
2024-10-08 09:29:18 +02:00
Pablo Lara
7572136cc8 feat: sign-up and sign-in pages are styled and ready to be merged 2024-10-08 08:46:35 +02:00
Pablo Lara
6b7fe81cf8 chore: tweak styles auth pages 2024-10-07 17:30:31 +02:00
Pablo Lara
f5e53e814b chore: tweak styles auth pages 2024-10-07 07:07:26 +02:00
Pablo Lara
b8b05b923f chore: tweak styles for Prowler logo in signIn page 2024-10-07 06:41:13 +02:00
Pablo Lara
22bacfdcb3 feat(sign-up/sign-in): remove unused component 2024-10-06 13:23:59 +02:00
Pablo Lara
d138c4eeb8 feat(sign-up/sign-in): styling the the auth page 2024-10-06 13:20:45 +02:00
Pablo Lara
f0f4e85f06 feat(sign-up): integrate sign-up functionality in the application 2024-10-05 19:08:28 +02:00
Pablo Lara
e2261af59f feat(auth): refresh access token on-demand when receiving 401 error 2024-10-05 14:43:02 +02:00
Pablo Lara
ff74edcc04 feat(auth): refresh access token on-demand when receiving 401 error 2024-10-05 14:29:41 +02:00
Pablo Lara
735f830251 feat: add function getUserByMe 2024-10-05 14:02:22 +02:00
Pablo Lara
abcf37ea92 feat: Reduce session cookie size drastically 2024-10-05 06:51:05 +02:00
Pablo Lara
8da95c7102 chore: The session will expire in 24 hours as the refreshToken coming from the API 2024-10-04 18:48:51 +02:00
Pablo Lara
72d875aa4f chore: WIP 2024-10-04 16:08:57 +02:00
Víctor Fernández Poyatos
8130880f2d chore(Tenant, Provider, Scan, Task, Resource): PRWLR-4966 Update default ordering in viewsets (#51)
* chore(Tenant, Provider, Scan, Task, Resource): PRWLR-4966 set default ordering to -inserted_at

* chore: PRWLR-4966 update API schema
2024-10-04 14:33:18 +02:00
Víctor Fernández Poyatos
d98b716dfc chore(Filters): PRWLR-4948 Refactor filter module to reduce complexity and improve docs (#50)
* chore(Django-filter): PRWLR-4948 bump django-filter version to 24.3

* fix(Middleware): PRWLR-4948 fix logging middleware when auth is not present in request

* fix(Task): PRWLR-4948 fix serializer state values

* chore(Filters): PRWLR-4948 use ChoiceFilter instead of implementing method for basic filters

* chore(Filters): PRWLR-4948 refactor complex filters to reduce complexity
2024-10-04 14:13:04 +02:00
Víctor Fernández Poyatos
6bd8a17a5f fix(Task): PRWLR-4970 Fix Celery task issues when status is pending and race conditions (#49)
* fix(Task): PRWLR-4970 add TaskResult entry to database when task reaches broker

* fix(Task, Scan): PRWLR-4970 remove race conditions using atomic transactions

* chore(Django): PRWLR-4970 bump Django version to 5.1.1
2024-10-04 11:54:15 +02:00
Víctor Fernández Poyatos
ded28baa2f feat(Scan, Resource, Finding): PRWLR-4015 Implement on demand scans and findings/resources in database (#48)
* feat(Users): PRWLR-4718 make user email the default login username

* feat(Token): PRWLR-4718 add serializers, views and urls for access and refresh tokens

* feat(Token): PRWLR-4718 add first membership tenant in token if not present in json body

* feat(Users): PRWLR-4718 add company_name to model

* feat(Users): PRWLR-4718 create tenant and membership when creating new user

* fix(BaseView): PRWLR-4718 add tenant_id to serializer context

* fix(Tests): PRWLR-4718 use authorization with unit tests

* fix(Views): PRWLR-4718 fix tenant retrieval from request

* fix(Tests): PRWLR-4718 fix tests

* fix(Fixtures): PRWLR-4718 fix tenant memberships ordering

* chore(Tokens): PRWLR-4718 update token url

* chore(Spec): PRWLR-4718 update API spec

* feat(Tokens): PRWLR-4718 enable token refresh blacklisting

* feat(Tokens): PRWLR-4718 implement RS256 algorithm and dev valid keys

* chore(env): PRWLR-4718 update .env.example

* chore(Deps): PRWLR-4015 update prowler dep

* fix(Resources, Findings): PRWLR-4015 fix permission issues on models and migrations

* feat(Scans, Tasks, Resources, Findings): PRWLR-4015 perform whole flow when executing scans

* fix(Settings): PRWLR-4015 fix devel JWT settings

* chore(Scans, Tasks): PRWLR-4015 improve docs and responses format

* test(Scan, Provider): PRWLR-4015 fix unit tests

* chore(Environment): PRWLR-4015 fix .env.example values

* test(Scan): PRWLR-4015 add unit tests for scan task

* chore(Task): PRWLR-4015 give proper format to task result on scan perform

* feat(Provider, Scan): PRWLR-4015 add all provider types to connection check and scan

* fix(Logging): PRWLR-4015 fix API logger middleware to include tenant and user IDs
2024-10-03 18:36:42 +02:00
Pablo Lara
5c0ee0cfb3 chore: remove dataProviders json file 2024-10-03 18:21:52 +02:00
Pablo Lara
c7d6484eb8 chore: WIP 2024-10-03 18:20:28 +02:00
Pablo Lara
42ebf91a67 chore: add the new colors for the dark mode 2024-10-03 06:22:35 +02:00
Pablo Lara
d8c9720723 fix: order by default using sorting param 2024-10-03 06:08:05 +02:00
Pablo Lara
8e7dfcaa76 WIP 2024-10-02 17:22:34 +02:00
Pablo Lara
a72b33597d WIP 2024-10-02 16:09:26 +02:00
Pablo Lara
6e37d8d850 chore: update all providers API requests 2024-10-02 10:00:54 +02:00
Pablo Lara
ce51108f7f fix: apply password match validation only on sign-up form 2024-10-02 06:37:29 +02:00
Pablo Lara
9e56a4a10d chore: add id attibute to the customInput component to make unique fields 2024-10-02 06:25:35 +02:00
Pablo Lara
76b1c83add chore: tweaks authFormSchema using zod validation for client side 2024-10-01 14:29:58 +02:00
Pablo Lara
650b95c4f1 chore: add confirmPassword input in sign-up page 2024-10-01 14:15:05 +02:00
Pablo Lara
ceebfc9aca chore: remove unused dependency 2024-10-01 14:14:26 +02:00
Pablo Lara
2e443db362 chore: comanyName is now optional and added confirmPassword field 2024-10-01 14:13:49 +02:00
Pablo Lara
e15690781f Merge pull request #64 from prowler-cloud/PRWLR-4917-Improving-Filtering-Impacts-the-whole-app-followUp
Codebase improvements: Tailwind formatting, accessibility fixes, and search optimization
2024-10-01 08:16:54 +02:00
Pablo Lara
35f7c90c19 chore: rename for consistency custom-button component 2024-10-01 06:02:22 +02:00
Pablo Lara
717f9765e1 chore: run prettier-plugin-tailwindcss 2024-10-01 05:55:20 +02:00
Pablo Lara
607cd5d1e0 feat: install, configure and run prettier-plugin-tailwindcss 2024-10-01 05:44:24 +02:00
Pablo Lara
4e5bb81906 chore: Style tweaks for filters 2024-10-01 05:30:47 +02:00
Pablo Lara
24163b2644 chore: Style tweaks for filters 2024-10-01 04:59:07 +02:00
Víctor Fernández Poyatos
54bb034cac feat(Tokens): PRWLR-4718 implement user authorization with JWT (#47)
* feat(Users): PRWLR-4718 make user email the default login username

* feat(Token): PRWLR-4718 add serializers, views and urls for access and refresh tokens

* feat(Token): PRWLR-4718 add first membership tenant in token if not present in json body

* feat(Users): PRWLR-4718 add company_name to model

* feat(Users): PRWLR-4718 create tenant and membership when creating new user

* fix(BaseView): PRWLR-4718 add tenant_id to serializer context

* fix(Tests): PRWLR-4718 use authorization with unit tests

* fix(Views): PRWLR-4718 fix tenant retrieval from request

* fix(Tests): PRWLR-4718 fix tests

* fix(Fixtures): PRWLR-4718 fix tenant memberships ordering

* chore(Tokens): PRWLR-4718 update token url

* chore(Spec): PRWLR-4718 update API spec

* feat(Tokens): PRWLR-4718 enable token refresh blacklisting

* feat(Tokens): PRWLR-4718 implement RS256 algorithm and dev valid keys

* fix(Environment): PRWLR-4718 fix jwt keys env vars

* fix(Environment): PRWLR-4718 fix jwt keys env vars (testing)

* chore(Settings): PRWLR-4718 remove drf-spectacular unused settings

* fix(Environment): PRWLR-4718 remove jwt signature keys from dev and testing modules
2024-09-30 17:45:09 +02:00
Pablo Lara
7c2f7d7eeb chore: Fix issue with invalid keys being passed to selectedKeys 2024-09-30 17:37:09 +02:00
Pablo Lara
fcd1aa5d76 chore: impot lodash correctly 2024-09-30 17:25:08 +02:00
Pablo Lara
1f5ee1ee3f chore: tweak styles 2024-09-30 17:23:52 +02:00
Pablo Lara
bbbcc4a185 chore: Add aria-labels to fix errors accessibility 2024-09-30 17:03:15 +02:00
Pablo Lara
f8c5f4f1cc chore: Add aria-label to buttons for improved accessibility 2024-09-30 16:54:33 +02:00
Pablo Lara
78f8badddd Merge pull request #63 from prowler-cloud/PRWLR-4917-Improving-Filtering-Impacts-the-whole-app
Big Refactor: Integrated React Hook Form, Improved UI Consistency and added new features
2024-09-30 16:32:36 +02:00
Pablo Lara
5223cf3763 chore: rename component properly 2024-09-30 16:31:15 +02:00
Pablo Lara
39b7fca11f chore: rename component properly 2024-09-30 16:30:38 +02:00
Pablo Lara
904a4a61e9 chore: rename component properly 2024-09-30 16:16:24 +02:00
Pablo Lara
f146946319 feat: big refactor for filters and tons of components 2024-09-30 16:15:43 +02:00
Pablo Lara
db9faa2f4b chore: WIP 2024-09-30 09:43:23 +02:00
Pablo Lara
d9ec74b149 chore: WIP 2024-09-30 06:21:56 +02:00
Pablo Lara
ba1f8c9a3a chore: handle lib folder dependencies with nextui 2024-09-28 06:13:28 +02:00
Pablo Lara
f496896884 feat: change render order by default, rename components, simplify structure 2024-09-28 05:29:04 +02:00
Pablo Lara
1ea8addb04 chore: remove unused console log 2024-09-27 15:53:16 +02:00
Pablo Lara
f7df63e2af feat: add new functionality for adding provider and remove the old one 2024-09-27 15:33:36 +02:00
Pablo Lara
2807fc2b8e chore: replace the new field date value coming from the API 2024-09-27 11:15:02 +02:00
Pablo Lara
fbb5ede272 chore: add types in the proper directory 2024-09-27 10:45:12 +02:00
Pablo Lara
8e1c8304d8 feat: fix TS errors in customButton component 2024-09-27 10:42:16 +02:00
Pablo Lara
dbfc11e822 chore: tweak filter controls 2024-09-27 10:20:38 +02:00
Pablo Lara
0235f37faa chore: tweak styles for button with icons 2024-09-27 10:04:41 +02:00
Pablo Lara
ef7272cf80 chore: edit and delete provider form have been refactored using custom buttons 2024-09-27 09:42:48 +02:00
Pablo Lara
840df1dab6 feat: hide scrollbar when needed 2024-09-27 07:47:17 +02:00
Pablo Lara
1f75d70d4e fix: fix the providerId, the value coming from the API changed 2024-09-26 16:05:17 +02:00
Pablo Lara
ede597d02d chore: add new icons 2024-09-26 16:03:13 +02:00
Pablo Lara
8db20eb2ba chore: add new colors 2024-09-26 16:02:52 +02:00
Pablo Lara
a70fcf488d chore: add new colors 2024-09-26 16:02:13 +02:00
Pablo Lara
c544a069a2 feat: create and integrate custom button component 2024-09-26 16:01:42 +02:00
Pablo Lara
4b74a8a008 feat: add a header to use basic auth 2024-09-26 16:01:16 +02:00
Víctor Fernández Poyatos
4c83351b26 feat(Tenants, Memberships): PRWLR-4719 Add memberships endpoints and security changes (#44)
* feat(SimpleJWT): PRWLR-4717 add djangorestframework-simplejwt dep

* feat(SimpleJWT): PRWLR-4717 add basic configuration and env variables

* feat(Users): PRWLR-4717 add model and security constraints

* feat(Users): PRWLR-4717 add serializers

* feat(Users): PRWLR-4717 add views

* test(Conftest): PRWLR-4717 add user and authenticated client fixtures

* fix(Unit tests): PRWLR-4717 add automated authentication to all unit tests

* fix(Authentication): PRWLR-4717 add authentication class and update tests

* test(Users): PRWLR-4717 add unit tests

* test(Users): PRWLR-4717 add integration tests

* chore(Schema): PRWLR-4717 update API schema

* fix(User): PRWLR-4717 fix password validation

* feat(Validators): PRWLR-4717 add MaxLength password validator

* fix(User): PRWLR-4717 update User model to delete admin fields

* chore(Serializers): PRWLR-4717 add docstrings and update serializers

* chore(Fixtures): PRWLR-4717 add dev user

* feat(Memberships): PRWLR-4719 add membership.Roles postgres enums

* feat(Memberships): PRWLR-4719 add model

* feat(Tenants): PRWLR-4719 add owner membership when creating a new one

* chore(Users): PRWLR-4717 raise DRF NotFound instead of returning response

* chore(Deps): PRWLR-4719 add drf-nested-routers

* feat(Memberships): PRWLR-4719 add serializers, urls and views

* feat(Tenants): PRWLR-4719 add RLS based on memberships

* chore(Views): PRWLR-4719 unify tenant related views dispatch methods

* test(Tenants): PRWLR-4719 add membership to test user when creating tenants

* test(Users): PRWLR-4719 add name field to model

* chore(Deps): PRWLR-4719 add drf-nested-routers

* feat(Memberships): PRWLR-4719 separate membership endpoints

* feat(Memberships): PRWLR-4719 add filters

* test(Memberships): PRWLR-4719 add unit tests

* test(Tenants): PRWLR-4719 add membership unit tests

* chore(API): PRWLR-4719 update spec

* chore(API): PRWLR-4719 update Django dev fixtures

* test(Memberships): PRWLR-4719 add more unit tests

* chore(Memberships): PRWLR-4719 move /memberships to /users/me/

* feat(Users, Tenants, Memberships): PRWLR-4719 update responses and routes

* feat(Memberships): PRWLR-4719 adjust tenant membership view results under membership role

* chore(Scans): PRWLR-4719 rename django fixture
2024-09-25 13:12:15 +02:00
Pablo Lara
e67f4e5f29 feat: WIP 2024-09-25 06:56:34 +02:00
Pablo Lara
087ffcbb95 Merge pull request #62 from prowler-cloud/PRWLR-4041-Providers-Page-Manage-Providers-Modal-Delete-Providers-Modal
Providers page manage providers modal
2024-09-24 13:12:11 +02:00
Pablo Lara
b860e35408 feat: fuctionality tweaks handling errors 2024-09-24 11:43:51 +02:00
Pablo Lara
94eba806e3 feat: big refactor for CustomInput component 2024-09-24 08:40:48 +02:00
Pablo Lara
fa77455c3e feat: edit provider has client validation now 2024-09-24 08:09:02 +02:00
Víctor Fernández Poyatos
4a881fd2fd chore: delete LICENSE (#46) 2024-09-23 17:27:00 +02:00
Pablo Lara
4f7d6a8402 Merge branch 'main' into PRWLR-4041-Providers-Page-Manage-Providers-Modal-Delete-Providers-Modal 2024-09-23 13:39:30 +02:00
Jon Young
4ca95b08e2 feat(Findings): Partitioned database tables (#45)
* feat(Findings): initial findings model

* fix(Findings): add view, serializers, migration for enums

* fix(Findings): incomplete jsonb_to_tsvector wrapper

will not run as written

* fix(Findings): use Severity and Status enums from prowler SDK

* tests(Findings): add failing view tests

* fix(Finding): add resource relationship

not returning correct data from serializer, missing links

* fix(FindingSerializer): get Scan & Resource relationships to show up

* fix(FindingFilter): add more filter fields

* fix(FindingFilter): filter on provider id

* fix(FindingSerializer): return Resource in relationship

not ResourceFindingMapping

* fix(FindingModel): update migration

* fix(FindingFilter): full text search on findings

* fix(Resources): include Findings in ResourceSerializer

* fix(FindingFilter): expand text search columns

* fix(DbUtils): docstring, not comment

* fix(BaseViews): remove TODO

comment not applicable right now

* fix(Fixtures): add more findings to fixture file

and change on_delete behavior for resource_finding_mapping

* fix(Resources): rename index to match others

* fix(Findings): update Findigns RLS to allow for full CRUD

eventually we'll let users enter a manual finding
which implies INSERT, UPDATE, DELETE

* fix(Findings): use TextChoices directly for Status enum

* fix(FindingSerializer): build a set instead of a list

* consistency in fixtures

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>

* fix(API): update v1 spec for findings

* feat(Findings): store findings in a partitioned table

* fix(Settings): change unit of partition max age

to match unit when creating

* docs(Partitions): document how to manage partitions via manage.py

* fix(Findings): add tag for spec/docs

* fix(Findings): clean up migrations

* fix(Findings): convert scan_id and inserted_at filters into finding.id filters

* fix(Findings): add default filter for today

and set default sort order

* fix(Findings): add default filter for today

and set default sort order

* fix(Findings): update fixtures so datetime matches id

* fix(Findings): partition the ResourceFindingMapping table to match Findings

* docs(Partitions): document postgres config values more

* docs(UUIDUtils): do not use raw query strigns (typo)

* docs(Partitions): change unit in comment description

* fix(Findings): change resource_name & tags to be Finding

* docs(Partitions): change unit in partitions settings docstring

* fix(Findings): remove conflicting logic & filters

* chore: apply suggested changes

* chore: optimize imports

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-09-23 11:39:03 +02:00
Pablo Lara
0d5be65879 Merge pull request #61 from prowler-cloud/PRWLR-4763-Confirmation-screen
Confirmation modal component
2024-09-23 08:25:39 +02:00
Pablo Lara
3b96d14f84 chore: rename getProviders action and add modal for editing provider info 2024-09-22 15:48:47 +02:00
Pablo Lara
1dfde958bf chore: rename getProviders action and add modal for editing provider info 2024-09-22 15:48:03 +02:00
Pablo Lara
cb20f595ac rename: rename table components 2024-09-21 22:15:04 +02:00
Pablo Lara
720256968e feat: confirmation screen works as expected 2024-09-21 21:51:51 +02:00
Pablo Lara
7fb6250029 chore: WIP 2024-09-20 18:16:37 +02:00
Pablo Lara
3cac32ac78 Merge pull request #60 from prowler-cloud/ack/fix-dockerfile
Ack/fix dockerfile
2024-09-19 17:08:13 +02:00
Drew Kerrigan
a5fb1205af fix(): put line ending back 2024-09-19 10:56:34 -04:00
Drew Kerrigan
41e7dce861 fix(): cleanup comment 2024-09-19 10:55:56 -04:00
Drew Kerrigan
10f68a4630 fix(): ignore local .env file 2024-09-19 10:54:38 -04:00
Drew Kerrigan
94090f6997 fix(): add missing copy commands 2024-09-19 10:54:19 -04:00
Pablo Lara
f50f1680df Merge pull request #57 from prowler-cloud/dependabot/npm_and_yarn/next-14.2.12
chore(deps): bump next from 14.2.7 to 14.2.12
2024-09-19 13:01:34 +02:00
Pablo Lara
fd1832243e Merge pull request #59 from prowler-cloud/PRWLR-4823-add-menu-items
chore: add new items to the menu
2024-09-19 12:51:48 +02:00
Pablo Lara
52e8ba702d chore: add new items to the menu 2024-09-19 12:43:02 +02:00
Pablo Lara
ed9bbd30a3 chore: add new items to the menu 2024-09-19 12:41:24 +02:00
Pablo Lara
035d06bbfe Merge pull request #58 from prowler-cloud/fix/build-errors
fix: fix build errors
2024-09-19 09:11:40 +02:00
Pablo Lara
39c6fa9e55 fix: fix build errors 2024-09-19 09:08:22 +02:00
Jon Young
489ac20141 feat(Findings): add the /findings endpoint (#38)
* feat(Findings): initial findings model

* fix(Findings): add view, serializers, migration for enums

* fix(Findings): incomplete jsonb_to_tsvector wrapper

will not run as written

* fix(Findings): use Severity and Status enums from prowler SDK

* tests(Findings): add failing view tests

* fix(Finding): add resource relationship

not returning correct data from serializer, missing links

* fix(FindingSerializer): get Scan & Resource relationships to show up

* fix(FindingFilter): add more filter fields

* fix(FindingFilter): filter on provider id

* fix(FindingSerializer): return Resource in relationship

not ResourceFindingMapping

* fix(FindingModel): update migration

* fix(FindingFilter): full text search on findings

* fix(Resources): include Findings in ResourceSerializer

* fix(FindingFilter): expand text search columns

* fix(DbUtils): docstring, not comment

* fix(BaseViews): remove TODO

comment not applicable right now

* fix(Fixtures): add more findings to fixture file

and change on_delete behavior for resource_finding_mapping

* fix(Resources): rename index to match others

* fix(Findings): update Findigns RLS to allow for full CRUD

eventually we'll let users enter a manual finding
which implies INSERT, UPDATE, DELETE

* fix(Findings): use TextChoices directly for Status enum

* fix(FindingSerializer): build a set instead of a list

* consistency in fixtures

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>

* fix(API): update v1 spec for findings

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-09-18 19:28:03 +02:00
Víctor Fernández Poyatos
9ffde34198 feat(Users): #PRWLR-4717 add /users endpoints and basic auth (#43)
* feat(SimpleJWT): PRWLR-4717 add djangorestframework-simplejwt dep

* feat(SimpleJWT): PRWLR-4717 add basic configuration and env variables

* feat(Users): PRWLR-4717 add model and security constraints

* feat(Users): PRWLR-4717 add serializers

* feat(Users): PRWLR-4717 add views

* test(Conftest): PRWLR-4717 add user and authenticated client fixtures

* fix(Unit tests): PRWLR-4717 add automated authentication to all unit tests

* fix(Authentication): PRWLR-4717 add authentication class and update tests

* test(Users): PRWLR-4717 add unit tests

* test(Users): PRWLR-4717 add integration tests

* chore(Schema): PRWLR-4717 update API schema

* fix(User): PRWLR-4717 fix password validation

* feat(Validators): PRWLR-4717 add MaxLength password validator

* fix(User): PRWLR-4717 update User model to delete admin fields

* chore(Serializers): PRWLR-4717 add docstrings and update serializers

* chore(Fixtures): PRWLR-4717 add dev user

* chore(Users): PRWLR-4717 raise DRF NotFound instead of returning response
2024-09-18 10:19:44 +02:00
dependabot[bot]
0100b805ee chore(deps): bump next from 14.2.7 to 14.2.12
Bumps [next](https://github.com/vercel/next.js) from 14.2.7 to 14.2.12.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v14.2.7...v14.2.12)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-18 06:34:03 +00:00
Jon Young
6a341b88f0 fix(Providers, Resources, Scans): rename provider_id and filter on more provider fields (#42)
* fix(Providers, Resources, Scans): filter on more provider fields

* Apply suggestions from code review

more python-y

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-09-13 16:09:09 +02:00
Víctor Fernández Poyatos
1cef6f0db7 feat(Tasks): PRWLR-4826 add task_args to serializer (#41) 2024-09-12 09:07:08 -04:00
Jon Young
f7645e8f25 feat(Resources): add the /resources endpoint (#34)
* fix(Resources): add basic Resource MVC

* fix(Resources): implement many-to-many tags via through table

* fix(Resources): tsvector & migration

migration needs work, need to create a custom
django migration field to build the GENERATED ALWAYS
column.

Without it, django will complain about the ts column
not exisiting when we try to create an index.

* test(Resources): add tests for /resources views

* fix(Resources): get basic test cases to pass

need to work on tsvector column
and filtering by provider columns like alias, name

* fix(Resources): provide way to get tags as dict

not a list of ResourceTag models

* fix(Resources): annotate with return type

* fix(Resources): rename search field to not conflict with filters

* fix(Resources): filter by provider.id

* fix(Resources): remove filter and sort by provider

must use provider_id first

* fix(Resources): test adding, clearing tags

* fix(Scans): filter by provider_id

* fix(Resources): remove FIXME comments

* fix(Resources): filter and search on tags

* fix(Resources): full text search

* fix(Resources): full text search to include both resources and tags

and get rid of the distinct() query

* fix(Resources): document text search a bit more

* fix(Resources): remove TODO comments

* fix(Resources): move Resource migrations into 0001_initital

* fix(Config): revert to match main

* fix(Resources): use Django's default query builder for full text search

* Apply suggestions from code review

Mostly formatting changes

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>

* fix(Resources): just use text search

instead of guessing at allowed split characters for each provider

* fix(Resources): remove unused tests

these cases are covered in parameterized lists

* fix(Resources): set a read-only RLS policy

* fix(Resources): rename add_tags to be upsert_or_delete_tags

* fix(Resources): include primary key on through table

django query builder doesn't like tables without primary keys

* fix(Resources): default xx_at filters to date

instead of date time

* docs(Resources): describe what a Resource is

in API docs

* chore(Resources): rename file to match others

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-09-11 18:04:34 +02:00
Pablo Lara
0adb8c142b Merge pull request #56 from prowler-cloud/PRWLR-4776-Implementing-check-connection-real-CASE
Starting implementing check connection and style tweaks for the Provider's table
2024-09-11 16:54:24 +02:00
Pablo Lara
e7eb57375e feat: the search debounce is working now as expected 2024-09-11 16:49:43 +02:00
Pablo Lara
d264a16065 Merge branch 'main' into PRWLR-4776-Implementing-check-connection-real-CASE 2024-09-11 15:04:23 +02:00
Pablo Lara
67f572285b refactor: tweaks styles for providers table 2024-09-11 15:03:51 +02:00
Pablo Lara
d5d76e248f Merge pull request #55 from prowler-cloud/update/env-varNames
update: update env var names
2024-09-11 09:06:42 +02:00
Pablo Lara
67fcc8ac67 update: update env var names 2024-09-11 09:05:37 +02:00
Pablo Lara
ceca5dd0c4 update: update env var names 2024-09-11 09:03:12 +02:00
dependabot[bot]
2420aedde9 chore(deps): bump cryptography from 43.0.0 to 43.0.1 (#40)
Bumps [cryptography](https://github.com/pyca/cryptography) from 43.0.0 to 43.0.1.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/43.0.0...43.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-10 18:19:21 +02:00
Pablo Lara
5163bcb72c chore: add new component for provider ID 2024-09-10 14:13:08 +02:00
Pablo Lara
457c845af8 chore: WIP 2024-09-10 11:28:36 +02:00
Pablo Lara
3a87b30140 chore: change delay for debouncedSearchQuery function 2024-09-10 08:35:21 +02:00
Víctor Fernández Poyatos
73330ecb1a chore/PRWLR-4775 update datetime default filter for date on inserted_at and updated_at API attributes (#39)
* chore(API): PRWLR-4775 change inserted and updated at filters to filter by date by default

* test(API): PRWLR-4775 replace datetime strings for date

* feat(API): PRWLR-4775 update started_at default behavior and unit tests
2024-09-09 16:52:32 -04:00
Pablo Lara
b605316560 Merge pull request #54 from prowler-cloud/revert-53-PRWLR-4788-Update-NextJS-version-to-the-latest
Revert "Update Nextjs to the latest version"
2024-09-09 18:27:40 +02:00
Pablo Lara
ed116b688f Revert "Update Nextjs to the latest version" 2024-09-09 18:26:28 +02:00
Víctor Fernández Poyatos
c3346ff605 fix(Docker): #PRWLR-4781 fix docker environment issues and celery worker container connection (#37)
* build(Dockerfile): PRWLR-4781 remove versions from dockerfile deps

* fix(Docker): PRWLR-4781 fix celery worker container and apply dev fixtures by default

* build(docker-compose): PRWLR-4781 set default django settings to production in worker service
2024-09-09 09:52:06 -04:00
Pablo Lara
412d25db30 Merge pull request #53 from prowler-cloud/PRWLR-4788-Update-NextJS-version-to-the-latest
update: update Nextjs to the latest version
2024-09-09 09:28:36 +02:00
Pablo Lara
1ed670cf40 update: update Nextjs to the latest version 2024-09-09 09:22:06 +02:00
Víctor Fernández Poyatos
ec67fc12e0 feat/PRWLR-4177 Add /tasks endpoints and data model (#35)
* feat(Backend): PRWLR-4177 add Task model and migrations

* feat(Tasks): PRWLR-4177 add RLSTask class

* feat(API): PRWLR-4177 add Task serializers

* feat(Backend, DB): PRWLR-4177 refactor db variables and add policy on task runner tasks

* feat(API): PRWLR-4177 add Tasks filters and sort fields

* feat(API, Tasks): PRWLR-4177 add deletion tasks and revoke logic to /tasks

* test(Task): PRWLR-4177 add deletion tasks unit tests

* test(Views): PRWLR-4177 add Tasks views unit tests and update outdated ones

* chore(API): PRWLR-4177 improve drf-spectacular annotations

* chore(API): PRWLR-4177 add PROGRESS task state

* chore(API): PRWLR-4177 update spec

* chore(API): PRWLR-4177 remove force query parameter from DELETE /tasks

* feat(Backend): PRWLR-4177 add APITimeoutError and raise when TaskResult is not created

* feat(Backend): PRWLR-4177 add specific error class for task timeouts
2024-09-06 20:47:51 -04:00
Pablo Lara
09ef68e1c5 Merge pull request #52 from prowler-cloud/PRWLR-4626-Implement-newTable-Providers
Implement filters, search with the API
2024-09-06 16:47:00 +02:00
Pablo Lara
3cc9910f61 fix: prevent crash when there is no connection with the API 2024-09-06 16:45:01 +02:00
Pablo Lara
3d120b3505 chore: WIP 2024-09-06 16:42:12 +02:00
Jon Young
f5462c9b27 fix(Scans): rename 'type' to 'trigger'. (#36)
'type' is a reserved word in JSON:API schemas,
and python.

'trigger' more accurately describes the enum value.
2024-09-06 15:13:27 +02:00
Pablo Lara
a30c6520d4 feat: clear all button only appears if there is changes on search params 2024-09-06 11:25:09 +02:00
Pablo Lara
5326ffbcc9 feat: add CustomRegionSelection for the filters 2024-09-06 11:10:14 +02:00
Pablo Lara
ff0ba89a3f feat: clean all filters button is removing now the sort param 2024-09-06 10:25:57 +02:00
Pablo Lara
bc7c3bd74b refactor: remove two components and create a new one, reducing code and improving efficiency 2024-09-06 10:20:59 +02:00
Pablo Lara
a9ff875a3a style: re-style action dropdown 2024-09-06 09:10:41 +02:00
Pablo Lara
4e8aae4f9e feat: add new component for search input 2024-09-06 07:59:35 +02:00
Pablo Lara
1bc6ac06a4 feat: restore datepicker component when the filters are clean 2024-09-05 19:29:07 +02:00
Pablo Lara
122dddea9e Merge pull request #51 from prowler-cloud/PRWLR-4626-Implement-filtering-Providers
Implement sort providers table.
2024-09-05 19:12:05 +02:00
Pablo Lara
97616213db chore: main filters are working and tweaks styles 2024-09-05 19:05:36 +02:00
Pablo Lara
2e09667bab fix: fix type for SearchParamsProps in all pages 2024-09-05 13:13:02 +02:00
Pablo Lara
bb32af93b2 feat: filters, search and sorting is working as expected 2024-09-05 13:12:20 +02:00
Pablo Lara
ac93672752 chore: WIP 2024-09-04 17:10:26 +02:00
Pablo Lara
a1021fbca7 chore: improve sorting 2024-09-04 09:00:18 +02:00
Pablo Lara
45f398bf30 chore: add sorting to provider's table 2024-09-03 16:31:05 +02:00
Pablo Lara
81743c9c29 Merge pull request #50 from prowler-cloud/PRWLR-4627-Implement-zustand-for-global-state
Add Zustand for global state management
2024-09-03 07:45:54 +02:00
Pablo Lara
d8ae2bf455 feat: integrate Zustand for global state management and apply it to the sidebar 2024-09-02 14:12:42 +02:00
Pablo Lara
2d07186eb1 feat: integrate Zustand for global state management and apply it to the sidebar 2024-09-02 12:41:35 +02:00
Pablo Lara
d1cd8848eb Merge pull request #49 from prowler-cloud/PRWLR-4698-Following-up-authNext
Fix TS types on auth.ts
2024-09-02 07:43:58 +02:00
Pablo Lara
0acfb6040e feat: fix TS types on auth.ts 2024-09-02 07:33:57 +02:00
Víctor Fernández Poyatos
24857eaa7f feat/PRWLR-4002 add /scans endpoints (without SDK integration) (#33)
* feat(Backend): PRWLR-4992 add Scan db model

* feat(API): PRWLR-4002 add viewset and required tools for /scans endpoint

* feat(API): PRWLR-4002 improve /scans filters

* feat(API): PRWLR-4002 add relationships links

* feat(API): PRWLR-4002 implement POST /scan custom logic

* fix(API): PRWLR-4002 fix Scan.type keyword usage

* feat(API): PRWLR-4002 implement PATCH /scans

* feat(API): PRWLR-4002 refactor serializers for write operations

* fix(API): PRWLR-4002 fix providers on ScanSerializer

* test(API): PRWLR-4002 add unit tests for /scans

* feat(Backend, Test): PRWLR-4002 refactor routing and unit tests db connections

* build(CI): PRWLR-4002 update CI env vars for postgres

* fix(Tests): PRWLR-4002 fix close_db_connections fixture

* feat(Backend, API): PRWLR-4002 apply requested changes to Scan model and filters

* chore(Tests): PRWLR-4002 rename pytest fixtures

* feat(Backend): PRWLR-4002 remove unique constraint from Scan model

* fix(Backend, Tests): PRWLR-4002 fix db routing and migration mechanism for tests

* chore(deps): PRWLR-4002 add uuid6 to poetry deps

* chore(Backend): PRWLR-4002 refactor filter methods

* fix(Tests): PRWLR-4002 fix wrong postgres credentials for testing

* feat(API): PRWLR-4002 implement merging mechanism for Scans.scanner_args

* feat(API): PRWLR-4002 implement merging mechanism for Scans.scanner_args

* feat(Backend): PRWLR-4002 add indexes to Scan model

* feat(Backend): PRWLR-4002 remove id index from Scan model (redundant)

* feat(API): PRWLR-4002 add datetime fields to Scan serializer
2024-08-30 14:32:13 -04:00
Sophia Dao
c281f85742 Users Page - Add User Modal, Edit User Modal (#45)
* feat(users): Add in Add User modal, add in Label component

* feat(users): Make adjustments to Add User modal and Edit user modal

* feat(users): Populate data from mock API

* feat(users): Permissions - do not show team info to users, redirect users
2024-08-30 08:30:10 -05:00
Pablo Lara
aa44572be5 Merge pull request #47 from prowler-cloud/update/nextjs-latest
Update nextjs and react to the latest version
2024-08-30 10:48:01 +02:00
Pablo Lara
631885e364 feat: update nextjs and react to the latest version 2024-08-30 10:42:11 +02:00
dependabot[bot]
fed489f9d9 chore(deps): bump micromatch from 4.0.7 to 4.0.8 (#46)
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.7 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.7...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-29 19:06:07 -05:00
Víctor Fernández Poyatos
8183207802 feat/PRWLR-4014 Implement SDK integration for POST /providers/{provider_id}/connection (#30)
* chore(deps): PRWLR-4014 include prowler library in python deps

* feat(Backend,API): PRWLR-4014 add AWS provider test_connection through celery tasks

* fix(Backend,API): PRWLR-4014 fix model handling in celery tasks

* test(Tasks): PRWLR-4014 add unit tests for celery tasks

* docs(API): PRWLR-4014 update endpoint tag

* feat(Backend): PRWLR-4014 add decorator for tenant dependant Celery tasks

* chore(Backend): PRWLR-4014 remove TODOs and improve docstrings

* feat(Backend): PRWLR-4014 replace timezone.now for datetime.now(timezone.utc)

* feat(Backend): PRWLR-4014 use SET LOCAL for api.tenant_id setting

* feat(Backend, Tasks): PRWLR-4014 refactor tasks module to abstract business logic

* fix(Backend): PRWLR-4014 use set_config for RLS config and set transaction at request dispatch level

* fix(Tasks): PRWLR-4014 fix tasks tenant decorator
2024-08-29 09:53:07 -04:00
Pablo Lara
7c76d4efa1 Merge pull request #42 from prowler-cloud/PRWLR-4393-Setup-NextAuth-client-session
Setup next auth -
2024-08-29 09:09:44 +02:00
Pablo Lara
0a090b5694 chore: remove console logs 2024-08-28 12:29:08 +02:00
Pablo Lara
c0a20b0f5d feat: the logOut button is working nicely now 2024-08-28 12:24:32 +02:00
Pablo Lara
b5a40d07cf feat: Nextauth is working 2024-08-27 18:37:45 +02:00
Pablo Lara
1985b16824 feat: add nexthauth.d.ts to have the DefaultSession info available 2024-08-27 17:05:09 +02:00
Pablo Lara
06d05ec860 Merge branch 'main' into PRWLR-4393-Setup-NextAuth-client-session 2024-08-26 15:46:03 +02:00
Pablo Lara
11af5e1429 Merge pull request #44 from prowler-cloud/PRWLR-4673-Main-menu-tweaks
feat: add new items to the main menu
2024-08-26 15:43:49 +02:00
Pablo Lara
440e95515a feat: add new items to the main menu 2024-08-26 15:33:07 +02:00
Pablo Lara
4cf5d9cb43 chore: WIP 2024-08-23 23:00:41 +02:00
Sophia Dao
c910167ff6 Users Page - Table Row (#43)
* feat(users): Add in Users page and sidebar

* feat(users): Fix grammar, add in Users action

* feat(users): Add in more API info

* feat(users): Continue work on table, pass data through to table, style skeleton

* feat(users): Format Status column

* feat(users): Style table

* feat(users): Change data, update Users to User
2024-08-23 09:44:48 -05:00
Pablo Lara
ed0d975e43 chore: WIP 2024-08-22 18:04:30 +02:00
Víctor Fernández Poyatos
8f2bd45872 feat/PRWLR-4413 Add Postgres Enums for Django and update Provider.provider field (#28)
* feat(db): PRWLR-4413 add Provider Postgres Enum type for Django

* fix(Backend): PRWLR-4413 Fix initial migration for Providers

* feat(Backend): PRWLR-4413 add provider enum to Provider model

* fix(Backend, API): PRWLR-4413 fix ProviderEnum representation

* chore(Backend): PRWLR-4413 remove max_length constraint from provider enum

* chore(Backend): PRWLR-4413 refactor postgres enum creation to avoid boilerplate

* chore(Backend): PRWLR-4413 improve comments
2024-08-21 18:02:46 +02:00
Pablo Lara
063de00e45 chore: create 2024-08-21 14:33:53 +02:00
Pablo Lara
4b18397e69 chore: add bcrypt dependency 2024-08-21 12:32:33 +02:00
Pablo Lara
52dd08883f chore: add AuthForm component 2024-08-21 11:53:17 +02:00
Víctor Fernández Poyatos
8a2cfea677 feat/PRWLR-4368 Remove TenantMiddleware and set tenant_id at view level (#31)
* feat(API): PRWLR-4368 remove TenantMiddleware in favour of transaction based setup

* feat(API): PRWLR-4368 override initial request method to perform atomic transactions on RLS viewsets
2024-08-21 10:10:01 +02:00
Pablo Lara
4e104194bc Merge branch 'main' into PRWLR-4393-Setup-NextAuth-client-session 2024-08-21 09:20:11 +02:00
Pablo Lara
80d05c276f chore: add basic routing for next auth 2024-08-20 16:23:02 +02:00
Sophia Dao
f676ca9078 Compliance Page & Compliance Card (#40)
* feat(compliance): Add in initial shell for Compliance page

* feat(compliance): Mock data in the same way as Services and Providers, create files for rest of page and card structure

* feat(compliance): Add in more data to json, continue building Compliance Card

* feat(compliance): Add in icons for Compliance types, update Compliance skeleton

* feat(compliance): Compliance card/page - add in colors for progress bar, styling

* feat(compliance): Add image definitions to fix CI

* feat(compliance): Add in aws.svg instead of .png

* Fix file suffix

* feat(compliance) remove duplicate spacer
2024-08-20 08:30:36 -05:00
Pablo Lara
967158f216 Merge pull request #41 from prowler-cloud/PRWLR-4104-Overview-Page-Findings-by-Status-and-Severity-Chart
chore: adjusted the gaps a bit and centered it along the X-axis for now
2024-08-20 10:08:30 +02:00
Pablo Lara
3b621e73f6 chore: adjusted the gaps a bit and centered it along the X-axis for now 2024-08-20 10:06:03 +02:00
Pablo Lara
357c9b0813 Merge pull request #39 from prowler-cloud/PRWLR-4104-Overview-Page-Findings-by-Status-and-Severity-Chart
Graphs for finding by status and severity
2024-08-20 10:03:51 +02:00
Pablo Lara
71a56031e2 chore: aling to the middle for charts components for now 2024-08-19 17:13:15 +02:00
Pablo Lara
d714213cc2 chore: fix lint error 2024-08-19 16:55:00 +02:00
Pablo Lara
33a5556b8a #PRWLR-4106: modify gap for attack surface component 2024-08-19 16:49:44 +02:00
Pablo Lara
a864c76955 feat: add attack surface component 2024-08-19 16:43:45 +02:00
Pablo Lara
109a477f9e chore: fix English typo error 2024-08-19 16:42:44 +02:00
Pablo Lara
c159fb1dac feat: update chart dependency to fix an error 2024-08-19 16:40:46 +02:00
Pablo Lara
52e21a020e feat: add container class to fit all resolutions 2024-08-19 16:40:12 +02:00
Pablo Lara
9296e0cc0d chore: add severity's colors 2024-08-19 16:39:15 +02:00
Pablo Lara
f61ed5ddf5 chore: simplify AttackSurface component 2024-08-19 12:14:17 +02:00
Pablo Lara
f236d2087a feat: Attack Surface component is ready 2024-08-19 12:11:50 +02:00
Pablo Lara
441945e075 feat: Status chart is ready 2024-08-19 10:52:44 +02:00
Pablo Lara
26ab6513a2 fix: resolve casing conflict for Chart.tsx 2024-08-16 12:44:12 +02:00
Pablo Lara
b0ec7a2a82 fix: temporary rename to resolve casing conflict 2024-08-16 12:43:02 +02:00
Pablo Lara
caa5e7dd96 chore: add recharts library 2024-08-16 11:21:29 +02:00
Pablo Lara
75f4f0d43a chore: update tailwind-merge dependencie 2024-08-16 11:16:42 +02:00
Pablo Lara
6ea3057b23 feat: create CustomBox component 2024-08-16 10:59:09 +02:00
Pablo Lara
1724e25c3b Merge pull request #38 from prowler-cloud/PRWLR-4375-Services-Page-Card
Services Page
2024-08-15 09:15:43 +02:00
Pablo Lara
5af439d926 feat: add Skeleton for services page 2024-08-15 09:09:43 +02:00
Pablo Lara
40991c4b7e Merge branch 'main' into PRWLR-4375-Services-Page-Card 2024-08-15 08:41:05 +02:00
Pablo Lara
614548f58a chore: adjust breakpoints for improved responsiveness 2024-08-15 08:29:03 +02:00
Pablo Lara
d7fe3595d3 chore: Add breakpoint to optimize layouts for large screens 2024-08-15 08:16:52 +02:00
Pablo Lara
088b4fa4fe rename: rename ServiceCard component 2024-08-15 08:16:15 +02:00
Pablo Lara
ca3da473d7 chore: add input for muted findings 2024-08-14 16:29:52 +02:00
Pablo Lara
11518a0806 chore: style tweaks 2024-08-14 16:01:56 +02:00
Pablo Lara
ebd3bb386c feat: mock the API for services page and creating components 2024-08-14 15:21:52 +02:00
Sophia Dao
afc4189577 Findings Page - Findings Card Components (#37) 2024-08-14 08:06:27 -05:00
Pablo Lara
4c0a14b96c chore: update components with the new paths 2024-08-14 09:52:03 +02:00
Pablo Lara
8dba9a7d9e feat: add kubernetes as a supported provider 2024-08-14 09:50:33 +02:00
Pablo Lara
891c171247 feat: add providers-badge component for global use and filter components 2024-08-14 09:06:47 +02:00
Víctor Fernández Poyatos
308f52c6f9 build(deps): bump gunicorn version to 23.0.0 (#29) 2024-08-13 16:28:39 +02:00
Pablo Lara
092ad10c56 chore: add all icons for services 2024-08-13 10:12:48 +02:00
Pablo Lara
c492d25f4c Prwlr 4408 clean area labels warning in the console tab (#36)
* feat: remove 2 high severity vulnerabilities

* chore: solve accesibility warnings

* feat: all accesibility warnings have been solved
2024-08-12 11:41:17 -05:00
Víctor Fernández Poyatos
4f99518d52 fix(Dockerfile): add curl-dev to base image (#27) 2024-08-12 12:34:55 +02:00
Jon Young
a2ab216531 chore(Celery): add basic Celery worker with broker only (#20)
* chore(Celery): add basic Celery worker with broker only

* chore(Celery): saving progress. Not able to schedule tasks

* fix(Celery): add celery app for use by django

* fix(Celery): register tasks

* fix(Docker): add celery workers to docker-compose

* chore(Celery): add django-celery-results backend

to store results using Django ORM

* fix(Celery): get app config the correct way

* fix(Docker): start connecting docker Celery workers to Valkey

not yet operational

* fix(Celery): get celery & django to work in docker-compose

* docs(Celery): document how to run Celery in development environment

includes changes to support the configuration and deployment
of Celery worker and its dependencies, Valkey and Postgres.

* fix(GHA): add valkey to CI services

* fix(GHA): add valkey to CI services

* fix(GHA): add valkey-cli ping to CI services

* fix(GHA): use right port for valkey

* fix(Views): remove debug task code

* test(Celery): start adding celery task tests

not yet working!

* fix(pyproject): rollback django upgrade

* fix(docker): updated docker runtime and env vars

based on feedback from #20

* fix(Dockerfile): include dependencies for psutil

psutil was introduced by pytest-celery

* fix(Backend): PRWLR-4013 fix celery settings structure

* fix(Celery): update celery app to work with new settings structure

* fix(Views): remove debug task code

* fix(Config): remove debug code

* fix(Celery): update celery app name when running worker

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-08-09 16:47:35 +02:00
Sophia Dao
7ab46d61b5 Findings page Severity component (#35)
* feat(findings): Severity and Status badge WIP

* feat(findings): Status and Severity badge changes

* Fix font color for dark mode
2024-08-09 09:16:55 -05:00
Pablo Lara
b5928be876 Merge pull request #32 from prowler-cloud/PRWLR-4409-Pagination-and-sorting-in-the-Provider-table
Add Pagination component and DataTableColumnHeader component
2024-08-09 16:15:11 +02:00
Pablo Lara
abc2a3fa72 chore: solve conflicts with main branch 2024-08-09 13:10:52 +02:00
Pablo Lara
10fc131e13 feat: remove dependency 2024-08-09 13:06:09 +02:00
Pablo Lara
5bb3c012c9 feat: add functionality to the Pagination component 2024-08-09 11:54:58 +02:00
Sophia Dao
b5b2e225ce Findings page Status component (#34)
* feat(findings): Severity and Status badge WIP

* Remove SeverityBadge from PR
2024-08-08 15:04:47 -05:00
Pablo Lara
bed2b1e7f7 feat: add Pagination - WIP 2024-08-08 20:08:11 +02:00
dependabot[bot]
6d48265618 chore(deps): bump django from 5.0.7 to 5.0.8 (#33)
Bumps [django](https://github.com/django/django) from 5.0.7 to 5.0.8.
- [Commits](https://github.com/django/django/compare/5.0.7...5.0.8)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-08 10:51:52 -05:00
dependabot[bot]
43c9e70a65 chore(deps): bump django from 5.0.7 to 5.0.8 (#26)
Bumps [django](https://github.com/django/django) from 5.0.7 to 5.0.8.
- [Commits](https://github.com/django/django/compare/5.0.7...5.0.8)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-08 10:57:10 -04:00
Víctor Fernández Poyatos
e2fc83c81b docs(README): add migration and fixtures commands (#23)
* docs(README): add migration and fixtures commands

* docs(README): add env variables info
2024-08-08 10:56:03 -04:00
Sophia Dao
ae8098d53e Findings card initial setup (#31)
* feat(findings): WIP - add on click for row, select one row at a time, pass ID to function

* feat(findings) More WIP for Findings Card - add in dummy data, pass selected row into card

* feat(findings): Pass selected row through

* Fix additional merge conflict

* feat(findings): Update to new file structure

* feat(findings): Hook up initial card with hard-coded data as a sidepanel that expands when a row element is clicked

* Merge main
2024-08-07 17:26:32 -05:00
Víctor Fernández Poyatos
857edd9aa6 chore(Backend,API): PRWLR-4341 restructure project based on versions (#25) 2024-08-07 16:40:18 -04:00
Pablo Lara
ca3d076607 feat: add Pagination component and DataTableColumnHeader component 2024-08-07 13:56:36 +02:00
Jon Young
35128b89b1 chore(API): rename project to be Prowler API (#22) 2024-08-07 10:05:05 +02:00
Pablo Lara
157c475f5c Merge pull request #30 from prowler-cloud/PRWLR-4410-Refactor-the-index.ts-file-for-exporting-Components
Refactor the index.ts file for exporting components
2024-08-07 09:16:27 +02:00
Pablo Lara
4483baae19 chore: rename DataTable to DataTableProvider for more specificity 2024-08-07 09:14:17 +02:00
Pablo Lara
3511cd977a chore: remove the old modal component 2024-08-07 09:06:38 +02:00
Pablo Lara
d69c35fa3c chore: solve conflicts with main branch 2024-08-07 09:02:41 +02:00
Pablo Lara
dee7e621de Merge pull request #29 from prowler-cloud/PRWLR-4141-Providers-Page-Add-Providers-modal-2
Providers page add providers modal -
2024-08-07 08:51:19 +02:00
Pablo Lara
0ae248926d chore: fix provider name 2024-08-07 08:50:14 +02:00
Víctor Fernández Poyatos
4371ad1535 feat/PRWLR-3999 Implement providers endpoints (#21)
* feat(Backend): PRWLR-3989 add RLS to postgresql db and base models

* feat(API): PRWLR-3989 add TenantMiddleware

* chore(API, Backend): PRWLR-3989 create new db user without RLS bypass on migrations

* chore(Backend): PRWLR-3989 fix RLS bypasser for POST requests

* fix(Backend): PRWLR-3989 fix user permissions when migrating new models

* chore(Backend): PRWLR-3989 add testing view for RLS manual tests

* feat(API): PRWLR-3989 add tenant_id to API logging

* chore(API, Backend): PRWLR-3989 add TODOs

* test(API): PRWLR-3989 add new middleware unit tests

* chore(API): PRWLR-3989 refactor RLS code

* fix(tests): PRWLR-3989 fix testing db connector

* chore: PRWLR-3989 add references to JIRA tickets

* fix: PRWLR-3989 remove bypass logic and fix serializers

* fix: PRWLR-3989 improve drop SQL query for RLS models

* feat(Backend): PRWLR-3989 add specific permissions on each model

* fix(Backend): PRWLR-3989 fix database routing and grant select perms

* fix(test): PRWLR-3989 fix routing issues with unit tests

* chore: PRWLR-3989 remove references to JIRA tickets

* feat(Backend): PRWLR-3999 add Provider model

* feat: PRWLR-3999 add providers view logic

* fix: PRWLR-3999 fix unique index fields

* feat(API): PRWLR-3999 add custom exception handlers

* feat(API): PRWLR-3999 add /providers/{provider_id}/connection endpoint

* test(API): PRWLR-3999 add base unit tests for providers

* fix(API, Backend): PRWLR-3999 fix bugs after rebase

* chore(API, docker): PRWLR-3999 add dev feats for demo

* feat(API): PRWLR-3999 add drf-spectacular-jsonapi and improve docs

* test(API): PRWLR-3999 add providers unit tests

* chore(Backend): PRWLR-3989 adjust privileges for user on table tenant

* chore: PRWLR-3999 rename model custom validation error

* chore: PRWLR-3999 remove Test references

* chore: PRWLR-3999 update API v1 spec

* fix: PRWLR-3999 apply requested changes to filter and models

* feat: PRWLR-3999 add validation to PATCH /providers payload

* fix: PRWLR-3999 fix providers enum description

* chore: add more providers fixtures

* fix: PRWLR-3999 make providers.alias optional
2024-08-06 12:39:08 -04:00
Pablo Lara
4137eaec6d chore: fix typo 2024-08-06 17:24:18 +02:00
Pablo Lara
14ff4282c0 feat: refactor the modal's content for providers 2024-08-06 14:59:19 +02:00
Pablo Lara
b7d324f1b0 feat: add modal and functionality for adding providers 2024-08-06 14:59:04 +02:00
Pablo Lara
81bf3fc15f chore: adding a new index.ts file to improve the way we're exporting components (ui) 2024-08-06 12:05:10 +02:00
Pablo Lara
22ebe00cf6 chore: adding a new index.ts file to improve the way we're exporting components (providers) 2024-08-06 11:56:00 +02:00
Pablo Lara
3ae00cadb9 Merge pull request #27 from prowler-cloud/PRWLR-4365-Implement-CRUD-methods-for-Providers-page-using-real-API
Implement crud methods for providers page using real api
2024-08-06 09:43:19 +02:00
Pablo Lara
1992ef050a feat: refactor the modal's content for providers 2024-08-05 16:00:02 +02:00
Pablo Lara
e7f79589d4 feat: add modal and functionality for adding providers 2024-08-05 13:09:44 +02:00
Pablo Lara
ff3f90ac94 chore: replace CrossIcon for the toast and change variants when error 2024-08-05 09:39:18 +02:00
Pablo Lara
dff3462113 fix: solve conflicts with main branch 2024-08-05 05:55:18 +02:00
Pablo Lara
a2172d12f4 fix: run the lint fix to be able to build the app 2024-08-04 20:02:55 +02:00
Pablo Lara
ffb91d2733 feat: method POST to check the provider connection is working 2024-08-04 18:55:20 +02:00
Pablo Lara
485482c868 feat: GET and POST provider are working as expected and the error is shown correctly 2024-08-04 18:18:53 +02:00
Pablo Lara
b16a7150fa chore: add deleteProvider action 2024-08-04 11:55:34 +02:00
Pablo Lara
00613cdda3 add Toast library and handling server errors - WIP 2024-08-02 18:43:58 +02:00
Pablo Lara
32ecc5dbad Merge pull request #26 from prowler-cloud/PRWLR-4377-Findings-Page-Findings-Row
Findings Table - Initial Setup
2024-08-02 17:57:28 +02:00
Víctor Fernández Poyatos
e1a12bcb14 feat/PRWLR-3989 Add RLS full implementation (#18)
* feat(Backend): PRWLR-3989 add RLS to postgresql db and base models

* feat(API): PRWLR-3989 add TenantMiddleware

* chore(API, Backend): PRWLR-3989 create new db user without RLS bypass on migrations

* chore(Backend): PRWLR-3989 fix RLS bypasser for POST requests

* fix(Backend): PRWLR-3989 fix user permissions when migrating new models

* chore(Backend): PRWLR-3989 add testing view for RLS manual tests

* feat(API): PRWLR-3989 add tenant_id to API logging

* chore(API, Backend): PRWLR-3989 add TODOs

* test(API): PRWLR-3989 add new middleware unit tests

* chore(API): PRWLR-3989 refactor RLS code

* fix(tests): PRWLR-3989 fix testing db connector

* chore: PRWLR-3989 add references to JIRA tickets

* fix: PRWLR-3989 remove bypass logic and fix serializers

* fix: PRWLR-3989 improve drop SQL query for RLS models

* feat(Backend): PRWLR-3989 add specific permissions on each model

* fix(Backend): PRWLR-3989 fix database routing and grant select perms

* fix(test): PRWLR-3989 fix routing issues with unit tests

* chore: PRWLR-3989 remove references to JIRA tickets

* chore(Backend): PRWLR-3989 adjust privileges for user on table tenant

* chore: PRWLR-3989 add comments on migrations
2024-08-02 11:29:05 -04:00
Sophia Dao
0283b34190 feat(findings): Fix folder structure 2024-08-02 06:02:26 -05:00
Pablo Lara
26cfbeb3a8 chore: add pending conecction for ProviderInfo component and its icon 2024-08-02 10:43:17 +02:00
Pablo Lara
b95d48e2ad chore: rendering real data for Providers and relocate action folder 2024-08-02 10:24:47 +02:00
Sophia Dao
2bfa37ca2e feat(findings): WIP - add in initial data table setup, add in some hardcoded value for display purposes, future skeleton loader 2024-08-01 17:41:05 -05:00
Pablo Lara
6a7b6f3e6b Merge pull request #25 from prowler-cloud/fix/package-lock
fix: SWR NextJS compiler
2024-08-01 16:41:30 +02:00
Pablo Lara
a9462da78e fix: SWR NextJS compiler 2024-08-01 16:39:31 +02:00
Pablo Lara
02f2043a8c Merge pull request #24 from prowler-cloud/PRWLR-4374-Create-container-image-for-the-NextJS-UI
Create container image for the next js UI
2024-08-01 16:13:26 +02:00
Pablo Lara
acfbdc6405 chore: optimize the Dockerfile, remove all related with .nextjs folder 2024-08-01 15:56:11 +02:00
Pablo Lara
25ec271a7f chore: optimize the Dockerfile 2024-08-01 15:52:06 +02:00
Pablo Lara
a3555af684 chore: disable telemetry during the runtime 2024-08-01 15:48:11 +02:00
Pablo Lara
de55eeb183 chore: disable telemetry during the build 2024-08-01 15:44:42 +02:00
Pablo Lara
8fc9204946 chore: optimize the Dockerfile 2024-08-01 15:04:30 +02:00
Pablo Lara
5b31ce8484 feat: add Dockerfile and .dockerignore 2024-08-01 13:38:51 +02:00
Pablo Lara
e5a328e9ea feat: change configuration and generate package-lock file 2024-08-01 12:09:37 +02:00
Pablo Lara
14a10fc6f0 Merge pull request #23 from prowler-cloud/PRWLR-4367-add-react-suspense
Add React Suspense
2024-08-01 10:30:59 +02:00
Pablo Lara
941bdfb2e1 Merge pull request #22 from prowler-cloud/PRWLR-4363-Handling-Boundaries-Errors
Handling boundaries errors
2024-08-01 06:46:46 +02:00
Pablo Lara
d431516270 chore:remove library not used for icons 2024-07-31 21:56:50 +02:00
Pablo Lara
92e88674f6 feat: update TypeScript to the latest version and remove library not used for icons 2024-07-31 21:56:05 +02:00
Pablo Lara
89d15c40da feat: update TypeScript to the latest version 2024-07-31 21:52:59 +02:00
Pablo Lara
ddf9a3ef2d feat: implement error boundary functionality 2024-07-31 08:55:02 +02:00
Pablo Lara
0a0a08b97d chore: remove SWR library from the project and add alert from shadcn 2024-07-31 08:50:31 +02:00
Pablo Lara
3fa614341f fix: fix typo error 2024-07-30 17:25:58 +02:00
Pablo Lara
b112202f41 feat: handle error when the endpoint is not working 2024-07-30 17:24:42 +02:00
Pablo Lara
9d66a7ec4a feat: handle error when the endpoint is not working 2024-07-30 12:54:52 +02:00
Pablo Lara
48f633889a Providers page table (#20)
* fix: add suppressHydrationWarning to resolve console errors

* chore: add server-only library

* WIP: Mock API for providers and start rendering data

* chore: relocate utils folder to proper directory

* chore: install shadcn for tables, adding sttings page

* refactor: improve sidebar display behavior

* chore: add fake data to the dataProviders

* chore: remove the old table and rename ProviderInfo component

* refactor: improve sidebar display behavior adding a custom hook

* feat: the Providers table is rendering real data

* chore: set the default valuef or isCollapse to false

* chore: Added a helper function getProviderAttributes for cleaner access to provider attributes
2024-07-30 00:04:54 -05:00
Pablo Lara
fd9cff9392 chore: Added a helper function getProviderAttributes for cleaner access to provider attributes 2024-07-30 06:21:25 +02:00
Pablo Lara
86a4938b5f chore: set the default valuef or isCollapse to false 2024-07-30 05:48:18 +02:00
Pablo Lara
9fd642fe0e feat: the Providers table is rendering real data 2024-07-29 12:41:02 +02:00
Pablo Lara
0035c8c08e refactor: improve sidebar display behavior adding a custom hook 2024-07-29 12:26:25 +02:00
Pablo Lara
151fca146e chore: remove the old table and rename ProviderInfo component 2024-07-29 11:16:18 +02:00
Pablo Lara
1bea55c5e8 chore: add fake data to the dataProviders 2024-07-29 11:14:30 +02:00
Pablo Lara
8ce28dd311 refactor: improve sidebar display behavior 2024-07-29 11:13:39 +02:00
Pablo Lara
54b3fc3ae6 chore: install shadcn for tables, adding sttings page 2024-07-28 16:40:29 +02:00
Pablo Lara
b8de713497 chore: relocate utils folder to proper directory 2024-07-28 16:35:45 +02:00
Pablo Lara
0ee60efaa7 WIP: Mock API for providers and start rendering data 2024-07-26 18:01:50 +02:00
Pablo Lara
1244cdb73e Merge branch 'main' into PRWLR-4123-Providers-Page-Table 2024-07-26 09:33:01 +02:00
Pablo Lara
4b63fc4757 chore: add server-only library 2024-07-26 09:32:48 +02:00
Pablo Lara
b65159dd43 Merge pull request #11 from prowler-cloud/PRWLR-4172-Modal-component
Modal Component
2024-07-26 08:27:05 +02:00
Sophia Dao
842608afa0 feat(modal): Code review feedback 2024-07-25 09:01:49 -05:00
Pablo Lara
57f5fd51e6 fix: add suppressHydrationWarning to resolve console errors 2024-07-25 10:30:28 +02:00
Jon Young
6a135cb47c PRWLR-4236: fix(CI): use postgres for unit tests (#19)
* fix(Config): use local postgres for unit tests

* fix(CI): use postgres for unit tests in GHA
2024-07-25 10:00:58 +02:00
Sophia Dao
1ac3ab48f2 Merge branch 'main' into PRWLR-4172-Modal-component 2024-07-24 21:00:40 -05:00
Pablo Lara
7f104bdc91 Merge pull request #18 from prowler-cloud/PRWLR-4233-Providers-Date-Component
DateWithTime component
2024-07-24 16:21:48 +02:00
Pablo Lara
e927413e11 Merge branch 'main' into PRWLR-4233-Providers-Date-Component 2024-07-24 16:21:26 +02:00
Pablo Lara
b4adacd9e0 Merge pull request #17 from prowler-cloud/PRWLR-4227-Provider-Status-Component
Status component - Provider table
2024-07-24 16:19:57 +02:00
Pablo Lara
04bd613fc9 chore: fix conflict 2024-07-24 16:17:19 +02:00
Pablo Lara
dd2c92d805 feat: account component is ready to use it (#16) 2024-07-24 09:08:15 -05:00
Pablo Lara
044c8dbb3a feat: DateWithTime component is ready to use it 2024-07-24 09:39:34 +02:00
Sophia Dao
1c5859d93c feat(modal): Use server to pass event handler 2024-07-23 22:40:54 -05:00
Sophia Dao
8388aad831 merge main 2024-07-23 20:16:11 -05:00
Víctor Fernández Poyatos
de97b9f298 feat/PRWLR-3999 Add providers endpoint with mock data (#17)
* chore: PRWLR-3996 add drf-jsonapi library to project

* feat: PRWLR-3996 implement /tenants endpoint and basic JSON:API spec

* feat: PRWLR-3996 implement new middleware to ingest metadata on API responses

* chore: PRWLR-3996 annotate views with drf-spectacular

* feat: PRWLR-3996 add cache-control to tenants endpoints

* feat: PRWLR-3996 update views filters

* chore: PRWLR-3996 remove meta middleware in favour of meta fields in serializers

* test(API): PRWLR-3996 add unit tests for /tenants

* chore: PRWLR-3996 turn DEBUG on on devel environment

* test: PRWLR-3996 rework tenants unit tests

* chore: PRWLR-3996 refactor filter classes

* fix(Backend,API): PRWLR-3996 use correct filter backend

* feat(API): PRWLR-3999 implement mocked /providers endpoints

* feat(API): PRWLR-3999 add /providers/check_connection mocked endpoint and loc headers
2024-07-23 12:34:48 -04:00
Pablo Lara
db30c0253d feat: ScanStatus component is ready to use it 2024-07-23 15:37:10 +02:00
Pablo Lara
0590c00c9b feat: add date-fns library to the project 2024-07-23 15:23:39 +02:00
Pablo Lara
6ab0a42f67 feat: account component is ready to use it 2024-07-23 13:14:34 +02:00
Víctor Fernández Poyatos
7cb3a4e16e feat/PRWLR-3996 implement /tenants endpoint and basic filters logic (#14)
* chore: PRWLR-3996 add drf-jsonapi library to project

* feat: PRWLR-3996 implement /tenants endpoint and basic JSON:API spec

* feat: PRWLR-3996 implement new middleware to ingest metadata on API responses

* chore: PRWLR-3996 annotate views with drf-spectacular

* feat: PRWLR-3996 add cache-control to tenants endpoints

* feat: PRWLR-3996 update views filters

* chore: PRWLR-3996 remove meta middleware in favour of meta fields in serializers

* test(API): PRWLR-3996 add unit tests for /tenants

* chore: PRWLR-3996 turn DEBUG on on devel environment

* test: PRWLR-3996 rework tenants unit tests

* chore: PRWLR-3996 refactor filter classes

* fix(Backend,API): PRWLR-3996 use correct filter backend
2024-07-22 16:06:57 -04:00
Pepe Fagoaga
b2d3f492ec chore(CODEOWNERS): Update with new team (#15) 2024-07-22 08:25:37 -05:00
Jon Young
43f79663d9 chore(CODEOWNERS): Update for team name change (#16)
* chore(CODEOWNERS): update CODEOWNERS

* chore(CODEOWNERS): update CODEOWNERS

* chore(CODEOWNERS): update CODEOWNERS
2024-07-22 08:43:50 +02:00
Pablo Lara
e6d84cb245 feat: replace the favIcon (#14) 2024-07-19 16:50:19 -05:00
Pablo Lara
0403c1f1b5 Prwlr 4167 table component (#13)
* feat: now the import works as expected

* feat: now the import works as expected

* feat: create a CustomTable component
2024-07-18 14:03:03 -05:00
Pablo Lara
91eb26dac2 Merge pull request #12 from prowler-cloud/PRWLR-4180-Add-GitHub-PR-template
Add in PR template
2024-07-18 09:07:51 +02:00
Sophia Dao
93a8f91eb1 chore(github): Add in pr template 2024-07-17 13:48:42 -05:00
Sophia Dao
7093261f84 feat(modal): Add in prop for Close button text 2024-07-17 12:47:25 -05:00
Sophia Dao
ec7df134b4 feat(modal): make code review changes 2024-07-17 12:43:33 -05:00
Sophia Dao
bfa98646c1 feat(modal): Change name of modal 2024-07-16 15:51:58 -05:00
Sophia Dao
3bd84a0efd feat(modal): Add in modal component v1 2024-07-16 15:50:37 -05:00
Jon Young
cd7d7c303a PRWLR-3997: fix(Models): create BaseModel & TenantModel (#13)
* fix(Models): create BaseModel & TenantModel

* update description to match class

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>

* fix(Tenants): rename TenantModel to Tenant

---------

Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com>
2024-07-16 15:44:59 +02:00
Víctor Fernández Poyatos
8f41b38bbf chore: PRWLR-4055 Update project structure and add env vars (#12)
* chore: PRWLR-4055 update project structure and add env vars

* chore: PRWLR-4055 make production settings default

* chore: PRWLR-4055 change default values to env variables

* chore: PRWLR-4055 apply requested changes on default values

* chore: PRWLR-4055 adapt testing environment
2024-07-16 09:33:56 -04:00
Pablo Lara
0bdfa1a3b9 Chore: Update import paths for consistency (#10) 2024-07-16 08:06:47 -05:00
Pablo Lara
9ae201bddf Make the link active when visiting the page (#9)
* chore: set overview as a default selected key in the sidebar

* feat: use the usePathname hook from Next.js App Router to get the current pathname and use it as the active key for the Sidebar component.

* feat: make it works also for / the overview page
2024-07-15 13:42:54 -05:00
Pablo Lara
7773858340 Merge pull request #8 from prowler-cloud/PRWLR-4117-nested-layouts
Nested layouts, set routing
2024-07-15 15:32:05 +02:00
Pablo Lara
93e44a6019 fix: fix width for ProwlerExtended logo 2024-07-15 11:07:06 +02:00
Pablo Lara
3edb2ea9f2 refactor: rename cloud page to providers page 2024-07-15 10:51:23 +02:00
Pablo Lara
725dbd2979 chore: remove unused icons 2024-07-12 12:29:26 +02:00
Pablo Lara
a61554bd04 fix: resolve merge conflicts in SidebarWrap component 2024-07-12 11:56:46 +02:00
Pablo Lara
fe0d005f97 Merge pull request #6 from prowler-cloud/PRWLR-4035-UI-Sidebar
Sidebar component
2024-07-12 11:51:07 +02:00
Pablo Lara
c4074d842d feat: establish routing and implement nested structure for layouts 2024-07-12 11:49:41 +02:00
Pablo Lara
e7d4143f47 chore: use clsx library instead of custom cn utility for managing class names 2024-07-12 10:05:42 +02:00
Pablo Lara
08059e3a32 refactor: clean up and organize exports in sidebar components 2024-07-12 09:58:09 +02:00
Pablo Lara
0bef1a157b feat: centralize exports with index.ts in all directories 2024-07-12 09:42:37 +02:00
Pablo Lara
c427878820 chore: remove NextUI boilerplate code 2024-07-12 09:39:36 +02:00
Pablo Lara
23cd6553a9 chore: remove NextUI boilerplate code 2024-07-12 09:39:18 +02:00
Víctor Fernández Poyatos
9df759da60 feat: PRWLR-3989 add PostgreSQL to project (#10)
* feat: PRWLR-3989 add postgresql to project

* chore: PRWLR-3989 add requested changes to docker structure

* chore: PRWLR-3989 update poetry.lock
2024-07-11 10:39:09 -04:00
Pablo Lara
f31a92ea98 feat(sidebar): add state persistence using localStorage 2024-07-11 15:32:49 +02:00
Pablo Lara
79966db251 feat(sidebar): add state persistence using localStorage 2024-07-11 15:31:24 +02:00
Pablo Lara
443e6b6bee Merge pull request #7 from prowler-cloud/dependabot/pip/django-5.0.7
build(deps): bump django from 5.0.6 to 5.0.7
2024-07-11 10:40:59 +02:00
dependabot[bot]
157a54f30c chore(deps): bump django from 5.0.6 to 5.0.7 (#11)
Bumps [django](https://github.com/django/django) from 5.0.6 to 5.0.7.
- [Commits](https://github.com/django/django/compare/5.0.6...5.0.7)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-11 10:34:41 +02:00
Pablo Lara
746b427943 feat: set basic sidebar and the main layout 2024-07-11 10:31:06 +02:00
dependabot[bot]
86df1fd98e build(deps): bump django from 5.0.6 to 5.0.7
Bumps [django](https://github.com/django/django) from 5.0.6 to 5.0.7.
- [Commits](https://github.com/django/django/compare/5.0.6...5.0.7)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-10 22:08:57 +00:00
Víctor Fernández Poyatos
f0a276773e feat(backend): PRWLR-4030 Implement Gunicorn as Django WSGI (#9)
* feat: PRWLR-4030 implement Gunicorn server and logging

* build: PRWLR-4030 update docker files

* docs: PRWLR-4030 update README

* chore: PRWLR-4030 change binding address to 0.0.0.0 by default
2024-07-10 16:32:56 +02:00
Pablo Lara
d4b21cbe6a Merge pull request #1 from prowler-cloud/dependabot/pip/djangorestframework-3.15.2
build(deps): bump djangorestframework from 3.15.1 to 3.15.2
2024-07-10 15:51:07 +02:00
Pablo Lara
160990f979 Merge branch 'main' into PRWLR-4035-UI-Sidebar 2024-07-10 09:45:36 +02:00
Pablo Lara
ee640da9e7 Add eslint-plugin-security and pre-commit hooks. (#5)
* feat: add eslint-plugin-security

* chore: relocate devDependencies to the appropriate section in package.json

* feat: add husky library for pre-commit hooks

* feat: add husky library for pre-commit hooks

* chore: improve prettierrc config
2024-07-09 10:11:45 -05:00
Pablo Lara
4d43a6bdd6 chore: rename temp_files.tsx to fix case sensitivity issue on GitHub 2024-07-09 13:43:49 +02:00
Pablo Lara
d80622ca69 chore: rename temp_files.tsx to fix case sensitivity issue on GitHub 2024-07-09 13:42:45 +02:00
Pablo Lara
4beff6e62f chore: trigger CI build 2024-07-09 13:28:39 +02:00
Pablo Lara
6138c7da9d chore: update prettier config and fix linting issues 2024-07-09 13:04:04 +02:00
Pablo Lara
cf49641d5c chore: improve prettierrc config 2024-07-09 12:44:25 +02:00
Víctor Fernández Poyatos
457801f752 chore: update CODEOWNERS to include restful-api team (#8) 2024-07-08 13:09:04 +02:00
Pablo Lara
f7c7b6a5ba feat: add husky library for pre-commit hooks 2024-07-08 11:26:26 +02:00
Pablo Lara
2337b203d0 feat: add husky library for pre-commit hooks 2024-07-08 11:12:57 +02:00
Pablo Lara
e10bb9e3f2 chore: relocate devDependencies to the appropriate section in package.json 2024-07-08 10:59:43 +02:00
Pablo Lara
b63d1f1292 feat: add eslint-plugin-security 2024-07-08 10:20:39 +02:00
Pablo Lara
a29c9bf563 Merge pull request #4 from prowler-cloud/PRWLR-4069-remove-be-code
Clean-up repo
2024-07-08 08:52:04 +02:00
Pablo Lara
f19adde4e5 fix: add 'run' command to checks.yml to resolve pipeline issue 2024-07-08 08:49:19 +02:00
Sophia Dao
721aea945a chore: clean up due to linter rules 2024-07-07 09:56:54 -05:00
Sophia Dao
01a0d07151 chore: clean-up repo 2024-07-07 09:50:48 -05:00
Sophia Dao
15c9edd49f Merge pull request #3 from prowler-cloud/PRWLR-4039-Frontend-Build-pipeline-for-UI-repo
Build pipeline
2024-07-06 18:23:04 -05:00
Víctor Fernández Poyatos
3a502c5b3d feat(Backend): PRWLR-3990 Add custom logging (#6)
* chore: PRWLR-4022 add django-cors-headers

* chore: PRWLR-4022 configure basic CORS

* feat: PRWLR-4022 add drf-spectacular and spec/docs endpoints

* build: PRWLR-4022 add basic docker development deployment

* chore: PRWLR-4022 update schema generation

* chore: PRWLR-4022 bump required Python version to 3.12

* feat: PRWLR-3990 add basic custom Django logging

* feat: PRWLR-3990 add tasks logger

* chore: PRWLR-3990 update API logging middleware to follow updated syntax

* docs: PRWLR-3990 add docstring for APILoggingMiddleware class

* chore: PRWLR-3990 add testing dependencies to poetry

* test(API): PRWLR-3990 add new middleware unit tests and base setup

* feat(API, Backend): PRWLR-3990 add NDJSONFormatter and transaction_id

* feat(API): PRWLR-3990 add dev/test model, views and urls

* chore(backend): PRWLR-3990 refactor logging settings and modules

* chore(backend): PRWLR-3990 add BackendLogger enum and refactor logging modules

* chore(backend): PRWLR-3990 refactor module importing

* style(backend): PRWLR-3990 remove extra endlines

* chore: PRWLR-3990 update poetry.lock

* chore: PRWLR-3990 run pre-commit
2024-07-05 10:13:04 -04:00
Jon Young
30775373dc chore(CI): add labeler definition (#7) 2024-07-05 09:30:24 -04:00
Jon Young
7e194407f6 chore(CI): PRWLR-3897: add Continuous Integration workflows (#3)
* chore(CI): import pre-commit-config.yaml from prowler-cloud/prowler

* chore(CI): import pre-commit-config.yaml from prowler-cloud/prowler

* chore(CI): add safety package to pre-commit

* chore(CI): use poetry run to access venv for local checks

* docs(repo): add community focused docs

* chore(GitHub): add ISSUE_TEMPLATEs

same as prowler-cloud/prowler repo

* chore(CI): add pull-request.yml workflow

runs on PRs and pushes to main

* chore(CI): add additional workflows

same as those on prowler-cloud/prowler

* fix(CI): use correct path

* fix(API): fix flake8 F401 failures

* fix(API, Backend): format with black

* fix( Backend): format with black

* fix(CI): use correct path

* fix(CI): move pyproject.toml

* fix(CI): simplify tools with ruff

* fix(CI): use ruff instead of flake8, black

* fix(CI): change ruff commands for GHA

* fix(CI): use correct ruff command name

* fix(Backend): ruff format

* fix(CI): ignore safety jinja2 vuln id 70612

and add mypy for future usage

* fix(CI): set file path for hadolint

* fix(CI): add dockle

* fix(CI): update dockle version

* fix(CI): fix hadolint errors

* fix(CI): add simple tests for CI

* fix(Docker): multi-stage docker build

* docs(README): update docs for poetry location
2024-07-05 09:01:02 -04:00
Pablo Lara
8caae5996e chore: remove develop branch, we'll use just main 2024-07-05 13:44:17 +02:00
Pablo Lara
0664032ef7 feat: add CI checks using GitHub actions 2024-07-05 13:06:36 +02:00
Pablo Lara
67c6a12be4 feat: add CI checks using GitHub actions 2024-07-05 12:55:30 +02:00
Pablo Lara
6b028142ee chore: add eslint-plugin-simple-import-sort as a dev dependencie 2024-07-05 11:15:51 +02:00
Pablo Lara
d4eabf2d7e chore: add nvmrc file 2024-07-05 11:01:34 +02:00
Pablo Lara
c7abc37671 chore: add prettier config files 2024-07-05 11:01:12 +02:00
Pablo Lara
1637325625 chore: replace eslintrc.json by eslintrc.cjs 2024-07-05 11:00:42 +02:00
Víctor Fernández Poyatos
a69a155679 docs(backend): PRWLR-3988 Include Django development guide (#5)
* docs: PRWLR-3988 add development guide to README

* docs: PRWLR-3988 add description to README
2024-07-03 11:45:54 -04:00
Víctor Fernández Poyatos
7ff6d860ce feat(backend): PRWLR-4022 Basic Django and DRF setup and dev tools (#4)
* chore: PRWLR-4022 add django-cors-headers

* chore: PRWLR-4022 configure basic CORS

* feat: PRWLR-4022 add drf-spectacular and spec/docs endpoints

* build: PRWLR-4022 add basic docker development deployment

* chore: PRWLR-4022 update schema generation

* chore: PRWLR-4022 bump required Python version to 3.12
2024-07-03 09:34:29 -04:00
dependabot[bot]
b440be717c chore(deps): bump djangorestframework from 3.15.1 to 3.15.2 in /src (#2)
Bumps [djangorestframework](https://github.com/encode/django-rest-framework) from 3.15.1 to 3.15.2.
- [Release notes](https://github.com/encode/django-rest-framework/releases)
- [Commits](https://github.com/encode/django-rest-framework/compare/3.15.1...3.15.2)

---
updated-dependencies:
- dependency-name: djangorestframework
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-02 10:00:59 +02:00
Jon Young
d8752719c1 Merge pull request #1 from prowler-cloud/PRWLR-3980-project-setup
feat: PRWLR-3980 Setup base project structure
2024-07-01 12:20:20 -04:00
Víctor Fernández Poyatos
737a0ff9cb chore: update .gitignore 2024-07-01 18:04:13 +02:00
Víctor Fernández Poyatos
1c8e676822 chore: update CODEOWNERS 2024-07-01 18:03:27 +02:00
Víctor Fernández Poyatos
7b98f0fc92 chore: update pull request template 2024-07-01 18:00:47 +02:00
Víctor Fernández Poyatos
45865f2e71 chore: add required files for project base structure 2024-07-01 17:43:05 +02:00
Víctor Fernández Poyatos
eded2df687 chore: add .github folder and related files 2024-07-01 17:42:29 +02:00
Víctor Fernández Poyatos
766d3f6670 chore: PRWLR-3980 add Django project and API 2024-07-01 17:42:03 +02:00
Víctor Fernández Poyatos
3f2d0a13af chore: PRWLR-3980 add poetry files 2024-07-01 17:41:18 +02:00
Víctor Fernández Poyatos
690957e1c3 chore: PRWLR-3980 update .gitignore 2024-07-01 17:19:19 +02:00
Jon Young
3092b56fd6 Initial commit 2024-07-01 10:42:55 -04:00
dependabot[bot]
c000aa2602 build(deps): bump djangorestframework from 3.15.1 to 3.15.2
Bumps [djangorestframework](https://github.com/encode/django-rest-framework) from 3.15.1 to 3.15.2.
- [Release notes](https://github.com/encode/django-rest-framework/releases)
- [Commits](https://github.com/encode/django-rest-framework/compare/3.15.1...3.15.2)

---
updated-dependencies:
- dependency-name: djangorestframework
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-26 19:33:40 +00:00
Sophia Dao
ccfc46d743 feat(poc): Add in more data from api 2024-06-26 08:31:02 -05:00
Víctor Fernández Poyatos
385eb5cc18 feat(django-be): update models and serializers 2024-06-26 11:12:00 +02:00
Sophia Dao
2ff7d81a9b Comment out console.log 2024-06-26 01:33:56 -05:00
Sophia Dao
644c4fd3a4 WIP Hook up API and display data 2024-06-26 01:32:45 -05:00
Sophia Dao
d0a931bae8 feat(poc): Switch to global next.ui package, update python settings for ngrok - wip, add in next table layout 2024-06-25 19:36:10 -05:00
Sophia Dao
5583714c7a feat(poc): Add in current PoC to the repo that will be used by Vercel 2024-06-25 13:58:54 -05:00
2182 changed files with 227865 additions and 12767 deletions

126
.env Normal file
View File

@@ -0,0 +1,126 @@
#### Important Note ####
# This file is used to store environment variables for the Prowler App.
# For production, it is recommended to use a secure method to store these variables and change the default secret keys.
#### Prowler UI Configuration ####
PROWLER_UI_VERSION="stable"
SITE_URL=http://localhost:3000
API_BASE_URL=http://prowler-api:8080/api/v1
NEXT_PUBLIC_API_DOCS_URL=http://prowler-api:8080/api/v1/docs
AUTH_TRUST_HOST=true
UI_PORT=3000
# openssl rand -base64 32
AUTH_SECRET="N/c6mnaS5+SWq81+819OrzQZlmx1Vxtp/orjttJSmw8="
#### Prowler API Configuration ####
PROWLER_API_VERSION="stable"
# PostgreSQL settings
# If running Django and celery on host, use 'localhost', else use 'postgres-db'
POSTGRES_HOST=postgres-db
POSTGRES_PORT=5432
POSTGRES_ADMIN_USER=prowler_admin
POSTGRES_ADMIN_PASSWORD=postgres
POSTGRES_USER=prowler
POSTGRES_PASSWORD=postgres
POSTGRES_DB=prowler_db
# Valkey settings
# If running Valkey and celery on host, use localhost, else use 'valkey'
VALKEY_HOST=valkey
VALKEY_PORT=6379
VALKEY_DB=0
# API scan settings
# The path to the directory where scan output should be stored
DJANGO_TMP_OUTPUT_DIRECTORY = "/tmp/prowler_api_output"
# The maximum number of findings to process in a single batch
DJANGO_FINDINGS_BATCH_SIZE = 1000
# The AWS access key to be used when uploading scan output to an S3 bucket
# If left empty, default AWS credentials resolution behavior will be used
DJANGO_OUTPUT_S3_AWS_ACCESS_KEY_ID=""
# The AWS secret key to be used when uploading scan output to an S3 bucket
DJANGO_OUTPUT_S3_AWS_SECRET_ACCESS_KEY=""
# An optional AWS session token
DJANGO_OUTPUT_S3_AWS_SESSION_TOKEN=""
# The AWS region where your S3 bucket is located (e.g., "us-east-1")
DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION=""
# The name of the S3 bucket where scan output should be stored
DJANGO_OUTPUT_S3_AWS_OUTPUT_BUCKET=""
# Django settings
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,prowler-api
DJANGO_BIND_ADDRESS=0.0.0.0
DJANGO_PORT=8080
DJANGO_DEBUG=False
DJANGO_SETTINGS_MODULE=config.django.production
# Select one of [ndjson|human_readable]
DJANGO_LOGGING_FORMATTER=human_readable
# Select one of [DEBUG|INFO|WARNING|ERROR|CRITICAL]
# Applies to both Django and Celery Workers
DJANGO_LOGGING_LEVEL=INFO
# Defaults to the maximum available based on CPU cores if not set.
DJANGO_WORKERS=4
# Token lifetime is in minutes
DJANGO_ACCESS_TOKEN_LIFETIME=30
# Token lifetime is in minutes
DJANGO_REFRESH_TOKEN_LIFETIME=1440
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-----"
# 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-----"
# openssl rand -base64 32
DJANGO_SECRETS_ENCRYPTION_KEY="oE/ltOhp/n1TdbHjVmzcjDPLcLA41CVI/4Rk+UB5ESc="
DJANGO_BROKER_VISIBILITY_TIMEOUT=86400
DJANGO_SENTRY_DSN=
# Sentry settings
SENTRY_ENVIRONMENT=local
SENTRY_RELEASE=local
#### Prowler release version ####
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.4.5

9
.github/CODEOWNERS vendored
View File

@@ -1,5 +1,6 @@
* @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
# To protect a repository fully against unauthorized changes, you also need to define an owner for the CODEOWNERS file itself.
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-and-branch-protection
/* @prowler-cloud/sdk
/.github/ @prowler-cloud/sdk
prowler @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
tests @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
api @prowler-cloud/api
ui @prowler-cloud/ui

3
.github/codeql/api-codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
name: "API - CodeQL Config"
paths:
- "api/"

4
.github/codeql/sdk-codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
name: "SDK - CodeQL Config"
paths-ignore:
- "api/"
- "ui/"

3
.github/codeql/ui-codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
name: "UI - CodeQL Config"
paths:
- "ui/"

View File

@@ -5,6 +5,7 @@
version: 2
updates:
# v5
- package-ecosystem: "pip"
directory: "/"
schedule:
@@ -14,6 +15,18 @@ updates:
labels:
- "dependencies"
- "pip"
- package-ecosystem: "pip"
directory: "/api"
schedule:
interval: "daily"
open-pull-requests-limit: 10
target-branch: master
labels:
- "dependencies"
- "pip"
- "component/api"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
@@ -24,20 +37,77 @@ updates:
- "dependencies"
- "github_actions"
- package-ecosystem: "npm"
directory: "/ui"
schedule:
interval: "daily"
open-pull-requests-limit: 10
target-branch: master
labels:
- "dependencies"
- "npm"
- "component/ui"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: master
labels:
- "dependencies"
- "docker"
# v4.6
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
open-pull-requests-limit: 10
target-branch: v4.6
labels:
- "dependencies"
- "pip"
- "v4"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: v4.6
labels:
- "dependencies"
- "github_actions"
- "v4"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: v4.6
labels:
- "dependencies"
- "docker"
- "v4"
# v3
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
target-branch: v3
labels:
- "dependencies"
- "pip"
- "v3"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "monthly"
open-pull-requests-limit: 10
target-branch: v3
labels:

18
.github/labeler.yml vendored
View File

@@ -22,6 +22,11 @@ provider/kubernetes:
- any-glob-to-any-file: "prowler/providers/kubernetes/**"
- any-glob-to-any-file: "tests/providers/kubernetes/**"
provider/github:
- changed-files:
- any-glob-to-any-file: "prowler/providers/github/**"
- any-glob-to-any-file: "tests/providers/github/**"
github_actions:
- changed-files:
- any-glob-to-any-file: ".github/workflows/*"
@@ -80,9 +85,20 @@ output/csv:
- any-glob-to-any-file: "prowler/lib/outputs/csv/**"
- any-glob-to-any-file: "tests/lib/outputs/csv/**"
component/api:
- changed-files:
- any-glob-to-any-file: "api/**"
component/ui:
- changed-files:
- any-glob-to-any-file: "ui/**"
compliance:
- changed-files:
- any-glob-to-any-file: "prowler/compliance/**"
- any-glob-to-any-file: "prowler/lib/outputs/compliance/**"
- any-glob-to-any-file: "tests/lib/outputs/compliance/**"
- any-glob-to-any-file: "prowler/compliance/**"
review-django-migrations:
- changed-files:
- any-glob-to-any-file: "api/src/backend/api/migrations/**"

View File

@@ -15,6 +15,12 @@ Please include a summary of the change and which issue is fixed. List any depend
- [ ] Review if the code is being covered by tests.
- [ ] 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)
#### API
- [ ] Verify if API specs need to be regenerated.
- [ ] Check if version updates are required (e.g., specs, Poetry, etc.).
- [ ] Ensure new entries are added to [CHANGELOG.md](https://github.com/prowler-cloud/prowler/blob/master/api/CHANGELOG.md), if applicable.
### License

View File

@@ -0,0 +1,114 @@
name: API - Build and Push containers
on:
push:
branches:
- "master"
paths:
- "api/**"
- ".github/workflows/api-build-lint-push-containers.yml"
# Uncomment the code below to test this action on PRs
# pull_request:
# branches:
# - "master"
# paths:
# - "api/**"
# - ".github/workflows/api-build-lint-push-containers.yml"
release:
types: [published]
env:
# Tags
LATEST_TAG: latest
RELEASE_TAG: ${{ github.event.release.tag_name }}
STABLE_TAG: stable
WORKING_DIRECTORY: ./api
# Container Registries
PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-api
jobs:
repository-check:
name: Repository check
runs-on: ubuntu-latest
outputs:
is_repo: ${{ steps.repository_check.outputs.is_repo }}
steps:
- name: Repository check
id: repository_check
working-directory: /tmp
run: |
if [[ ${{ github.repository }} == "prowler-cloud/prowler" ]]
then
echo "is_repo=true" >> "${GITHUB_OUTPUT}"
else
echo "This action only runs for prowler-cloud/prowler"
echo "is_repo=false" >> "${GITHUB_OUTPUT}"
fi
# Build Prowler OSS container
container-build-push:
needs: repository-check
if: needs.repository-check.outputs.is_repo == 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ env.WORKING_DIRECTORY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set short git commit SHA
id: vars
run: |
shortSha=$(git rev-parse --short ${{ github.sha }})
echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push container image (latest)
# Comment the following line for testing
if: github.event_name == 'push'
uses: docker/build-push-action@v6
with:
context: ${{ env.WORKING_DIRECTORY }}
# Set push: false for testing
push: true
tags: |
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.SHORT_SHA }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push container image (release)
if: github.event_name == 'release'
uses: docker/build-push-action@v6
with:
context: ${{ env.WORKING_DIRECTORY }}
push: true
tags: |
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger deployment
if: github.event_name == 'push'
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
repository: ${{ secrets.CLOUD_DISPATCH }}
event-type: prowler-api-deploy
client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ env.SHORT_SHA }}"}'

View File

@@ -9,14 +9,21 @@
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
name: API - CodeQL
on:
push:
branches: [ "master", "v3", "v4.*" ]
branches:
- "master"
- "v5.*"
paths:
- "api/**"
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master", "v3", "v4.*" ]
branches:
- "master"
- "v5.*"
paths:
- "api/**"
schedule:
- cron: '00 12 * * *'
@@ -44,12 +51,7 @@ jobs:
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
config-file: ./.github/codeql/api-codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

189
.github/workflows/api-pull-request.yml vendored Normal file
View File

@@ -0,0 +1,189 @@
name: API - Pull Request
on:
push:
branches:
- "master"
- "v5.*"
paths:
- ".github/workflows/api-pull-request.yml"
- "api/**"
pull_request:
branches:
- "master"
- "v5.*"
paths:
- "api/**"
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_ADMIN_USER: prowler
POSTGRES_ADMIN_PASSWORD: S3cret
POSTGRES_USER: prowler_user
POSTGRES_PASSWORD: prowler
POSTGRES_DB: postgres-db
VALKEY_HOST: localhost
VALKEY_PORT: 6379
VALKEY_DB: 0
API_WORKING_DIR: ./api
IMAGE_NAME: prowler-api
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.12"]
# Service containers to run with `test`
services:
# Label used to access the service container
postgres:
image: postgres
env:
POSTGRES_HOST: ${{ env.POSTGRES_HOST }}
POSTGRES_PORT: ${{ env.POSTGRES_PORT }}
POSTGRES_USER: ${{ env.POSTGRES_USER }}
POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
POSTGRES_DB: ${{ env.POSTGRES_DB }}
# Set health checks to wait until postgres has started
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
valkey:
image: valkey/valkey:7-alpine3.19
env:
VALKEY_HOST: ${{ env.VALKEY_HOST }}
VALKEY_PORT: ${{ env.VALKEY_PORT }}
VALKEY_DB: ${{ env.VALKEY_DB }}
# Set health checks to wait until postgres has started
ports:
- 6379:6379
options: >-
--health-cmd "valkey-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Test if changes are in not ignored paths
id: are-non-ignored-files-changed
uses: tj-actions/changed-files@v45
with:
files: api/**
files_ignore: |
api/.github/**
api/docs/**
api/permissions/**
api/README.md
api/mkdocs.yml
- name: Install poetry
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
python -m pip install --upgrade pip
pipx install poetry==1.8.5
- name: Set up Python ${{ matrix.python-version }}
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "poetry"
- name: Install dependencies
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry install
poetry run pip list
VERSION=$(curl --silent "https://api.github.com/repos/hadolint/hadolint/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/' \
) && curl -L -o /tmp/hadolint "https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64" \
&& chmod +x /tmp/hadolint
- name: Poetry check
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry check --lock
- name: Lint with ruff
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run ruff check . --exclude contrib
- name: Check Format with ruff
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run ruff format --check . --exclude contrib
- name: Lint with pylint
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run pylint --disable=W,C,R,E -j 0 -rn -sn src/
- name: Bandit
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run bandit -q -lll -x '*_test.py,./contrib/' -r .
- name: Safety
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run safety check --ignore 70612,66963
- name: Vulture
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run vulture --exclude "contrib,tests,conftest.py" --min-confidence 100 .
- name: Hadolint
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
/tmp/hadolint Dockerfile --ignore=DL3013
- name: Test with pytest
working-directory: ./api
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run pytest --cov=./src/backend --cov-report=xml src/backend
- name: Upload coverage reports to Codecov
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: api
test-container-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Container
uses: docker/build-push-action@v6
with:
context: ${{ env.API_WORKING_DIR }}
push: false
tags: ${{ env.IMAGE_NAME }}:latest
outputs: type=docker
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -1,42 +1,47 @@
name: Automatic Backport
name: Prowler - Automatic Backport
on:
pull_request_target:
branches: ['master']
types: ['labeled', 'closed']
env:
# The prefix of the label that triggers the backport must not contain the branch name
# so, for example, if the branch is 'master', the label should be 'backport-to-<branch>'
BACKPORT_LABEL_PREFIX: backport-to-
BACKPORT_LABEL_IGNORE: was-backported
jobs:
backport:
name: Backport PR
if: github.event.pull_request.merged == true && !(contains(github.event.pull_request.labels.*.name, 'backport'))
if: github.event.pull_request.merged == true && !(contains(github.event.pull_request.labels.*.name, 'backport')) && !(contains(github.event.pull_request.labels.*.name, 'was-backported'))
runs-on: ubuntu-latest
permissions:
id-token: write
pull-requests: write
contents: write
steps:
# Workaround not to fail the workflow if the PR does not need a backport
# https://github.com/sorenlouv/backport-github-action/issues/127#issuecomment-2258561266
- name: Check for backport labels
id: check_labels
run: |-
labels='${{ toJSON(github.event.pull_request.labels.*.name) }}'
echo "$labels"
matched=$(echo "${labels}" | jq '. | map(select(startswith("backport-to-"))) | length')
echo "matched=$matched"
echo "matched=$matched" >> $GITHUB_OUTPUT
- name: Check labels
id: preview_label_check
uses: docker://agilepathway/pull-request-label-checker:v1.6.55
with:
allow_failure: true
prefix_mode: true
any_of: ${{ env.BACKPORT_LABEL_PREFIX }}
none_of: ${{ env.BACKPORT_LABEL_IGNORE }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
- name: Backport Action
if: fromJSON(steps.check_labels.outputs.matched) > 0
if: steps.preview_label_check.outputs.label_check == 'success'
uses: sorenlouv/backport-github-action@v9.5.1
with:
github_token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
auto_backport_label_prefix: backport-to-
auto_backport_label_prefix: ${{ env.BACKPORT_LABEL_PREFIX }}
- name: Info log
if: ${{ success() && fromJSON(steps.check_labels.outputs.matched) > 0 }}
if: ${{ success() && steps.preview_label_check.outputs.label_check == 'success' }}
run: cat ~/.backport/backport.info.log
- name: Debug log
if: ${{ failure() && fromJSON(steps.check_labels.outputs.matched) > 0 }}
if: ${{ failure() && steps.preview_label_check.outputs.label_check == 'success' }}
run: cat ~/.backport/backport.debug.log

View File

@@ -1,4 +1,4 @@
name: Pull Request Documentation Link
name: Prowler - Pull Request Documentation Link
on:
pull_request:

View File

@@ -0,0 +1,23 @@
name: Prowler - Conventional Commit
on:
pull_request:
types:
- "opened"
- "edited"
- "synchronize"
branches:
- "master"
- "v3"
- "v4.*"
- "v5.*"
jobs:
conventional-commit-check:
runs-on: ubuntu-latest
steps:
- name: conventional-commit-check
id: conventional-commit-check
uses: agenthunt/conventional-commit-checker-action@v2.0.0
with:
pr-title-regex: '^([^\s(]+)(?:\(([^)]+)\))?: (.+)'

View File

@@ -1,4 +1,4 @@
name: find-secrets
name: Prowler - Find secrets
on: pull_request
@@ -11,9 +11,9 @@ jobs:
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@v3.84.1
uses: trufflesecurity/trufflehog@v3.88.14
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --only-verified
extra_args: --only-verified

View File

@@ -1,4 +1,4 @@
name: "Pull Request Labeler"
name: Prowler - PR Labeler
on:
pull_request_target:

View File

@@ -1,14 +1,20 @@
name: build-lint-push-containers
name: SDK - Build and Push containers
on:
push:
branches:
# For `v3-latest`
- "v3"
# For `v4-latest`
- "v4.6"
# For `latest`
- "master"
paths-ignore:
- ".github/**"
- "README.md"
- "docs/**"
- "ui/**"
- "api/**"
release:
types: [published]
@@ -36,6 +42,10 @@ env:
# Python configuration
PYTHON_VERSION: 3.12
# Container Registries
PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
PROWLERCLOUD_DOCKERHUB_IMAGE: prowler
jobs:
# Build Prowler OSS container
container-build-push:
@@ -58,7 +68,7 @@ jobs:
- name: Install Poetry
run: |
pipx install poetry
pipx install poetry==1.8.5
pipx inject poetry poetry-bumpversion
- name: Get Prowler version
@@ -79,7 +89,13 @@ jobs:
echo "STABLE_TAG=v3-stable" >> "${GITHUB_ENV}"
;;
4)
echo "LATEST_TAG=v4-latest" >> "${GITHUB_ENV}"
echo "STABLE_TAG=v4-stable" >> "${GITHUB_ENV}"
;;
5)
echo "LATEST_TAG=latest" >> "${GITHUB_ENV}"
echo "STABLE_TAG=stable" >> "${GITHUB_ENV}"
;;
@@ -117,6 +133,7 @@ jobs:
tags: |
${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.LATEST_TAG }}
${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.LATEST_TAG }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}
file: ${{ env.DOCKERFILE_PATH }}
cache-from: type=gha
cache-to: type=gha,mode=max
@@ -134,6 +151,8 @@ jobs:
${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.STABLE_TAG }}
${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.PROWLER_VERSION }}
${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.STABLE_TAG }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.PROWLER_VERSION }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }}
file: ${{ env.DOCKERFILE_PATH }}
cache-from: type=gha
cache-to: type=gha,mode=max

65
.github/workflows/sdk-codeql.yml vendored Normal file
View File

@@ -0,0 +1,65 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: SDK - CodeQL
on:
push:
branches:
- "master"
- "v3"
- "v4.*"
- "v5.*"
paths-ignore:
- 'ui/**'
- 'api/**'
pull_request:
branches:
- "master"
- "v3"
- "v4.*"
- "v5.*"
paths-ignore:
- 'ui/**'
- 'api/**'
schedule:
- cron: '00 12 * * *'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/sdk-codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@@ -1,4 +1,4 @@
name: pr-lint-test
name: SDK - Pull Request
on:
push:
@@ -6,11 +6,13 @@ on:
- "master"
- "v3"
- "v4.*"
- "v5.*"
pull_request:
branches:
- "master"
- "v3"
- "v4.*"
- "v5.*"
jobs:
build:
runs-on: ubuntu-latest
@@ -20,6 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test if changes are in not ignored paths
id: are-non-ignored-files-changed
uses: tj-actions/changed-files@v45
@@ -27,22 +30,31 @@ jobs:
files: ./**
files_ignore: |
.github/**
README.md
docs/**
permissions/**
api/**
ui/**
README.md
mkdocs.yml
.backportrc.json
.env
docker-compose*
examples/**
.gitignore
- name: Install poetry
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
python -m pip install --upgrade pip
pipx install poetry
pipx install poetry==1.8.5
- name: Set up Python ${{ matrix.python-version }}
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "poetry"
- name: Install dependencies
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
@@ -53,44 +65,56 @@ jobs:
sed -E 's/.*"v([^"]+)".*/\1/' \
) && curl -L -o /tmp/hadolint "https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64" \
&& chmod +x /tmp/hadolint
- name: Poetry check
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry lock --check
poetry check --lock
- name: Lint with flake8
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run flake8 . --ignore=E266,W503,E203,E501,W605,E128 --exclude contrib
poetry run flake8 . --ignore=E266,W503,E203,E501,W605,E128 --exclude contrib,ui,api
- name: Checking format with black
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run black --check .
poetry run black --exclude api ui --check .
- name: Lint with pylint
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run pylint --disable=W,C,R,E -j 0 -rn -sn prowler/
- name: Bandit
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run bandit -q -lll -x '*_test.py,./contrib/' -r .
poetry run bandit -q -lll -x '*_test.py,./contrib/,./api/,./ui' -r .
- name: Safety
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run safety check --ignore 70612
poetry run safety check --ignore 70612 -r pyproject.toml
- name: Vulture
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run vulture --exclude "contrib" --min-confidence 100 .
poetry run vulture --exclude "contrib,api,ui" --min-confidence 100 .
- name: Hadolint
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
/tmp/hadolint Dockerfile --ignore=DL3013
- name: Test with pytest
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
poetry run pytest -n auto --cov=./prowler --cov-report=xml tests
- name: Upload coverage reports to Codecov
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: prowler

View File

@@ -1,4 +1,4 @@
name: pypi-release
name: SDK - PyPI release
on:
release:
@@ -10,12 +10,40 @@ env:
CACHE: "poetry"
jobs:
repository-check:
name: Repository check
runs-on: ubuntu-latest
outputs:
is_repo: ${{ steps.repository_check.outputs.is_repo }}
steps:
- name: Repository check
id: repository_check
working-directory: /tmp
run: |
if [[ ${{ github.repository }} == "prowler-cloud/prowler" ]]
then
echo "is_repo=true" >> "${GITHUB_OUTPUT}"
else
echo "This action only runs for prowler-cloud/prowler"
echo "is_repo=false" >> "${GITHUB_OUTPUT}"
fi
release-prowler-job:
runs-on: ubuntu-latest
needs: repository-check
if: needs.repository-check.outputs.is_repo == 'true'
env:
POETRY_VIRTUALENVS_CREATE: "false"
name: Release Prowler to PyPI
steps:
- name: Repository check
working-directory: /tmp
run: |
if [[ "${{ github.repository }}" != "prowler-cloud/prowler" ]]; then
echo "This action only runs for prowler-cloud/prowler"
exit 1
fi
- name: Get Prowler version
run: |
PROWLER_VERSION="${{ env.RELEASE_TAG }}"
@@ -27,6 +55,9 @@ jobs:
4)
echo "Releasing Prowler v4 with tag ${PROWLER_VERSION}"
;;
5)
echo "Releasing Prowler v5 with tag ${PROWLER_VERSION}"
;;
*)
echo "Releasing another Prowler major version, aborting..."
exit 1
@@ -37,7 +68,7 @@ jobs:
- name: Install dependencies
run: |
pipx install poetry
pipx install poetry==1.8.5
- name: Setup Python
uses: actions/setup-python@v5

View File

@@ -1,6 +1,6 @@
# This is a basic workflow to help you get started with Actions
name: Refresh regions of AWS services
name: SDK - Refresh AWS services' regions
on:
schedule:

View File

@@ -0,0 +1,118 @@
name: UI - Build and Push containers
on:
push:
branches:
- "master"
paths:
- "ui/**"
- ".github/workflows/ui-build-lint-push-containers.yml"
# Uncomment the below code to test this action on PRs
# pull_request:
# branches:
# - "master"
# paths:
# - "ui/**"
# - ".github/workflows/ui-build-lint-push-containers.yml"
release:
types: [published]
env:
# Tags
LATEST_TAG: latest
RELEASE_TAG: ${{ github.event.release.tag_name }}
STABLE_TAG: stable
WORKING_DIRECTORY: ./ui
# Container Registries
PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-ui
jobs:
repository-check:
name: Repository check
runs-on: ubuntu-latest
outputs:
is_repo: ${{ steps.repository_check.outputs.is_repo }}
steps:
- name: Repository check
id: repository_check
working-directory: /tmp
run: |
if [[ ${{ github.repository }} == "prowler-cloud/prowler" ]]
then
echo "is_repo=true" >> "${GITHUB_OUTPUT}"
else
echo "This action only runs for prowler-cloud/prowler"
echo "is_repo=false" >> "${GITHUB_OUTPUT}"
fi
# Build Prowler OSS container
container-build-push:
needs: repository-check
if: needs.repository-check.outputs.is_repo == 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ env.WORKING_DIRECTORY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set short git commit SHA
id: vars
run: |
shortSha=$(git rev-parse --short ${{ github.sha }})
echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push container image (latest)
# Comment the following line for testing
if: github.event_name == 'push'
uses: docker/build-push-action@v6
with:
context: ${{ env.WORKING_DIRECTORY }}
build-args: |
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=${{ env.SHORT_SHA }}
# Set push: false for testing
push: true
tags: |
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.SHORT_SHA }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push container image (release)
if: github.event_name == 'release'
uses: docker/build-push-action@v6
with:
context: ${{ env.WORKING_DIRECTORY }}
build-args: |
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${{ env.RELEASE_TAG }}
push: true
tags: |
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }}
${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger deployment
if: github.event_name == 'push'
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
repository: ${{ secrets.CLOUD_DISPATCH }}
event-type: prowler-ui-deploy
client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ env.SHORT_SHA }}"}'

59
.github/workflows/ui-codeql.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: UI - CodeQL
on:
push:
branches:
- "master"
- "v5.*"
paths:
- "ui/**"
pull_request:
branches:
- "master"
- "v5.*"
paths:
- "ui/**"
schedule:
- cron: "00 12 * * *"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["javascript"]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/ui-codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

62
.github/workflows/ui-pull-request.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: UI - Pull Request
on:
push:
branches:
- "master"
- "v5.*"
paths:
- ".github/workflows/ui-pull-request.yml"
- "ui/**"
pull_request:
branches:
- master
- "v5.*"
paths:
- 'ui/**'
env:
UI_WORKING_DIR: ./ui
IMAGE_NAME: prowler-ui
jobs:
test-and-coverage:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest]
node-version: [20.x]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
working-directory: ./ui
run: npm install
- 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@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Container
uses: docker/build-push-action@v6
with:
context: ${{ env.UI_WORKING_DIR }}
# Always build using `prod` target
target: prod
push: false
tags: ${{ env.IMAGE_NAME }}:latest
outputs: type=docker
build-args: |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51LwpXXXX

10
.gitignore vendored
View File

@@ -12,6 +12,7 @@ build/
/dist/
*.egg-info/
*/__pycache__/*.pyc
.idea/
# Session
Session.vim
@@ -30,7 +31,7 @@ tags
*.DS_Store
# Prowler output
output/
/output
# Prowler found secrets
secrets-*/
@@ -44,9 +45,11 @@ junit-reports/
# Terraform
.terraform*
*.tfstate
*.tfstate.*
# .env
.env*
ui/.env*
api/.env*
# Coverage
.coverage*
@@ -55,3 +58,6 @@ coverage*
# Node
node_modules
# Persistent data
_data/

View File

@@ -27,6 +27,7 @@ repos:
hooks:
- id: shellcheck
exclude: contrib
## PYTHON
- repo: https://github.com/myint/autoflake
rev: v2.3.1
@@ -61,8 +62,25 @@ repos:
rev: 1.8.0
hooks:
- id: poetry-check
name: API - poetry-check
args: ["--directory=./api"]
pass_filenames: false
- id: poetry-lock
args: ["--no-update"]
name: API - poetry-lock
args: ["--no-update", "--directory=./api"]
pass_filenames: false
- id: poetry-check
name: SDK - poetry-check
args: ["--directory=./"]
pass_filenames: false
- id: poetry-lock
name: SDK - poetry-lock
args: ["--no-update", "--directory=./"]
pass_filenames: false
- repo: https://github.com/hadolint/hadolint
rev: v2.13.0-beta
@@ -90,19 +108,19 @@ repos:
- id: bandit
name: bandit
description: "Bandit is a tool for finding common security issues in Python code"
entry: bash -c 'bandit -q -lll -x '*_test.py,./contrib/' -r .'
entry: bash -c '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 'safety check --ignore 70612'
entry: bash -c 'safety check --ignore 70612,66963'
language: system
- id: vulture
name: vulture
description: "Vulture finds unused code in Python programs."
entry: bash -c 'vulture --exclude "contrib" --min-confidence 100 .'
entry: bash -c 'vulture --exclude "contrib,.venv,api/src/backend/api/tests/,api/src/backend/conftest.py,api/src/backend/tasks/tests/" --min-confidence 100 .'
language: system
files: '.*\.py'

View File

@@ -1,4 +1,4 @@
FROM python:3.12-alpine
FROM python:3.12.9-alpine3.20
LABEL maintainer="https://github.com/prowler-cloud/prowler"

163
README.md
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 SaaS </b> and <b>Prowler Open Source</b> are as dynamic and adaptable as the environment theyre meant to protect. Trusted by the leaders in security.
<b><i>Prowler Open Source</b> is as dynamic and adaptable as the environment theyre meant to protect. Trusted by the leaders in security.
</p>
<p align="center">
<b>Learn more at <a href="https://prowler.com">prowler.com</i></b>
@@ -29,7 +29,7 @@
<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?include_prereleases"></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"><img alt="License" src="https://img.shields.io/github/license/prowler-cloud/prowler"></a>
@@ -43,7 +43,15 @@
# Description
**Prowler** is an Open Source security tool to perform AWS, Azure, Google Cloud and Kubernetes security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness, and also remediations! We have Prowler CLI (Command Line Interface) that we call Prowler Open Source and a service on top of it that we call <a href="https://prowler.com">Prowler SaaS</a>.
**Prowler** is an Open Source security tool to perform AWS, Azure, Google Cloud and Kubernetes security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness, and also remediations! We have Prowler CLI (Command Line Interface) that we call Prowler Open Source and a service on top of it that we call <a href="https://prowler.com">Prowler Cloud</a>.
## Prowler App
Prowler App is a web application that allows you to run Prowler in your cloud provider accounts and visualize the results in a user-friendly interface.
![Prowler App](docs/img/overview.png)
>More details at [Prowler App Documentation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-app-installation)
## Prowler CLI
@@ -63,51 +71,168 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe
| 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 | 553 | 77 -> `prowler aws --list-services` | 30 -> `prowler aws --list-compliance` | 9 -> `prowler aws --list-categories` |
| GCP | 77 | 13 -> `prowler gcp --list-services` | 3 -> `prowler gcp --list-compliance` | 2 -> `prowler gcp --list-categories`|
| Azure | 138 | 17 -> `prowler azure --list-services` | 4 -> `prowler azure --list-compliance` | 2 -> `prowler azure --list-categories` |
| Kubernetes | 83 | 7 -> `prowler kubernetes --list-services` | 1 -> `prowler kubernetes --list-compliance` | 7 -> `prowler kubernetes --list-categories` |
| AWS | 564 | 82 | 33 | 10 |
| GCP | 77 | 13 | 5 | 3 |
| Azure | 140 | 18 | 6 | 3 |
| Kubernetes | 83 | 7 | 2 | 7 |
| Microsoft365 | 5 | 2 | 1 | 0 |
> You can list the checks, services, compliance frameworks and categories with `prowler <provider> --list-checks`, `prowler <provider> --list-services`, `prowler <provider> --list-compliance` and `prowler <provider> --list-categories`.
# 💻 Installation
## Pip package
Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-cloud/), thus can be installed using pip with Python >= 3.9, < 3.13:
## Prowler App
Prowler App can be installed in different ways, depending on your environment:
> See how to use Prowler App in the [Prowler App Usage Guide](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app/).
### Docker Compose
**Requirements**
* `Docker Compose` installed: https://docs.docker.com/compose/install/.
**Commands**
``` console
curl -LO https://raw.githubusercontent.com/prowler-cloud/prowler/refs/heads/master/docker-compose.yml
curl -LO https://raw.githubusercontent.com/prowler-cloud/prowler/refs/heads/master/.env
docker compose up -d
```
> Containers are built for `linux/amd64`. If your workstation's architecture is different, please set `DOCKER_DEFAULT_PLATFORM=linux/amd64` in your environment or use the `--platform linux/amd64` flag in the docker command.
> Enjoy Prowler App at http://localhost:3000 by signing up with your email and password.
### From GitHub
**Requirements**
* `git` installed.
* `poetry` installed: [poetry installation](https://python-poetry.org/docs/#installation).
* `npm` installed: [npm installation](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).
* `Docker Compose` installed: https://docs.docker.com/compose/install/.
**Commands to run the API**
``` console
git clone https://github.com/prowler-cloud/prowler
cd prowler/api
poetry install
eval $(poetry env activate)
set -a
source .env
docker compose up postgres valkey -d
cd src/backend
python manage.py migrate --database admin
gunicorn -c config/guniconf.py config.wsgi:application
```
> [!IMPORTANT]
> Starting from Poetry v2.0.0, `poetry shell` has been deprecated in favor of `poetry env activate`.
>
> If your poetry version is below 2.0.0 you must keep using `poetry shell` to activate your environment.
> In case you have any doubts, consult the Poetry environment activation guide: https://python-poetry.org/docs/managing-environments/#activating-the-environment
> Now, you can access the API documentation at http://localhost:8080/api/v1/docs.
**Commands to run the API Worker**
``` console
git clone https://github.com/prowler-cloud/prowler
cd prowler/api
poetry install
eval $(poetry env activate)
set -a
source .env
cd src/backend
python -m celery -A config.celery worker -l info -E
```
**Commands to run the API Scheduler**
``` console
git clone https://github.com/prowler-cloud/prowler
cd prowler/api
poetry install
eval $(poetry env activate)
set -a
source .env
cd src/backend
python -m celery -A config.celery beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
```
**Commands to run the UI**
``` console
git clone https://github.com/prowler-cloud/prowler
cd prowler/ui
npm install
npm run build
npm start
```
> Enjoy Prowler App at http://localhost:3000 by signing up with your email and password.
## Prowler CLI
### Pip package
Prowler CLI is available as a project in [PyPI](https://pypi.org/project/prowler-cloud/), thus can be installed using pip with Python > 3.9.1, < 3.13:
```console
pip install prowler
prowler -v
```
>More details at [https://docs.prowler.com](https://docs.prowler.com/projects/prowler-open-source/en/latest/)
>More details at [https://docs.prowler.com](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-cli-installation)
## Containers
### Containers
The available versions of Prowler are the following:
The available versions of Prowler CLI are the following:
- `latest`: in sync with `master` branch (bear in mind that it is not a stable version)
- `v4-latest`: in sync with `v4` branch (bear in mind that it is not a stable version)
- `v3-latest`: in sync with `v3` branch (bear in mind that it is not a stable version)
- `<x.y.z>` (release): you can find the releases [here](https://github.com/prowler-cloud/prowler/releases), those are stable releases.
- `stable`: this tag always point to the latest release.
- `v4-stable`: this tag always point to the latest release for v4.
- `v3-stable`: this tag always point to the latest release for v3.
The container images are available here:
- Prowler CLI:
- [DockerHub](https://hub.docker.com/r/toniblyx/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)
- [DockerHub - Prowler API](https://hub.docker.com/r/prowlercloud/prowler-api/tags)
- [DockerHub](https://hub.docker.com/r/toniblyx/prowler/tags)
- [AWS Public ECR](https://gallery.ecr.aws/prowler-cloud/prowler)
### From GitHub
## From GitHub
Python > 3.9.1, < 3.13 is required with pip and poetry:
Python >= 3.9, < 3.13 is required with pip and poetry:
```
``` console
git clone https://github.com/prowler-cloud/prowler
cd prowler
poetry shell
eval $(poetry env activate)
poetry install
python prowler.py -v
```
> [!IMPORTANT]
> Starting from Poetry v2.0.0, `poetry shell` has been deprecated in favor of `poetry env activate`.
>
> If your poetry version is below 2.0.0 you must keep using `poetry shell` to activate your environment.
> In case you have any doubts, consult the Poetry environment activation guide: https://python-poetry.org/docs/managing-environments/#activating-the-environment
> If you want to clone Prowler from Windows, use `git config core.longpaths true` to allow long file paths.
# 📐✏️ High level architecture
## Prowler App
The **Prowler App** consists of three main components:
- **Prowler UI**: A user-friendly web interface for running Prowler and viewing results, powered by Next.js.
- **Prowler API**: The backend API that executes Prowler scans and stores the results, built with Django REST Framework.
- **Prowler SDK**: A Python SDK that integrates with the Prowler CLI for advanced functionality.
![Prowler App Architecture](docs/img/prowler-app-architecture.png)
## Prowler CLI
You can run Prowler from your workstation, a Kubernetes Job, a Google Compute Engine, an Azure VM, an EC2 instance, Fargate or any other container, CloudShell and many more.
![Architecture](docs/img/architecture.png)

58
api/.env.example Normal file
View File

@@ -0,0 +1,58 @@
# Django settings
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
DJANGO_BIND_ADDRESS=0.0.0.0
DJANGO_PORT=8000
DJANGO_DEBUG=False
# Select one of [production|devel]
DJANGO_SETTINGS_MODULE=config.django.[production|devel]
# Select one of [ndjson|human_readable]
DJANGO_LOGGING_FORMATTER=[ndjson|human_readable]
# Select one of [DEBUG|INFO|WARNING|ERROR|CRITICAL]
# Applies to both Django and Celery Workers
DJANGO_LOGGING_LEVEL=INFO
DJANGO_WORKERS=4 # Defaults to the maximum available based on CPU cores if not set.
DJANGO_TOKEN_SIGNING_KEY=""
DJANGO_TOKEN_VERIFYING_KEY=""
# Token lifetime is in minutes
DJANGO_ACCESS_TOKEN_LIFETIME=30
DJANGO_REFRESH_TOKEN_LIFETIME=1440
DJANGO_CACHE_MAX_AGE=3600
DJANGO_STALE_WHILE_REVALIDATE=60
DJANGO_SECRETS_ENCRYPTION_KEY=""
# Decide whether to allow Django manage database table partitions
DJANGO_MANAGE_DB_PARTITIONS=[True|False]
DJANGO_CELERY_DEADLOCK_ATTEMPTS=5
DJANGO_BROKER_VISIBILITY_TIMEOUT=86400
DJANGO_SENTRY_DSN=
# PostgreSQL settings
# If running django and celery on host, use 'localhost', else use 'postgres-db'
POSTGRES_HOST=[localhost|postgres-db]
POSTGRES_PORT=5432
POSTGRES_ADMIN_USER=prowler
POSTGRES_ADMIN_PASSWORD=S3cret
POSTGRES_USER=prowler_user
POSTGRES_PASSWORD=S3cret
POSTGRES_DB=prowler_db
# Valkey settings
# If running django and celery on host, use localhost, else use 'valkey'
VALKEY_HOST=[localhost|valkey]
VALKEY_PORT=6379
VALKEY_DB=0
# Sentry settings
SENTRY_ENVIRONMENT=local
SENTRY_RELEASE=local
# Social login credentials
DJANGO_GOOGLE_OAUTH_CLIENT_ID=""
DJANGO_GOOGLE_OAUTH_CLIENT_SECRET=""
DJANGO_GOOGLE_OAUTH_CALLBACK_URL=""
DJANGO_GITHUB_OAUTH_CLIENT_ID=""
DJANGO_GITHUB_OAUTH_CLIENT_SECRET=""
DJANGO_GITHUB_OAUTH_CALLBACK_URL=""
# Deletion Task Batch Size
DJANGO_DELETION_BATCH_SIZE=5000

168
api/.gitignore vendored Normal file
View File

@@ -0,0 +1,168 @@
# 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/

View File

@@ -0,0 +1,91 @@
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'
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'

59
api/CHANGELOG.md Normal file
View File

@@ -0,0 +1,59 @@
# Prowler API Changelog
All notable changes to the **Prowler API** are documented in this file.
---
## [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).
---
## [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).
---
## [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).
---
## [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).
---
## [v1.5.0] (Prowler v5.4.0)
### 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).
- 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).
---
## [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).
- Increase the allowed length of the provider UID for Kubernetes providers [(#6869)](https://github.com/prowler-cloud/prowler/pull/6869).
---

46
api/Dockerfile Normal file
View File

@@ -0,0 +1,46 @@
FROM python:3.12.8-alpine3.20 AS build
LABEL maintainer="https://github.com/prowler-cloud/api"
# hadolint ignore=DL3018
RUN apk --no-cache add gcc python3-dev musl-dev linux-headers curl-dev
RUN apk --no-cache upgrade && \
addgroup -g 1000 prowler && \
adduser -D -u 1000 -G prowler prowler
USER prowler
WORKDIR /home/prowler
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"
RUN poetry install && \
rm -rf ~/.cache/pip
COPY docker-entrypoint.sh ./docker-entrypoint.sh
WORKDIR /home/prowler/backend
# Development image
# hadolint ignore=DL3006
FROM build AS dev
USER 0
# hadolint ignore=DL3018
RUN apk --no-cache add curl vim
USER prowler
ENTRYPOINT ["../docker-entrypoint.sh", "dev"]
# Production image
FROM build
ENTRYPOINT ["../docker-entrypoint.sh", "prod"]

334
api/README.md Normal file
View File

@@ -0,0 +1,334 @@
# Description
This repository contains the JSON API and Task Runner components for Prowler, which facilitate a complete backend that interacts with the Prowler SDK and is used by the Prowler UI.
# Components
The Prowler API is composed of the following components:
- The JSON API, which is an API built with Django Rest Framework.
- The Celery worker, which is responsible for executing the background tasks that are defined in the JSON API.
- The PostgreSQL database, which is used to store the data.
- The Valkey database, which is an in-memory database which is used as a message broker for the Celery workers.
## Note about Valkey
[Valkey](https://valkey.io/) is an open source (BSD) high performance key/value datastore.
Valkey exposes a Redis 7.2 compliant API. Any service that exposes the Redis API can be used with Prowler API.
# Modify environment variables
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.
## 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.
To do this, you can run:
```console
poetry shell
set -a
source .env
```
# 🚀 Production deployment
## Docker deployment
This method requires `docker` and `docker compose`.
### Clone the repository
```console
# HTTPS
git clone https://github.com/prowler-cloud/api.git
# SSH
git clone git@github.com:prowler-cloud/api.git
```
### Build the base image
```console
docker compose --profile prod build
```
### Run the production service
This command will start the Django production server and the Celery worker and also the Valkey and PostgreSQL databases.
```console
docker compose --profile prod up -d
```
You can access the server in `http://localhost:8080`.
> **NOTE:** notice how the port is different. When developing using docker, the port will be `8080` to prevent conflicts.
### View the Production Server Logs
To view the logs for any component (e.g., Django, Celery worker), you can use the following command with a wildcard. This command will follow logs for any container that matches the specified pattern:
```console
docker logs -f $(docker ps --format "{{.Names}}" | grep 'api-')
## Local deployment
To use this method, you'll need to set up a Python virtual environment (version ">=3.11,<3.13") and keep dependencies updated. Additionally, ensure that `poetry` and `docker compose` are installed.
### Clone the repository
```console
# HTTPS
git clone https://github.com/prowler-cloud/api.git
# SSH
git clone git@github.com:prowler-cloud/api.git
```
### Install all dependencies with Poetry
```console
poetry install
poetry shell
```
## Start the PostgreSQL Database and Valkey
The PostgreSQL database (version 16.3) and Valkey (version 7) are required for the development environment. To make development easier, we have provided a `docker-compose` file that will start these components for you.
**Note:** Make sure to use the specified versions, as there are features in our setup that may not be compatible with older versions of PostgreSQL and Valkey.
```console
docker compose up postgres valkey -d
```
## Deploy Django and the Celery worker
### Run migrations
For migrations, you need to force the `admin` database router. Assuming you have the correct environment variables and Python virtual environment, run:
```console
cd src/backend
python manage.py migrate --database admin
```
### Run the Celery worker
```console
cd src/backend
python -m celery -A config.celery worker -l info -E
```
### Run the Django server with Gunicorn
```console
cd src/backend
gunicorn -c config/guniconf.py config.wsgi:application
```
> By default, the Gunicorn server will try to use as many workers as your machine can handle. You can manually change that in the `src/backend/config/guniconf.py` file.
# 🧪 Development guide
## Local deployment
To use this method, you'll need to set up a Python virtual environment (version ">=3.11,<3.13") and keep dependencies updated. Additionally, ensure that `poetry` and `docker compose` are installed.
### Clone the repository
```console
# HTTPS
git clone https://github.com/prowler-cloud/api.git
# SSH
git clone git@github.com:prowler-cloud/api.git
```
### Start the PostgreSQL Database and Valkey
The PostgreSQL database (version 16.3) and Valkey (version 7) are required for the development environment. To make development easier, we have provided a `docker-compose` file that will start these components for you.
**Note:** Make sure to use the specified versions, as there are features in our setup that may not be compatible with older versions of PostgreSQL and Valkey.
```console
docker compose up postgres valkey -d
```
### Install the Python dependencies
> You must have Poetry installed
```console
poetry install
poetry shell
```
### Apply migrations
For migrations, you need to force the `admin` database router. Assuming you have the correct environment variables and Python virtual environment, run:
```console
cd src/backend
python manage.py migrate --database admin
```
### Run the Django development server
```console
cd src/backend
python manage.py runserver
```
You can access the server in `http://localhost:8000`.
All changes in the code will be automatically reloaded in the server.
### Run the Celery worker
```console
python -m celery -A config.celery worker -l info -E
```
The Celery worker does not detect and reload changes in the code, so you need to restart it manually when you make changes.
## Docker deployment
This method requires `docker` and `docker compose`.
### Clone the repository
```console
# HTTPS
git clone https://github.com/prowler-cloud/api.git
# SSH
git clone git@github.com:prowler-cloud/api.git
```
### Build the base image
```console
docker compose --profile dev build
```
### Run the development service
This command will start the Django development server and the Celery worker and also the Valkey and PostgreSQL databases.
```console
docker compose --profile dev up -d
```
You can access the server in `http://localhost:8080`.
All changes in the code will be automatically reloaded in the server.
> **NOTE:** notice how the port is different. When developing using docker, the port will be `8080` to prevent conflicts.
### View the development server logs
To view the logs for any component (e.g., Django, Celery worker), you can use the following command with a wildcard. This command will follow logs for any container that matches the specified pattern:
```console
docker logs -f $(docker ps --format "{{.Names}}" | grep 'api-')
## Applying migrations
For migrations, you need to force the `admin` database router. Assuming you have the correct environment variables and Python virtual environment, run:
```console
poetry shell
cd src/backend
python manage.py migrate --database admin
```
## Apply fixtures
Fixtures are used to populate the database with initial development data.
```console
poetry shell
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`
## Run tests
Note that the tests will fail if you use the same `.env` file as the development environment.
For best results, run in a new shell with no environment variables set.
```console
poetry shell
cd src/backend
pytest
```
# Custom commands
Django provides a way to create custom commands that can be run from the command line.
> These commands can be found in: ```prowler/api/src/backend/api/management/commands```
To run a custom command, you need to be in the `prowler/api/src/backend` directory and run:
```console
poetry shell
python manage.py <command_name>
```
## Generate dummy data
```console
python manage.py findings --tenant
<TENANT_ID> --findings <NUM_FINDINGS> --re
sources <NUM_RESOURCES> --batch <TRANSACTION_BATCH_SIZE> --alias <ALIAS>
```
This command creates, for a given tenant, a provider, scan and a set of findings and resources related altogether.
> Scan progress and state are updated in real time.
> - 0-33%: Create resources.
> - 33-66%: Create findings.
> - 66%: Create resource-finding mapping.
>
> The last step is required to access the findings details, since the UI needs that to print all the information.
### Example
```console
~/backend $ poetry run python manage.py findings --tenant
fffb1893-3fc7-4623-a5d9-fae47da1c528 --findings 25000 --re
sources 1000 --batch 5000 --alias test-script
Starting data population
Tenant: fffb1893-3fc7-4623-a5d9-fae47da1c528
Alias: test-script
Resources: 1000
Findings: 25000
Batch size: 5000
Creating resources...
100%|███████████████████████| 1/1 [00:00<00:00, 7.72it/s]
Resources created successfully.
Creating findings...
100%|███████████████████████| 5/5 [00:05<00:00, 1.09s/it]
Findings created successfully.
Creating resource-finding mappings...
100%|███████████████████████| 5/5 [00:02<00:00, 1.81it/s]
Resource-finding mappings created successfully.
Successfully populated test data.
```

125
api/docker-compose.yml Normal file
View File

@@ -0,0 +1,125 @@
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"

71
api/docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,71 @@
#!/bin/sh
apply_migrations() {
echo "Applying database migrations..."
poetry run python manage.py migrate --database admin
}
apply_fixtures() {
echo "Applying Django fixtures..."
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
}
start_dev_server() {
echo "Starting the development server..."
poetry run python manage.py runserver 0.0.0.0:"${DJANGO_PORT:-8080}"
}
start_prod_server() {
echo "Starting the Gunicorn server..."
poetry run gunicorn -c config/guniconf.py config.wsgi:application
}
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 -E --max-tasks-per-child 1
}
start_worker_beat() {
echo "Starting the worker-beat..."
sleep 15
poetry run python -m celery -A config.celery beat -l "${DJANGO_LOGGING_LEVEL:-info}" --scheduler django_celery_beat.schedulers:DatabaseScheduler
}
manage_db_partitions() {
if [ "${DJANGO_MANAGE_DB_PARTITIONS}" = "True" ]; then
echo "Managing DB partitions..."
# For now we skip the deletion of partitions until we define the data retention policy
# --yes auto approves the operation without the need of an interactive terminal
poetry run python manage.py pgpartition --using admin --skip-delete --yes
fi
}
case "$1" in
dev)
apply_migrations
apply_fixtures
manage_db_partitions
start_dev_server
;;
prod)
apply_migrations
manage_db_partitions
start_prod_server
;;
worker)
start_worker
;;
beat)
start_worker_beat
;;
*)
echo "Usage: $0 {dev|prod|worker|beat}"
exit 1
;;
esac

65
api/docs/partitions.md Normal file
View File

@@ -0,0 +1,65 @@
# Partitions
## Overview
Partitions are used to split the data in a table into smaller chunks, allowing for more efficient querying and storage.
The Prowler API uses partitions to store findings. The partitions are created based on the UUIDv7 `id` field.
You can use the Prowler API without ever creating additional partitions. This documentation is only relevant if you want to manage partitions to gain additional query performance.
### Required Postgres Configuration
There are 3 configuration options that need to be set in the `postgres.conf` file to get the most performance out of the partitioning:
- `enable_partition_pruning = on` (default is on)
- `enable_partitionwise_join = on` (default is off)
- `enable_partitionwise_aggregate = on` (default is off)
For more information on these options, see the [Postgres documentation](https://www.postgresql.org/docs/current/runtime-config-query.html).
## Partitioning Strategy
The partitioning strategy is defined in the `api.partitions` module. The strategy is responsible for creating and deleting partitions based on the provided configuration.
## Managing Partitions
The application will run without any extra work on your part. If you want to add or delete partitions, you can use the following commands:
To manage the partitions, run `python manage.py pgpartition --using admin`
This command will generate a list of partitions to create and delete based on the provided configuration.
By default, the command will prompt you to accept the changes before applying them.
```shell
Finding:
+ 2024_nov
name: 2024_nov
from_values: 0192e505-9000-72c8-a47c-cce719d8fb93
to_values: 01937f84-5418-7eb8-b2a6-e3be749e839d
size_unit: months
size_value: 1
+ 2024_dec
name: 2024_dec
from_values: 01937f84-5800-7b55-879c-9cdb46f023f6
to_values: 01941f29-7818-7f9f-b4be-20b05bb2f574
size_unit: months
size_value: 1
0 partitions will be deleted
2 partitions will be created
```
If you choose to apply the partitions, tables will be generated with the following format: `<table_name>_<year>_<month>`.
For more info on the partitioning manager, see https://github.com/SectorLabs/django-postgres-extra
### Changing the Partitioning Parameters
There are 4 environment variables that can be used to change the partitioning parameters:
- `DJANGO_MANAGE_DB_PARTITIONS`: Allow Django to manage database partitons. By default is set to `False`.
- `FINDINGS_TABLE_PARTITION_MONTHS`: Set the months for each partition. Setting the partition monts to 1 will create partitions with a size of 1 natural month.
- `FINDINGS_TABLE_PARTITION_COUNT`: Set the number of partitions to create
- `FINDINGS_TABLE_PARTITION_MAX_AGE_MONTHS`: Set the number of months to keep partitions before deleting them. Setting this to `None` will keep partitions indefinitely.

5189
api/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

59
api/pyproject.toml Normal file
View File

@@ -0,0 +1,59 @@
[build-system]
build-backend = "poetry.core.masonry.api"
requires = ["poetry-core"]
[tool.poetry]
authors = ["Prowler Team"]
description = "Prowler's API (Django/DRF)"
license = "Apache-2.0"
name = "prowler-api"
package-mode = false
version = "1.5.4"
[tool.poetry.dependencies]
celery = {extras = ["pytest"], version = "^5.4.0"}
dj-rest-auth = {extras = ["with_social", "jwt"], version = "7.0.1"}
django = "5.1.5"
django-celery-beat = "^2.7.0"
django-celery-results = "^2.5.1"
django-cors-headers = "4.4.0"
django-environ = "0.11.2"
django-filter = "24.3"
django-guid = "3.5.0"
django-postgres-extra = "^2.0.8"
djangorestframework = "3.15.2"
djangorestframework-jsonapi = "7.0.2"
djangorestframework-simplejwt = "^5.3.1"
drf-nested-routers = "^0.94.1"
drf-spectacular = "0.27.2"
drf-spectacular-jsonapi = "0.5.1"
gunicorn = "23.0.0"
prowler = {git = "https://github.com/prowler-cloud/prowler.git", branch = "v5.4"}
psycopg2-binary = "2.9.9"
pytest-celery = {extras = ["redis"], version = "^1.0.1"}
# Needed for prowler compatibility
python = ">=3.11,<3.13"
sentry-sdk = {extras = ["django"], version = "^2.20.0"}
uuid6 = "2024.7.10"
[tool.poetry.group.dev.dependencies]
bandit = "1.7.9"
coverage = "7.5.4"
django-silk = "5.3.2"
docker = "7.1.0"
freezegun = "1.5.1"
mypy = "1.10.1"
pylint = "3.2.5"
pytest = "8.2.2"
pytest-cov = "5.0.0"
pytest-django = "4.8.0"
pytest-env = "1.1.3"
pytest-randomly = "3.15.0"
pytest-xdist = "3.6.1"
ruff = "0.5.0"
safety = "3.2.9"
tqdm = "4.67.1"
vulture = "2.14"
[tool.poetry.scripts]
celery = "src.backend.config.settings.celery"

0
api/src/__init__.py Normal file
View File

View File

View File

View File

@@ -0,0 +1,57 @@
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from django.db import transaction
from api.db_router import MainRouter
from api.db_utils import rls_transaction
from api.models import Membership, Role, Tenant, User, UserRoleRelationship
class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter):
@staticmethod
def get_user_by_email(email: str):
try:
return User.objects.get(email=email)
except User.DoesNotExist:
return None
def pre_social_login(self, request, sociallogin):
# Link existing accounts with the same email address
email = sociallogin.account.extra_data.get("email")
if email:
existing_user = self.get_user_by_email(email)
if existing_user:
sociallogin.connect(request, existing_user)
def save_user(self, request, sociallogin, form=None):
"""
Called after the user data is fully populated from the provider
and is about to be saved to the DB for the first time.
"""
with transaction.atomic(using=MainRouter.admin_db):
user = super().save_user(request, sociallogin, form)
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,
)
return user

View File

@@ -0,0 +1,3 @@
# from django.contrib import admin
# Register your models here.

View File

@@ -0,0 +1,12 @@
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "api"
def ready(self):
from api import signals # noqa: F401
from api.compliance import load_prowler_compliance
load_prowler_compliance()

View File

@@ -0,0 +1,152 @@
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from rest_framework import permissions
from rest_framework.exceptions import NotAuthenticated
from rest_framework.filters import SearchFilter
from rest_framework_json_api import filters
from rest_framework_json_api.views import ModelViewSet
from rest_framework_simplejwt.authentication import JWTAuthentication
from api.db_router import MainRouter
from api.db_utils import POSTGRES_USER_VAR, rls_transaction
from api.filters import CustomDjangoFilterBackend
from api.models import Role, Tenant
from api.rbac.permissions import HasPermissions
class BaseViewSet(ModelViewSet):
authentication_classes = [JWTAuthentication]
required_permissions = []
permission_classes = [permissions.IsAuthenticated, HasPermissions]
filter_backends = [
filters.QueryParameterValidationFilter,
filters.OrderingFilter,
CustomDjangoFilterBackend,
SearchFilter,
]
filterset_fields = []
search_fields = []
ordering_fields = "__all__"
ordering = ["id"]
def initial(self, request, *args, **kwargs):
"""
Sets required_permissions before permissions are checked.
"""
self.set_required_permissions()
super().initial(request, *args, **kwargs)
def set_required_permissions(self):
"""This is an abstract method that must be implemented by subclasses."""
NotImplemented
def get_queryset(self):
raise NotImplementedError
class BaseRLSViewSet(BaseViewSet):
def dispatch(self, request, *args, **kwargs):
with transaction.atomic():
return super().dispatch(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
# Ideally, this logic would be in the `.setup()` method but DRF view sets don't call it
# https://docs.djangoproject.com/en/5.1/ref/class-based-views/base/#django.views.generic.base.View.setup
if request.auth is None:
raise NotAuthenticated
tenant_id = request.auth.get("tenant_id")
if tenant_id is None:
raise NotAuthenticated("Tenant ID is not present in token")
with rls_transaction(tenant_id):
self.request.tenant_id = tenant_id
return super().initial(request, *args, **kwargs)
def get_serializer_context(self):
context = super().get_serializer_context()
context["tenant_id"] = self.request.tenant_id
return context
class BaseTenantViewset(BaseViewSet):
def dispatch(self, request, *args, **kwargs):
with transaction.atomic():
tenant = super().dispatch(request, *args, **kwargs)
try:
# If the request is a POST, create the admin role
if request.method == "POST":
isinstance(tenant, dict) and self._create_admin_role(tenant.data["id"])
except Exception as e:
self._handle_creation_error(e, tenant)
raise
return tenant
def _create_admin_role(self, tenant_id):
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,
)
def _handle_creation_error(self, error, tenant):
if tenant.data.get("id"):
try:
Tenant.objects.using(MainRouter.admin_db).filter(
id=tenant.data["id"]
).delete()
except ObjectDoesNotExist:
pass # Tenant might not exist, handle gracefully
def initial(self, request, *args, **kwargs):
if (
request.resolver_match.url_name != "tenant-detail"
and request.method != "DELETE"
):
user_id = str(request.user.id)
with rls_transaction(value=user_id, parameter=POSTGRES_USER_VAR):
return super().initial(request, *args, **kwargs)
# TODO: DRY this when we have time
if request.auth is None:
raise NotAuthenticated
tenant_id = request.auth.get("tenant_id")
if tenant_id is None:
raise NotAuthenticated("Tenant ID is not present in token")
with rls_transaction(tenant_id):
self.request.tenant_id = tenant_id
return super().initial(request, *args, **kwargs)
class BaseUserViewset(BaseViewSet):
def dispatch(self, request, *args, **kwargs):
with transaction.atomic():
return super().dispatch(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
# TODO refactor after improving RLS on users
if request.stream is not None and request.stream.method == "POST":
return super().initial(request, *args, **kwargs)
if request.auth is None:
raise NotAuthenticated
tenant_id = request.auth.get("tenant_id")
if tenant_id is None:
raise NotAuthenticated("Tenant ID is not present in token")
with rls_transaction(tenant_id):
self.request.tenant_id = tenant_id
return super().initial(request, *args, **kwargs)

View File

@@ -0,0 +1,209 @@
from types import MappingProxyType
from prowler.lib.check.compliance_models import Compliance
from prowler.lib.check.models import CheckMetadata
from api.models import Provider
PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE = {}
PROWLER_CHECKS = {}
def get_prowler_provider_checks(provider_type: Provider.ProviderChoices):
"""
Retrieve all check IDs for the specified provider type.
This function fetches the check metadata for the given cloud provider
and returns an iterable of check IDs.
Args:
provider_type (Provider.ProviderChoices): The provider type
(e.g., 'aws', 'azure') for which to retrieve check IDs.
Returns:
Iterable[str]: An iterable of check IDs associated with the specified provider type.
"""
return CheckMetadata.get_bulk(provider_type).keys()
def get_prowler_provider_compliance(provider_type: Provider.ProviderChoices) -> dict:
"""
Retrieve the Prowler compliance data for a specified provider type.
This function fetches the compliance frameworks and their associated
requirements for the given cloud provider.
Args:
provider_type (Provider.ProviderChoices): The provider type
(e.g., 'aws', 'azure') for which to retrieve compliance data.
Returns:
dict: A dictionary mapping compliance framework names to their respective
Compliance objects for the specified provider.
"""
return Compliance.get_bulk(provider_type)
def load_prowler_compliance():
"""
Load and initialize the Prowler compliance data and checks for all provider types.
This function retrieves compliance data for all supported provider types,
generates a compliance overview template, and populates the global variables
`PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE` and `PROWLER_CHECKS` with read-only mappings
of the compliance templates and checks, respectively.
"""
global PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE
global PROWLER_CHECKS
prowler_compliance = {
provider_type: get_prowler_provider_compliance(provider_type)
for provider_type in Provider.ProviderChoices.values
}
template = generate_compliance_overview_template(prowler_compliance)
PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE = MappingProxyType(template)
PROWLER_CHECKS = MappingProxyType(load_prowler_checks(prowler_compliance))
def load_prowler_checks(prowler_compliance):
"""
Generate a mapping of checks to the compliance frameworks that include them.
This function processes the provided compliance data and creates a dictionary
mapping each provider type to a dictionary where each check ID maps to a set
of compliance names that include that check.
Args:
prowler_compliance (dict): The compliance data for all provider types,
as returned by `get_prowler_provider_compliance`.
Returns:
dict: A nested dictionary where the first-level keys are provider types,
and the values are dictionaries mapping check IDs to sets of compliance names.
"""
checks = {}
for provider_type in Provider.ProviderChoices.values:
checks[provider_type] = {
check_id: set() for check_id in get_prowler_provider_checks(provider_type)
}
for compliance_name, compliance_data in prowler_compliance[
provider_type
].items():
for requirement in compliance_data.Requirements:
for check in requirement.Checks:
try:
checks[provider_type][check].add(compliance_name)
except KeyError:
continue
return checks
def generate_scan_compliance(
compliance_overview, provider_type: str, check_id: str, status: str
):
"""
Update the compliance overview with the status of a specific check.
This function updates the compliance overview by setting the status of the given check
within all compliance frameworks and requirements that include it. It then updates the
requirement status to 'FAIL' if any of its checks have failed, and adjusts the counts
of passed and failed requirements in the compliance overview.
Args:
compliance_overview (dict): The compliance overview data structure to update.
provider_type (str): The provider type (e.g., 'aws', 'azure') associated with the check.
check_id (str): The identifier of the check whose status is being updated.
status (str): The status of the check (e.g., 'PASS', 'FAIL', 'MUTED').
Returns:
None: This function modifies the compliance_overview in place.
"""
for compliance_id in PROWLER_CHECKS[provider_type][check_id]:
for requirement in compliance_overview[compliance_id]["requirements"].values():
if check_id in requirement["checks"]:
requirement["checks"][check_id] = status
requirement["checks_status"][status.lower()] += 1
if requirement["status"] != "FAIL" and any(
value == "FAIL" for value in requirement["checks"].values()
):
requirement["status"] = "FAIL"
compliance_overview[compliance_id]["requirements_status"]["passed"] -= 1
compliance_overview[compliance_id]["requirements_status"]["failed"] += 1
def generate_compliance_overview_template(prowler_compliance: dict):
"""
Generate a compliance overview template for all provider types.
This function creates a nested dictionary structure representing the compliance
overview template for each provider type, compliance framework, and requirement.
It initializes the status of all checks and requirements, and calculates initial
counts for requirements status.
Args:
prowler_compliance (dict): The compliance data for all provider types,
as returned by `get_prowler_provider_compliance`.
Returns:
dict: A nested dictionary representing the compliance overview template,
structured by provider type and compliance framework.
"""
template = {}
for provider_type in Provider.ProviderChoices.values:
provider_compliance = template.setdefault(provider_type, {})
compliance_data_dict = prowler_compliance[provider_type]
for compliance_name, compliance_data in compliance_data_dict.items():
compliance_requirements = {}
requirements_status = {"passed": 0, "failed": 0, "manual": 0}
total_requirements = 0
for requirement in compliance_data.Requirements:
total_requirements += 1
total_checks = len(requirement.Checks)
checks_dict = {check: None for check in requirement.Checks}
# Build requirement dictionary
requirement_dict = {
"name": requirement.Name or requirement.Id,
"description": requirement.Description,
"attributes": [
dict(attribute) for attribute in requirement.Attributes
],
"checks": checks_dict,
"checks_status": {
"pass": 0,
"fail": 0,
"manual": 0,
"total": total_checks,
},
"status": "PASS",
}
# Update requirements status
if total_checks == 0:
requirements_status["manual"] += 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,
"version": compliance_data.Version,
"provider": provider_type,
"description": compliance_data.Description,
"requirements": compliance_requirements,
"requirements_status": requirements_status,
"total_requirements": total_requirements,
}
# Add compliance to provider compliance
provider_compliance[compliance_name] = compliance_dict
return template

View File

@@ -0,0 +1,29 @@
ALLOWED_APPS = ("django", "socialaccount", "account", "authtoken", "silk")
class MainRouter:
default_db = "default"
admin_db = "admin"
def db_for_read(self, model, **hints): # noqa: F841
model_table_name = model._meta.db_table
if model_table_name.startswith("django_") or any(
model_table_name.startswith(f"{app}_") for app in ALLOWED_APPS
):
return self.admin_db
return None
def db_for_write(self, model, **hints): # noqa: F841
model_table_name = model._meta.db_table
if any(model_table_name.startswith(f"{app}_") for app in ALLOWED_APPS):
return self.admin_db
return None
def allow_migrate(self, db, app_label, model_name=None, **hints): # noqa: F841
return db == self.admin_db
def allow_relation(self, obj1, obj2, **hints): # noqa: F841
# Allow relations if both objects are in either "default" or "admin" db connectors
if {obj1._state.db, obj2._state.db} <= {self.default_db, self.admin_db}:
return True
return None

View File

@@ -0,0 +1,335 @@
import secrets
import uuid
from contextlib import contextmanager
from datetime import datetime, timedelta, timezone
from django.conf import settings
from django.contrib.auth.models import BaseUserManager
from django.db import connection, models, transaction
from django_celery_beat.models import PeriodicTask
from psycopg2 import connect as psycopg2_connect
from psycopg2.extensions import AsIs, new_type, register_adapter, register_type
from rest_framework_json_api.serializers import ValidationError
DB_USER = settings.DATABASES["default"]["USER"] if not settings.TESTING else "test"
DB_PASSWORD = (
settings.DATABASES["default"]["PASSWORD"] if not settings.TESTING else "test"
)
DB_PROWLER_USER = (
settings.DATABASES["prowler_user"]["USER"] if not settings.TESTING else "test"
)
DB_PROWLER_PASSWORD = (
settings.DATABASES["prowler_user"]["PASSWORD"] if not settings.TESTING else "test"
)
TASK_RUNNER_DB_TABLE = "django_celery_results_taskresult"
POSTGRES_TENANT_VAR = "api.tenant_id"
POSTGRES_USER_VAR = "api.user_id"
SET_CONFIG_QUERY = "SELECT set_config(%s, %s::text, TRUE);"
@contextmanager
def psycopg_connection(database_alias: str):
psycopg2_connection = None
try:
admin_db = settings.DATABASES[database_alias]
psycopg2_connection = psycopg2_connect(
dbname=admin_db["NAME"],
user=admin_db["USER"],
password=admin_db["PASSWORD"],
host=admin_db["HOST"],
port=admin_db["PORT"],
)
yield psycopg2_connection
finally:
if psycopg2_connection is not None:
psycopg2_connection.close()
@contextmanager
def rls_transaction(value: str, parameter: str = POSTGRES_TENANT_VAR):
"""
Creates a new database transaction setting the given configuration value for Postgres RLS. It validates the
if the value is a valid UUID.
Args:
value (str): Database configuration parameter value.
parameter (str): Database configuration parameter name, by default is 'api.tenant_id'.
"""
with transaction.atomic():
with connection.cursor() as cursor:
try:
# just in case the value is an UUID object
uuid.UUID(str(value))
except ValueError:
raise ValidationError("Must be a valid UUID")
cursor.execute(SET_CONFIG_QUERY, [parameter, value])
yield cursor
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The email field must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def get_by_natural_key(self, email):
return self.get(email__iexact=email)
def enum_to_choices(enum_class):
"""
This function converts a Python Enum to a list of tuples, where the first element is the value and the second element is the name.
It's for use with Django's `choices` attribute, which expects a list of tuples.
"""
return [(item.value, item.name.replace("_", " ").title()) for item in enum_class]
def one_week_from_now():
"""
Return a datetime object with a date one week from now.
"""
return datetime.now(timezone.utc) + timedelta(days=7)
def generate_random_token(length: int = 14, symbols: str | None = None) -> str:
"""
Generate a random token with the specified length.
"""
_symbols = "23456789ABCDEFGHJKMNPQRSTVWXYZ"
return "".join(secrets.choice(symbols or _symbols) for _ in range(length))
def batch_delete(tenant_id, queryset, batch_size=settings.DJANGO_DELETION_BATCH_SIZE):
"""
Deletes objects in batches and returns the total number of deletions and a summary.
Args:
tenant_id (str): Tenant ID the queryset belongs to.
queryset (QuerySet): The queryset of objects to delete.
batch_size (int): The number of objects to delete in each batch.
Returns:
tuple: (total_deleted, deletion_summary)
"""
total_deleted = 0
deletion_summary = {}
while True:
with rls_transaction(tenant_id, POSTGRES_TENANT_VAR):
# Get a batch of IDs to delete
batch_ids = set(
queryset.values_list("id", flat=True).order_by("id")[:batch_size]
)
if not batch_ids:
# No more objects to delete
break
deleted_count, deleted_info = queryset.filter(id__in=batch_ids).delete()
total_deleted += deleted_count
for model_label, count in deleted_info.items():
deletion_summary[model_label] = deletion_summary.get(model_label, 0) + count
return total_deleted, deletion_summary
def delete_related_daily_task(provider_id: str):
"""
Deletes the periodic task associated with a specific provider.
Args:
provider_id (str): The unique identifier for the provider
whose related periodic task should be deleted.
"""
task_name = f"scan-perform-scheduled-{provider_id}"
PeriodicTask.objects.filter(name=task_name).delete()
# Postgres Enums
class PostgresEnumMigration:
def __init__(self, enum_name: str, enum_values: tuple):
self.enum_name = enum_name
self.enum_values = enum_values
def create_enum_type(self, apps, schema_editor): # noqa: F841
string_enum_values = ", ".join([f"'{value}'" for value in self.enum_values])
with schema_editor.connection.cursor() as cursor:
cursor.execute(
f"CREATE TYPE {self.enum_name} AS ENUM ({string_enum_values});"
)
def drop_enum_type(self, apps, schema_editor): # noqa: F841
with schema_editor.connection.cursor() as cursor:
cursor.execute(f"DROP TYPE {self.enum_name};")
class PostgresEnumField(models.Field):
def __init__(self, enum_type_name, *args, **kwargs):
self.enum_type_name = enum_type_name
super().__init__(*args, **kwargs)
def db_type(self, connection):
return self.enum_type_name
def from_db_value(self, value, expression, connection): # noqa: F841
return value
def to_python(self, value):
if isinstance(value, EnumType):
return value.value
return value
def get_prep_value(self, value):
if isinstance(value, EnumType):
return value.value
return value
class EnumType:
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
def enum_adapter(enum_obj):
return AsIs(f"'{enum_obj.value}'::{enum_obj.__class__.enum_type_name}")
def get_enum_oid(connection, enum_type_name: str):
with connection.cursor() as cursor:
cursor.execute("SELECT oid FROM pg_type WHERE typname = %s;", (enum_type_name,))
result = cursor.fetchone()
if result is None:
raise ValueError(f"Enum type '{enum_type_name}' not found")
return result[0]
def register_enum(apps, schema_editor, enum_class): # noqa: F841
with psycopg_connection(schema_editor.connection.alias) as connection:
enum_oid = get_enum_oid(connection, enum_class.enum_type_name)
enum_instance = new_type(
(enum_oid,),
enum_class.enum_type_name,
lambda value, cur: value, # noqa: F841
)
register_type(enum_instance, connection)
register_adapter(enum_class, enum_adapter)
# Postgres enum definition for member role
class MemberRoleEnum(EnumType):
enum_type_name = "member_role"
class MemberRoleEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("member_role", *args, **kwargs)
# Postgres enum definition for Provider.provider
class ProviderEnum(EnumType):
enum_type_name = "provider"
class ProviderEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("provider", *args, **kwargs)
# Postgres enum definition for Scan.type
class ScanTriggerEnum(EnumType):
enum_type_name = "scan_trigger"
class ScanTriggerEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("scan_trigger", *args, **kwargs)
# Postgres enum definition for state
class StateEnum(EnumType):
enum_type_name = "state"
class StateEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("state", *args, **kwargs)
# Postgres enum definition for Finding.Delta
class FindingDeltaEnum(EnumType):
enum_type_name = "finding_delta"
class FindingDeltaEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("finding_delta", *args, **kwargs)
# Postgres enum definition for Severity
class SeverityEnum(EnumType):
enum_type_name = "severity"
class SeverityEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("severity", *args, **kwargs)
# Postgres enum definition for Status
class StatusEnum(EnumType):
enum_type_name = "status"
class StatusEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("status", *args, **kwargs)
# Postgres enum definition for Provider secrets type
class ProviderSecretTypeEnum(EnumType):
enum_type_name = "provider_secret_type"
class ProviderSecretTypeEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("provider_secret_type", *args, **kwargs)
# Postgres enum definition for Provider secrets type
class InvitationStateEnum(EnumType):
enum_type_name = "invitation_state"
class InvitationStateEnumField(PostgresEnumField):
def __init__(self, *args, **kwargs):
super().__init__("invitation_state", *args, **kwargs)

View File

@@ -0,0 +1,68 @@
import uuid
from functools import wraps
from django.db import connection, transaction
from rest_framework_json_api.serializers import ValidationError
from api.db_utils import POSTGRES_TENANT_VAR, SET_CONFIG_QUERY
def set_tenant(func=None, *, keep_tenant=False):
"""
Decorator to set the tenant context for a Celery task based on the provided tenant_id.
This decorator extracts the `tenant_id` from the task's keyword arguments,
and uses it to set the tenant context for the current database session.
The `tenant_id` is then removed from the kwargs before the task function
is executed. If `tenant_id` is not provided, a KeyError is raised.
Args:
func (function): The Celery task function to be decorated.
Raises:
KeyError: If `tenant_id` is not found in the task's keyword arguments.
Returns:
function: The wrapped function with tenant context set.
Example:
# This decorator MUST be defined the last in the decorator chain
@shared_task
@set_tenant
def some_task(arg1, **kwargs):
# Task logic here
pass
# When calling the task
some_task.delay(arg1, tenant_id="8db7ca86-03cc-4d42-99f6-5e480baf6ab5")
# The tenant context will be set before the task logic executes.
"""
def decorator(func):
@wraps(func)
@transaction.atomic
def wrapper(*args, **kwargs):
try:
if not keep_tenant:
tenant_id = kwargs.pop("tenant_id")
else:
tenant_id = kwargs["tenant_id"]
except KeyError:
raise KeyError("This task requires the tenant_id")
try:
uuid.UUID(tenant_id)
except ValueError:
raise ValidationError("Tenant ID must be a valid UUID")
with connection.cursor() as cursor:
cursor.execute(SET_CONFIG_QUERY, [POSTGRES_TENANT_VAR, tenant_id])
return func(*args, **kwargs)
return wrapper
if func is None:
return decorator
else:
return decorator(func)

View File

@@ -0,0 +1,45 @@
from django.core.exceptions import ValidationError as django_validation_error
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
class ModelValidationError(ValidationError):
def __init__(
self,
detail: str | None = None,
code: str | None = None,
pointer: str | None = None,
status_code: int = 400,
):
super().__init__(
detail=[
{
"detail": detail,
"status": str(status_code),
"source": {"pointer": pointer},
"code": code,
}
]
)
class InvitationTokenExpiredException(APIException):
status_code = status.HTTP_410_GONE
default_detail = "The invitation token has expired and is no longer valid."
default_code = "token_expired"
def custom_exception_handler(exc, context):
if isinstance(exc, django_validation_error):
if hasattr(exc, "error_dict"):
exc = ValidationError(exc.message_dict)
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"]
]
return exception_handler(exc, context)

View File

@@ -0,0 +1,650 @@
from datetime import date, datetime, timedelta, timezone
from django.conf import settings
from django.db.models import Q
from django_filters.rest_framework import (
BaseInFilter,
BooleanFilter,
CharFilter,
ChoiceFilter,
DateFilter,
FilterSet,
UUIDFilter,
)
from rest_framework_json_api.django_filters.backends import DjangoFilterBackend
from rest_framework_json_api.serializers import ValidationError
from api.db_utils import (
FindingDeltaEnumField,
InvitationStateEnumField,
ProviderEnumField,
SeverityEnumField,
StatusEnumField,
)
from api.models import (
ComplianceOverview,
Finding,
Invitation,
Membership,
PermissionChoices,
Provider,
ProviderGroup,
ProviderSecret,
Resource,
ResourceTag,
Role,
Scan,
ScanSummary,
SeverityChoices,
StateChoices,
StatusChoices,
Task,
User,
)
from api.rls import Tenant
from api.uuid_utils import (
datetime_to_uuid7,
transform_into_uuid7,
uuid7_end,
uuid7_range,
uuid7_start,
)
from api.v1.serializers import TaskBase
class CustomDjangoFilterBackend(DjangoFilterBackend):
def to_html(self, _request, _queryset, _view):
"""Override this method to use the Browsable API in dev environments.
This disables the HTML render for the default filter.
"""
return None
def get_filterset_class(self, view, queryset=None):
# Check if the view has 'get_filterset_class' method
if hasattr(view, "get_filterset_class"):
return view.get_filterset_class()
# Fallback to the default implementation
return super().get_filterset_class(view, queryset)
class UUIDInFilter(BaseInFilter, UUIDFilter):
pass
class CharInFilter(BaseInFilter, CharFilter):
pass
class ChoiceInFilter(BaseInFilter, ChoiceFilter):
pass
class TenantFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
class Meta:
model = Tenant
fields = {
"name": ["exact", "icontains"],
"inserted_at": ["date", "gte", "lte"],
"updated_at": ["gte", "lte"],
}
class MembershipFilter(FilterSet):
date_joined = DateFilter(field_name="date_joined", lookup_expr="date")
role = ChoiceFilter(choices=Membership.RoleChoices.choices)
class Meta:
model = Membership
fields = {
"tenant": ["exact"],
"role": ["exact"],
"date_joined": ["date", "gte", "lte"],
}
class ProviderFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
connected = BooleanFilter()
provider = ChoiceFilter(choices=Provider.ProviderChoices.choices)
class Meta:
model = Provider
fields = {
"provider": ["exact", "in"],
"id": ["exact", "in"],
"uid": ["exact", "icontains", "in"],
"alias": ["exact", "icontains", "in"],
"inserted_at": ["gte", "lte"],
"updated_at": ["gte", "lte"],
}
filter_overrides = {
ProviderEnumField: {
"filter_class": CharFilter,
},
}
class ProviderRelationshipFilterSet(FilterSet):
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="provider__provider"
)
provider_type__in = ChoiceInFilter(
choices=Provider.ProviderChoices.choices, field_name="provider__provider"
)
provider_uid = CharFilter(field_name="provider__uid", lookup_expr="exact")
provider_uid__in = CharInFilter(field_name="provider__uid", lookup_expr="in")
provider_uid__icontains = CharFilter(
field_name="provider__uid", lookup_expr="icontains"
)
provider_alias = CharFilter(field_name="provider__alias", lookup_expr="exact")
provider_alias__in = CharInFilter(field_name="provider__alias", lookup_expr="in")
provider_alias__icontains = CharFilter(
field_name="provider__alias", lookup_expr="icontains"
)
class ProviderGroupFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
class Meta:
model = ProviderGroup
fields = {
"id": ["exact", "in"],
"name": ["exact", "in"],
"inserted_at": ["gte", "lte"],
"updated_at": ["gte", "lte"],
}
class ScanFilter(ProviderRelationshipFilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
completed_at = DateFilter(field_name="completed_at", lookup_expr="date")
started_at = DateFilter(field_name="started_at", lookup_expr="date")
next_scan_at = DateFilter(field_name="next_scan_at", lookup_expr="date")
trigger = ChoiceFilter(choices=Scan.TriggerChoices.choices)
state = ChoiceFilter(choices=StateChoices.choices)
state__in = ChoiceInFilter(
field_name="state", choices=StateChoices.choices, lookup_expr="in"
)
class Meta:
model = Scan
fields = {
"provider": ["exact", "in"],
"name": ["exact", "icontains"],
"started_at": ["gte", "lte"],
"next_scan_at": ["gte", "lte"],
"trigger": ["exact"],
}
class TaskFilter(FilterSet):
name = CharFilter(field_name="task_runner_task__task_name", lookup_expr="exact")
name__icontains = CharFilter(
field_name="task_runner_task__task_name", lookup_expr="icontains"
)
state = ChoiceFilter(
choices=StateChoices.choices, method="filter_state", lookup_expr="exact"
)
task_state_inverse_mapping_values = {
v: k for k, v in TaskBase.state_mapping.items()
}
def filter_state(self, queryset, name, value):
if value not in StateChoices:
raise ValidationError(
f"Invalid provider value: '{value}'. Valid values are: "
f"{', '.join(StateChoices)}"
)
return queryset.filter(
task_runner_task__status=self.task_state_inverse_mapping_values[value]
)
class Meta:
model = Task
fields = []
class ResourceTagFilter(FilterSet):
class Meta:
model = ResourceTag
fields = {
"key": ["exact", "icontains"],
"value": ["exact", "icontains"],
}
search = ["text_search"]
class ResourceFilter(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")
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
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"],
"inserted_at": ["gte", "lte"],
"updated_at": ["gte", "lte"],
}
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 FindingFilter(FilterSet):
# We filter providers from the scan in findings
provider = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
)
provider_type__in = ChoiceInFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
)
provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact")
provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in")
provider_uid__icontains = CharFilter(
field_name="scan__provider__uid", lookup_expr="icontains"
)
provider_alias = CharFilter(field_name="scan__provider__alias", lookup_expr="exact")
provider_alias__in = CharInFilter(
field_name="scan__provider__alias", lookup_expr="in"
)
provider_alias__icontains = CharFilter(
field_name="scan__provider__alias", lookup_expr="icontains"
)
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
uid = CharFilter(field_name="uid")
delta = ChoiceFilter(choices=Finding.DeltaChoices.choices)
status = ChoiceFilter(choices=StatusChoices.choices)
severity = ChoiceFilter(choices=SeverityChoices)
impact = ChoiceFilter(choices=SeverityChoices)
resources = UUIDInFilter(field_name="resource__id", lookup_expr="in")
region = CharFilter(field_name="resources__region")
region__in = CharInFilter(field_name="resources__region", lookup_expr="in")
region__icontains = CharFilter(
field_name="resources__region", lookup_expr="icontains"
)
service = CharFilter(field_name="resources__service")
service__in = CharInFilter(field_name="resources__service", lookup_expr="in")
service__icontains = CharFilter(
field_name="resources__service", lookup_expr="icontains"
)
resource_uid = CharFilter(field_name="resources__uid")
resource_uid__in = CharInFilter(field_name="resources__uid", lookup_expr="in")
resource_uid__icontains = CharFilter(
field_name="resources__uid", lookup_expr="icontains"
)
resource_name = CharFilter(field_name="resources__name")
resource_name__in = CharInFilter(field_name="resources__name", lookup_expr="in")
resource_name__icontains = CharFilter(
field_name="resources__name", lookup_expr="icontains"
)
resource_type = CharFilter(field_name="resources__type")
resource_type__in = CharInFilter(field_name="resources__type", lookup_expr="in")
resource_type__icontains = CharFilter(
field_name="resources__type", lookup_expr="icontains"
)
# Temporarily disabled until we implement tag filtering in the UI
# resource_tag_key = CharFilter(field_name="resources__tags__key")
# resource_tag_key__in = CharInFilter(
# field_name="resources__tags__key", lookup_expr="in"
# )
# resource_tag_key__icontains = CharFilter(
# field_name="resources__tags__key", lookup_expr="icontains"
# )
# resource_tag_value = CharFilter(field_name="resources__tags__value")
# resource_tag_value__in = CharInFilter(
# field_name="resources__tags__value", lookup_expr="in"
# )
# resource_tag_value__icontains = CharFilter(
# field_name="resources__tags__value", lookup_expr="icontains"
# )
# resource_tags = CharInFilter(
# method="filter_resource_tag",
# lookup_expr="in",
# help_text="Filter by resource tags `key:value` pairs.\nMultiple values may be "
# "separated by commas.",
# )
scan = UUIDFilter(method="filter_scan_id")
scan__in = UUIDInFilter(method="filter_scan_id_in")
inserted_at = DateFilter(method="filter_inserted_at", lookup_expr="date")
inserted_at__date = DateFilter(method="filter_inserted_at", lookup_expr="date")
inserted_at__gte = DateFilter(
method="filter_inserted_at_gte",
help_text=f"Maximum date range is {settings.FINDINGS_MAX_DAYS_IN_RANGE} days.",
)
inserted_at__lte = DateFilter(
method="filter_inserted_at_lte",
help_text=f"Maximum date range is {settings.FINDINGS_MAX_DAYS_IN_RANGE} days.",
)
class Meta:
model = Finding
fields = {
"id": ["exact", "in"],
"uid": ["exact", "in"],
"scan": ["exact", "in"],
"delta": ["exact", "in"],
"status": ["exact", "in"],
"severity": ["exact", "in"],
"impact": ["exact", "in"],
"check_id": ["exact", "in", "icontains"],
"inserted_at": ["date", "gte", "lte"],
"updated_at": ["gte", "lte"],
}
filter_overrides = {
FindingDeltaEnumField: {
"filter_class": CharFilter,
},
StatusEnumField: {
"filter_class": CharFilter,
},
SeverityEnumField: {
"filter_class": CharFilter,
},
}
def filter_queryset(self, queryset):
if not (self.data.get("scan") or self.data.get("scan__in")) and not (
self.data.get("inserted_at")
or self.data.get("inserted_at__date")
or self.data.get("inserted_at__gte")
or self.data.get("inserted_at__lte")
):
raise ValidationError(
[
{
"detail": "At least one date filter is required: filter[inserted_at], filter[inserted_at.gte], "
"or filter[inserted_at.lte].",
"status": 400,
"source": {"pointer": "/data/attributes/inserted_at"},
"code": "required",
}
]
)
gte_date = (
datetime.strptime(self.data.get("inserted_at__gte"), "%Y-%m-%d").date()
if self.data.get("inserted_at__gte")
else datetime.now(timezone.utc).date()
)
lte_date = (
datetime.strptime(self.data.get("inserted_at__lte"), "%Y-%m-%d").date()
if self.data.get("inserted_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/inserted_at"},
"code": "invalid",
}
]
)
return super().filter_queryset(queryset)
# Convert filter values to UUIDv7 values for use with partitioning
def filter_scan_id(self, queryset, name, value):
try:
value_uuid = transform_into_uuid7(value)
start = uuid7_start(value_uuid)
end = uuid7_end(value_uuid, settings.FINDINGS_TABLE_PARTITION_MONTHS)
except ValidationError as validation_error:
detail = str(validation_error.detail[0])
raise ValidationError(
[
{
"detail": detail,
"status": 400,
"source": {"pointer": "/data/relationships/scan"},
"code": "invalid",
}
]
)
return (
queryset.filter(id__gte=start).filter(id__lt=end).filter(scan_id=value_uuid)
)
def filter_scan_id_in(self, queryset, name, value):
try:
uuid_list = [
transform_into_uuid7(value_uuid)
for value_uuid in value
if value_uuid is not None
]
start, end = uuid7_range(uuid_list)
except ValidationError as validation_error:
detail = str(validation_error.detail[0])
raise ValidationError(
[
{
"detail": detail,
"status": 400,
"source": {"pointer": "/data/relationships/scan"},
"code": "invalid",
}
]
)
if start == end:
return queryset.filter(id__gte=start).filter(scan_id__in=uuid_list)
else:
return (
queryset.filter(id__gte=start)
.filter(id__lt=end)
.filter(scan_id__in=uuid_list)
)
def filter_inserted_at(self, queryset, name, value):
datetime_value = self.maybe_date_to_datetime(value)
start = uuid7_start(datetime_to_uuid7(datetime_value))
end = uuid7_start(datetime_to_uuid7(datetime_value + timedelta(days=1)))
return queryset.filter(id__gte=start, id__lt=end)
def filter_inserted_at_gte(self, queryset, name, value):
datetime_value = self.maybe_date_to_datetime(value)
start = uuid7_start(datetime_to_uuid7(datetime_value))
return queryset.filter(id__gte=start)
def filter_inserted_at_lte(self, queryset, name, value):
datetime_value = self.maybe_date_to_datetime(value)
end = uuid7_start(datetime_to_uuid7(datetime_value + timedelta(days=1)))
return queryset.filter(id__lt=end)
def filter_resource_tag(self, queryset, name, value):
overall_query = Q()
for key_value_pair in value:
tag_key, tag_value = key_value_pair.split(":", 1)
overall_query |= Q(
resources__tags__key__icontains=tag_key,
resources__tags__value__icontains=tag_value,
)
return queryset.filter(overall_query).distinct()
@staticmethod
def maybe_date_to_datetime(value):
dt = value
if isinstance(value, date):
dt = datetime.combine(value, datetime.min.time(), tzinfo=timezone.utc)
return dt
class ProviderSecretFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
provider = UUIDFilter(field_name="provider__id", lookup_expr="exact")
class Meta:
model = ProviderSecret
fields = {
"name": ["exact", "icontains"],
}
class InvitationFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
expires_at = DateFilter(field_name="expires_at", lookup_expr="date")
state = ChoiceFilter(choices=Invitation.State.choices)
state__in = ChoiceInFilter(choices=Invitation.State.choices, lookup_expr="in")
class Meta:
model = Invitation
fields = {
"email": ["exact", "icontains"],
"inserted_at": ["date", "gte", "lte"],
"updated_at": ["date", "gte", "lte"],
"expires_at": ["date", "gte", "lte"],
"inviter": ["exact"],
}
filter_overrides = {
InvitationStateEnumField: {
"filter_class": CharFilter,
}
}
class UserFilter(FilterSet):
date_joined = DateFilter(field_name="date_joined", lookup_expr="date")
class Meta:
model = User
fields = {
"name": ["exact", "icontains"],
"email": ["exact", "icontains"],
"company_name": ["exact", "icontains"],
"date_joined": ["date", "gte", "lte"],
"is_active": ["exact"],
}
class RoleFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
permission_state = ChoiceFilter(
choices=PermissionChoices.choices, method="filter_permission_state"
)
def filter_permission_state(self, queryset, name, value):
return Role.filter_by_permission_state(queryset, value)
class Meta:
model = Role
fields = {
"id": ["exact", "in"],
"name": ["exact", "in"],
"inserted_at": ["gte", "lte"],
"updated_at": ["gte", "lte"],
}
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")
class Meta:
model = ComplianceOverview
fields = {
"inserted_at": ["date", "gte", "lte"],
"compliance_id": ["exact", "icontains"],
"framework": ["exact", "iexact", "icontains"],
"version": ["exact", "icontains"],
"region": ["exact", "icontains", "in"],
}
class ScanSummaryFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider_type = ChoiceFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
)
provider_type__in = ChoiceInFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
)
region = CharFilter(field_name="region")
muted_findings = BooleanFilter(method="filter_muted_findings")
def filter_muted_findings(self, queryset, name, value):
if not value:
return queryset.exclude(muted__gt=0)
return queryset
class Meta:
model = ScanSummary
fields = {
"inserted_at": ["date", "gte", "lte"],
"region": ["exact", "icontains", "in"],
}
class ServiceOverviewFilter(ScanSummaryFilter):
muted_findings = None
def is_valid(self):
# Check if at least one of the inserted_at filters is present
inserted_at_filters = [
self.data.get("inserted_at"),
self.data.get("inserted_at__gte"),
self.data.get("inserted_at__lte"),
]
if not any(inserted_at_filters):
raise ValidationError(
{
"inserted_at": [
"At least one of filter[inserted_at], filter[inserted_at__gte], or "
"filter[inserted_at__lte] is required."
]
}
)
return super().is_valid()

View File

@@ -0,0 +1,28 @@
[
{
"model": "api.user",
"pk": "8b38e2eb-6689-4f1e-a4ba-95b275130200",
"fields": {
"password": "pbkdf2_sha256$720000$vA62S78kog2c2ytycVQdke$Fp35GVLLMyy5fUq3krSL9I02A+ocQ+RVa4S22LIAO5s=",
"last_login": null,
"name": "Devie Prowlerson",
"email": "dev@prowler.com",
"company_name": "Prowler Developers",
"is_active": true,
"date_joined": "2024-09-17T09:04:20.850Z"
}
},
{
"model": "api.user",
"pk": "b6493a3a-c997-489b-8b99-278bf74de9f6",
"fields": {
"password": "pbkdf2_sha256$720000$vA62S78kog2c2ytycVQdke$Fp35GVLLMyy5fUq3krSL9I02A+ocQ+RVa4S22LIAO5s=",
"last_login": null,
"name": "Devietoo Prowlerson",
"email": "dev2@prowler.com",
"company_name": "Prowler Developers",
"is_active": true,
"date_joined": "2024-09-18T09:04:20.850Z"
}
}
]

View File

@@ -0,0 +1,50 @@
[
{
"model": "api.tenant",
"pk": "12646005-9067-4d2a-a098-8bb378604362",
"fields": {
"inserted_at": "2024-03-21T23:00:00Z",
"updated_at": "2024-03-21T23:00:00Z",
"name": "Tenant1"
}
},
{
"model": "api.tenant",
"pk": "0412980b-06e3-436a-ab98-3c9b1d0333d3",
"fields": {
"inserted_at": "2024-03-21T23:00:00Z",
"updated_at": "2024-03-21T23:00:00Z",
"name": "Tenant2"
}
},
{
"model": "api.membership",
"pk": "2b0db93a-7e0b-4edf-a851-ea448676b7eb",
"fields": {
"user": "8b38e2eb-6689-4f1e-a4ba-95b275130200",
"tenant": "0412980b-06e3-436a-ab98-3c9b1d0333d3",
"role": "owner",
"date_joined": "2024-09-19T11:03:59.712Z"
}
},
{
"model": "api.membership",
"pk": "797d7cee-abc9-4598-98bb-4bf4bfb97f27",
"fields": {
"user": "8b38e2eb-6689-4f1e-a4ba-95b275130200",
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"role": "owner",
"date_joined": "2024-09-19T11:02:59.712Z"
}
},
{
"model": "api.membership",
"pk": "dea37563-7009-4dcf-9f18-25efb41462a7",
"fields": {
"user": "b6493a3a-c997-489b-8b99-278bf74de9f6",
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"role": "member",
"date_joined": "2024-09-19T11:03:59.712Z"
}
}
]

View File

@@ -0,0 +1,193 @@
[
{
"model": "api.provider",
"pk": "37b065f8-26b0-4218-a665-0b23d07b27d9",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-01T17:20:27.050Z",
"updated_at": "2024-08-01T17:20:27.050Z",
"provider": "gcp",
"uid": "a12322-test321",
"alias": "gcp_testing_2",
"connected": null,
"connection_last_checked_at": null,
"metadata": {}
}
},
{
"model": "api.provider",
"pk": "8851db6b-42e5-4533-aa9e-30a32d67e875",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-01T17:19:42.453Z",
"updated_at": "2024-08-01T17:19:42.453Z",
"provider": "gcp",
"uid": "a12345-test123",
"alias": "gcp_testing_1",
"connected": null,
"connection_last_checked_at": null,
"metadata": {}
}
},
{
"model": "api.provider",
"pk": "b85601a8-4b45-4194-8135-03fb980ef428",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-01T17:19:09.556Z",
"updated_at": "2024-08-01T17:19:09.556Z",
"provider": "aws",
"uid": "123456789020",
"alias": "aws_testing_2",
"connected": null,
"connection_last_checked_at": null,
"metadata": {}
}
},
{
"model": "api.provider",
"pk": "baa7b895-8bac-4f47-b010-4226d132856e",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-01T17:20:16.962Z",
"updated_at": "2024-08-01T17:20:16.962Z",
"provider": "gcp",
"uid": "a12322-test123",
"alias": "gcp_testing_3",
"connected": null,
"connection_last_checked_at": null,
"metadata": {}
}
},
{
"model": "api.provider",
"pk": "d7c7ea89-d9af-423b-a364-1290dcad5a01",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-01T17:18:58.132Z",
"updated_at": "2024-08-01T17:18:58.132Z",
"provider": "aws",
"uid": "123456789015",
"alias": "aws_testing_1",
"connected": null,
"connection_last_checked_at": null,
"metadata": {}
}
},
{
"model": "api.provider",
"pk": "1b59e032-3eb6-4694-93a5-df84cd9b3ce2",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-06T16:03:26.176Z",
"updated_at": "2024-08-06T16:03:26.176Z",
"provider": "azure",
"uid": "8851db6b-42e5-4533-aa9e-30a32d67e875",
"alias": "azure_testing",
"connected": null,
"connection_last_checked_at": null,
"metadata": {},
"scanner_args": {}
}
},
{
"model": "api.provider",
"pk": "26e55a24-cb2c-4cef-ac87-6f91fddb2c97",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-08-06T16:03:07.037Z",
"updated_at": "2024-08-06T16:03:07.037Z",
"provider": "kubernetes",
"uid": "kubernetes-test-12345",
"alias": "k8s_testing",
"connected": null,
"connection_last_checked_at": null,
"metadata": {},
"scanner_args": {}
}
},
{
"model": "api.provider",
"pk": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:45:26.352Z",
"updated_at": "2024-10-18T11:16:23.533Z",
"provider": "aws",
"uid": "106908755759",
"alias": "real testing aws provider",
"connected": true,
"connection_last_checked_at": "2024-10-18T11:16:23.503Z",
"metadata": {},
"scanner_args": {}
}
},
{
"model": "api.provider",
"pk": "7791914f-d646-4fe2-b2ed-73f2c6499a36",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:45:26.352Z",
"updated_at": "2024-10-18T11:16:23.533Z",
"provider": "kubernetes",
"uid": "gke_lucky-coast-419309_us-central1_autopilot-cluster-2",
"alias": "k8s_testing_2",
"connected": true,
"connection_last_checked_at": "2024-10-18T11:16:23.503Z",
"metadata": {},
"scanner_args": {}
}
},
{
"model": "api.providersecret",
"pk": "11491b47-75ae-4f71-ad8d-3e630a72182e",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-11T08:03:05.026Z",
"updated_at": "2024-10-11T08:04:47.033Z",
"name": "GCP static secrets",
"secret_type": "static",
"_secret": "Z0FBQUFBQm5DTndmZW9KakRZUHM2UHhQN2V3RzN0QmM1cERham8yMHp5cnVTT0lzdGFyS1FuVmJXUlpYSGsyU0cxR3RMMEdQYXlYMUVsaWtqLU1OZWlaVUp6OFREYlotZTVBY3BuTlZYbm9YcUJydzAxV2p5dkpLamI1Y2tUYzA0MmJUNWxsNTBRM0E1SDRCa0pPQWVlb05YU3dfeUhkLTRmOEh3dGczOGh1ZGhQcVdZdVAtYmtoSWlwNXM4VGFoVmF3dno2X1hrbk5GZjZTWjVuWEdEZUFXeHJSQjEzbTlVakhNdzYyWTdiVEpvUEc2MTNpRzUtczhEank1eGI0b3MyMlAyaGN6dlByZmtUWHByaDNUYWFqYS1tYnNBUkRKTzBacFNSRjFuVmd5bUtFUEJhd1ZVS1ZDd2xSUV9PaEtLTnc0XzVkY2lhM01WTjQwaWdJSk9wNUJSXzQ4RUNQLXFPNy1VdzdPYkZyWkVkU3RyQjVLTS1MVHN0R3k4THNKZ2NBNExaZnl3Q1EwN2dwNGRsUXptMjB0LXUzTUpzTDE2Q1hmS0ZSN2g1ZjBPeV8taFoxNUwxc2FEcktXX0dCM1IzeUZTTHNiTmNxVXBvNWViZTJScUVWV2VYTFQ4UHlid21PY1A0UjdNMGtERkZCd0lLMlJENDMzMVZUM09DQ0twd1N3VHlZd09XLUctOWhYcFJIR1p5aUlZeEUzejc2dWRYdGNsd0xOODNqRUFEczhSTWNtWU0tdFZ1ZTExaHNHUVYtd0Zxdld1LTdKVUNINzlZTGdHODhKeVVpQmRZMHRUNTJRRWhwS1F1Y3I2X2Iwc0c1NHlXSVRLZWxreEt0dVRnOTZFMkptU2VMS1dWXzdVOVRzMUNUWXM2aFlxVDJXdGo3d2cxSVZGWlI2ZWhIZzZBcEl4bEJ6UnVHc0RYWVNHcjFZUHI5ZUYyWG9rSlo0QUVSUkFCX3h2UmtJUTFzVXJUZ25vTmk2VzdoTTNta05ucmNfTi0yR1ZxN1E2MnZJOVVKOGxmMXMzdHMxVndmSVhQbUItUHgtMVpVcHJwMU5JVHJLb0Y1aHV5OEEwS0kzQkEtcFJkdkRnWGxmZnprNFhndWg1TmQyd09yTFdTRmZ3d2ZvZFUtWXp4a2VYb3JjckFIcE13MDUzX0RHSnlzM0N2ZE5IRzJzMXFMc0k4MDRyTHdLZFlWOG9SaFF0LU43Ynd6VFlEcVNvdFZ0emJEVk10aEp4dDZFTFNFNzk0UUo2WTlVLWRGYm1fanZHaFZreHBIMmtzVjhyS0xPTk9fWHhiVTJHQXZwVlVuY3JtSjFUYUdHQzhEaHFNZXhwUHBmY0kxaUVrOHo4a0FYOTdpZVJDbFRvdFlQeWo3eFZHX1ZMZ1Myc3prU3o2c3o2eXNja1U4N0Y1T0d1REVjZFRGNTByUkgyemVCSjlQYkY2bmJ4YTZodHB0cUNzd2xZcENycUdsczBIaEZPbG1jVUlqNlM2cEE3aGpVaWswTzBDLVFGUHM5UHhvM09saWNtaDhaNVlsc3FZdktKeWlheDF5OGhTODE2N3JWamdTZG5Fa3JSQ2ZUSEVfRjZOZXdreXRZLTBZRFhleVFFeC1YUzc0cWhYeEhobGxvdnZ3Rm15WFlBWXp0dm1DeTA5eExLeEFRRXVRSXBXdTNEaWdZZ3JDenItdDhoZlFiTzI0SGZ1c01FR1FNaFVweVBKR1YxWGRUMW1Mc2JVdW9raWR6UHk2ZTBnS05pV3oyZVBjREdkY3k4ZHZPUWE5S281MkJRSHF3NnpTclZ5bl90bk1wUEh6Tkp5dXlDcE5paWRqcVhxRFVObWIzRldWOGJ2aC1CRHZpbFZrb0hjNGpCMm5POGRiS2lETUpMLUVfQlhCdTZPLW9USW1LTFlTSF9zRUJYZ1NKeFFEQjNOR215ZXJDbkFndmcxWl9rWlk9",
"provider": "8851db6b-42e5-4533-aa9e-30a32d67e875"
}
},
{
"model": "api.providersecret",
"pk": "40191ad5-d8c2-40a9-826d-241397626b68",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-10T11:11:44.515Z",
"updated_at": "2024-10-11T07:59:56.102Z",
"name": "AWS static secrets",
"secret_type": "static",
"_secret": "Z0FBQUFBQm5DTnI4Y1RyV19UWEJzc3kzQUExcU5tdlQzbFVLeDdZMWd1MzkwWkl2UF9oZGhiVEJHVWpSMXV4MjYyN3g2OVpvNVpkQUQ3S0VGaGdQLTFhQWE3MkpWZUt2cnVhODc4d3FpY3FVZkpwdHJzNUJPeFRwZ3N4bGpPZTlkNWRNdFlwTHU3aTNWR3JjSzJwLWRITHdfQWpXb1F0c1l3bVFxbnFrTEpPTGgxcnF1VUprSzZ5dGRQU2VGYmZhTTlwbVpsNFBNWlFhVW9RbjJyYnZ5N0oweE5kV0ZEaUdpUUpNVExOa3oyQ2dNREVSenJ0TEFZc0RrRWpXNUhyMmtybGNLWDVOR0FabEl4QVR1bkZyb2hBLWc1MFNIekVyeXI0SmVreHBjRnJ1YUlVdXpVbW9JZkk0aEgxYlM1VGhSRlhtcS14YzdTYUhXR2xodElmWjZuNUVwaHozX1RVTG1QWHdPZWd4clNHYnAyOTBsWEl5UU83RGxZb0RKWjdadjlsTmJtSHQ0Yl9uaDJoODB0QV9sWmFYbFAxcjA1bmhNVlNqc2xEeHlvcUJFbVZvY250ZENnMnZLT1psb1JDclB3WVR6NGdZb2pzb3U4Ny04QlB0UTZub0dMOXZEUTZEcVJhZldCWEZZSDdLTy02UVZqck5zVTZwS3pObGlOejNJeHUzbFRabFM2V2xaekZVRjZtX3VzZlplendnOWQzT01WMFd3ejNadHVlTFlqRGR2dk5Da29zOFYwOUdOaEc4OHhHRnJFMmJFMk12VDNPNlBBTGlsXy13cUM1QkVYb0o1Z2U4ZXJnWXpZdm1sWjA5bzQzb2NFWC1xbmIycGZRbGtCaGNaOWlkX094UUNNampwbkZoREctNWI4QnZRaE8zM3BEQ1BwNzA1a3BzOGczZXdIM2s1NHFGN1ZTbmJhZkc4RVdfM0ZIZU5udTBYajd1RGxpWXZpRWdSMmhHa2RKOEIzbmM0X2F1OGxrN2p6LW9UVldDOFVpREoxZ1UzcTBZX19OQ0xJb0syWlhNSlQ4MzQwdzRtVG94Y01GS3FMLV95UVlxOTFORk8zdjE5VGxVaXdhbGlzeHdoYWNzazZWai1GUGtUM2gzR0ZWTTY4SThWeVFnZldIaklOTTJqTTg1VkhEYW5wNmdEVllXMmJCV2tpVmVYeUV2c0E1T00xbHJRNzgzVG9wb0Q1cV81UEhqYUFsQ2p1a0VpRDVINl9SVkpyZVRNVnVXQUxwY3NWZnJrNmRVREpiLWNHYUpXWmxkQlhNbWhuR1NmQ1BaVDlidUxCWHJMaHhZbk1FclVBaEVZeWg1ZlFoenZzRHlKbV8wa3lmMGZrd3NmTDZjQkE0UXNSUFhpTWtUUHBrX29BVzc4QzEtWEJIQW1GMGFuZVlXQWZIOXJEamloeGFCeHpYMHNjMFVfNXpQdlJfSkk2bzFROU5NU0c1SHREWW1nbkFNZFZ0UjdPRGdjaF96RGplY1hjdFFzLVR6MTVXYlRjbHIxQ2JRejRpVko5NWhBU0ZHR3ZvczU5elljRGpHRTdIc0FsSm5fUHEwT1gtTS1lN3M3X3ZZRnlkYUZoZXRQeEJsZlhLdFdTUzU1NUl4a29aOWZIdTlPM0Fnak1xYWVkYTNiMmZXUHlXS2lwUVBZLXQyaUxuRmtQNFFieE9SVmdZVW9WTHlzbnBPZlNIdGVHOE1LNVNESjN3cGtVSHVpT1NJWHE1ZzNmUTVTOC0xX3NGSmJqU19IbjZfQWtMRG1YNUQtRy13TUJIZFlyOXJkQzFQbkdZVXVzM2czbS1HWHFBT1pXdVd3N09tcG82SVhnY1ZtUWxqTEg2UzJCUmllb2pweVN2aGwwS1FVRUhjNEN2amRMc3MwVU4zN3dVMWM5Slg4SERtenFaQk1yMWx0LWtxVWtLZVVtbU4yejVEM2h6TEt0RGdfWE09",
"provider": "b85601a8-4b45-4194-8135-03fb980ef428"
}
},
{
"model": "api.providersecret",
"pk": "ed89d1ea-366a-4d12-a602-f2ab77019742",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-10T11:11:44.515Z",
"updated_at": "2024-10-11T07:59:56.102Z",
"name": "Azure static secrets",
"secret_type": "static",
"_secret": "Z0FBQUFBQm5DTnI4Y1RyV19UWEJzc3kzQUExcU5tdlQzbFVLeDdZMWd1MzkwWkl2UF9oZGhiVEJHVWpSMXV4MjYyN3g2OVpvNVpkQUQ3S0VGaGdQLTFhQWE3MkpWZUt2cnVhODc4d3FpY3FVZkpwdHJzNUJPeFRwZ3N4bGpPZTlkNWRNdFlwTHU3aTNWR3JjSzJwLWRITHdfQWpXb1F0c1l3bVFxbnFrTEpPTGgxcnF1VUprSzZ5dGRQU2VGYmZhTTlwbVpsNFBNWlFhVW9RbjJyYnZ5N0oweE5kV0ZEaUdpUUpNVExOa3oyQ2dNREVSenJ0TEFZc0RrRWpXNUhyMmtybGNLWDVOR0FabEl4QVR1bkZyb2hBLWc1MFNIekVyeXI0SmVreHBjRnJ1YUlVdXpVbW9JZkk0aEgxYlM1VGhSRlhtcS14YzdTYUhXR2xodElmWjZuNUVwaHozX1RVTG1QWHdPZWd4clNHYnAyOTBsWEl5UU83RGxZb0RKWjdadjlsTmJtSHQ0Yl9uaDJoODB0QV9sWmFYbFAxcjA1bmhNVlNqc2xEeHlvcUJFbVZvY250ZENnMnZLT1psb1JDclB3WVR6NGdZb2pzb3U4Ny04QlB0UTZub0dMOXZEUTZEcVJhZldCWEZZSDdLTy02UVZqck5zVTZwS3pObGlOejNJeHUzbFRabFM2V2xaekZVRjZtX3VzZlplendnOWQzT01WMFd3ejNadHVlTFlqRGR2dk5Da29zOFYwOUdOaEc4OHhHRnJFMmJFMk12VDNPNlBBTGlsXy13cUM1QkVYb0o1Z2U4ZXJnWXpZdm1sWjA5bzQzb2NFWC1xbmIycGZRbGtCaGNaOWlkX094UUNNampwbkZoREctNWI4QnZRaE8zM3BEQ1BwNzA1a3BzOGczZXdIM2s1NHFGN1ZTbmJhZkc4RVdfM0ZIZU5udTBYajd1RGxpWXZpRWdSMmhHa2RKOEIzbmM0X2F1OGxrN2p6LW9UVldDOFVpREoxZ1UzcTBZX19OQ0xJb0syWlhNSlQ4MzQwdzRtVG94Y01GS3FMLV95UVlxOTFORk8zdjE5VGxVaXdhbGlzeHdoYWNzazZWai1GUGtUM2gzR0ZWTTY4SThWeVFnZldIaklOTTJqTTg1VkhEYW5wNmdEVllXMmJCV2tpVmVYeUV2c0E1T00xbHJRNzgzVG9wb0Q1cV81UEhqYUFsQ2p1a0VpRDVINl9SVkpyZVRNVnVXQUxwY3NWZnJrNmRVREpiLWNHYUpXWmxkQlhNbWhuR1NmQ1BaVDlidUxCWHJMaHhZbk1FclVBaEVZeWg1ZlFoenZzRHlKbV8wa3lmMGZrd3NmTDZjQkE0UXNSUFhpTWtUUHBrX29BVzc4QzEtWEJIQW1GMGFuZVlXQWZIOXJEamloeGFCeHpYMHNjMFVfNXpQdlJfSkk2bzFROU5NU0c1SHREWW1nbkFNZFZ0UjdPRGdjaF96RGplY1hjdFFzLVR6MTVXYlRjbHIxQ2JRejRpVko5NWhBU0ZHR3ZvczU5elljRGpHRTdIc0FsSm5fUHEwT1gtTS1lN3M3X3ZZRnlkYUZoZXRQeEJsZlhLdFdTUzU1NUl4a29aOWZIdTlPM0Fnak1xYWVkYTNiMmZXUHlXS2lwUVBZLXQyaUxuRmtQNFFieE9SVmdZVW9WTHlzbnBPZlNIdGVHOE1LNVNESjN3cGtVSHVpT1NJWHE1ZzNmUTVTOC0xX3NGSmJqU19IbjZfQWtMRG1YNUQtRy13TUJIZFlyOXJkQzFQbkdZVXVzM2czbS1HWHFBT1pXdVd3N09tcG82SVhnY1ZtUWxqTEg2UzJCUmllb2pweVN2aGwwS1FVRUhjNEN2amRMc3MwVU4zN3dVMWM5Slg4SERtenFaQk1yMWx0LWtxVWtLZVVtbU4yejVEM2h6TEt0RGdfWE09",
"provider": "1b59e032-3eb6-4694-93a5-df84cd9b3ce2"
}
},
{
"model": "api.providersecret",
"pk": "ae48ecde-75cd-4814-92ab-18f48719e5d9",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:45:26.412Z",
"updated_at": "2024-10-18T10:45:26.412Z",
"name": "Valid AWS Credentials",
"secret_type": "static",
"_secret": "Z0FBQUFBQm5FanhHa3dXS0I3M2NmWm56SktiaGNqdDZUN0xQU1QwUi15QkhLZldFUmRENk1BXzlscG9JSUxVSTF5ekxuMkdEanlJNjhPUS1VSV9wVTBvU2l4ZnNGOVJhYW93RC1LTEhmc2pyOTJvUWwyWnpFY19WN1pRQk5IdDYwYnBDQnF1eU9nUzdwTGU3QU5qMGFyX1E4SXdpSk9paGVLcVpOVUhwb3duaXgxZ0ZxME5Pcm40QzBGWEZKY2lmRVlCMGFuVFVzemxuVjVNalZVQ2JsY2ZqNWt3Z01IYUZ0dk92YkdtSUZ5SlBvQWZoVU5DWlRFWmExNnJGVEY4Q1Bnd2VJUW9TSWdRcG9rSDNfREQwRld3Q1RYVnVYWVJLWWIxZmpsWGpwd0xQM0dtLTlYUjdHOVhhNklLWXFGTHpFQUVyVmNhYW9CU0tocGVyX3VjMkVEcVdjdFBfaVpsLTBzaUxrWTlta3dpelNtTG9xYVhBUHUzNUE4RnI1WXdJdHcxcFVfaG1XRHhDVFBKamxJb1FaQ2lsQ3FzRmxZbEJVemVkT1E2aHZfbDJqWDJPT3ViOWJGYzQ3eTNWNlFQSHBWRDFiV2tneDM4SmVqMU9Bd01TaXhPY2dmWG5RdENURkM2b2s5V3luVUZQcnFKNldnWEdYaWE2MnVNQkEwMHd6cUY5cVJkcGw4bHBtNzhPeHhkREdwSXNEc1JqQkxUR1FYRTV0UFNwbVlVSWF5LWgtbVhJZXlPZ0Q4cG9HX2E0Qld0LTF1TTFEVy1XNGdnQTRpLWpQQmFJUEdaOFJGNDVoUVJnQ25YVU5DTENMaTY4YmxtYWJFRERXTjAydVN2YnBDb3RkUE0zSDRlN1A3TXc4d2h1Wmd0LWUzZEcwMUstNUw2YnFyS2Z0NEVYMXllQW5GLVBpeU55SkNhczFIeFhrWXZpVXdwSFVrTDdiQjQtWHZJdERXVThzSnJsT2FNZzJDaUt6Y2NXYUZhUlo3VkY0R1BrSHNHNHprTmxjYmp1TXVKakRha0VtNmRFZWRmZHJWdnRCOVNjVGFVWjVQM3RwWWl4SkNmOU1pb2xqMFdOblhNY3Y3aERpOHFlWjJRc2dtRDkzZm1Qc29wdk5OQmJPbGk5ZUpGM1I2YzRJN2gxR3FEMllXR1pma1k0emVqSjZyMUliMGZsc3NfSlVDbGt4QzJTc3hHOU9FRHlZb09zVnlvcDR6WC1uclRSenI0Yy13WlFWNzJWRkwydjhmSjFZdnZ5X3NmZVF6UWRNMXo5STVyV3B0d09UUlFtOURITGhXSDVIUl9zYURJc05KWUNxekVyYkxJclNFNV9leEk4R2xsMGJod3lYeFIwaXR2dllwLTZyNWlXdDRpRkxVYkxWZFdvYUhKck5aeElBZUtKejNKS2tYVW1rTnVrRjJBQmdlZmV6ckozNjNwRmxLS1FaZzRVTTBZYzFFYi1idjBpZkQ3bWVvbEdRZXJrWFNleWZmSmFNdG1wQlp0YmxjWDV5T0tEbHRsYnNHbjRPRjl5MkttOUhRWlJtd1pmTnY4Z1lPRlZoTzFGVDdTZ0RDY1ByV0RndTd5LUNhcHNXUnNIeXdLMEw3WS1tektRTWFLQy1zakpMLWFiM3FOakE1UWU4LXlOX2VPbmd4MTZCRk9OY3Z4UGVDSWxhRlg4eHI4X1VUTDZZM0pjV0JDVi1UUjlTUl85cm1LWlZ0T1dzU0lpdWUwbXgtZ0l6eHNSNExRTV9MczJ6UkRkVElnRV9Rc0RoTDFnVHRZSEFPb2paX200TzZiRzVmRE5hOW5CTjh5Qi1WaEtueEpqRzJDY1luVWZtX1pseUpQSE5lQ0RrZ05EbWo5cU9MZ0ZkcXlqUll4UUkyejRfY2p4RXdEeC1PS1JIQVNUcmNIdkRJbzRiUktMWEQxUFM3aGNzeVFWUDdtcm5xNHlOYUU9",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555"
}
}
]

View File

@@ -0,0 +1,256 @@
[
{
"model": "api.scan",
"pk": "0191e280-9d2f-71c8-9b18-487a23ba185e",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "37b065f8-26b0-4218-a665-0b23d07b27d9",
"trigger": "manual",
"name": "test scan 1",
"state": "completed",
"unique_resource_count": 1,
"duration": 5,
"scanner_args": {
"checks_to_execute": ["accessanalyzer_enabled"]
},
"inserted_at": "2024-09-01T17:25:27.050Z",
"started_at": "2024-09-01T17:25:27.050Z",
"updated_at": "2024-09-01T17:25:27.050Z",
"completed_at": "2024-09-01T17:25:32.050Z"
}
},
{
"model": "api.scan",
"pk": "01920573-aa9c-73c9-bcda-f2e35c9b19d2",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "b85601a8-4b45-4194-8135-03fb980ef428",
"trigger": "manual",
"name": "test aws scan 2",
"state": "completed",
"unique_resource_count": 1,
"duration": 20,
"scanner_args": {
"checks_to_execute": ["accessanalyzer_enabled"]
},
"inserted_at": "2024-09-02T17:24:27.050Z",
"started_at": "2024-09-02T17:24:27.050Z",
"updated_at": "2024-09-02T17:24:27.050Z",
"completed_at": "2024-09-01T17:24:37.050Z"
}
},
{
"model": "api.scan",
"pk": "01920573-ea5b-77fd-a93f-1ed2ae12f728",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "baa7b895-8bac-4f47-b010-4226d132856e",
"trigger": "manual",
"name": "test gcp scan",
"state": "completed",
"unique_resource_count": 10,
"duration": 10,
"scanner_args": {
"checks_to_execute": ["cloudsql_instance_automated_backups"]
},
"inserted_at": "2024-09-02T19:26:27.050Z",
"started_at": "2024-09-02T19:26:27.050Z",
"updated_at": "2024-09-02T19:26:27.050Z",
"completed_at": "2024-09-01T17:26:37.050Z"
}
},
{
"model": "api.scan",
"pk": "01920573-ea5b-77fd-a93f-1ed2ae12f728",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "b85601a8-4b45-4194-8135-03fb980ef428",
"trigger": "manual",
"name": "test aws scan",
"state": "completed",
"unique_resource_count": 1,
"duration": 35,
"scanner_args": {
"checks_to_execute": ["accessanalyzer_enabled"]
},
"inserted_at": "2024-09-02T19:27:27.050Z",
"started_at": "2024-09-02T19:27:27.050Z",
"updated_at": "2024-09-02T19:27:27.050Z",
"completed_at": "2024-09-01T17:27:37.050Z"
}
},
{
"model": "api.scan",
"pk": "c281c924-23f3-4fcc-ac63-73a22154b7de",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "b85601a8-4b45-4194-8135-03fb980ef428",
"trigger": "scheduled",
"name": "test scheduled aws scan",
"state": "available",
"scanner_args": {
"checks_to_execute": ["cloudformation_stack_outputs_find_secrets"]
},
"scheduled_at": "2030-09-02T19:20:27.050Z",
"inserted_at": "2024-09-02T19:24:27.050Z",
"updated_at": "2024-09-02T19:24:27.050Z"
}
},
{
"model": "api.scan",
"pk": "25c8907c-b26e-4ec0-966b-a1f53a39d8e6",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "b85601a8-4b45-4194-8135-03fb980ef428",
"trigger": "scheduled",
"name": "test scheduled aws scan 2",
"state": "available",
"scanner_args": {
"checks_to_execute": [
"accessanalyzer_enabled",
"cloudformation_stack_outputs_find_secrets"
]
},
"scheduled_at": "2030-08-02T19:31:27.050Z",
"inserted_at": "2024-09-02T19:38:27.050Z",
"updated_at": "2024-09-02T19:38:27.050Z"
}
},
{
"model": "api.scan",
"pk": "25c8907c-b26e-4ec0-966b-a1f53a39d8e6",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "baa7b895-8bac-4f47-b010-4226d132856e",
"trigger": "scheduled",
"name": "test scheduled gcp scan",
"state": "available",
"scanner_args": {
"checks_to_execute": [
"cloudsql_instance_automated_backups",
"iam_audit_logs_enabled"
]
},
"scheduled_at": "2030-07-02T19:30:27.050Z",
"inserted_at": "2024-09-02T19:29:27.050Z",
"updated_at": "2024-09-02T19:29:27.050Z"
}
},
{
"model": "api.scan",
"pk": "25c8907c-b26e-4ec0-966b-a1f53a39d8e6",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "1b59e032-3eb6-4694-93a5-df84cd9b3ce2",
"trigger": "scheduled",
"name": "test scheduled azure scan",
"state": "available",
"scanner_args": {
"checks_to_execute": [
"aks_cluster_rbac_enabled",
"defender_additional_email_configured_with_a_security_contact"
]
},
"scheduled_at": "2030-08-05T19:32:27.050Z",
"inserted_at": "2024-09-02T19:29:27.050Z",
"updated_at": "2024-09-02T19:29:27.050Z"
}
},
{
"model": "api.scan",
"pk": "01929f3b-ed2e-7623-ad63-7c37cd37828f",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "real scan 1",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"trigger": "manual",
"state": "completed",
"unique_resource_count": 19,
"progress": 100,
"scanner_args": {
"checks_to_execute": ["accessanalyzer_enabled"]
},
"duration": 7,
"scheduled_at": null,
"inserted_at": "2024-10-18T10:45:57.678Z",
"updated_at": "2024-10-18T10:46:05.127Z",
"started_at": "2024-10-18T10:45:57.909Z",
"completed_at": "2024-10-18T10:46:05.127Z"
}
},
{
"model": "api.scan",
"pk": "6dd8925f-a52d-48de-a546-d2d90db30ab1",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "real scan azure",
"provider": "1b59e032-3eb6-4694-93a5-df84cd9b3ce2",
"trigger": "manual",
"state": "completed",
"unique_resource_count": 20,
"progress": 100,
"scanner_args": {
"checks_to_execute": [
"accessanalyzer_enabled",
"account_security_contact_information_is_registered"
]
},
"duration": 4,
"scheduled_at": null,
"inserted_at": "2024-10-18T11:16:21.358Z",
"updated_at": "2024-10-18T11:16:26.060Z",
"started_at": "2024-10-18T11:16:21.593Z",
"completed_at": "2024-10-18T11:16:26.060Z"
}
},
{
"model": "api.scan",
"pk": "4ca7ce89-3236-41a8-a369-8937bc152af5",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "real scan k8s",
"provider": "7791914f-d646-4fe2-b2ed-73f2c6499a36",
"trigger": "manual",
"state": "completed",
"unique_resource_count": 20,
"progress": 100,
"scanner_args": {
"checks_to_execute": [
"accessanalyzer_enabled",
"account_security_contact_information_is_registered"
]
},
"duration": 4,
"scheduled_at": null,
"inserted_at": "2024-10-18T11:16:21.358Z",
"updated_at": "2024-10-18T11:16:26.060Z",
"started_at": "2024-10-18T11:16:21.593Z",
"completed_at": "2024-10-18T11:16:26.060Z"
}
},
{
"model": "api.scan",
"pk": "01929f57-c0ee-7553-be0b-cbde006fb6f7",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "real scan 2",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"trigger": "manual",
"state": "completed",
"unique_resource_count": 20,
"progress": 100,
"scanner_args": {
"checks_to_execute": [
"accessanalyzer_enabled",
"account_security_contact_information_is_registered"
]
},
"duration": 4,
"scheduled_at": null,
"inserted_at": "2024-10-18T11:16:21.358Z",
"updated_at": "2024-10-18T11:16:26.060Z",
"started_at": "2024-10-18T11:16:21.593Z",
"completed_at": "2024-10-18T11:16:26.060Z"
}
}
]

View File

@@ -0,0 +1,322 @@
[
{
"model": "api.resource",
"pk": "0234477d-0b8e-439f-87d3-ce38dff3a434",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.772Z",
"updated_at": "2024-10-18T11:16:24.466Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root",
"name": "",
"region": "eu-south-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'eu':7C 'eu-south':6C 'iam':3A 'other':11 'root':5A 'south':8C"
}
},
{
"model": "api.resource",
"pk": "17ce30a3-6e77-42a5-bb08-29dfcad7396a",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.882Z",
"updated_at": "2024-10-18T11:16:24.533Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root2",
"name": "",
"region": "eu-west-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'eu':7C 'eu-west':6C 'iam':3A 'other':11 'root':5A 'west':8C"
}
},
{
"model": "api.resource",
"pk": "1f9de587-ba5b-415a-b9b0-ceed4c6c9f32",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.091Z",
"updated_at": "2024-10-18T11:16:24.637Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root3",
"name": "",
"region": "ap-northeast-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'ap':7C 'ap-northeast':6C 'arn':1A 'aws':2A 'iam':3A 'northeast':8C 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "29b35668-6dad-411d-bfec-492311889892",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.008Z",
"updated_at": "2024-10-18T11:16:24.600Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root4",
"name": "",
"region": "us-west-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'iam':3A 'other':11 'root':5A 'us':7C 'us-west':6C 'west':8C"
}
},
{
"model": "api.resource",
"pk": "30505514-01d4-42bb-8b0c-471bbab27460",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T11:16:26.014Z",
"updated_at": "2024-10-18T11:16:26.023Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root5",
"name": "",
"region": "us-east-1",
"service": "account",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'account':10 'arn':1A 'aws':2A 'east':8C 'iam':3A 'other':11 'root':5A 'us':7C 'us-east':6C"
}
},
{
"model": "api.resource",
"pk": "372932f0-e4df-4968-9721-bb4f6236fae4",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.848Z",
"updated_at": "2024-10-18T11:16:24.516Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root6",
"name": "",
"region": "eu-west-3",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'3':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'eu':7C 'eu-west':6C 'iam':3A 'other':11 'root':5A 'west':8C"
}
},
{
"model": "api.resource",
"pk": "3a37d124-7637-43f6-9df7-e9aa7ef98c53",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.979Z",
"updated_at": "2024-10-18T11:16:24.585Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root7",
"name": "",
"region": "sa-east-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'east':8C 'iam':3A 'other':11 'root':5A 'sa':7C 'sa-east':6C"
}
},
{
"model": "api.resource",
"pk": "3c49318e-03c6-4f12-876f-40451ce7de3d",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.072Z",
"updated_at": "2024-10-18T11:16:24.630Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root8",
"name": "",
"region": "ap-southeast-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'ap':7C 'ap-southeast':6C 'arn':1A 'aws':2A 'iam':3A 'other':11 'root':5A 'southeast':8C"
}
},
{
"model": "api.resource",
"pk": "430bf313-8733-4bc5-ac70-5402adfce880",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.994Z",
"updated_at": "2024-10-18T11:16:24.593Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root9",
"name": "",
"region": "eu-north-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'eu':7C 'eu-north':6C 'iam':3A 'north':8C 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "78bd2a52-82f9-45df-90a9-4ad78254fdc4",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.055Z",
"updated_at": "2024-10-18T11:16:24.622Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root10",
"name": "",
"region": "ap-northeast-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'ap':7C 'ap-northeast':6C 'arn':1A 'aws':2A 'iam':3A 'northeast':8C 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "7973e332-795e-4a74-b4d4-a53a21c98c80",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.896Z",
"updated_at": "2024-10-18T11:16:24.542Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root11",
"name": "",
"region": "us-east-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'east':8C 'iam':3A 'other':11 'root':5A 'us':7C 'us-east':6C"
}
},
{
"model": "api.resource",
"pk": "8ca0a188-5699-436e-80fd-e566edaeb259",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.938Z",
"updated_at": "2024-10-18T11:16:24.565Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root12",
"name": "",
"region": "ca-central-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'ca':7C 'ca-central':6C 'central':8C 'iam':3A 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "8fe4514f-71d7-46ab-b0dc-70cef23b4d13",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.965Z",
"updated_at": "2024-10-18T11:16:24.578Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root13",
"name": "",
"region": "eu-west-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'eu':7C 'eu-west':6C 'iam':3A 'other':11 'root':5A 'west':8C"
}
},
{
"model": "api.resource",
"pk": "9ab35225-dc7c-4ebd-bbc0-d81fb5d9de77",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.909Z",
"updated_at": "2024-10-18T11:16:24.549Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root14",
"name": "",
"region": "ap-south-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'ap':7C 'ap-south':6C 'arn':1A 'aws':2A 'iam':3A 'other':11 'root':5A 'south':8C"
}
},
{
"model": "api.resource",
"pk": "9be26c1d-adf0-4ba8-9ca9-c740f4a0dc4e",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.863Z",
"updated_at": "2024-10-18T11:16:24.524Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root15",
"name": "",
"region": "eu-central-2",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'2':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'central':8C 'eu':7C 'eu-central':6C 'iam':3A 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "ba108c01-bcad-44f1-b211-c1d8985da89d",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.110Z",
"updated_at": "2024-10-18T11:16:24.644Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root16",
"name": "",
"region": "ap-northeast-3",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'3':9C '112233445566':4A 'accessanalyzer':10 'ap':7C 'ap-northeast':6C 'arn':1A 'aws':2A 'iam':3A 'northeast':8C 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "dc6cfb5d-6835-4c7b-9152-c18c734a6eaa",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.038Z",
"updated_at": "2024-10-18T11:16:24.615Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root17",
"name": "",
"region": "eu-central-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'central':8C 'eu':7C 'eu-central':6C 'iam':3A 'other':11 'root':5A"
}
},
{
"model": "api.resource",
"pk": "e0664164-cfda-44a4-b743-acee1c69386c",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.924Z",
"updated_at": "2024-10-18T11:16:24.557Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root18",
"name": "",
"region": "us-west-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'arn':1A 'aws':2A 'iam':3A 'other':11 'root':5A 'us':7C 'us-west':6C 'west':8C"
}
},
{
"model": "api.resource",
"pk": "e1929daa-a984-4116-8131-492a48321dba",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:05.023Z",
"updated_at": "2024-10-18T11:16:24.607Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:iam::112233445566:root19",
"name": "",
"region": "ap-southeast-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9C '112233445566':4A 'accessanalyzer':10 'ap':7C 'ap-southeast':6C 'arn':1A 'aws':2A 'iam':3A 'other':11 'root':5A 'southeast':8C"
}
},
{
"model": "api.resource",
"pk": "e37bb1f1-1669-4bb3-be86-e3378ddfbcba",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"inserted_at": "2024-10-18T10:46:04.952Z",
"updated_at": "2024-10-18T11:16:24.571Z",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"uid": "arn:aws:access-analyzer:us-east-1:112233445566:analyzer/ConsoleAnalyzer-83b66ad7-d024-454e-b851-52d11cc1cf7c",
"name": "",
"region": "us-east-1",
"service": "accessanalyzer",
"type": "Other",
"text_search": "'1':9A,15C '112233445566':10A 'access':4A 'access-analyzer':3A 'accessanalyzer':16 'analyzer':5A 'analyzer/consoleanalyzer-83b66ad7-d024-454e-b851-52d11cc1cf7c':11A 'arn':1A 'aws':2A 'east':8A,14C 'other':17 'us':7A,13C 'us-east':6A,12C"
}
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
[
{
"model": "api.providergroup",
"pk": "3fe28fb8-e545-424c-9b8f-69aff638f430",
"fields": {
"name": "first_group",
"inserted_at": "2024-11-13T11:36:19.503Z",
"updated_at": "2024-11-13T11:36:19.503Z",
"tenant": "12646005-9067-4d2a-a098-8bb378604362"
}
},
{
"model": "api.providergroup",
"pk": "525e91e7-f3f3-4254-bbc3-27ce1ade86b1",
"fields": {
"name": "second_group",
"inserted_at": "2024-11-13T11:36:25.421Z",
"updated_at": "2024-11-13T11:36:25.421Z",
"tenant": "12646005-9067-4d2a-a098-8bb378604362"
}
},
{
"model": "api.providergroup",
"pk": "481769f5-db2b-447b-8b00-1dee18db90ec",
"fields": {
"name": "third_group",
"inserted_at": "2024-11-13T11:36:37.603Z",
"updated_at": "2024-11-13T11:36:37.603Z",
"tenant": "12646005-9067-4d2a-a098-8bb378604362"
}
},
{
"model": "api.providergroupmembership",
"pk": "13625bd3-f428-4021-ac1b-b0bd41b6e02f",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "1b59e032-3eb6-4694-93a5-df84cd9b3ce2",
"provider_group": "3fe28fb8-e545-424c-9b8f-69aff638f430",
"inserted_at": "2024-11-13T11:55:17.138Z"
}
},
{
"model": "api.providergroupmembership",
"pk": "54784ebe-42d2-4937-aa6a-e21c62879567",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"provider_group": "3fe28fb8-e545-424c-9b8f-69aff638f430",
"inserted_at": "2024-11-13T11:55:17.138Z"
}
},
{
"model": "api.providergroupmembership",
"pk": "c8bd52d5-42a5-48fe-8e0a-3eef154b8ebe",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"provider": "15fce1fa-ecaa-433f-a9dc-62553f3a2555",
"provider_group": "525e91e7-f3f3-4254-bbc3-27ce1ade86b1",
"inserted_at": "2024-11-13T11:55:41.237Z"
}
},
{
"model": "api.role",
"pk": "3f01e759-bdf9-4a99-8888-1ab805b79f93",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "admin_test",
"manage_users": true,
"manage_account": true,
"manage_billing": true,
"manage_providers": true,
"manage_integrations": true,
"manage_scans": true,
"unlimited_visibility": true,
"inserted_at": "2024-11-20T15:32:42.402Z",
"updated_at": "2024-11-20T15:32:42.402Z"
}
},
{
"model": "api.role",
"pk": "845ff03a-87ef-42ba-9786-6577c70c4df0",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "first_role",
"manage_users": true,
"manage_account": true,
"manage_billing": true,
"manage_providers": true,
"manage_integrations": false,
"manage_scans": false,
"unlimited_visibility": true,
"inserted_at": "2024-11-20T15:31:53.239Z",
"updated_at": "2024-11-20T15:31:53.239Z"
}
},
{
"model": "api.role",
"pk": "902d726c-4bd5-413a-a2a4-f7b4754b6b20",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"name": "third_role",
"manage_users": false,
"manage_account": false,
"manage_billing": false,
"manage_providers": false,
"manage_integrations": false,
"manage_scans": true,
"unlimited_visibility": false,
"inserted_at": "2024-11-20T15:34:05.440Z",
"updated_at": "2024-11-20T15:34:05.440Z"
}
},
{
"model": "api.roleprovidergrouprelationship",
"pk": "57fd024a-0a7f-49b4-a092-fa0979a07aaf",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"role": "3f01e759-bdf9-4a99-8888-1ab805b79f93",
"provider_group": "3fe28fb8-e545-424c-9b8f-69aff638f430",
"inserted_at": "2024-11-20T15:32:42.402Z"
}
},
{
"model": "api.roleprovidergrouprelationship",
"pk": "a3cd0099-1c13-4df1-a5e5-ecdfec561b35",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"role": "3f01e759-bdf9-4a99-8888-1ab805b79f93",
"provider_group": "481769f5-db2b-447b-8b00-1dee18db90ec",
"inserted_at": "2024-11-20T15:32:42.402Z"
}
},
{
"model": "api.roleprovidergrouprelationship",
"pk": "cfd84182-a058-40c2-af3c-0189b174940f",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"role": "3f01e759-bdf9-4a99-8888-1ab805b79f93",
"provider_group": "525e91e7-f3f3-4254-bbc3-27ce1ade86b1",
"inserted_at": "2024-11-20T15:32:42.402Z"
}
},
{
"model": "api.userrolerelationship",
"pk": "92339663-e954-4fd8-98fb-8bfe15949975",
"fields": {
"tenant": "12646005-9067-4d2a-a098-8bb378604362",
"role": "3f01e759-bdf9-4a99-8888-1ab805b79f93",
"user": "8b38e2eb-6689-4f1e-a4ba-95b275130200",
"inserted_at": "2024-11-20T15:36:14.302Z"
}
}
]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,237 @@
import random
from datetime import datetime, timezone
from math import ceil
from uuid import uuid4
from django.core.management.base import BaseCommand
from tqdm import tqdm
from api.db_utils import rls_transaction
from api.models import (
Finding,
Provider,
Resource,
ResourceFindingMapping,
Scan,
StatusChoices,
)
from prowler.lib.check.models import CheckMetadata
class Command(BaseCommand):
help = "Populates the database with test data for performance testing."
def add_arguments(self, parser):
parser.add_argument(
"--tenant",
type=str,
required=True,
help="Tenant id for which the data will be populated.",
)
parser.add_argument(
"--resources",
type=int,
required=True,
help="The number of resources to create.",
)
parser.add_argument(
"--findings",
type=int,
required=True,
help="The number of findings to create.",
)
parser.add_argument(
"--batch", type=int, required=True, help="The batch size for bulk creation."
)
parser.add_argument(
"--alias",
type=str,
required=False,
help="Optional alias for the provider and scan",
)
def handle(self, *args, **options):
tenant_id = options["tenant"]
num_resources = options["resources"]
num_findings = options["findings"]
batch_size = options["batch"]
alias = options["alias"] or "Testing"
uid_token = str(uuid4())
self.stdout.write(self.style.NOTICE("Starting data population"))
self.stdout.write(self.style.NOTICE(f"\tTenant: {tenant_id}"))
self.stdout.write(self.style.NOTICE(f"\tAlias: {alias}"))
self.stdout.write(self.style.NOTICE(f"\tResources: {num_resources}"))
self.stdout.write(self.style.NOTICE(f"\tFindings: {num_findings}"))
self.stdout.write(self.style.NOTICE(f"\tBatch size: {batch_size}\n\n"))
# Resource metadata
possible_regions = [
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
"ca-central-1",
"eu-central-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"ap-southeast-1",
"ap-southeast-2",
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"sa-east-1",
]
possible_services = []
possible_types = []
bulk_check_metadata = CheckMetadata.get_bulk(provider="aws")
for check_metadata in bulk_check_metadata.values():
if check_metadata.ServiceName not in possible_services:
possible_services.append(check_metadata.ServiceName)
if (
check_metadata.ResourceType
and check_metadata.ResourceType not in possible_types
):
possible_types.append(check_metadata.ResourceType)
with rls_transaction(tenant_id):
provider, _ = Provider.all_objects.get_or_create(
tenant_id=tenant_id,
provider="aws",
connected=True,
uid=str(random.randint(100000000000, 999999999999)),
defaults={
"alias": alias,
},
)
with rls_transaction(tenant_id):
scan = Scan.all_objects.create(
tenant_id=tenant_id,
provider=provider,
name=alias,
trigger="manual",
state="executing",
progress=0,
started_at=datetime.now(timezone.utc),
)
scan_state = "completed"
try:
# Create resources
resources = []
for i in range(num_resources):
resources.append(
Resource(
tenant_id=tenant_id,
provider_id=provider.id,
uid=f"testing-{uid_token}-{i}",
name=f"Testing {uid_token}-{i}",
region=random.choice(possible_regions),
service=random.choice(possible_services),
type=random.choice(possible_types),
)
)
num_batches = ceil(len(resources) / batch_size)
self.stdout.write(self.style.WARNING("Creating resources..."))
for i in tqdm(range(0, len(resources), batch_size), total=num_batches):
with rls_transaction(tenant_id):
Resource.all_objects.bulk_create(resources[i : i + batch_size])
self.stdout.write(self.style.SUCCESS("Resources created successfully.\n\n"))
with rls_transaction(tenant_id):
scan.progress = 33
scan.save()
# Create Findings
findings = []
possible_deltas = ["new", "changed", None]
possible_severities = ["critical", "high", "medium", "low"]
findings_resources_mapping = []
for i in range(num_findings):
severity = random.choice(possible_severities)
check_id = random.randint(1, 1000)
assigned_resource_num = random.randint(0, len(resources) - 1)
assigned_resource = resources[assigned_resource_num]
findings_resources_mapping.append(assigned_resource_num)
findings.append(
Finding(
tenant_id=tenant_id,
scan=scan,
uid=f"testing-{uid_token}-{i}",
delta=random.choice(possible_deltas),
check_id=f"check-{check_id}",
status=random.choice(list(StatusChoices)),
severity=severity,
impact=severity,
raw_result={},
check_metadata={
"checktitle": f"Test title for check {check_id}",
"risk": f"Testing risk {uid_token}-{i}",
"provider": "aws",
"severity": severity,
"categories": ["category1", "category2", "category3"],
"description": "This is a random description that should not matter for testing purposes.",
"servicename": assigned_resource.service,
"resourcetype": assigned_resource.type,
},
)
)
num_batches = ceil(len(findings) / batch_size)
self.stdout.write(self.style.WARNING("Creating findings..."))
for i in tqdm(range(0, len(findings), batch_size), total=num_batches):
with rls_transaction(tenant_id):
Finding.all_objects.bulk_create(findings[i : i + batch_size])
self.stdout.write(self.style.SUCCESS("Findings created successfully.\n\n"))
with rls_transaction(tenant_id):
scan.progress = 66
scan.save()
# Create ResourceFindingMapping
mappings = []
for index, f in enumerate(findings):
mappings.append(
ResourceFindingMapping(
tenant_id=tenant_id,
resource=resources[findings_resources_mapping[index]],
finding=f,
)
)
num_batches = ceil(len(mappings) / batch_size)
self.stdout.write(
self.style.WARNING("Creating resource-finding mappings...")
)
for i in tqdm(range(0, len(mappings), batch_size), total=num_batches):
with rls_transaction(tenant_id):
ResourceFindingMapping.objects.bulk_create(
mappings[i : i + batch_size]
)
self.stdout.write(
self.style.SUCCESS(
"Resource-finding mappings created successfully.\n\n"
)
)
except Exception as e:
self.stdout.write(self.style.ERROR(f"Failed to populate test data: {e}"))
scan_state = "failed"
finally:
scan.completed_at = datetime.now(timezone.utc)
scan.duration = int(
(datetime.now(timezone.utc) - scan.started_at).total_seconds()
)
scan.progress = 100
scan.state = scan_state
scan.unique_resource_count = num_resources
with rls_transaction(tenant_id):
scan.save()
self.stdout.write(self.style.NOTICE("Successfully populated test data."))

View File

@@ -0,0 +1,49 @@
import logging
import time
from config.custom_logging import BackendLogger
def extract_auth_info(request) -> dict:
if getattr(request, "auth", None) is not None:
tenant_id = request.auth.get("tenant_id", "N/A")
user_id = request.auth.get("sub", "N/A")
else:
tenant_id, user_id = "N/A", "N/A"
return {"tenant_id": tenant_id, "user_id": user_id}
class APILoggingMiddleware:
"""
Middleware for logging API requests.
This middleware logs details of API requests, including the typical request metadata among other useful information.
Args:
get_response (Callable): A callable to get the response, typically the next middleware or view.
"""
def __init__(self, get_response):
self.get_response = get_response
self.logger = logging.getLogger(BackendLogger.API)
def __call__(self, request):
request_start_time = time.time()
response = self.get_response(request)
duration = time.time() - request_start_time
auth_info = extract_auth_info(request)
self.logger.info(
"",
extra={
"user_id": auth_info["user_id"],
"tenant_id": auth_info["tenant_id"],
"method": request.method,
"path": request.path,
"query_params": request.GET.dict(),
"status_code": response.status_code,
"duration": duration,
},
)
return response

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
from django.conf import settings
from django.db import migrations
from api.db_utils import DB_PROWLER_USER
DB_NAME = settings.DATABASES["default"]["NAME"]
class Migration(migrations.Migration):
dependencies = [
("api", "0001_initial"),
("token_blacklist", "0012_alter_outstandingtoken_user"),
]
operations = [
migrations.RunSQL(
f"""
GRANT SELECT, INSERT, UPDATE, DELETE ON token_blacklist_blacklistedtoken TO {DB_PROWLER_USER};
GRANT SELECT, INSERT, UPDATE, DELETE ON token_blacklist_outstandingtoken TO {DB_PROWLER_USER};
GRANT SELECT, DELETE ON django_admin_log TO {DB_PROWLER_USER};
"""
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.1.1 on 2024-12-20 13:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0002_token_migrations"),
]
operations = [
migrations.RemoveConstraint(
model_name="provider",
name="unique_provider_uids",
),
migrations.AddConstraint(
model_name="provider",
constraint=models.UniqueConstraint(
fields=("tenant_id", "provider", "uid", "is_deleted"),
name="unique_provider_uids",
),
),
]

View File

@@ -0,0 +1,248 @@
# Generated by Django 5.1.1 on 2024-12-05 12:29
import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import api.rls
class Migration(migrations.Migration):
dependencies = [
("api", "0003_update_provider_unique_constraint_with_is_deleted"),
]
operations = [
migrations.CreateModel(
name="Role",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("name", models.CharField(max_length=255)),
("manage_users", models.BooleanField(default=False)),
("manage_account", models.BooleanField(default=False)),
("manage_billing", models.BooleanField(default=False)),
("manage_providers", models.BooleanField(default=False)),
("manage_integrations", models.BooleanField(default=False)),
("manage_scans", models.BooleanField(default=False)),
("unlimited_visibility", models.BooleanField(default=False)),
("inserted_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": "roles",
},
),
migrations.CreateModel(
name="RoleProviderGroupRelationship",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "role_provider_group_relationship",
},
),
migrations.CreateModel(
name="UserRoleRelationship",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "role_user_relationship",
},
),
migrations.AddField(
model_name="roleprovidergrouprelationship",
name="provider_group",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.providergroup"
),
),
migrations.AddField(
model_name="roleprovidergrouprelationship",
name="role",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.role"
),
),
migrations.AddField(
model_name="role",
name="provider_groups",
field=models.ManyToManyField(
related_name="roles",
through="api.RoleProviderGroupRelationship",
to="api.providergroup",
),
),
migrations.AddField(
model_name="userrolerelationship",
name="role",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.role"
),
),
migrations.AddField(
model_name="userrolerelationship",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
migrations.AddField(
model_name="role",
name="users",
field=models.ManyToManyField(
related_name="roles",
through="api.UserRoleRelationship",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddConstraint(
model_name="roleprovidergrouprelationship",
constraint=models.UniqueConstraint(
fields=("role_id", "provider_group_id"),
name="unique_role_provider_group_relationship",
),
),
migrations.AddConstraint(
model_name="roleprovidergrouprelationship",
constraint=api.rls.RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_roleprovidergrouprelationship",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
migrations.AddConstraint(
model_name="userrolerelationship",
constraint=models.UniqueConstraint(
fields=("role_id", "user_id"), name="unique_role_user_relationship"
),
),
migrations.AddConstraint(
model_name="userrolerelationship",
constraint=api.rls.RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_userrolerelationship",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
migrations.AddConstraint(
model_name="role",
constraint=models.UniqueConstraint(
fields=("tenant_id", "name"), name="unique_role_per_tenant"
),
),
migrations.AddConstraint(
model_name="role",
constraint=api.rls.RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_role",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
migrations.CreateModel(
name="InvitationRoleRelationship",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("inserted_at", models.DateTimeField(auto_now_add=True)),
(
"invitation",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.invitation"
),
),
(
"role",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.role"
),
),
(
"tenant",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
),
),
],
options={
"db_table": "role_invitation_relationship",
},
),
migrations.AddConstraint(
model_name="invitationrolerelationship",
constraint=models.UniqueConstraint(
fields=("role_id", "invitation_id"),
name="unique_role_invitation_relationship",
),
),
migrations.AddConstraint(
model_name="invitationrolerelationship",
constraint=api.rls.RowLevelSecurityConstraint(
"tenant_id",
name="rls_on_invitationrolerelationship",
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
migrations.AddField(
model_name="role",
name="invitations",
field=models.ManyToManyField(
related_name="roles",
through="api.InvitationRoleRelationship",
to="api.invitation",
),
),
]

View File

@@ -0,0 +1,44 @@
from django.db import migrations
from api.db_router import MainRouter
def create_admin_role(apps, schema_editor):
Tenant = apps.get_model("api", "Tenant")
Role = apps.get_model("api", "Role")
User = apps.get_model("api", "User")
UserRoleRelationship = apps.get_model("api", "UserRoleRelationship")
for tenant in Tenant.objects.using(MainRouter.admin_db).all():
admin_role, _ = Role.objects.using(MainRouter.admin_db).get_or_create(
name="admin",
tenant=tenant,
defaults={
"manage_users": True,
"manage_account": True,
"manage_billing": True,
"manage_providers": True,
"manage_integrations": True,
"manage_scans": True,
"unlimited_visibility": True,
},
)
users = User.objects.using(MainRouter.admin_db).filter(
membership__tenant=tenant
)
for user in users:
UserRoleRelationship.objects.using(MainRouter.admin_db).get_or_create(
user=user,
role=admin_role,
tenant=tenant,
)
class Migration(migrations.Migration):
dependencies = [
("api", "0004_rbac"),
]
operations = [
migrations.RunPython(create_admin_role),
]

View File

@@ -0,0 +1,15 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0005_rbac_missing_admin_roles"),
]
operations = [
migrations.AddField(
model_name="finding",
name="first_seen_at",
field=models.DateTimeField(editable=False, null=True),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 5.1.5 on 2025-01-28 15:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0006_findings_first_seen"),
]
operations = [
migrations.AddIndex(
model_name="scan",
index=models.Index(
fields=["tenant_id", "provider_id", "state", "inserted_at"],
name="scans_prov_state_insert_idx",
),
),
migrations.AddIndex(
model_name="scansummary",
index=models.Index(
fields=["tenant_id", "scan_id"], name="scan_summaries_tenant_scan_idx"
),
),
]

View File

@@ -0,0 +1,64 @@
import json
from datetime import datetime, timedelta, timezone
import django.db.models.deletion
from django.db import migrations, models
from django_celery_beat.models import PeriodicTask
from api.db_utils import rls_transaction
from api.models import Scan, StateChoices
def migrate_daily_scheduled_scan_tasks(apps, schema_editor):
for daily_scheduled_scan_task in PeriodicTask.objects.filter(
task="scan-perform-scheduled"
):
task_kwargs = json.loads(daily_scheduled_scan_task.kwargs)
tenant_id = task_kwargs["tenant_id"]
provider_id = task_kwargs["provider_id"]
current_time = datetime.now(timezone.utc)
scheduled_time_today = datetime.combine(
current_time.date(),
daily_scheduled_scan_task.start_time.time(),
tzinfo=timezone.utc,
)
if current_time < scheduled_time_today:
next_scan_date = scheduled_time_today
else:
next_scan_date = scheduled_time_today + timedelta(days=1)
with rls_transaction(tenant_id):
Scan.objects.create(
tenant_id=tenant_id,
name="Daily scheduled scan",
provider_id=provider_id,
trigger=Scan.TriggerChoices.SCHEDULED,
state=StateChoices.SCHEDULED,
scheduled_at=next_scan_date,
scheduler_task_id=daily_scheduled_scan_task.id,
)
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0007_scan_and_scan_summaries_indexes"),
("django_celery_beat", "0019_alter_periodictasks_options"),
]
operations = [
migrations.AddField(
model_name="scan",
name="scheduler_task",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="django_celery_beat.periodictask",
),
),
migrations.RunPython(migrate_daily_scheduled_scan_tasks),
]

View File

@@ -0,0 +1,22 @@
# Generated by Django 5.1.5 on 2025-02-07 09:42
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0008_daily_scheduled_tasks_update"),
]
operations = [
migrations.AlterField(
model_name="provider",
name="uid",
field=models.CharField(
max_length=250,
validators=[django.core.validators.MinLengthValidator(3)],
verbose_name="Unique identifier for the provider, set by the provider",
),
),
]

View File

@@ -0,0 +1,109 @@
from functools import partial
from django.db import connection, migrations
def create_index_on_partitions(
apps, schema_editor, parent_table: str, index_name: str, index_details: str
):
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT inhrelid::regclass::text
FROM pg_inherits
WHERE inhparent = %s::regclass;
""",
[parent_table],
)
partitions = [row[0] for row in cursor.fetchall()]
# Iterate over partitions and create index concurrently.
# Note: PostgreSQL does not allow CONCURRENTLY inside a transaction,
# so we need atomic = False for this migration.
for partition in partitions:
sql = (
f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {partition.replace('.', '_')}_{index_name} ON {partition} "
f"{index_details};"
)
schema_editor.execute(sql)
def drop_index_on_partitions(apps, schema_editor, parent_table: str, index_name: str):
with schema_editor.connection.cursor() as cursor:
cursor.execute(
"""
SELECT inhrelid::regclass::text
FROM pg_inherits
WHERE inhparent = %s::regclass;
""",
[parent_table],
)
partitions = [row[0] for row in cursor.fetchall()]
# Iterate over partitions and drop index concurrently.
for partition in partitions:
partition_index = f"{partition.replace('.', '_')}_{index_name}"
sql = f"DROP INDEX CONCURRENTLY IF EXISTS {partition_index};"
schema_editor.execute(sql)
class Migration(migrations.Migration):
atomic = False
dependencies = [
("api", "0009_increase_provider_uid_maximum_length"),
]
operations = [
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="findings",
index_name="findings_tenant_and_id_idx",
index_details="(tenant_id, id)",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="findings",
index_name="findings_tenant_and_id_idx",
),
),
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="findings",
index_name="find_tenant_scan_idx",
index_details="(tenant_id, scan_id)",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="findings",
index_name="find_tenant_scan_idx",
),
),
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="findings",
index_name="find_tenant_scan_id_idx",
index_details="(tenant_id, scan_id, id)",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="findings",
index_name="find_tenant_scan_id_idx",
),
),
migrations.RunPython(
partial(
create_index_on_partitions,
parent_table="findings",
index_name="find_delta_new_idx",
index_details="(tenant_id, id) where delta = 'new'",
),
reverse_code=partial(
drop_index_on_partitions,
parent_table="findings",
index_name="find_delta_new_idx",
),
),
]

View File

@@ -0,0 +1,49 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0010_findings_performance_indexes_partitions"),
]
operations = [
migrations.AddIndex(
model_name="finding",
index=models.Index(
fields=["tenant_id", "id"], name="findings_tenant_and_id_idx"
),
),
migrations.AddIndex(
model_name="finding",
index=models.Index(
fields=["tenant_id", "scan_id"], name="find_tenant_scan_idx"
),
),
migrations.AddIndex(
model_name="finding",
index=models.Index(
fields=["tenant_id", "scan_id", "id"], name="find_tenant_scan_id_idx"
),
),
migrations.AddIndex(
model_name="finding",
index=models.Index(
condition=models.Q(("delta", "new")),
fields=["tenant_id", "id"],
name="find_delta_new_idx",
),
),
migrations.AddIndex(
model_name="resourcetagmapping",
index=models.Index(
fields=["tenant_id", "resource_id"], name="resource_tag_tenant_idx"
),
),
migrations.AddIndex(
model_name="resource",
index=models.Index(
fields=["tenant_id", "service", "region", "type"],
name="resource_tenant_metadata_idx",
),
),
]

View File

@@ -0,0 +1,15 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0011_findings_performance_indexes_parent"),
]
operations = [
migrations.AddField(
model_name="scan",
name="output_location",
field=models.CharField(blank=True, max_length=200, null=True),
),
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
from rest_framework_json_api.pagination import JsonApiPageNumberPagination
class ComplianceOverviewPagination(JsonApiPageNumberPagination):
page_size = 50
max_page_size = 100

View File

@@ -0,0 +1,203 @@
from datetime import datetime, timezone
from typing import Generator, Optional
from dateutil.relativedelta import relativedelta
from django.conf import settings
from psqlextra.partitioning import (
PostgresPartitioningManager,
PostgresRangePartition,
PostgresRangePartitioningStrategy,
PostgresTimePartitionSize,
PostgresPartitioningError,
)
from psqlextra.partitioning.config import PostgresPartitioningConfig
from uuid6 import UUID
from api.models import Finding, ResourceFindingMapping
from api.rls import RowLevelSecurityConstraint
from api.uuid_utils import datetime_to_uuid7
class PostgresUUIDv7RangePartition(PostgresRangePartition):
def __init__(
self,
from_values: UUID,
to_values: UUID,
size: PostgresTimePartitionSize,
name_format: Optional[str] = None,
**kwargs,
) -> None:
self.from_values = from_values
self.to_values = to_values
self.size = size
self.name_format = name_format
self.rls_statements = None
if "rls_statements" in kwargs:
self.rls_statements = kwargs["rls_statements"]
start_timestamp_ms = self.from_values.time
self.start_datetime = datetime.fromtimestamp(
start_timestamp_ms / 1000, timezone.utc
)
def name(self) -> str:
if not self.name_format:
raise PostgresPartitioningError("Unknown size/unit")
return self.start_datetime.strftime(self.name_format).lower()
def deconstruct(self) -> dict:
return {
**super().deconstruct(),
"size_unit": self.size.unit.value,
"size_value": self.size.value,
}
def create(
self,
model,
schema_editor,
comment,
) -> None:
super().create(model, schema_editor, comment)
# if this model has RLS statements, add them to the partition
if isinstance(self.rls_statements, list):
schema_editor.add_constraint(
model,
constraint=RowLevelSecurityConstraint(
"tenant_id",
name=f"rls_on_{self.name()}",
partition_name=self.name(),
statements=self.rls_statements,
),
)
class PostgresUUIDv7PartitioningStrategy(PostgresRangePartitioningStrategy):
def __init__(
self,
size: PostgresTimePartitionSize,
count: int,
start_date: datetime = None,
max_age: Optional[relativedelta] = None,
name_format: Optional[str] = None,
**kwargs,
) -> None:
self.start_date = start_date.replace(
day=1, hour=0, minute=0, second=0, microsecond=0
)
self.size = size
self.count = count
self.max_age = max_age
self.name_format = name_format
self.rls_statements = None
if "rls_statements" in kwargs:
self.rls_statements = kwargs["rls_statements"]
def to_create(self) -> Generator[PostgresUUIDv7RangePartition, None, None]:
current_datetime = (
self.start_date if self.start_date else self.get_start_datetime()
)
for _ in range(self.count):
end_datetime = (
current_datetime + self.size.as_delta() - relativedelta(microseconds=1)
)
start_uuid7 = datetime_to_uuid7(current_datetime)
end_uuid7 = datetime_to_uuid7(end_datetime)
yield PostgresUUIDv7RangePartition(
from_values=start_uuid7,
to_values=end_uuid7,
size=self.size,
name_format=self.name_format,
rls_statements=self.rls_statements,
)
current_datetime += self.size.as_delta()
def to_delete(self) -> Generator[PostgresUUIDv7RangePartition, None, None]:
if not self.max_age:
return
current_datetime = self.get_start_datetime() - self.max_age
while True:
end_datetime = current_datetime + self.size.as_delta()
start_uuid7 = datetime_to_uuid7(current_datetime)
end_uuid7 = datetime_to_uuid7(end_datetime)
# dropping table will delete indexes and policies
yield PostgresUUIDv7RangePartition(
from_values=start_uuid7,
to_values=end_uuid7,
size=self.size,
name_format=self.name_format,
)
current_datetime -= self.size.as_delta()
def get_start_datetime(self) -> datetime:
"""
Gets the start of the current month in UTC timezone.
This function returns a `datetime` object set to the first day of the current
month, at midnight (00:00:00), in UTC.
Returns:
datetime: A `datetime` object representing the start of the current month in UTC.
"""
return datetime.now(timezone.utc).replace(
day=1, hour=0, minute=0, second=0, microsecond=0
)
def relative_days_or_none(value):
if value is None:
return None
return relativedelta(days=value)
#
# To manage the partitions, run `python manage.py pgpartition --using admin`
#
# For more info on the partitioning manager, see https://github.com/SectorLabs/django-postgres-extra
manager = PostgresPartitioningManager(
[
PostgresPartitioningConfig(
model=Finding,
strategy=PostgresUUIDv7PartitioningStrategy(
start_date=datetime.now(timezone.utc),
size=PostgresTimePartitionSize(
months=settings.FINDINGS_TABLE_PARTITION_MONTHS
),
count=settings.FINDINGS_TABLE_PARTITION_COUNT,
max_age=relative_days_or_none(
settings.FINDINGS_TABLE_PARTITION_MAX_AGE_MONTHS
),
name_format="%Y_%b",
rls_statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
),
),
# ResourceFindingMapping should always follow the Finding partitioning
PostgresPartitioningConfig(
model=ResourceFindingMapping,
strategy=PostgresUUIDv7PartitioningStrategy(
start_date=datetime.now(timezone.utc),
size=PostgresTimePartitionSize(
months=settings.FINDINGS_TABLE_PARTITION_MONTHS
),
count=settings.FINDINGS_TABLE_PARTITION_COUNT,
max_age=relative_days_or_none(
settings.FINDINGS_TABLE_PARTITION_MAX_AGE_MONTHS
),
name_format="%Y_%b",
rls_statements=["SELECT"],
),
),
]
)

View File

@@ -0,0 +1,75 @@
from enum import Enum
from typing import Optional
from django.db.models import QuerySet
from rest_framework.permissions import BasePermission
from api.db_router import MainRouter
from api.models import Provider, Role, User
class Permissions(Enum):
MANAGE_USERS = "manage_users"
MANAGE_ACCOUNT = "manage_account"
MANAGE_BILLING = "manage_billing"
MANAGE_PROVIDERS = "manage_providers"
MANAGE_INTEGRATIONS = "manage_integrations"
MANAGE_SCANS = "manage_scans"
UNLIMITED_VISIBILITY = "unlimited_visibility"
class HasPermissions(BasePermission):
"""
Custom permission to check if the user's role has the required permissions.
The required permissions should be specified in the view as a list in `required_permissions`.
"""
def has_permission(self, request, view):
required_permissions = getattr(view, "required_permissions", [])
if not required_permissions:
return True
user_roles = (
User.objects.using(MainRouter.admin_db).get(id=request.user.id).roles.all()
)
if not user_roles:
return False
for perm in required_permissions:
if not getattr(user_roles[0], perm.value, False):
return False
return True
def get_role(user: User) -> Optional[Role]:
"""
Retrieve the first role assigned to the given user.
Returns:
The user's first Role instance if the user has any roles, otherwise None.
"""
return user.roles.first()
def get_providers(role: Role) -> QuerySet[Provider]:
"""
Return a distinct queryset of Providers accessible by the given role.
If the role has no associated provider groups, an empty queryset is returned.
Args:
role: A Role instance.
Returns:
A QuerySet of Provider objects filtered by the role's provider groups.
If the role has no provider groups, returns an empty queryset.
"""
tenant = role.tenant
provider_groups = role.provider_groups.all()
if not provider_groups.exists():
return Provider.objects.none()
return Provider.objects.filter(
tenant=tenant, provider_groups__in=provider_groups
).distinct()

View File

@@ -0,0 +1,23 @@
from contextlib import nullcontext
from rest_framework_json_api.renderers import JSONRenderer
from api.db_utils import rls_transaction
class APIJSONRenderer(JSONRenderer):
"""JSONRenderer override to apply tenant RLS when there are included resources in the request."""
def render(self, data, accepted_media_type=None, renderer_context=None):
request = renderer_context.get("request")
tenant_id = getattr(request, "tenant_id", None) if request else None
include_param_present = "include" in request.query_params if request else False
# Use rls_transaction if needed for included resources, otherwise do nothing
context_manager = (
rls_transaction(tenant_id)
if tenant_id and include_param_present
else nullcontext()
)
with context_manager:
return super().render(data, accepted_media_type, renderer_context)

188
api/src/backend/api/rls.py Normal file
View File

@@ -0,0 +1,188 @@
from typing import Any
from uuid import uuid4
from django.core.exceptions import ValidationError
from django.db import DEFAULT_DB_ALIAS
from django.db import models
from django.db.backends.ddl_references import Statement, Table
from api.db_utils import DB_USER, POSTGRES_TENANT_VAR
class Tenant(models.Model):
"""
The Tenant is the basic grouping in the system. It is used to separate data between customers.
"""
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)
class Meta:
db_table = "tenants"
class JSONAPIMeta:
resource_name = "tenants"
class RowLevelSecurityConstraint(models.BaseConstraint):
"""
Model constraint to enforce row-level security on a tenant based model, in addition to the least privileges.
The constraint can be applied to a partitioned table by specifying the `partition_name` keyword argument.
"""
rls_sql_query = """
ALTER TABLE %(table_name)s ENABLE ROW LEVEL SECURITY;
ALTER TABLE %(table_name)s FORCE ROW LEVEL SECURITY;
"""
policy_sql_query = """
CREATE POLICY %(db_user)s_%(table_name)s_{statement}
ON %(table_name)s
FOR {statement}
TO %(db_user)s
{clause} (
CASE
WHEN current_setting('%(tenant_setting)s', True) IS NULL THEN FALSE
ELSE %(field_column)s = current_setting('%(tenant_setting)s')::uuid
END
);
"""
grant_sql_query = """
GRANT {statement} ON %(table_name)s TO %(db_user)s;
"""
drop_sql_query = """
ALTER TABLE %(table_name)s NO FORCE ROW LEVEL SECURITY;
ALTER TABLE %(table_name)s DISABLE ROW LEVEL SECURITY;
REVOKE ALL ON TABLE %(table_name) TO %(db_user)s;
"""
drop_policy_sql_query = """
DROP POLICY IF EXISTS %(db_user)s_%(table_name)s_{statement} on %(table_name)s;
"""
def __init__(
self, field: str, name: str, statements: list | None = None, **kwargs
) -> None:
super().__init__(name=name)
self.target_field: str = field
self.statements = statements or ["SELECT"]
self.partition_name = None
if "partition_name" in kwargs:
self.partition_name = kwargs["partition_name"]
def create_sql(self, model: Any, schema_editor: Any) -> Any:
field_column = schema_editor.quote_name(self.target_field)
policy_queries = ""
grant_queries = ""
for statement in self.statements:
clause = f"{'WITH CHECK' if statement == 'INSERT' else 'USING'}"
policy_queries = f"{policy_queries}{self.policy_sql_query.format(statement=statement, clause=clause)}"
grant_queries = (
f"{grant_queries}{self.grant_sql_query.format(statement=statement)}"
)
full_create_sql_query = (
f"{self.rls_sql_query}" f"{policy_queries}" f"{grant_queries}"
)
table_name = model._meta.db_table
if self.partition_name:
table_name = f"{table_name}_{self.partition_name}"
return Statement(
full_create_sql_query,
table_name=table_name,
field_column=field_column,
db_user=DB_USER,
tenant_setting=POSTGRES_TENANT_VAR,
partition_name=self.partition_name,
)
def remove_sql(self, model: Any, schema_editor: Any) -> Any:
field_column = schema_editor.quote_name(self.target_field)
full_drop_sql_query = (
f"{self.drop_sql_query}"
f"{''.join([self.drop_policy_sql_query.format(statement) for statement in self.statements])}"
)
table_name = model._meta.db_table
if self.partition_name:
table_name = f"{table_name}_{self.partition_name}"
return Statement(
full_drop_sql_query,
table_name=Table(table_name, schema_editor.quote_name),
field_column=field_column,
db_user=DB_USER,
partition_name=self.partition_name,
)
def __eq__(self, other: object) -> bool:
if isinstance(other, RowLevelSecurityConstraint):
return self.name == other.name and self.target_field == other.target_field
return super().__eq__(other)
def deconstruct(self) -> tuple[str, tuple, dict]:
path, _, kwargs = super().deconstruct()
return (path, (self.target_field,), kwargs)
def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS): # noqa: F841
if not hasattr(instance, "tenant_id"):
raise ValidationError(f"{model.__name__} does not have a tenant_id field.")
class BaseSecurityConstraint(models.BaseConstraint):
"""Model constraint to grant the least privileges to the API database user."""
grant_sql_query = """
GRANT {statement} ON %(table_name)s TO %(db_user)s;
"""
drop_sql_query = """
REVOKE ALL ON TABLE %(table_name) TO %(db_user)s;
"""
def __init__(self, name: str, statements: list | None = None) -> None:
super().__init__(name=name)
self.statements = statements or ["SELECT"]
def create_sql(self, model: Any, schema_editor: Any) -> Any:
grant_queries = ""
for statement in self.statements:
grant_queries = (
f"{grant_queries}{self.grant_sql_query.format(statement=statement)}"
)
return Statement(
grant_queries,
table_name=model._meta.db_table,
db_user=DB_USER,
)
def remove_sql(self, model: Any, schema_editor: Any) -> Any:
return Statement(
self.drop_sql_query,
table_name=Table(model._meta.db_table, schema_editor.quote_name),
db_user=DB_USER,
)
def __eq__(self, other: object) -> bool:
if isinstance(other, BaseSecurityConstraint):
return self.name == other.name
return super().__eq__(other)
def deconstruct(self) -> tuple[str, tuple, dict]:
path, args, kwargs = super().deconstruct()
return path, args, kwargs
class RowLevelSecurityProtectedModel(models.Model):
tenant = models.ForeignKey("Tenant", on_delete=models.CASCADE)
class Meta:
abstract = True

View File

@@ -0,0 +1,34 @@
from celery import states
from celery.signals import before_task_publish
from config.celery import celery_app
from django.db.models.signals import post_delete
from django.dispatch import receiver
from django_celery_results.backends.database import DatabaseBackend
from api.db_utils import delete_related_daily_task
from api.models import Provider
def create_task_result_on_publish(sender=None, headers=None, **kwargs): # noqa: F841
"""Celery signal to store TaskResult entries when tasks reach the broker."""
db_result_backend = DatabaseBackend(celery_app)
request = type("request", (object,), headers)
db_result_backend.store_result(
headers["id"],
None,
states.PENDING,
traceback=None,
request=request,
)
before_task_publish.connect(
create_task_result_on_publish, dispatch_uid="create_task_result_on_publish"
)
@receiver(post_delete, sender=Provider)
def delete_provider_scan_task(sender, instance, **kwargs): # noqa: F841
# Delete the associated periodic task when the provider is deleted
delete_related_daily_task(instance.id)

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,300 @@
import pytest
from conftest import TEST_PASSWORD, get_api_tokens, get_authorization_header
from django.urls import reverse
from rest_framework.test import APIClient
from api.models import Membership, User
@pytest.mark.django_db
def test_basic_authentication():
client = APIClient()
test_user = "test_email@prowler.com"
test_password = "test_password"
# Check that a 401 is returned when no basic authentication is provided
no_auth_response = client.get(reverse("provider-list"))
assert no_auth_response.status_code == 401
# Check that we can create a new user without any kind of authentication
user_creation_response = client.post(
reverse("user-list"),
data={
"data": {
"type": "users",
"attributes": {
"name": "test",
"email": test_user,
"password": test_password,
},
}
},
format="vnd.api+json",
)
assert user_creation_response.status_code == 201
# Check that using our new user's credentials we can authenticate and get the providers
access_token, _ = get_api_tokens(client, test_user, test_password)
auth_headers = get_authorization_header(access_token)
auth_response = client.get(
reverse("provider-list"),
headers=auth_headers,
)
assert auth_response.status_code == 200
@pytest.mark.django_db
def test_refresh_token(create_test_user, tenants_fixture):
client = APIClient()
# Assert that we can obtain a new access token using the refresh one
access_token, refresh_token = get_api_tokens(
client, create_test_user.email, TEST_PASSWORD
)
valid_refresh_response = client.post(
reverse("token-refresh"),
data={
"data": {
"type": "tokens-refresh",
"attributes": {"refresh": refresh_token},
}
},
format="vnd.api+json",
)
assert valid_refresh_response.status_code == 200
assert (
valid_refresh_response.json()["data"]["attributes"]["refresh"] != refresh_token
)
# Assert the former refresh token gets invalidated
invalid_refresh_response = client.post(
reverse("token-refresh"),
data={
"data": {
"type": "tokens-refresh",
"attributes": {"refresh": refresh_token},
}
},
format="vnd.api+json",
)
assert invalid_refresh_response.status_code == 400
# Assert that the new refresh token could be used
new_refresh_response = client.post(
reverse("token-refresh"),
data={
"data": {
"type": "tokens-refresh",
"attributes": {
"refresh": valid_refresh_response.json()["data"]["attributes"][
"refresh"
]
},
}
},
format="vnd.api+json",
)
assert new_refresh_response.status_code == 200
@pytest.mark.django_db
def test_user_me_when_inviting_users(create_test_user, tenants_fixture, roles_fixture):
client = APIClient()
role = roles_fixture[0]
user1_email = "user1@testing.com"
user2_email = "user2@testing.com"
password = "thisisapassword123"
user1_response = client.post(
reverse("user-list"),
data={
"data": {
"type": "users",
"attributes": {
"name": "user1",
"email": user1_email,
"password": password,
},
}
},
format="vnd.api+json",
)
assert user1_response.status_code == 201
user1_access_token, _ = get_api_tokens(client, user1_email, password)
user1_headers = get_authorization_header(user1_access_token)
user2_invitation = client.post(
reverse("invitation-list"),
data={
"data": {
"type": "invitations",
"attributes": {"email": user2_email},
"relationships": {
"roles": {
"data": [
{
"type": "roles",
"id": str(role.id),
}
]
}
},
}
},
format="vnd.api+json",
headers=user1_headers,
)
assert user2_invitation.status_code == 201
invitation_token = user2_invitation.json()["data"]["attributes"]["token"]
user2_response = client.post(
reverse("user-list") + f"?invitation_token={invitation_token}",
data={
"data": {
"type": "users",
"attributes": {
"name": "user2",
"email": user2_email,
"password": password,
},
}
},
format="vnd.api+json",
)
assert user2_response.status_code == 201
user2_access_token, _ = get_api_tokens(client, user2_email, password)
user2_headers = get_authorization_header(user2_access_token)
user1_me = client.get(reverse("user-me"), headers=user1_headers)
assert user1_me.status_code == 200
assert user1_me.json()["data"]["attributes"]["email"] == user1_email
user2_me = client.get(reverse("user-me"), headers=user2_headers)
assert user2_me.status_code == 200
assert user2_me.json()["data"]["attributes"]["email"] == user2_email
@pytest.mark.django_db
class TestTokenSwitchTenant:
def test_switch_tenant_with_valid_token(self, tenants_fixture, providers_fixture):
client = APIClient()
test_user = "test_email@prowler.com"
test_password = "test_password"
# Check that we can create a new user without any kind of authentication
user_creation_response = client.post(
reverse("user-list"),
data={
"data": {
"type": "users",
"attributes": {
"name": "test",
"email": test_user,
"password": test_password,
},
}
},
format="vnd.api+json",
)
assert user_creation_response.status_code == 201
# Create a new relationship between this user and another tenant
tenant_id = tenants_fixture[0].id
user_instance = User.objects.get(email=test_user)
Membership.objects.create(user=user_instance, tenant_id=tenant_id)
# Check that using our new user's credentials we can authenticate and get the providers
access_token, _ = get_api_tokens(client, test_user, test_password)
auth_headers = get_authorization_header(access_token)
user_me_response = client.get(
reverse("user-me"),
headers=auth_headers,
)
assert user_me_response.status_code == 200
# Assert this user belongs to two tenants
assert (
user_me_response.json()["data"]["relationships"]["memberships"]["meta"][
"count"
]
== 2
)
provider_response = client.get(
reverse("provider-list"),
headers=auth_headers,
)
assert provider_response.status_code == 200
# Empty response since there are no providers in this tenant
assert not provider_response.json()["data"]
switch_tenant_response = client.post(
reverse("token-switch"),
data={
"data": {
"type": "tokens-switch-tenant",
"attributes": {"tenant_id": tenant_id},
}
},
headers=auth_headers,
)
assert switch_tenant_response.status_code == 200
new_access_token = switch_tenant_response.json()["data"]["attributes"]["access"]
new_auth_headers = get_authorization_header(new_access_token)
provider_response = client.get(
reverse("provider-list"),
headers=new_auth_headers,
)
assert provider_response.status_code == 200
# Now it must be data because we switched to another tenant with providers
assert provider_response.json()["data"]
def test_switch_tenant_with_invalid_token(self, create_test_user, tenants_fixture):
client = APIClient()
access_token, refresh_token = get_api_tokens(
client, create_test_user.email, TEST_PASSWORD
)
auth_headers = get_authorization_header(access_token)
invalid_token_response = client.post(
reverse("token-switch"),
data={
"data": {
"type": "tokens-switch-tenant",
"attributes": {"tenant_id": "invalid_tenant_id"},
}
},
headers=auth_headers,
)
assert invalid_token_response.status_code == 400
assert invalid_token_response.json()["errors"][0]["code"] == "invalid"
assert (
invalid_token_response.json()["errors"][0]["detail"]
== "Must be a valid UUID."
)
invalid_tenant_response = client.post(
reverse("token-switch"),
data={
"data": {
"type": "tokens-switch-tenant",
"attributes": {"tenant_id": tenants_fixture[-1].id},
}
},
headers=auth_headers,
)
assert invalid_tenant_response.status_code == 400
assert invalid_tenant_response.json()["errors"][0]["code"] == "invalid"
assert invalid_tenant_response.json()["errors"][0]["detail"] == (
"Tenant does not exist or user is not a " "member."
)

View File

@@ -0,0 +1,85 @@
from unittest.mock import Mock, patch
import pytest
from conftest import get_api_tokens, get_authorization_header
from django.urls import reverse
from rest_framework.test import APIClient
from api.models import Provider
@patch("api.v1.views.Task.objects.get")
@patch("api.v1.views.delete_provider_task.delay")
@pytest.mark.django_db
def test_delete_provider_without_executing_task(
mock_delete_task, mock_task_get, create_test_user, tenants_fixture, tasks_fixture
):
client = APIClient()
test_user = "test_email@prowler.com"
test_password = "test_password"
prowler_task = tasks_fixture[0]
task_mock = Mock()
task_mock.id = prowler_task.id
mock_delete_task.return_value = task_mock
mock_task_get.return_value = prowler_task
user_creation_response = client.post(
reverse("user-list"),
data={
"data": {
"type": "users",
"attributes": {
"name": "test",
"email": test_user,
"password": test_password,
},
}
},
format="vnd.api+json",
)
assert user_creation_response.status_code == 201
access_token, _ = get_api_tokens(client, test_user, test_password)
auth_headers = get_authorization_header(access_token)
create_provider_response = client.post(
reverse("provider-list"),
data={
"data": {
"type": "providers",
"attributes": {
"provider": Provider.ProviderChoices.AWS,
"uid": "123456789012",
},
}
},
format="vnd.api+json",
headers=auth_headers,
)
assert create_provider_response.status_code == 201
provider_id = create_provider_response.json()["data"]["id"]
provider_uid = create_provider_response.json()["data"]["attributes"]["uid"]
remove_provider = client.delete(
reverse("provider-detail", kwargs={"pk": provider_id}),
headers=auth_headers,
)
assert remove_provider.status_code == 202
recreate_provider_response = client.post(
reverse("provider-list"),
data={
"data": {
"type": "providers",
"attributes": {
"provider": Provider.ProviderChoices.AWS,
"uid": provider_uid,
},
}
},
format="vnd.api+json",
headers=auth_headers,
)
assert recreate_provider_response.status_code == 201

View File

@@ -0,0 +1,98 @@
from unittest.mock import patch
import pytest
from django.urls import reverse
from conftest import TEST_USER, TEST_PASSWORD, get_api_tokens, get_authorization_header
@patch("api.v1.views.schedule_provider_scan")
@pytest.mark.django_db
def test_check_resources_between_different_tenants(
schedule_mock,
enforce_test_user_db_connection,
authenticated_api_client,
tenants_fixture,
set_user_admin_roles_fixture,
):
client = authenticated_api_client
tenant1 = str(tenants_fixture[0].id)
tenant2 = str(tenants_fixture[1].id)
tenant1_token, _ = get_api_tokens(
client, TEST_USER, TEST_PASSWORD, tenant_id=tenant1
)
tenant2_token, _ = get_api_tokens(
client, TEST_USER, TEST_PASSWORD, tenant_id=tenant2
)
tenant1_headers = get_authorization_header(tenant1_token)
tenant2_headers = get_authorization_header(tenant2_token)
# Create a provider on tenant 1
provider_data = {
"data": {
"type": "providers",
"attributes": {
"alias": "test_provider_tenant_1",
"provider": "aws",
"uid": "123456789012",
},
}
}
provider1_response = client.post(
reverse("provider-list"),
data=provider_data,
format="vnd.api+json",
headers=tenant1_headers,
)
assert provider1_response.status_code == 201
provider1_id = provider1_response.json()["data"]["id"]
# Create a provider on tenant 2
provider_data = {
"data": {
"type": "providers",
"attributes": {
"alias": "test_provider_tenant_2",
"provider": "aws",
"uid": "123456789013",
},
}
}
provider2_response = client.post(
reverse("provider-list"),
data=provider_data,
format="vnd.api+json",
headers=tenant2_headers,
)
assert provider2_response.status_code == 201
provider2_id = provider2_response.json()["data"]["id"]
# Try to get the provider from tenant 1 on tenant 2 and vice versa
tenant1_response = client.get(
reverse("provider-detail", kwargs={"pk": provider1_id}),
headers=tenant2_headers,
)
assert tenant1_response.status_code == 404
tenant2_response = client.get(
reverse("provider-detail", kwargs={"pk": provider1_id}),
headers=tenant1_headers,
)
assert tenant2_response.status_code == 200
assert tenant2_response.json()["data"]["id"] == provider1_id
# Vice versa
tenant2_response = client.get(
reverse("provider-detail", kwargs={"pk": provider2_id}),
headers=tenant1_headers,
)
assert tenant2_response.status_code == 404
tenant1_response = client.get(
reverse("provider-detail", kwargs={"pk": provider2_id}),
headers=tenant2_headers,
)
assert tenant1_response.status_code == 200
assert tenant1_response.json()["data"]["id"] == provider2_id

View File

@@ -0,0 +1,284 @@
from unittest.mock import patch, MagicMock
from api.compliance import (
get_prowler_provider_checks,
get_prowler_provider_compliance,
load_prowler_compliance,
load_prowler_checks,
generate_scan_compliance,
generate_compliance_overview_template,
)
from api.models import Provider
class TestCompliance:
@patch("api.compliance.CheckMetadata")
def test_get_prowler_provider_checks(self, mock_check_metadata):
provider_type = Provider.ProviderChoices.AWS
mock_check_metadata.get_bulk.return_value = {
"check1": MagicMock(),
"check2": MagicMock(),
"check3": MagicMock(),
}
checks = get_prowler_provider_checks(provider_type)
assert set(checks) == {"check1", "check2", "check3"}
mock_check_metadata.get_bulk.assert_called_once_with(provider_type)
@patch("api.compliance.Compliance")
def test_get_prowler_provider_compliance(self, mock_compliance):
provider_type = Provider.ProviderChoices.AWS
mock_compliance.get_bulk.return_value = {
"compliance1": MagicMock(),
"compliance2": MagicMock(),
}
compliance_data = get_prowler_provider_compliance(provider_type)
assert compliance_data == mock_compliance.get_bulk.return_value
mock_compliance.get_bulk.assert_called_once_with(provider_type)
@patch("api.models.Provider.ProviderChoices")
@patch("api.compliance.get_prowler_provider_compliance")
@patch("api.compliance.generate_compliance_overview_template")
@patch("api.compliance.load_prowler_checks")
def test_load_prowler_compliance(
self,
mock_load_prowler_checks,
mock_generate_compliance_overview_template,
mock_get_prowler_provider_compliance,
mock_provider_choices,
):
mock_provider_choices.values = ["aws", "azure"]
compliance_data_aws = {"compliance_aws": MagicMock()}
compliance_data_azure = {"compliance_azure": MagicMock()}
compliance_data_dict = {
"aws": compliance_data_aws,
"azure": compliance_data_azure,
}
def mock_get_compliance(provider_type):
return compliance_data_dict[provider_type]
mock_get_prowler_provider_compliance.side_effect = mock_get_compliance
mock_generate_compliance_overview_template.return_value = {
"template_key": "template_value"
}
mock_load_prowler_checks.return_value = {"checks_key": "checks_value"}
load_prowler_compliance()
from api.compliance import PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE, PROWLER_CHECKS
assert PROWLER_COMPLIANCE_OVERVIEW_TEMPLATE == {
"template_key": "template_value"
}
assert PROWLER_CHECKS == {"checks_key": "checks_value"}
expected_prowler_compliance = compliance_data_dict
mock_get_prowler_provider_compliance.assert_any_call("aws")
mock_get_prowler_provider_compliance.assert_any_call("azure")
mock_generate_compliance_overview_template.assert_called_once_with(
expected_prowler_compliance
)
mock_load_prowler_checks.assert_called_once_with(expected_prowler_compliance)
@patch("api.compliance.get_prowler_provider_checks")
@patch("api.models.Provider.ProviderChoices")
def test_load_prowler_checks(
self, mock_provider_choices, mock_get_prowler_provider_checks
):
mock_provider_choices.values = ["aws"]
mock_get_prowler_provider_checks.return_value = ["check1", "check2", "check3"]
prowler_compliance = {
"aws": {
"compliance1": MagicMock(
Requirements=[
MagicMock(
Checks=["check1", "check2"],
),
],
),
},
}
expected_checks = {
"aws": {
"check1": {"compliance1"},
"check2": {"compliance1"},
"check3": set(),
}
}
checks = load_prowler_checks(prowler_compliance)
assert checks == expected_checks
mock_get_prowler_provider_checks.assert_called_once_with("aws")
@patch("api.compliance.PROWLER_CHECKS", new_callable=dict)
def test_generate_scan_compliance(self, mock_prowler_checks):
mock_prowler_checks["aws"] = {
"check1": {"compliance1"},
"check2": {"compliance1", "compliance2"},
}
compliance_overview = {
"compliance1": {
"requirements": {
"requirement1": {
"checks": {"check1": None, "check2": None},
"checks_status": {
"pass": 0,
"fail": 0,
"manual": 0,
"total": 2,
},
"status": "PASS",
}
},
"requirements_status": {"passed": 1, "failed": 0, "manual": 0},
},
"compliance2": {
"requirements": {
"requirement2": {
"checks": {"check2": None},
"checks_status": {
"pass": 0,
"fail": 0,
"manual": 0,
"total": 1,
},
"status": "PASS",
}
},
"requirements_status": {"passed": 1, "failed": 0, "manual": 0},
},
}
provider_type = "aws"
check_id = "check2"
status = "FAIL"
generate_scan_compliance(compliance_overview, provider_type, check_id, status)
assert (
compliance_overview["compliance1"]["requirements"]["requirement1"][
"checks"
]["check2"]
== "FAIL"
)
assert (
compliance_overview["compliance1"]["requirements"]["requirement1"][
"checks_status"
]["fail"]
== 1
)
assert (
compliance_overview["compliance1"]["requirements"]["requirement1"]["status"]
== "FAIL"
)
assert compliance_overview["compliance1"]["requirements_status"]["passed"] == 0
assert compliance_overview["compliance1"]["requirements_status"]["failed"] == 1
assert (
compliance_overview["compliance2"]["requirements"]["requirement2"][
"checks"
]["check2"]
== "FAIL"
)
assert (
compliance_overview["compliance2"]["requirements"]["requirement2"][
"checks_status"
]["fail"]
== 1
)
assert (
compliance_overview["compliance2"]["requirements"]["requirement2"]["status"]
== "FAIL"
)
assert compliance_overview["compliance2"]["requirements_status"]["passed"] == 0
assert compliance_overview["compliance2"]["requirements_status"]["failed"] == 1
assert (
compliance_overview["compliance1"]["requirements"]["requirement1"][
"checks"
]["check1"]
is None
)
@patch("api.models.Provider.ProviderChoices")
def test_generate_compliance_overview_template(self, mock_provider_choices):
mock_provider_choices.values = ["aws"]
requirement1 = MagicMock(
Id="requirement1",
Name="Requirement 1",
Description="Description of requirement 1",
Attributes=[],
Checks=["check1", "check2"],
)
requirement2 = MagicMock(
Id="requirement2",
Name="Requirement 2",
Description="Description of requirement 2",
Attributes=[],
Checks=[],
)
compliance1 = MagicMock(
Requirements=[requirement1, requirement2],
Framework="Framework 1",
Version="1.0",
Description="Description of compliance1",
)
prowler_compliance = {"aws": {"compliance1": compliance1}}
template = generate_compliance_overview_template(prowler_compliance)
expected_template = {
"aws": {
"compliance1": {
"framework": "Framework 1",
"version": "1.0",
"provider": "aws",
"description": "Description of compliance1",
"requirements": {
"requirement1": {
"name": "Requirement 1",
"description": "Description of requirement 1",
"attributes": [],
"checks": {"check1": None, "check2": None},
"checks_status": {
"pass": 0,
"fail": 0,
"manual": 0,
"total": 2,
},
"status": "PASS",
},
"requirement2": {
"name": "Requirement 2",
"description": "Description of requirement 2",
"attributes": [],
"checks": {},
"checks_status": {
"pass": 0,
"fail": 0,
"manual": 0,
"total": 0,
},
"status": "PASS",
},
},
"requirements_status": {
"passed": 1, # total_requirements - manual
"failed": 0,
"manual": 1, # requirement2 has 0 checks
},
"total_requirements": 2,
}
}
}
assert template == expected_template

View File

@@ -0,0 +1,31 @@
import pytest
from django.conf import settings
from django.db.migrations.recorder import MigrationRecorder
from django.db.utils import ConnectionRouter
from api.db_router import MainRouter
from api.rls import Tenant
from config.django.base import DATABASE_ROUTERS as PROD_DATABASE_ROUTERS
from unittest.mock import patch
@patch("api.db_router.MainRouter.admin_db", new="admin")
class TestMainDatabaseRouter:
@pytest.fixture(scope="module")
def router(self):
testing_routers = settings.DATABASE_ROUTERS.copy()
settings.DATABASE_ROUTERS = PROD_DATABASE_ROUTERS
yield ConnectionRouter()
settings.DATABASE_ROUTERS = testing_routers
@pytest.mark.parametrize("api_model", [Tenant])
def test_router_api_models(self, api_model, router):
assert router.db_for_read(api_model) == "default"
assert router.db_for_write(api_model) == "default"
assert router.allow_migrate_model(MainRouter.admin_db, api_model)
assert not router.allow_migrate_model("default", api_model)
def test_router_django_models(self, router):
assert router.db_for_read(MigrationRecorder.Migration) == MainRouter.admin_db
assert not router.db_for_read(MigrationRecorder.Migration) == "default"

View File

@@ -0,0 +1,140 @@
from datetime import datetime, timezone
from enum import Enum
from unittest.mock import patch
import pytest
from api.db_utils import (
batch_delete,
enum_to_choices,
generate_random_token,
one_week_from_now,
)
from api.models import Provider
class TestEnumToChoices:
def test_enum_to_choices_simple(self):
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
expected_result = [
(1, "Red"),
(2, "Green"),
(3, "Blue"),
]
result = enum_to_choices(Color)
assert result == expected_result
def test_enum_to_choices_with_underscores(self):
class Status(Enum):
PENDING_APPROVAL = "pending"
IN_PROGRESS = "in_progress"
COMPLETED_SUCCESSFULLY = "completed"
expected_result = [
("pending", "Pending Approval"),
("in_progress", "In Progress"),
("completed", "Completed Successfully"),
]
result = enum_to_choices(Status)
assert result == expected_result
def test_enum_to_choices_empty_enum(self):
class EmptyEnum(Enum):
pass
expected_result = []
result = enum_to_choices(EmptyEnum)
assert result == expected_result
def test_enum_to_choices_numeric_values(self):
class Numbers(Enum):
ONE = 1
TWO = 2
THREE = 3
expected_result = [
(1, "One"),
(2, "Two"),
(3, "Three"),
]
result = enum_to_choices(Numbers)
assert result == expected_result
class TestOneWeekFromNow:
def test_one_week_from_now(self):
with patch("api.db_utils.datetime") as mock_datetime:
mock_datetime.now.return_value = datetime(2023, 1, 1, tzinfo=timezone.utc)
expected_result = datetime(2023, 1, 8, tzinfo=timezone.utc)
result = one_week_from_now()
assert result == expected_result
def test_one_week_from_now_with_timezone(self):
with patch("api.db_utils.datetime") as mock_datetime:
mock_datetime.now.return_value = datetime(
2023, 6, 15, 12, 0, tzinfo=timezone.utc
)
expected_result = datetime(2023, 6, 22, 12, 0, tzinfo=timezone.utc)
result = one_week_from_now()
assert result == expected_result
class TestGenerateRandomToken:
def test_generate_random_token_default_length(self):
token = generate_random_token()
assert len(token) == 14
def test_generate_random_token_custom_length(self):
length = 20
token = generate_random_token(length=length)
assert len(token) == length
def test_generate_random_token_with_symbols(self):
symbols = "ABC123"
token = generate_random_token(length=10, symbols=symbols)
assert len(token) == 10
assert all(char in symbols for char in token)
def test_generate_random_token_unique(self):
tokens = {generate_random_token() for _ in range(1000)}
# Assuming that generating 1000 tokens should result in unique values
assert len(tokens) == 1000
def test_generate_random_token_no_symbols_provided(self):
token = generate_random_token(length=5, symbols="")
# Default symbols
assert len(token) == 5
class TestBatchDelete:
@pytest.fixture
def create_test_providers(self, tenants_fixture):
tenant = tenants_fixture[0]
provider_id = 123456789012
provider_count = 10
for i in range(provider_count):
Provider.objects.create(
tenant=tenant,
uid=f"{provider_id + i}",
provider=Provider.ProviderChoices.AWS,
)
return provider_count
@pytest.mark.django_db
def test_batch_delete(self, tenants_fixture, create_test_providers):
tenant_id = str(tenants_fixture[0].id)
_, summary = batch_delete(
tenant_id, Provider.objects.all(), batch_size=create_test_providers // 2
)
assert Provider.objects.all().count() == 0
assert summary == {"api.Provider": create_test_providers}

View File

@@ -0,0 +1,36 @@
import uuid
from unittest.mock import call, patch
import pytest
from api.db_utils import POSTGRES_TENANT_VAR, SET_CONFIG_QUERY
from api.decorators import set_tenant
@pytest.mark.django_db
class TestSetTenantDecorator:
@patch("api.decorators.connection.cursor")
def test_set_tenant(self, mock_cursor):
mock_cursor.return_value.__enter__.return_value = mock_cursor
@set_tenant
def random_func(arg):
return arg
tenant_id = str(uuid.uuid4())
result = random_func("test_arg", tenant_id=tenant_id)
assert (
call(SET_CONFIG_QUERY, [POSTGRES_TENANT_VAR, tenant_id])
in mock_cursor.execute.mock_calls
)
assert result == "test_arg"
def test_set_tenant_exception(self):
@set_tenant
def random_func(arg):
return arg
with pytest.raises(KeyError):
random_func("test_arg")

View File

@@ -0,0 +1,54 @@
from unittest.mock import MagicMock, patch
import pytest
from django.http import HttpResponse
from django.test import RequestFactory
from api.middleware import APILoggingMiddleware
@pytest.mark.django_db
@patch("logging.getLogger")
def test_api_logging_middleware_logging(mock_logger):
factory = RequestFactory()
request = factory.get("/test-path?param1=value1&param2=value2")
request.method = "GET"
response = HttpResponse()
response.status_code = 200
get_response = MagicMock(return_value=response)
with patch("api.middleware.extract_auth_info") as mock_extract_auth_info:
mock_extract_auth_info.return_value = {
"user_id": "user123",
"tenant_id": "tenant456",
}
with patch("api.middleware.logging.getLogger") as mock_get_logger:
mock_logger = MagicMock()
mock_get_logger.return_value = mock_logger
middleware = APILoggingMiddleware(get_response)
with patch("api.middleware.time.time") as mock_time:
mock_time.side_effect = [1000.0, 1001.0] # Start time and end time
middleware(request)
get_response.assert_called_once_with(request)
mock_extract_auth_info.assert_called_once_with(request)
expected_extra = {
"user_id": "user123",
"tenant_id": "tenant456",
"method": "GET",
"path": "/test-path",
"query_params": {"param1": "value1", "param2": "value2"},
"status_code": 200,
"duration": 1.0,
}
mock_logger.info.assert_called_once_with("", extra=expected_extra)

View File

@@ -0,0 +1,94 @@
import pytest
from api.models import Resource, ResourceTag
@pytest.mark.django_db
class TestResourceModel:
def test_setting_tags(self, providers_fixture):
provider, *_ = providers_fixture
tenant_id = provider.tenant_id
resource = Resource.objects.create(
tenant_id=tenant_id,
provider=provider,
uid="arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
name="My Instance 1",
region="us-east-1",
service="ec2",
type="prowler-test",
)
tags = [
ResourceTag.objects.create(
tenant_id=tenant_id,
key="key",
value="value",
),
ResourceTag.objects.create(
tenant_id=tenant_id,
key="key2",
value="value2",
),
]
resource.upsert_or_delete_tags(tags)
assert len(tags) == len(resource.tags.filter(tenant_id=tenant_id))
tags_dict = resource.get_tags(tenant_id=tenant_id)
for tag in tags:
assert tag.key in tags_dict
assert tag.value == tags_dict[tag.key]
def test_adding_tags(self, resources_fixture):
resource, *_ = resources_fixture
tenant_id = str(resource.tenant_id)
tags = [
ResourceTag.objects.create(
tenant_id=tenant_id,
key="env",
value="test",
),
]
before_count = len(resource.tags.filter(tenant_id=tenant_id))
resource.upsert_or_delete_tags(tags)
assert before_count + 1 == len(resource.tags.filter(tenant_id=tenant_id))
tags_dict = resource.get_tags(tenant_id=tenant_id)
assert "env" in tags_dict
assert tags_dict["env"] == "test"
def test_adding_duplicate_tags(self, resources_fixture):
resource, *_ = resources_fixture
tenant_id = str(resource.tenant_id)
tags = resource.tags.filter(tenant_id=tenant_id)
before_count = len(resource.tags.filter(tenant_id=tenant_id))
resource.upsert_or_delete_tags(tags)
# should be the same number of tags
assert before_count == len(resource.tags.filter(tenant_id=tenant_id))
def test_add_tags_none(self, resources_fixture):
resource, *_ = resources_fixture
tenant_id = str(resource.tenant_id)
resource.upsert_or_delete_tags(None)
assert len(resource.tags.filter(tenant_id=tenant_id)) == 0
assert resource.get_tags(tenant_id=tenant_id) == {}
def test_clear_tags(self, resources_fixture):
resource, *_ = resources_fixture
tenant_id = str(resource.tenant_id)
resource.clear_tags()
assert len(resource.tags.filter(tenant_id=tenant_id)) == 0
assert resource.get_tags(tenant_id=tenant_id) == {}

View File

@@ -0,0 +1,306 @@
import pytest
from django.urls import reverse
from rest_framework import status
from unittest.mock import patch, ANY, Mock
@pytest.mark.django_db
class TestUserViewSet:
def test_list_users_with_all_permissions(self, authenticated_client_rbac):
response = authenticated_client_rbac.get(reverse("user-list"))
assert response.status_code == status.HTTP_200_OK
assert isinstance(response.json()["data"], list)
def test_list_users_with_no_permissions(
self, authenticated_client_no_permissions_rbac
):
response = authenticated_client_no_permissions_rbac.get(reverse("user-list"))
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_retrieve_user_with_all_permissions(
self, authenticated_client_rbac, create_test_user_rbac
):
response = authenticated_client_rbac.get(
reverse("user-detail", kwargs={"pk": create_test_user_rbac.id})
)
assert response.status_code == status.HTTP_200_OK
assert (
response.json()["data"]["attributes"]["email"]
== create_test_user_rbac.email
)
def test_retrieve_user_with_no_roles(
self, authenticated_client_rbac_noroles, create_test_user_rbac_no_roles
):
response = authenticated_client_rbac_noroles.get(
reverse("user-detail", kwargs={"pk": create_test_user_rbac_no_roles.id})
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_retrieve_user_with_no_permissions(
self, authenticated_client_no_permissions_rbac, create_test_user
):
response = authenticated_client_no_permissions_rbac.get(
reverse("user-detail", kwargs={"pk": create_test_user.id})
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_create_user_with_all_permissions(self, authenticated_client_rbac):
valid_user_payload = {
"name": "test",
"password": "newpassword123",
"email": "new_user@test.com",
}
response = authenticated_client_rbac.post(
reverse("user-list"), data=valid_user_payload, format="vnd.api+json"
)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["data"]["attributes"]["email"] == "new_user@test.com"
def test_create_user_with_no_permissions(
self, authenticated_client_no_permissions_rbac
):
valid_user_payload = {
"name": "test",
"password": "newpassword123",
"email": "new_user@test.com",
}
response = authenticated_client_no_permissions_rbac.post(
reverse("user-list"), data=valid_user_payload, format="vnd.api+json"
)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["data"]["attributes"]["email"] == "new_user@test.com"
def test_partial_update_user_with_all_permissions(
self, authenticated_client_rbac, create_test_user_rbac
):
updated_data = {
"data": {
"type": "users",
"id": str(create_test_user_rbac.id),
"attributes": {"name": "Updated Name"},
},
}
response = authenticated_client_rbac.patch(
reverse("user-detail", kwargs={"pk": create_test_user_rbac.id}),
data=updated_data,
content_type="application/vnd.api+json",
)
assert response.status_code == status.HTTP_200_OK
assert response.json()["data"]["attributes"]["name"] == "Updated Name"
def test_partial_update_user_with_no_permissions(
self, authenticated_client_no_permissions_rbac, create_test_user
):
updated_data = {
"data": {
"type": "users",
"attributes": {"name": "Updated Name"},
}
}
response = authenticated_client_no_permissions_rbac.patch(
reverse("user-detail", kwargs={"pk": create_test_user.id}),
data=updated_data,
format="vnd.api+json",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_delete_user_with_all_permissions(
self, authenticated_client_rbac, create_test_user_rbac
):
response = authenticated_client_rbac.delete(
reverse("user-detail", kwargs={"pk": create_test_user_rbac.id})
)
assert response.status_code == status.HTTP_204_NO_CONTENT
def test_delete_user_with_no_permissions(
self, authenticated_client_no_permissions_rbac, create_test_user
):
response = authenticated_client_no_permissions_rbac.delete(
reverse("user-detail", kwargs={"pk": create_test_user.id})
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_me_with_all_permissions(
self, authenticated_client_rbac, create_test_user_rbac
):
response = authenticated_client_rbac.get(reverse("user-me"))
assert response.status_code == status.HTTP_200_OK
assert (
response.json()["data"]["attributes"]["email"]
== create_test_user_rbac.email
)
def test_me_with_no_permissions(
self, authenticated_client_no_permissions_rbac, create_test_user
):
response = authenticated_client_no_permissions_rbac.get(reverse("user-me"))
assert response.status_code == status.HTTP_200_OK
assert response.json()["data"]["attributes"]["email"] == "rbac_limited@rbac.com"
@pytest.mark.django_db
class TestProviderViewSet:
def test_list_providers_with_all_permissions(
self, authenticated_client_rbac, providers_fixture
):
response = authenticated_client_rbac.get(reverse("provider-list"))
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["data"]) == len(providers_fixture)
def test_list_providers_with_no_permissions(
self, authenticated_client_no_permissions_rbac
):
response = authenticated_client_no_permissions_rbac.get(
reverse("provider-list")
)
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["data"]) == 0
def test_retrieve_provider_with_all_permissions(
self, authenticated_client_rbac, providers_fixture
):
provider = providers_fixture[0]
response = authenticated_client_rbac.get(
reverse("provider-detail", kwargs={"pk": provider.id})
)
assert response.status_code == status.HTTP_200_OK
assert response.json()["data"]["attributes"]["alias"] == provider.alias
def test_retrieve_provider_with_no_permissions(
self, authenticated_client_no_permissions_rbac, providers_fixture
):
provider = providers_fixture[0]
response = authenticated_client_no_permissions_rbac.get(
reverse("provider-detail", kwargs={"pk": provider.id})
)
assert response.status_code == status.HTTP_404_NOT_FOUND
def test_create_provider_with_all_permissions(self, authenticated_client_rbac):
payload = {"provider": "aws", "uid": "111111111111", "alias": "new_alias"}
response = authenticated_client_rbac.post(
reverse("provider-list"), data=payload, format="json"
)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["data"]["attributes"]["alias"] == "new_alias"
def test_create_provider_with_no_permissions(
self, authenticated_client_no_permissions_rbac
):
payload = {"provider": "aws", "uid": "111111111111", "alias": "new_alias"}
response = authenticated_client_no_permissions_rbac.post(
reverse("provider-list"), data=payload, format="json"
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_partial_update_provider_with_all_permissions(
self, authenticated_client_rbac, providers_fixture
):
provider = providers_fixture[0]
payload = {
"data": {
"type": "providers",
"id": provider.id,
"attributes": {"alias": "updated_alias"},
},
}
response = authenticated_client_rbac.patch(
reverse("provider-detail", kwargs={"pk": provider.id}),
data=payload,
content_type="application/vnd.api+json",
)
assert response.status_code == status.HTTP_200_OK
assert response.json()["data"]["attributes"]["alias"] == "updated_alias"
def test_partial_update_provider_with_no_permissions(
self, authenticated_client_no_permissions_rbac, providers_fixture
):
provider = providers_fixture[0]
update_payload = {
"data": {
"type": "providers",
"attributes": {"alias": "updated_alias"},
}
}
response = authenticated_client_no_permissions_rbac.patch(
reverse("provider-detail", kwargs={"pk": provider.id}),
data=update_payload,
format="vnd.api+json",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@patch("api.v1.views.Task.objects.get")
@patch("api.v1.views.delete_provider_task.delay")
def test_delete_provider_with_all_permissions(
self,
mock_delete_task,
mock_task_get,
authenticated_client_rbac,
providers_fixture,
tasks_fixture,
):
prowler_task = tasks_fixture[0]
task_mock = Mock()
task_mock.id = prowler_task.id
mock_delete_task.return_value = task_mock
mock_task_get.return_value = prowler_task
provider1, *_ = providers_fixture
response = authenticated_client_rbac.delete(
reverse("provider-detail", kwargs={"pk": provider1.id})
)
assert response.status_code == status.HTTP_202_ACCEPTED
mock_delete_task.assert_called_once_with(
provider_id=str(provider1.id), tenant_id=ANY
)
assert "Content-Location" in response.headers
assert response.headers["Content-Location"] == f"/api/v1/tasks/{task_mock.id}"
def test_delete_provider_with_no_permissions(
self, authenticated_client_no_permissions_rbac, providers_fixture
):
provider = providers_fixture[0]
response = authenticated_client_no_permissions_rbac.delete(
reverse("provider-detail", kwargs={"pk": provider.id})
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@patch("api.v1.views.Task.objects.get")
@patch("api.v1.views.check_provider_connection_task.delay")
def test_connection_with_all_permissions(
self,
mock_provider_connection,
mock_task_get,
authenticated_client_rbac,
providers_fixture,
tasks_fixture,
):
prowler_task = tasks_fixture[0]
task_mock = Mock()
task_mock.id = prowler_task.id
task_mock.status = "PENDING"
mock_provider_connection.return_value = task_mock
mock_task_get.return_value = prowler_task
provider1, *_ = providers_fixture
assert provider1.connected is None
assert provider1.connection_last_checked_at is None
response = authenticated_client_rbac.post(
reverse("provider-connection", kwargs={"pk": provider1.id})
)
assert response.status_code == status.HTTP_202_ACCEPTED
mock_provider_connection.assert_called_once_with(
provider_id=str(provider1.id), tenant_id=ANY
)
assert "Content-Location" in response.headers
assert response.headers["Content-Location"] == f"/api/v1/tasks/{task_mock.id}"
def test_connection_with_no_permissions(
self, authenticated_client_no_permissions_rbac, providers_fixture
):
provider = providers_fixture[0]
response = authenticated_client_no_permissions_rbac.post(
reverse("provider-connection", kwargs={"pk": provider.id})
)
assert response.status_code == status.HTTP_403_FORBIDDEN

View File

@@ -0,0 +1,330 @@
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock, patch
import pytest
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.utils import (
get_prowler_provider_kwargs,
initialize_prowler_provider,
merge_dicts,
prowler_provider_connection_test,
return_prowler_provider,
validate_invitation,
)
from prowler.providers.aws.aws_provider import AwsProvider
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.gcp.gcp_provider import GcpProvider
from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider
class TestMergeDicts:
def test_simple_merge(self):
default_dict = {"key1": "value1", "key2": "value2"}
replacement_dict = {"key2": "new_value2", "key3": "value3"}
expected_result = {"key1": "value1", "key2": "new_value2", "key3": "value3"}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
def test_nested_merge(self):
default_dict = {
"key1": "value1",
"key2": {"nested_key1": "nested_value1", "nested_key2": "nested_value2"},
}
replacement_dict = {
"key2": {
"nested_key2": "new_nested_value2",
"nested_key3": "nested_value3",
},
"key3": "value3",
}
expected_result = {
"key1": "value1",
"key2": {
"nested_key1": "nested_value1",
"nested_key2": "new_nested_value2",
"nested_key3": "nested_value3",
},
"key3": "value3",
}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
def test_no_overlap(self):
default_dict = {"key1": "value1"}
replacement_dict = {"key2": "value2"}
expected_result = {"key1": "value1", "key2": "value2"}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
def test_replacement_dict_empty(self):
default_dict = {"key1": "value1", "key2": "value2"}
replacement_dict = {}
expected_result = {"key1": "value1", "key2": "value2"}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
def test_default_dict_empty(self):
default_dict = {}
replacement_dict = {"key1": "value1", "key2": "value2"}
expected_result = {"key1": "value1", "key2": "value2"}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
def test_nested_empty_in_replacement_dict(self):
default_dict = {"key1": {"nested_key1": "nested_value1"}}
replacement_dict = {"key1": {}}
expected_result = {"key1": {}}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
def test_deep_nested_merge(self):
default_dict = {"key1": {"nested_key1": {"deep_key1": "deep_value1"}}}
replacement_dict = {"key1": {"nested_key1": {"deep_key1": "new_deep_value1"}}}
expected_result = {"key1": {"nested_key1": {"deep_key1": "new_deep_value1"}}}
result = merge_dicts(default_dict, replacement_dict)
assert result == expected_result
class TestReturnProwlerProvider:
@pytest.mark.parametrize(
"provider_type, expected_provider",
[
(Provider.ProviderChoices.AWS.value, AwsProvider),
(Provider.ProviderChoices.GCP.value, GcpProvider),
(Provider.ProviderChoices.AZURE.value, AzureProvider),
(Provider.ProviderChoices.KUBERNETES.value, KubernetesProvider),
],
)
def test_return_prowler_provider(self, provider_type, expected_provider):
provider = MagicMock()
provider.provider = provider_type
prowler_provider = return_prowler_provider(provider)
assert prowler_provider == expected_provider
def test_return_prowler_provider_unsupported_provider(self):
provider = MagicMock()
provider.provider = "UNSUPPORTED_PROVIDER"
with pytest.raises(ValueError):
return return_prowler_provider(provider)
class TestInitializeProwlerProvider:
@patch("api.utils.return_prowler_provider")
def test_initialize_prowler_provider(self, mock_return_prowler_provider):
provider = MagicMock()
provider.secret.secret = {"key": "value"}
mock_return_prowler_provider.return_value = MagicMock()
initialize_prowler_provider(provider)
mock_return_prowler_provider.return_value.assert_called_once_with(key="value")
class TestProwlerProviderConnectionTest:
@patch("api.utils.return_prowler_provider")
def test_prowler_provider_connection_test(self, mock_return_prowler_provider):
provider = MagicMock()
provider.uid = "1234567890"
provider.secret.secret = {"key": "value"}
mock_return_prowler_provider.return_value = MagicMock()
prowler_provider_connection_test(provider)
mock_return_prowler_provider.return_value.test_connection.assert_called_once_with(
key="value", provider_id="1234567890", raise_on_exception=False
)
@pytest.mark.django_db
@patch("api.utils.return_prowler_provider")
def test_prowler_provider_connection_test_without_secret(
self, mock_return_prowler_provider, providers_fixture
):
mock_return_prowler_provider.return_value = MagicMock()
connection = prowler_provider_connection_test(providers_fixture[0])
assert connection.is_connected is False
assert isinstance(connection.error, Provider.secret.RelatedObjectDoesNotExist)
assert str(connection.error) == "Provider has no secret."
class TestGetProwlerProviderKwargs:
@pytest.mark.parametrize(
"provider_type, expected_extra_kwargs",
[
(
Provider.ProviderChoices.AWS.value,
{},
),
(
Provider.ProviderChoices.AZURE.value,
{"subscription_ids": ["provider_uid"]},
),
(
Provider.ProviderChoices.GCP.value,
{"project_ids": ["provider_uid"]},
),
(
Provider.ProviderChoices.KUBERNETES.value,
{"context": "provider_uid"},
),
],
)
def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs):
provider_uid = "provider_uid"
secret_dict = {"key": "value"}
secret_mock = MagicMock()
secret_mock.secret = secret_dict
provider = MagicMock()
provider.provider = provider_type
provider.secret = secret_mock
provider.uid = provider_uid
result = get_prowler_provider_kwargs(provider)
expected_result = {**secret_dict, **expected_extra_kwargs}
assert result == expected_result
def test_get_prowler_provider_kwargs_unsupported_provider(self):
# Setup
provider_uid = "provider_uid"
secret_dict = {"key": "value"}
secret_mock = MagicMock()
secret_mock.secret = secret_dict
provider = MagicMock()
provider.provider = "UNSUPPORTED_PROVIDER"
provider.secret = secret_mock
provider.uid = provider_uid
result = get_prowler_provider_kwargs(provider)
expected_result = secret_dict.copy()
assert result == expected_result
def test_get_prowler_provider_kwargs_no_secret(self):
# Setup
provider_uid = "provider_uid"
secret_mock = MagicMock()
secret_mock.secret = {}
provider = MagicMock()
provider.provider = Provider.ProviderChoices.AWS.value
provider.secret = secret_mock
provider.uid = provider_uid
result = get_prowler_provider_kwargs(provider)
expected_result = {}
assert result == expected_result
class TestValidateInvitation:
@pytest.fixture
def invitation(self):
invitation = MagicMock(spec=Invitation)
invitation.token = "VALID_TOKEN"
invitation.email = "user@example.com"
invitation.expires_at = datetime.now(timezone.utc) + timedelta(days=1)
invitation.state = Invitation.State.PENDING
invitation.tenant = MagicMock()
return invitation
def test_valid_invitation(self, invitation):
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="user@example.com"
)
def test_invitation_not_found_raises_validation_error(self):
with patch("api.utils.Invitation.objects.using") as mock_using:
mock_db = mock_using.return_value
mock_db.get.side_effect = Invitation.DoesNotExist
with pytest.raises(ValidationError) as exc_info:
validate_invitation("INVALID_TOKEN", "user@example.com")
assert exc_info.value.detail == {
"invitation_token": "Invalid invitation code."
}
mock_db.get.assert_called_once_with(
token="INVALID_TOKEN", email="user@example.com"
)
def test_invitation_not_found_raises_not_found(self):
with patch("api.utils.Invitation.objects.using") as mock_using:
mock_db = mock_using.return_value
mock_db.get.side_effect = Invitation.DoesNotExist
with pytest.raises(NotFound) as exc_info:
validate_invitation(
"INVALID_TOKEN", "user@example.com", raise_not_found=True
)
assert exc_info.value.detail == "Invitation is not valid."
mock_db.get.assert_called_once_with(
token="INVALID_TOKEN", email="user@example.com"
)
def test_invitation_expired(self, invitation):
expired_time = datetime.now(timezone.utc) - timedelta(days=1)
invitation.expires_at = expired_time
with (
patch("api.utils.Invitation.objects.using") as mock_using,
patch("api.utils.datetime") as mock_datetime,
):
mock_db = mock_using.return_value
mock_db.get.return_value = invitation
mock_datetime.now.return_value = datetime.now(timezone.utc)
with pytest.raises(InvitationTokenExpiredException):
validate_invitation("VALID_TOKEN", "user@example.com")
# Ensure the invitation state was updated to EXPIRED
assert invitation.state == Invitation.State.EXPIRED
invitation.save.assert_called_once_with(using=MainRouter.admin_db)
def test_invitation_not_pending(self, invitation):
invitation.state = Invitation.State.ACCEPTED
with patch("api.utils.Invitation.objects.using") as mock_using:
mock_db = mock_using.return_value
mock_db.get.return_value = invitation
with pytest.raises(ValidationError) as exc_info:
validate_invitation("VALID_TOKEN", "user@example.com")
assert exc_info.value.detail == {
"invitation_token": "This invitation is no longer valid."
}
def test_invitation_with_different_email(self):
with patch("api.utils.Invitation.objects.using") as mock_using:
mock_db = mock_using.return_value
mock_db.get.side_effect = Invitation.DoesNotExist
with pytest.raises(ValidationError) as exc_info:
validate_invitation("VALID_TOKEN", "different@example.com")
assert exc_info.value.detail == {
"invitation_token": "Invalid invitation code."
}
mock_db.get.assert_called_once_with(
token="VALID_TOKEN", email="different@example.com"
)

View File

@@ -0,0 +1,113 @@
from datetime import datetime, timezone
from uuid import uuid4
import pytest
from dateutil.relativedelta import relativedelta
from rest_framework_json_api.serializers import ValidationError
from uuid6 import UUID
from api.uuid_utils import (
transform_into_uuid7,
datetime_to_uuid7,
datetime_from_uuid7,
uuid7_start,
uuid7_end,
uuid7_range,
)
def test_transform_into_uuid7_valid():
uuid_v7 = datetime_to_uuid7(datetime.now(timezone.utc))
transformed_uuid = transform_into_uuid7(uuid_v7)
assert transformed_uuid == UUID(hex=uuid_v7.hex.upper())
assert transformed_uuid.version == 7
def test_transform_into_uuid7_invalid_version():
uuid_v4 = uuid4()
with pytest.raises(ValidationError) as exc_info:
transform_into_uuid7(UUID(str(uuid_v4)))
assert str(exc_info.value.detail[0]) == "Invalid UUIDv7 value."
@pytest.mark.parametrize(
"input_datetime",
[
datetime(2024, 9, 11, 7, 20, 27, tzinfo=timezone.utc),
datetime(2023, 1, 1, 0, 0, 0, tzinfo=timezone.utc),
],
)
def test_datetime_to_uuid7(input_datetime):
uuid7 = datetime_to_uuid7(input_datetime)
assert isinstance(uuid7, UUID)
assert uuid7.version == 7
expected_timestamp_ms = int(input_datetime.timestamp() * 1000) & 0xFFFFFFFFFFFF
assert uuid7.time == expected_timestamp_ms
@pytest.mark.parametrize(
"input_datetime",
[
datetime(2024, 9, 11, 7, 20, 27, tzinfo=timezone.utc),
datetime(2023, 1, 1, 0, 0, 0, tzinfo=timezone.utc),
],
)
def test_datetime_from_uuid7(input_datetime):
uuid7 = datetime_to_uuid7(input_datetime)
extracted_datetime = datetime_from_uuid7(uuid7)
assert extracted_datetime == input_datetime
def test_datetime_from_uuid7_invalid():
uuid_v4 = uuid4()
with pytest.raises(ValueError):
datetime_from_uuid7(UUID(str(uuid_v4)))
def test_uuid7_start():
dt = datetime.now(timezone.utc)
uuid = datetime_to_uuid7(dt)
start_uuid = uuid7_start(uuid)
expected_dt = dt.replace(hour=0, minute=0, second=0, microsecond=0)
expected_timestamp_ms = int(expected_dt.timestamp() * 1000) & 0xFFFFFFFFFFFF
assert start_uuid.time == expected_timestamp_ms
assert start_uuid.version == 7
@pytest.mark.parametrize("months_offset", [0, 1, 10, 30, 60])
def test_uuid7_end(months_offset):
dt = datetime.now(timezone.utc)
uuid = datetime_to_uuid7(dt)
end_uuid = uuid7_end(uuid, months_offset)
expected_dt = dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
expected_dt += relativedelta(months=months_offset, microseconds=-1)
expected_timestamp_ms = int(expected_dt.timestamp() * 1000) & 0xFFFFFFFFFFFF
assert end_uuid.time == expected_timestamp_ms
assert end_uuid.version == 7
def test_uuid7_range():
dt_now = datetime.now(timezone.utc)
uuid_list = [
datetime_to_uuid7(dt_now),
datetime_to_uuid7(dt_now.replace(year=2023)),
datetime_to_uuid7(dt_now.replace(year=2024)),
datetime_to_uuid7(dt_now.replace(year=2025)),
]
start_uuid, end_uuid = uuid7_range(uuid_list)
# Expected start of range
start_dt = datetime_from_uuid7(min(uuid_list, key=lambda u: u.time))
start_dt = start_dt.replace(hour=0, minute=0, second=0, microsecond=0)
expected_start_timestamp_ms = int(start_dt.timestamp() * 1000) & 0xFFFFFFFFFFFF
# Expected end of range
end_dt = datetime_from_uuid7(max(uuid_list, key=lambda u: u.time))
end_dt = end_dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
end_dt += relativedelta(months=1, microseconds=-1)
expected_end_timestamp_ms = int(end_dt.timestamp() * 1000) & 0xFFFFFFFFFFFF
assert start_uuid.time == expected_start_timestamp_ms
assert end_uuid.time == expected_end_timestamp_ms
assert start_uuid.version == 7
assert end_uuid.version == 7

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
from datetime import datetime, timezone
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
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 prowler.providers.aws.aws_provider import AwsProvider
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.kubernetes.kubernetes_provider import KubernetesProvider
class CustomOAuth2Client(OAuth2Client):
def __init__(self, client_id, secret, *args, **kwargs):
# Remove any duplicate "scope_delimiter" from kwargs
# Bug present in dj-rest-auth after version v7.0.1
# https://github.com/iMerica/dj-rest-auth/issues/673
kwargs.pop("scope_delimiter", None)
super().__init__(client_id, secret, *args, **kwargs)
def merge_dicts(default_dict: dict, replacement_dict: dict) -> dict:
"""
Recursively merge two dictionaries, using `default_dict` as the base and `replacement_dict` for overriding values.
Args:
default_dict (dict): The base dictionary containing default key-value pairs.
replacement_dict (dict): The dictionary containing values that should override those in `default_dict`.
Returns:
dict: A new dictionary containing all keys from `default_dict` with values from `replacement_dict` replacing
any overlapping keys. If a key in both `default_dict` and `replacement_dict` contains dictionaries,
this function will merge them recursively.
"""
result = default_dict.copy()
for key, value in replacement_dict.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
if value:
result[key] = merge_dicts(result[key], value)
else:
result[key] = value
else:
result[key] = value
return result
def return_prowler_provider(
provider: Provider,
) -> [AwsProvider | AzureProvider | GcpProvider | KubernetesProvider]:
"""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: The corresponding provider class.
Raises:
ValueError: If the provider type specified in `provider.provider` is not supported.
"""
match provider.provider:
case Provider.ProviderChoices.AWS.value:
prowler_provider = AwsProvider
case Provider.ProviderChoices.GCP.value:
prowler_provider = GcpProvider
case Provider.ProviderChoices.AZURE.value:
prowler_provider = AzureProvider
case Provider.ProviderChoices.KUBERNETES.value:
prowler_provider = KubernetesProvider
case _:
raise ValueError(f"Provider type {provider.provider} not supported")
return prowler_provider
def get_prowler_provider_kwargs(provider: Provider) -> 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.
Returns:
dict: The provider kwargs for the corresponding provider class.
"""
prowler_provider_kwargs = provider.secret.secret
if provider.provider == Provider.ProviderChoices.AZURE.value:
prowler_provider_kwargs = {
**prowler_provider_kwargs,
"subscription_ids": [provider.uid],
}
elif provider.provider == Provider.ProviderChoices.GCP.value:
prowler_provider_kwargs = {
**prowler_provider_kwargs,
"project_ids": [provider.uid],
}
elif provider.provider == Provider.ProviderChoices.KUBERNETES.value:
prowler_provider_kwargs = {**prowler_provider_kwargs, "context": provider.uid}
return prowler_provider_kwargs
def initialize_prowler_provider(
provider: Provider,
) -> AwsProvider | AzureProvider | GcpProvider | KubernetesProvider:
"""Initialize a Prowler provider instance based on the given provider type.
Args:
provider (Provider): The provider object containing the provider type and associated secrets.
Returns:
AwsProvider | AzureProvider | GcpProvider | KubernetesProvider: An instance of the corresponding provider class
(`AwsProvider`, `AzureProvider`, `GcpProvider`, or `KubernetesProvider`) initialized with the
provider's secrets.
"""
prowler_provider = return_prowler_provider(provider)
prowler_provider_kwargs = get_prowler_provider_kwargs(provider)
return prowler_provider(**prowler_provider_kwargs)
def prowler_provider_connection_test(provider: Provider) -> Connection:
"""Test the connection to a Prowler provider based on the given provider type.
Args:
provider (Provider): The provider object containing the provider type and associated secrets.
Returns:
Connection: A connection object representing the result of the connection test for the specified provider.
"""
prowler_provider = return_prowler_provider(provider)
try:
prowler_provider_kwargs = provider.secret.secret
except Provider.secret.RelatedObjectDoesNotExist as secret_error:
return Connection(is_connected=False, error=secret_error)
return prowler_provider.test_connection(
**prowler_provider_kwargs, provider_id=provider.uid, raise_on_exception=False
)
def validate_invitation(
invitation_token: str, email: str, raise_not_found=False
) -> Invitation:
"""
Validates an invitation based on the provided token and email.
This function attempts to retrieve an Invitation object using the given
`invitation_token` and `email`. It performs several checks to ensure that
the invitation is valid, not expired, and in the correct state for acceptance.
Args:
invitation_token (str): The token associated with the invitation.
email (str): The email address associated with the invitation.
raise_not_found (bool, optional): If True, raises a `NotFound` exception
when the invitation is not found. If False, raises a `ValidationError`.
Defaults to False.
Returns:
Invitation: The validated Invitation object.
Raises:
NotFound: If `raise_not_found` is True and the invitation does not exist.
ValidationError: If the invitation does not exist and `raise_not_found`
is False, or if the invitation is invalid or in an incorrect state.
InvitationTokenExpiredException: If the invitation has expired.
Notes:
- This function uses the admin database connector to bypass RLS protection
since the invitation may belong to a tenant the user is not a member of yet.
- If the invitation has expired, its state is updated to EXPIRED, and an
`InvitationTokenExpiredException` is raised.
- Only invitations in the PENDING state can be accepted.
Examples:
invitation = validate_invitation("TOKEN123", "user@example.com")
"""
try:
# 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
)
except Invitation.DoesNotExist:
if raise_not_found:
raise NotFound(detail="Invitation is not valid.")
else:
raise ValidationError({"invitation_token": "Invalid invitation code."})
# Check if the invitation has expired
if invitation.expires_at < datetime.now(timezone.utc):
invitation.state = Invitation.State.EXPIRED
invitation.save(using=MainRouter.admin_db)
raise InvitationTokenExpiredException()
# Check the state of the invitation
if invitation.state != Invitation.State.PENDING:
raise ValidationError(
{"invitation_token": "This invitation is no longer valid."}
)
return invitation

View File

@@ -0,0 +1,148 @@
from datetime import datetime, timezone
from random import getrandbits
from dateutil.relativedelta import relativedelta
from rest_framework_json_api.serializers import ValidationError
from uuid6 import UUID
def transform_into_uuid7(uuid_obj: UUID) -> UUID:
"""
Validates that the given UUID object is a UUIDv7 and returns it.
This function checks if the provided UUID object is of version 7.
If it is, it returns a new UUID object constructed from the uppercase
hexadecimal representation of the input UUID. If not, it raises a ValidationError.
Args:
uuid_obj (UUID): The UUID object to validate and transform.
Returns:
UUID: A new UUIDv7 object constructed from the uppercase hexadecimal
representation of the input UUID.
Raises:
ValidationError: If the provided UUID is not a version 7 UUID.
"""
try:
if uuid_obj.version != 7:
raise ValueError
return UUID(hex=uuid_obj.hex.upper())
except ValueError:
raise ValidationError("Invalid UUIDv7 value.")
def datetime_to_uuid7(dt: datetime) -> UUID:
"""
Generates a UUIDv7 from a given datetime object.
Constructs a UUIDv7 using the provided datetime timestamp.
Ensures that the version and variant bits are set correctly.
Args:
dt: A datetime object representing the desired timestamp for the UUIDv7.
Returns:
A UUIDv7 object corresponding to the given datetime.
"""
timestamp_ms = int(dt.timestamp() * 1000) & 0xFFFFFFFFFFFF # 48 bits
# Generate 12 bits of randomness for the sequence
rand_seq = getrandbits(12)
# Generate 62 bits of randomness for the node
rand_node = getrandbits(62)
# Build the UUID integer
uuid_int = timestamp_ms << 80 # Shift timestamp to bits 80-127
# Set the version to 7 in bits 76-79
uuid_int |= 0x7 << 76
# Set 12 bits of randomness in bits 64-75
uuid_int |= rand_seq << 64
# Set the variant to "10" in bits 62-63
uuid_int |= 0x2 << 62
# Set 62 bits of randomness in bits 0-61
uuid_int |= rand_node
return UUID(int=uuid_int)
def datetime_from_uuid7(uuid7: UUID) -> datetime:
"""
Extracts the timestamp from a UUIDv7 and returns it as a datetime object.
Args:
uuid7: A UUIDv7 object.
Returns:
A datetime object representing the timestamp encoded in the UUIDv7.
"""
timestamp_ms = uuid7.time
return datetime.fromtimestamp(timestamp_ms / 1000, tz=timezone.utc)
def uuid7_start(uuid_obj: UUID) -> UUID:
"""
Returns a UUIDv7 that represents the start of the day for the given UUID.
Args:
uuid_obj: A UUIDv7 object.
Returns:
A UUIDv7 object representing the start of the day for the given UUID's timestamp.
"""
start_of_day = datetime_from_uuid7(uuid_obj).replace(
hour=0, minute=0, second=0, microsecond=0
)
return datetime_to_uuid7(start_of_day)
def uuid7_end(uuid_obj: UUID, offset_months: int = 1) -> UUID:
"""
Returns a UUIDv7 that represents the end of the month for the given UUID.
Args:
uuid_obj: A UUIDv7 object.
offset_months: Number of months to offset from the given UUID's date. Defaults to 1 to handle if
partitions are not being used, if so the value will be the one set at FINDINGS_TABLE_PARTITION_MONTHS.
Returns:
A UUIDv7 object representing the end of the month for the given UUID's date plus offset_months.
"""
end_of_month = datetime_from_uuid7(uuid_obj).replace(
day=1, hour=0, minute=0, second=0, microsecond=0
)
end_of_month += relativedelta(months=offset_months, microseconds=-1)
return datetime_to_uuid7(end_of_month)
def uuid7_range(uuid_list: list[UUID]) -> list[UUID]:
"""
For the given list of UUIDv7s, returns the start and end UUIDv7 values that represent
the range of days covered by the UUIDs.
Args:
uuid_list: A list of UUIDv7 objects.
Returns:
A list containing two UUIDv7 objects: the start and end of the day range.
Raises:
ValidationError: If the list is empty or contains invalid UUIDv7 objects.
"""
if not uuid_list:
raise ValidationError("UUID list is empty.")
try:
start_uuid = min(uuid_list, key=lambda u: u.time)
end_uuid = max(uuid_list, key=lambda u: u.time)
except AttributeError:
raise ValidationError("Invalid UUIDv7 objects in the list.")
start_range = uuid7_start(start_uuid)
end_range = uuid7_end(end_uuid)
return [start_range, end_range]

View File

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