Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
898defc
[FR] Support Multi-Dataset Sequence Validation
Mikaayenson Sep 3, 2025
991ba7c
Add test for multiple integrations in a query
Mikaayenson Sep 3, 2025
32dd5f8
Add additional test cases
Mikaayenson Sep 3, 2025
9229c52
leverage eql to validate subquery with synthetic sequence
Mikaayenson Sep 4, 2025
6cf6665
Add additional unit test
Mikaayenson Sep 5, 2025
468c377
refactor related integration validation
Mikaayenson Sep 5, 2025
5bd2d79
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 5, 2025
50bd0bd
cleanup group by logic
Mikaayenson Sep 5, 2025
c29d07a
Merge branch 'support-multidatasource-eql-integration-queries' of git…
Mikaayenson Sep 5, 2025
cfc7364
refactor schema validation
Mikaayenson Sep 6, 2025
4ff77e7
minor bump
Mikaayenson Sep 6, 2025
da68568
add mapping for winlog
Mikaayenson Sep 8, 2025
908100b
add o365.audit.ExtendedProperties.RequestType to non-ecs-schema
Mikaayenson Sep 8, 2025
b5a6156
skip kql validation for stack combos when beats/endgame arent included.
Mikaayenson Sep 8, 2025
748373d
add problemchild fields to winlog non-ecs-schema
Mikaayenson Sep 8, 2025
721e496
add winlog fields to non-ecs-schema
Mikaayenson Sep 8, 2025
061c4cc
better error messages
Mikaayenson Sep 8, 2025
37a4593
Update non-ecs-schema.json
Aegrah Sep 9, 2025
ee35586
add more auditbeat fields to non-ecs
Mikaayenson Sep 9, 2025
4bfe850
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 9, 2025
890e208
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 9, 2025
9708ddc
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 10, 2025
d91afd9
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 10, 2025
7c00fc9
remove old test case
Mikaayenson Sep 10, 2025
0db8038
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 10, 2025
7a9768f
lint
Mikaayenson Sep 10, 2025
0714f67
adjust type hint
Mikaayenson Sep 10, 2025
91b87e7
build schemas on each retry
Mikaayenson Sep 10, 2025
b5a5b82
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 10, 2025
3350063
Merge branch 'main' into support-multidatasource-eql-integration-queries
Mikaayenson Sep 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions detection_rules/beats.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,20 @@ def get_beats_sub_schema(schema: dict[str, Any], beat: str, module: str, *datase

flattened: list[dict[str, Any]] = []
beat_dir = schema[beat]
module_dir = beat_dir.get("folders", {}).get("module", {}).get("folders", {}).get(module, {})
# Normalize module name in case callers include quotes from rendered AST
normalized_module = module.strip("\"' ")
module_dir = beat_dir.get("folders", {}).get("module", {}).get("folders", {}).get(normalized_module, {})

# if we only have a module then we'll work with what we got
all_datasets = datasets if datasets else [d for d in module_dir.get("folders", {}) if not d.startswith("_")]

for _dataset in all_datasets:
# replace aws.s3 -> s3
dataset = _dataset[len(module) + 1 :] if _dataset.startswith(module + ".") else _dataset
ds = _dataset.strip("\"' ")
dataset = ds[len(normalized_module) + 1 :] if ds.startswith(normalized_module + ".") else ds

dataset_dir = module_dir.get("folders", {}).get(dataset, {})
flattened.extend(get_field_schema(dataset_dir, prefix=module + ".", include_common=True))
flattened.extend(get_field_schema(dataset_dir, prefix=normalized_module + ".", include_common=True))

# we also need to capture (beta?) fields which are directly within the module _meta.files.fields
flattened.extend(get_field_schema(module_dir, include_common=True))
Expand Down Expand Up @@ -268,11 +271,11 @@ def get_datasets_and_modules(tree: eql.ast.BaseNode | kql.ast.BaseNode) -> tuple
and isinstance(node.right, eql.ast.String)
):
if node.left == eql.ast.Field("event", ["module"]):
modules.add(node.right.render()) # type: ignore[reportUnknownMemberType]
modules.add(node.right.value) # type: ignore[reportUnknownMemberType]
elif node.left == eql.ast.Field("event", ["dataset"]) or node.left == eql.ast.Field(
"data_stream", ["dataset"]
):
datasets.add(node.right.render()) # type: ignore[reportUnknownMemberType]
datasets.add(node.right.value) # type: ignore[reportUnknownMemberType]
elif isinstance(node, eql.ast.InSet):
if node.expression == eql.ast.Field("event", ["module"]):
modules.update(node.get_literals()) # type: ignore[reportUnknownMemberType]
Expand Down
16 changes: 15 additions & 1 deletion detection_rules/etc/non-ecs-schema.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"auditbeat-*": {
"auditd.data.addr": "keyword",
"auditd.data.grantors": "keyword",
"auditd.data.syscall": "keyword",
"auditd.data.terminal": "keyword",
"auditd.result": "keyword"
},
"endgame-*": {
"endgame": {
"metadata": {
Expand All @@ -8,6 +15,9 @@
}
},
"winlogbeat-*": {
"problemchild.prediction": "long",
"problemchild.prediction_probability": "long",
"blocklist_label": "long",
"winlog": {
"event_data": {
"AccessList": "keyword",
Expand All @@ -17,6 +27,7 @@
"AllowedToDelegateTo": "keyword",
"AttributeLDAPDisplayName": "keyword",
"AttributeValue": "keyword",
"AuditPolicyChangesDescription": "keyword",
"CallerProcessName": "keyword",
"CallTrace": "keyword",
"ClientProcessId": "keyword",
Expand Down Expand Up @@ -57,7 +68,9 @@
"Status": "keyword",
"EnabledPrivilegeList": "keyword",
"Operation": "keyword",
"OperationType": "keyword"
"OperationType": "keyword",
"NewUACList": "keyword",
"SubCategory": "keyword"
}
},
"winlog.logon.type": "keyword",
Expand Down Expand Up @@ -199,6 +212,7 @@
"azure.platformlogs.properties.id": "keyword"
},
"logs-o365.audit-*": {
"o365.audit.ExtendedProperties.RequestType": "keyword",
"o365.audit.ExtendedProperties.ResultStatusDetail": "keyword",
"o365.audit.OperationProperties.Name": "keyword",
"o365.audit.OperationProperties.Value": "keyword",
Expand Down
4 changes: 2 additions & 2 deletions detection_rules/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,8 @@ def get_beats_schema(
@cached
def get_endgame_schema(self, indices: list[str], endgame_version: str) -> endgame.EndgameSchema | None:
"""Get an assembled flat endgame schema."""

if indices and "endgame-*" not in indices:
# Only include endgame when explicitly requested by TOML via indices
if not indices or "endgame-*" not in indices:
return None

endgame_schema = endgame.read_endgame_schema(endgame_version=endgame_version)
Expand Down
Loading
Loading