Skip to content

Commit c812e28

Browse files
api-clients-generation-pipeline[bot]ci.datadog-api-spec
andauthored
Add SDS rule should_save_match field (#2791)
Co-authored-by: ci.datadog-api-spec <[email protected]>
1 parent d34602c commit c812e28

File tree

7 files changed

+187
-2
lines changed

7 files changed

+187
-2
lines changed

.generated-info

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"spec_repo_commit": "98e3371",
3-
"generated": "2025-08-27 08:45:21.765"
2+
"spec_repo_commit": "62a19e4",
3+
"generated": "2025-08-27 15:01:27.781"
44
}

.generator/schemas/v2/openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39445,6 +39445,12 @@ components:
3944539445
replacement_string:
3944639446
description: Required if type == 'replacement_string'.
3944739447
type: string
39448+
should_save_match:
39449+
description: "Only valid when type == `replacement_string`. When enabled,
39450+
matches can be unmasked in logs by users with \u2018Data Scanner Unmask\u2019
39451+
permission. As a security best practice, avoid masking for highly-sensitive,
39452+
long-lived data."
39453+
type: boolean
3944839454
type:
3944939455
$ref: '#/components/schemas/SensitiveDataScannerTextReplacementType'
3945039456
type: object
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
Create Scanning Rule with should_save_match returns "OK" response
3+
"""
4+
5+
from os import environ
6+
from datadog_api_client import ApiClient, Configuration
7+
from datadog_api_client.v2.api.sensitive_data_scanner_api import SensitiveDataScannerApi
8+
from datadog_api_client.v2.model.sensitive_data_scanner_group import SensitiveDataScannerGroup
9+
from datadog_api_client.v2.model.sensitive_data_scanner_group_data import SensitiveDataScannerGroupData
10+
from datadog_api_client.v2.model.sensitive_data_scanner_group_type import SensitiveDataScannerGroupType
11+
from datadog_api_client.v2.model.sensitive_data_scanner_meta_version_only import SensitiveDataScannerMetaVersionOnly
12+
from datadog_api_client.v2.model.sensitive_data_scanner_rule_attributes import SensitiveDataScannerRuleAttributes
13+
from datadog_api_client.v2.model.sensitive_data_scanner_rule_create import SensitiveDataScannerRuleCreate
14+
from datadog_api_client.v2.model.sensitive_data_scanner_rule_create_request import SensitiveDataScannerRuleCreateRequest
15+
from datadog_api_client.v2.model.sensitive_data_scanner_rule_relationships import SensitiveDataScannerRuleRelationships
16+
from datadog_api_client.v2.model.sensitive_data_scanner_rule_type import SensitiveDataScannerRuleType
17+
from datadog_api_client.v2.model.sensitive_data_scanner_text_replacement import SensitiveDataScannerTextReplacement
18+
from datadog_api_client.v2.model.sensitive_data_scanner_text_replacement_type import (
19+
SensitiveDataScannerTextReplacementType,
20+
)
21+
22+
# there is a valid "scanning_group" in the system
23+
GROUP_DATA_ID = environ["GROUP_DATA_ID"]
24+
25+
body = SensitiveDataScannerRuleCreateRequest(
26+
meta=SensitiveDataScannerMetaVersionOnly(),
27+
data=SensitiveDataScannerRuleCreate(
28+
type=SensitiveDataScannerRuleType.SENSITIVE_DATA_SCANNER_RULE,
29+
attributes=SensitiveDataScannerRuleAttributes(
30+
name="Example-Sensitive-Data-Scanner",
31+
pattern="pattern",
32+
text_replacement=SensitiveDataScannerTextReplacement(
33+
type=SensitiveDataScannerTextReplacementType.REPLACEMENT_STRING,
34+
replacement_string="REDACTED",
35+
should_save_match=True,
36+
),
37+
tags=[
38+
"sensitive_data:true",
39+
],
40+
is_enabled=True,
41+
priority=1,
42+
),
43+
relationships=SensitiveDataScannerRuleRelationships(
44+
group=SensitiveDataScannerGroupData(
45+
data=SensitiveDataScannerGroup(
46+
type=SensitiveDataScannerGroupType.SENSITIVE_DATA_SCANNER_GROUP,
47+
id=GROUP_DATA_ID,
48+
),
49+
),
50+
),
51+
),
52+
)
53+
54+
configuration = Configuration()
55+
with ApiClient(configuration) as api_client:
56+
api_instance = SensitiveDataScannerApi(api_client)
57+
response = api_instance.create_scanning_rule(body=body)
58+
59+
print(response)

src/datadog_api_client/v2/model/sensitive_data_scanner_text_replacement.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,22 @@ def openapi_types(_):
3535
return {
3636
"number_of_chars": (int,),
3737
"replacement_string": (str,),
38+
"should_save_match": (bool,),
3839
"type": (SensitiveDataScannerTextReplacementType,),
3940
}
4041

4142
attribute_map = {
4243
"number_of_chars": "number_of_chars",
4344
"replacement_string": "replacement_string",
45+
"should_save_match": "should_save_match",
4446
"type": "type",
4547
}
4648

4749
def __init__(
4850
self_,
4951
number_of_chars: Union[int, UnsetType] = unset,
5052
replacement_string: Union[str, UnsetType] = unset,
53+
should_save_match: Union[bool, UnsetType] = unset,
5154
type: Union[SensitiveDataScannerTextReplacementType, UnsetType] = unset,
5255
**kwargs,
5356
):
@@ -61,6 +64,9 @@ def __init__(
6164
:param replacement_string: Required if type == 'replacement_string'.
6265
:type replacement_string: str, optional
6366
67+
:param should_save_match: Only valid when type == ``replacement_string``. When enabled, matches can be unmasked in logs by users with ‘Data Scanner Unmask’ permission. As a security best practice, avoid masking for highly-sensitive, long-lived data.
68+
:type should_save_match: bool, optional
69+
6470
:param type: Type of the replacement text. None means no replacement.
6571
hash means the data will be stubbed. replacement_string means that
6672
one can chose a text to replace the data. partial_replacement_from_beginning
@@ -73,6 +79,8 @@ def __init__(
7379
kwargs["number_of_chars"] = number_of_chars
7480
if replacement_string is not unset:
7581
kwargs["replacement_string"] = replacement_string
82+
if should_save_match is not unset:
83+
kwargs["should_save_match"] = should_save_match
7684
if type is not unset:
7785
kwargs["type"] = type
7886
super().__init__(kwargs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2025-08-26T20:31:44.042Z
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
accept:
6+
- application/json
7+
method: GET
8+
uri: https://api.datadoghq.com/api/v2/sensitive-data-scanner/config
9+
response:
10+
body:
11+
string: '{"data":{"id":"7957915c634d4dcb581fa154157f5ad9c2947f50be632fb5599862069f4d2d87","attributes":{},"type":"sensitive_data_scanner_configuration","relationships":{"groups":{"data":[]}}},"meta":{"version":275277,"count_limit":250,"group_count_limit":20,"is_pci_compliant":false,"has_highlight_enabled":true,"has_multi_pass_enabled":true,"has_cascading_enabled":false,"is_configuration_superseded":false,"is_float_sampling_rate_enabled":false,"min_sampling_rate":10.0}}
12+
13+
'
14+
headers:
15+
content-type:
16+
- application/json
17+
status:
18+
code: 200
19+
message: OK
20+
- request:
21+
body: '{"data":{"attributes":{"filter":{"query":"*"},"is_enabled":false,"name":"my-test-group","product_list":["logs"],"samplings":[{"product":"logs","rate":100}]},"relationships":{"configuration":{"data":{"id":"7957915c634d4dcb581fa154157f5ad9c2947f50be632fb5599862069f4d2d87","type":"sensitive_data_scanner_configuration"}},"rules":{"data":[]}},"type":"sensitive_data_scanner_group"},"meta":{}}'
22+
headers:
23+
accept:
24+
- application/json
25+
content-type:
26+
- application/json
27+
method: POST
28+
uri: https://api.datadoghq.com/api/v2/sensitive-data-scanner/config/groups
29+
response:
30+
body:
31+
string: '{"data":{"id":"18cc2267-f3cc-4c15-917d-d3efb15deb03","attributes":{"name":"my-test-group","is_enabled":false,"filter":{"query":"*"},"product_list":["logs"],"samplings":[{"product":"logs","rate":100.0}]},"type":"sensitive_data_scanner_group","relationships":{"configuration":{"data":{"id":"7957915c634d4dcb581fa154157f5ad9c2947f50be632fb5599862069f4d2d87","type":"sensitive_data_scanner_configuration"}},"rules":{"data":[]}}},"meta":{"version":275278}}
32+
33+
'
34+
headers:
35+
content-type:
36+
- application/json
37+
status:
38+
code: 200
39+
message: OK
40+
- request:
41+
body: '{"data":{"attributes":{"is_enabled":true,"name":"Test-Create_Scanning_Rule_with_should_save_match_returns_OK_response-1756240304","pattern":"pattern","priority":1,"tags":["sensitive_data:true"],"text_replacement":{"replacement_string":"REDACTED","should_save_match":true,"type":"replacement_string"}},"relationships":{"group":{"data":{"id":"18cc2267-f3cc-4c15-917d-d3efb15deb03","type":"sensitive_data_scanner_group"}}},"type":"sensitive_data_scanner_rule"},"meta":{}}'
42+
headers:
43+
accept:
44+
- application/json
45+
content-type:
46+
- application/json
47+
method: POST
48+
uri: https://api.datadoghq.com/api/v2/sensitive-data-scanner/config/rules
49+
response:
50+
body:
51+
string: '{"data":{"id":"0e517b8a-04c1-4ae0-b57b-22b8e081190c","attributes":{"name":"Test-Create_Scanning_Rule_with_should_save_match_returns_OK_response-1756240304","namespaces":[],"excluded_namespaces":[],"pattern":"pattern","text_replacement":{"replacement_string":"REDACTED","should_save_match":true,"type":"replacement_string"},"tags":["sensitive_data:true"],"labels":[],"is_enabled":true,"priority":1},"type":"sensitive_data_scanner_rule","relationships":{"group":{"data":{"id":"18cc2267-f3cc-4c15-917d-d3efb15deb03","type":"sensitive_data_scanner_group"}}}},"meta":{"version":275279}}
52+
53+
'
54+
headers:
55+
content-type:
56+
- application/json
57+
status:
58+
code: 200
59+
message: OK
60+
- request:
61+
body: '{"meta":{}}'
62+
headers:
63+
accept:
64+
- application/json
65+
content-type:
66+
- application/json
67+
method: DELETE
68+
uri: https://api.datadoghq.com/api/v2/sensitive-data-scanner/config/rules/0e517b8a-04c1-4ae0-b57b-22b8e081190c
69+
response:
70+
body:
71+
string: '{"meta":{"version":275280}}
72+
73+
'
74+
headers:
75+
content-type:
76+
- application/json
77+
status:
78+
code: 200
79+
message: OK
80+
- request:
81+
body: '{"meta":{}}'
82+
headers:
83+
accept:
84+
- application/json
85+
content-type:
86+
- application/json
87+
method: DELETE
88+
uri: https://api.datadoghq.com/api/v2/sensitive-data-scanner/config/groups/18cc2267-f3cc-4c15-917d-d3efb15deb03
89+
response:
90+
body:
91+
string: '{"meta":{"version":275281}}
92+
93+
'
94+
headers:
95+
content-type:
96+
- application/json
97+
status:
98+
code: 200
99+
message: OK
100+
version: 1

tests/v2/features/sensitive_data_scanner.feature

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ Feature: Sensitive Data Scanner
5050
And the response "data.attributes.included_keyword_configuration.character_count" is equal to 35
5151
And the response "data.attributes.included_keyword_configuration.keywords[0]" is equal to "credit card"
5252

53+
@team:DataDog/sensitive-data-scanner
54+
Scenario: Create Scanning Rule with should_save_match returns "OK" response
55+
Given a valid "configuration" in the system
56+
And there is a valid "scanning_group" in the system
57+
And new "CreateScanningRule" request
58+
And body with value {"meta":{},"data":{"type":"sensitive_data_scanner_rule","attributes":{"name":"{{ unique }}","pattern":"pattern","text_replacement":{"type":"replacement_string","replacement_string":"REDACTED","should_save_match":true},"tags":["sensitive_data:true"],"is_enabled":true,"priority":1},"relationships":{"group":{"data":{"type":"{{ group.data.type }}","id":"{{ group.data.id }}"}}}}}
59+
When the request is sent
60+
Then the response status is 200 OK
61+
And the response "data.type" is equal to "sensitive_data_scanner_rule"
62+
And the response "data.attributes.name" is equal to "{{ unique }}"
63+
5364
@generated @skip @team:DataDog/sensitive-data-scanner
5465
Scenario: Delete Scanning Group returns "Bad Request" response
5566
Given new "DeleteScanningGroup" request

0 commit comments

Comments
 (0)