Skip to content

Commit 0cf6f2f

Browse files
authored
fix(api): add attack paths scan DB defaults (#11826)
1 parent cf18093 commit 0cf6f2f

4 files changed

Lines changed: 90 additions & 1 deletion

File tree

api/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
All notable changes to the **Prowler API** are documented in this file.
44

5+
## [1.33.1] (Prowler UNRELEASED)
6+
7+
### 🐞 Fixed
8+
9+
- Attack Paths: Scan rows now have database defaults for `is_migrated` and `sink_backend` so `scan-perform-scheduled` inserts survive deploy skew [(#11826)](https://github.com/prowler-cloud/prowler/pull/11826)
10+
11+
---
12+
513
## [1.33.0] (Prowler v5.32.0)
614

715
### 🚀 Added
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from django.db import migrations, models
2+
3+
4+
class Migration(migrations.Migration):
5+
dependencies = [
6+
("api", "0096_attack_paths_scan_is_migrated"),
7+
]
8+
9+
operations = [
10+
migrations.AlterField(
11+
model_name="attackpathsscan",
12+
name="is_migrated",
13+
field=models.BooleanField(db_default=False, default=False),
14+
),
15+
migrations.AlterField(
16+
model_name="attackpathsscan",
17+
name="sink_backend",
18+
field=models.CharField(
19+
choices=[("neo4j", "Neo4j"), ("neptune", "Neptune")],
20+
db_default="neo4j",
21+
default="neo4j",
22+
max_length=16,
23+
),
24+
),
25+
]

api/src/backend/api/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,9 +814,10 @@ class SinkBackendChoices(models.TextChoices):
814814
# still using the previous graph shape. Query catalog selection uses this
815815
# flag; physical read routing uses sink_backend below.
816816
# TODO: drop after Neptune cutover
817-
is_migrated = models.BooleanField(default=False)
817+
is_migrated = models.BooleanField(default=False, db_default=False)
818818
sink_backend = models.CharField(
819819
choices=SinkBackendChoices.choices,
820+
db_default=SinkBackendChoices.NEO4J,
820821
default=SinkBackendChoices.NEO4J,
821822
max_length=16,
822823
)

api/src/backend/tasks/tests/test_attack_paths_scan.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
from datetime import UTC, datetime, timedelta
33
from types import SimpleNamespace
44
from unittest.mock import MagicMock, call, patch
5+
from uuid import uuid4
56

67
import pytest
8+
from api.db_utils import rls_transaction
79
from api.models import (
810
AttackPathsScan,
911
Finding,
@@ -15,6 +17,7 @@
1517
StatusChoices,
1618
Task,
1719
)
20+
from django.db import DEFAULT_DB_ALIAS
1821
from django_celery_results.models import TaskResult
1922
from prowler.lib.check.models import Severity
2023
from tasks.jobs.attack_paths import findings as findings_module
@@ -2244,6 +2247,58 @@ def test_analysis_zero_exposed_resources(self):
22442247
class TestAttackPathsDbUtilsGraphDataReady:
22452248
"""Tests for db_utils functions related to graph_data_ready lifecycle."""
22462249

2250+
def test_database_defaults_allow_legacy_insert_without_cutover_columns(
2251+
self, tenants_fixture, providers_fixture, scans_fixture
2252+
):
2253+
tenant = tenants_fixture[0]
2254+
provider = providers_fixture[0]
2255+
provider.provider = Provider.ProviderChoices.AWS
2256+
provider.save()
2257+
scan = scans_fixture[0]
2258+
scan.provider = provider
2259+
scan.save()
2260+
2261+
attack_paths_scan_id = uuid4()
2262+
now = datetime.now(tz=UTC)
2263+
2264+
with rls_transaction(str(tenant.id), using=DEFAULT_DB_ALIAS) as cursor:
2265+
cursor.execute(
2266+
"""
2267+
INSERT INTO attack_paths_scans (
2268+
id,
2269+
inserted_at,
2270+
updated_at,
2271+
state,
2272+
progress,
2273+
graph_data_ready,
2274+
started_at,
2275+
tenant_id,
2276+
provider_id,
2277+
scan_id
2278+
)
2279+
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
2280+
""",
2281+
[
2282+
attack_paths_scan_id,
2283+
now,
2284+
now,
2285+
StateChoices.SCHEDULED,
2286+
0,
2287+
False,
2288+
now,
2289+
tenant.id,
2290+
provider.id,
2291+
scan.id,
2292+
],
2293+
)
2294+
2295+
attack_paths_scan = AttackPathsScan.objects.get(id=attack_paths_scan_id)
2296+
2297+
assert attack_paths_scan.is_migrated is False
2298+
assert (
2299+
attack_paths_scan.sink_backend == AttackPathsScan.SinkBackendChoices.NEO4J
2300+
)
2301+
22472302
def test_create_attack_paths_scan_first_scan_defaults_to_false(
22482303
self, tenants_fixture, providers_fixture, scans_fixture
22492304
):

0 commit comments

Comments
 (0)