-
Notifications
You must be signed in to change notification settings - Fork 611
[FR] [DAC] Add Arbitrary File location Support for Local Creation Date #4915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
ce4b940
6b363b5
8eab808
56767c6
e8380de
3e2222b
c2d17d6
e463e3a
7d85b16
3348a06
4c244c4
500152b
252cae0
3a0017b
7d57e73
276f3dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ | |
| import re | ||
| import sys | ||
| from pathlib import Path | ||
| from typing import Any | ||
| from typing import Any, cast | ||
|
|
||
| import click | ||
| import kql # type: ignore[reportMissingTypeStubs] | ||
|
|
@@ -28,6 +28,7 @@ | |
| from .misc import add_params, get_kibana_client, kibana_options, nested_set, raise_client_error | ||
| from .rule import TOMLRule, TOMLRuleContents, downgrade_contents_from_rule | ||
| from .rule_loader import RuleCollection, update_metadata_from_file | ||
| from .schemas import definitions # noqa: TC001 | ||
| from .utils import format_command_options, rulename_to_filename | ||
|
|
||
| RULES_CONFIG = parse_rules_config() | ||
|
|
@@ -250,6 +251,12 @@ def _process_imported_items( | |
| '"alert.attributes.tags: \\"test\\"" to filter for rules that have the tag "test"' | ||
| ), | ||
| ) | ||
| @click.option( | ||
| "--load-rule-loading", | ||
| "-lr", | ||
| is_flag=True, | ||
| help="Enable arbitrary rule loading from the rules directories (Can be very slow!)", | ||
| ) | ||
| @click.pass_context | ||
| def kibana_export_rules( # noqa: PLR0912, PLR0913, PLR0915 | ||
| ctx: click.Context, | ||
|
|
@@ -268,6 +275,7 @@ def kibana_export_rules( # noqa: PLR0912, PLR0913, PLR0915 | |
| local_updated_date: bool = False, | ||
| custom_rules_only: bool = False, | ||
| export_query: str | None = None, | ||
| load_rule_loading: bool = False, | ||
| ) -> list[TOMLRule]: | ||
| """Export custom rules from Kibana.""" | ||
| kibana = ctx.obj["kibana"] | ||
|
|
@@ -277,6 +285,10 @@ def kibana_export_rules( # noqa: PLR0912, PLR0913, PLR0915 | |
| if rule_name and rule_id: | ||
| raise click.UsageError("Cannot use --rule-id and --rule-name together. Please choose one.") | ||
|
|
||
| rules = None | ||
| if load_rule_loading: | ||
| rules = RuleCollection.default() | ||
|
|
||
| with kibana: | ||
| # Look up rule IDs by name if --rule-name was provided | ||
| if rule_name: | ||
|
|
@@ -358,10 +370,24 @@ def kibana_export_rules( # noqa: PLR0912, PLR0913, PLR0915 | |
| tactic_name = first_tactic if not no_tactic_filename else None # type: ignore[reportUnknownMemberType] | ||
| rule_name = rulename_to_filename(rule_resource.get("name"), tactic_name=tactic_name) # type: ignore[reportUnknownMemberType] | ||
|
|
||
| local_contents = None | ||
| save_path = directory / f"{rule_name}" | ||
|
|
||
| # Get local rule data if load_rule_loading is enabled. If not enabled rules variable will be None. | ||
| local_rule: dict[str, Any] = params.get("rule", {}) | ||
| input_rule_id: str | None = None | ||
|
|
||
| if local_rule: | ||
| input_rule_id = cast("definitions.UUIDString", local_rule.get("rule_id")) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May want to switch to constructor here. (request from peer review)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just as a note, cast is more performant (as it does not create a UUID string object whereas the constructor would). Additionally, there is no constructor for the UUIDString type in definitions. UUIDString is an alias and as such does not have a constructor. |
||
|
|
||
| if rules and input_rule_id and input_rule_id in rules.id_map: | ||
| save_path = rules.id_map[input_rule_id].path | ||
| local_contents = rules.id_map[input_rule_id].contents | ||
| params.update( | ||
| update_metadata_from_file( | ||
| save_path, {"creation_date": local_creation_date, "updated_date": local_updated_date} | ||
| {"creation_date": local_creation_date, "updated_date": local_updated_date}, | ||
| save_path, | ||
| local_contents, | ||
| ) | ||
| ) | ||
| contents = TOMLRuleContents.from_rule_resource(**params) # type: ignore[reportArgumentType] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -139,17 +139,24 @@ def load_locks_from_tag( | |
| return commit_hash, version, deprecated | ||
|
|
||
|
|
||
| def update_metadata_from_file(rule_path: Path, fields_to_update: dict[str, Any]) -> dict[str, Any]: | ||
| """Update metadata fields for a rule with local contents.""" | ||
| def update_metadata_from_file( | ||
| fields_to_update: dict[str, Any], rule_path: Path | None = None, local_contents: TOMLRuleContents | None = None | ||
| ) -> dict[str, Any]: | ||
| """Update metadata fields for a rule with local contents or provided contents.""" | ||
|
|
||
| contents: dict[str, Any] = {} | ||
| if not rule_path.exists(): | ||
| return contents | ||
| if not rule_path and not local_contents: | ||
| raise ValueError("Either 'rule_path' or 'local_contents' must be provided.") | ||
|
||
|
|
||
| rule_contents = RuleCollection().load_file(rule_path).contents | ||
| # If local_contents is provided, always prefer it vs loading from rule_path | ||
| rule_contents = None or local_contents | ||
| if rule_path and not rule_contents: | ||
| if not rule_path.exists(): | ||
| return contents | ||
| rule_contents = RuleCollection().load_file(rule_path).contents | ||
|
|
||
| if not isinstance(rule_contents, TOMLRuleContents): | ||
| raise TypeError("TOML rule expected") | ||
| raise TypeError("TOMLRuleContents expected") | ||
|
|
||
| local_metadata = rule_contents.metadata.to_dict() | ||
| if local_metadata: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.