Skip to content

Commit 5d4415d

Browse files
authored
feat(mute-rules): Support simple muting in API (#9051)
1 parent 5d84038 commit 5d4415d

File tree

15 files changed

+2874
-7
lines changed

15 files changed

+2874
-7
lines changed

api/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ All notable changes to the **Prowler API** are documented in this file.
1010
- Support for configuring multiple LLM providers [(#8772)](https://github.com/prowler-cloud/prowler/pull/8772)
1111
- Support C5 compliance framework for Azure provider [(#9081)](https://github.com/prowler-cloud/prowler/pull/9081)
1212
- Support for Oracle Cloud Infrastructure (OCI) provider [(#8927)](https://github.com/prowler-cloud/prowler/pull/8927)
13+
- Support muting findings based on simple rules with custom reason [(#9051)](https://github.com/prowler-cloud/prowler/pull/9051)
1314
- Support C5 compliance framework for the GCP provider [(#9097)](https://github.com/prowler-cloud/prowler/pull/9097)
1415

1516
## [1.14.1] (Prowler 5.13.1)

api/src/backend/api/filters.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
LighthouseProviderConfiguration,
3131
LighthouseProviderModels,
3232
Membership,
33+
MuteRule,
3334
OverviewStatusChoices,
3435
PermissionChoices,
3536
Processor,
@@ -980,3 +981,20 @@ class Meta:
980981
fields = {
981982
"model_id": ["exact", "icontains", "in"],
982983
}
984+
985+
986+
class MuteRuleFilter(FilterSet):
987+
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
988+
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
989+
created_by = UUIDFilter(field_name="created_by__id", lookup_expr="exact")
990+
991+
class Meta:
992+
model = MuteRule
993+
fields = {
994+
"id": ["exact", "in"],
995+
"name": ["exact", "icontains"],
996+
"reason": ["icontains"],
997+
"enabled": ["exact"],
998+
"inserted_at": ["gte", "lte"],
999+
"updated_at": ["gte", "lte"],
1000+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Generated by Django 5.1.13 on 2025-10-22 11:56
2+
3+
import uuid
4+
5+
import django.contrib.postgres.fields
6+
import django.core.validators
7+
import django.db.models.deletion
8+
from django.conf import settings
9+
from django.db import migrations, models
10+
11+
import api.rls
12+
13+
14+
class Migration(migrations.Migration):
15+
dependencies = [
16+
("api", "0051_oraclecloud_provider"),
17+
]
18+
19+
operations = [
20+
migrations.CreateModel(
21+
name="MuteRule",
22+
fields=[
23+
(
24+
"id",
25+
models.UUIDField(
26+
default=uuid.uuid4,
27+
editable=False,
28+
primary_key=True,
29+
serialize=False,
30+
),
31+
),
32+
("inserted_at", models.DateTimeField(auto_now_add=True)),
33+
("updated_at", models.DateTimeField(auto_now=True)),
34+
(
35+
"name",
36+
models.CharField(
37+
help_text="Human-readable name for this rule",
38+
max_length=100,
39+
validators=[django.core.validators.MinLengthValidator(3)],
40+
),
41+
),
42+
(
43+
"reason",
44+
models.TextField(
45+
help_text="Reason for muting",
46+
max_length=500,
47+
validators=[django.core.validators.MinLengthValidator(3)],
48+
),
49+
),
50+
(
51+
"enabled",
52+
models.BooleanField(
53+
default=True, help_text="Whether this rule is currently enabled"
54+
),
55+
),
56+
(
57+
"finding_uids",
58+
django.contrib.postgres.fields.ArrayField(
59+
base_field=models.CharField(max_length=255),
60+
help_text="List of finding UIDs to mute",
61+
size=None,
62+
),
63+
),
64+
],
65+
options={
66+
"db_table": "mute_rules",
67+
"abstract": False,
68+
},
69+
),
70+
migrations.AddField(
71+
model_name="finding",
72+
name="muted_at",
73+
field=models.DateTimeField(
74+
blank=True, help_text="Timestamp when this finding was muted", null=True
75+
),
76+
),
77+
migrations.AlterField(
78+
model_name="tenantapikey",
79+
name="name",
80+
field=models.CharField(
81+
max_length=100,
82+
validators=[django.core.validators.MinLengthValidator(3)],
83+
),
84+
),
85+
migrations.AddField(
86+
model_name="muterule",
87+
name="created_by",
88+
field=models.ForeignKey(
89+
help_text="User who created this rule",
90+
null=True,
91+
on_delete=django.db.models.deletion.SET_NULL,
92+
related_name="created_mute_rules",
93+
to=settings.AUTH_USER_MODEL,
94+
),
95+
),
96+
migrations.AddField(
97+
model_name="muterule",
98+
name="tenant",
99+
field=models.ForeignKey(
100+
on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
101+
),
102+
),
103+
migrations.AddConstraint(
104+
model_name="muterule",
105+
constraint=api.rls.RowLevelSecurityConstraint(
106+
"tenant_id",
107+
name="rls_on_muterule",
108+
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
109+
),
110+
),
111+
migrations.AddConstraint(
112+
model_name="muterule",
113+
constraint=models.UniqueConstraint(
114+
fields=("tenant_id", "name"), name="unique_mute_rule_name_per_tenant"
115+
),
116+
),
117+
]

api/src/backend/api/models.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,9 @@ class DeltaChoices(models.TextChoices):
823823
muted_reason = models.TextField(
824824
blank=True, null=True, validators=[MinLengthValidator(3)], max_length=500
825825
)
826+
muted_at = models.DateTimeField(
827+
null=True, blank=True, help_text="Timestamp when this finding was muted"
828+
)
826829
compliance = models.JSONField(default=dict, null=True, blank=True)
827830

828831
# Denormalize resource data for performance
@@ -1935,6 +1938,59 @@ class JSONAPIMeta:
19351938
resource_name = "lighthouse-configurations"
19361939

19371940

1941+
class MuteRule(RowLevelSecurityProtectedModel):
1942+
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
1943+
inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
1944+
updated_at = models.DateTimeField(auto_now=True, editable=False)
1945+
1946+
# Rule metadata
1947+
name = models.CharField(
1948+
max_length=100,
1949+
validators=[MinLengthValidator(3)],
1950+
help_text="Human-readable name for this rule",
1951+
)
1952+
reason = models.TextField(
1953+
validators=[MinLengthValidator(3)],
1954+
max_length=500,
1955+
help_text="Reason for muting",
1956+
)
1957+
enabled = models.BooleanField(
1958+
default=True, help_text="Whether this rule is currently enabled"
1959+
)
1960+
1961+
# Audit fields
1962+
created_by = models.ForeignKey(
1963+
User,
1964+
on_delete=models.SET_NULL,
1965+
null=True,
1966+
related_name="created_mute_rules",
1967+
help_text="User who created this rule",
1968+
)
1969+
1970+
# Rule criteria - array of finding UIDs
1971+
finding_uids = ArrayField(
1972+
models.CharField(max_length=255), help_text="List of finding UIDs to mute"
1973+
)
1974+
1975+
class Meta(RowLevelSecurityProtectedModel.Meta):
1976+
db_table = "mute_rules"
1977+
1978+
constraints = [
1979+
RowLevelSecurityConstraint(
1980+
field="tenant_id",
1981+
name="rls_on_%(class)s",
1982+
statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
1983+
),
1984+
models.UniqueConstraint(
1985+
fields=("tenant_id", "name"),
1986+
name="unique_mute_rule_name_per_tenant",
1987+
),
1988+
]
1989+
1990+
class JSONAPIMeta:
1991+
resource_name = "mute-rules"
1992+
1993+
19381994
class Processor(RowLevelSecurityProtectedModel):
19391995
class ProcessorChoices(models.TextChoices):
19401996
MUTELIST = "mutelist", _("Mutelist")

0 commit comments

Comments
 (0)