[Bug] Strip Non-Public Fields Prior to Uploading Rules (#2986)

This commit is contained in:
Mika Ayenson
2023-08-02 12:38:48 -05:00
committed by GitHub
parent 29fc61d55b
commit 3f9e7aced1
4 changed files with 34 additions and 28 deletions
+3 -10
View File
@@ -5,16 +5,16 @@
"""Kibana cli commands."""
import sys
import uuid
import click
import kql
from kibana import Signal, RuleResource
from .cli_utils import multi_collection
from .main import root
from .misc import add_params, client_error, kibana_options, get_kibana_client, nested_set
from .schemas import downgrade
from .rule import downgrade_contents_from_rule
from .utils import format_command_options
@@ -45,14 +45,7 @@ def upload_rule(ctx, rules, replace_id):
for rule in rules:
try:
payload = rule.contents.to_api_format()
payload.setdefault("meta", {}).update(rule.contents.metadata.to_dict())
if replace_id:
payload["rule_id"] = str(uuid.uuid4())
payload = downgrade(payload, target_version=kibana.version)
payload = downgrade_contents_from_rule(rule, kibana.version, replace_id=replace_id)
except ValueError as e:
client_error(f'{e} in version:{kibana.version}, for rule: {rule.name}', e, ctx=ctx)
+18 -7
View File
@@ -31,7 +31,8 @@ from .misc import load_current_package_version
from .mixins import MarshmallowDataclassMixin, StackCompatMixin
from .rule_formatter import nested_normalize, toml_write
from .schemas import (SCHEMA_DIR, definitions, downgrade,
get_min_supported_stack_version, get_stack_schemas)
get_min_supported_stack_version, get_stack_schemas,
strip_non_public_fields)
from .schemas.stack_compat import get_restricted_fields
from .utils import cached, convert_time_span, PatchedTemplate
@@ -1300,13 +1301,23 @@ class DeprecatedRule(dict):
return self.contents.name
def downgrade_contents_from_rule(rule: TOMLRule, target_version: str) -> dict:
def downgrade_contents_from_rule(rule: TOMLRule, target_version: str, replace_id: bool = True) -> dict:
"""Generate the downgraded contents from a rule."""
payload = rule.contents.to_api_format()
meta = payload.setdefault("meta", {})
meta["original"] = dict(id=rule.id, **rule.contents.metadata.to_dict())
payload["rule_id"] = str(uuid4())
payload = downgrade(payload, target_version)
rule_dict = rule.contents.to_dict()["rule"]
min_stack_version = target_version or rule.contents.metadata.min_stack_version or "8.3.0"
min_stack_version = Version.parse(min_stack_version,
optional_minor_and_patch=True)
rule_dict.setdefault("meta", {}).update(rule.contents.metadata.to_dict())
if replace_id:
rule_dict["rule_id"] = str(uuid4())
rule_dict = downgrade(rule_dict, target_version=str(min_stack_version))
meta = rule_dict.pop("meta")
rule_contents = TOMLRuleContents.from_dict({"rule": rule_dict, "metadata": meta,
"transform": rule.contents.transform})
payload = rule_contents.to_api_format()
payload = strip_non_public_fields(min_stack_version, payload)
return payload
+7 -11
View File
@@ -65,9 +65,6 @@ def get_schema_file(version: Version, rule_type: str) -> dict:
def strip_additional_properties(version: Version, api_contents: dict) -> dict:
"""Remove all fields that the target schema doesn't recognize."""
if Version.parse(version, optional_minor_and_patch=True) >= Version.parse("8.3.0"):
api_contents = strip_build_time_fields(api_contents)
stripped = {}
target_schema = get_schema_file(version, api_contents["type"])
@@ -80,14 +77,13 @@ def strip_additional_properties(version: Version, api_contents: dict) -> dict:
return stripped
def strip_build_time_fields(api_contents: dict) -> dict:
"""Remove all fields that are only used at build time."""
contents = api_contents.copy()
if "related_integrations" in contents:
del contents["related_integrations"]
if "required_fields" in contents:
del contents["required_fields"]
return contents
def strip_non_public_fields(min_stack_version: Version, data_dict: dict) -> dict:
"""Remove all non public fields."""
for field, version_range in definitions.NON_PUBLIC_FIELDS.items():
if version_range[0] <= min_stack_version <= (version_range[1] or min_stack_version):
if field in data_dict:
del data_dict[field]
return data_dict
@migrate("7.8")
+6
View File
@@ -9,6 +9,7 @@ from typing import List, Literal, Final
from marshmallow import validate
from marshmallow_dataclass import NewType
from semver import Version
ASSET_TYPE = "security_rule"
SAVED_OBJECT_TYPE = "security-rule"
@@ -28,6 +29,11 @@ MINOR_SEMVER = r'^\d+\.\d+$'
BRANCH_PATTERN = f'{VERSION_PATTERN}|^master$'
NON_DATASET_PACKAGES = ['apm', 'endpoint', 'system', 'windows', 'cloud_defend', 'network_traffic']
NON_PUBLIC_FIELDS = {
"related_integrations": (Version.parse('8.3.0'), None),
"required_fields": (Version.parse('8.3.0'), None),
"setup": (Version.parse('8.3.0'), None)
}
INTERVAL_PATTERN = r'^\d+[mshd]$'
TACTIC_URL = r'^https://attack.mitre.org/tactics/TA[0-9]+/$'
TECHNIQUE_URL = r'^https://attack.mitre.org/techniques/T[0-9]+/$'