2024-08-06 18:07:12 -04:00
|
|
|
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
|
|
|
# or more contributor license agreements. Licensed under the Elastic License
|
|
|
|
|
# 2.0; you may not use this file except in compliance with the Elastic License
|
|
|
|
|
# 2.0.
|
|
|
|
|
|
|
|
|
|
"""Commands for supporting custom rules."""
|
2025-07-01 15:20:55 +02:00
|
|
|
|
2024-08-06 18:07:12 -04:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
import click
|
|
|
|
|
import yaml
|
2025-03-10 12:59:12 -04:00
|
|
|
from semver import Version
|
2024-08-06 18:07:12 -04:00
|
|
|
|
2025-03-07 14:34:51 +01:00
|
|
|
from .docs import REPO_DOCS_DIR
|
2025-03-10 12:59:12 -04:00
|
|
|
from .main import root
|
|
|
|
|
from .utils import ROOT_DIR, get_etc_path, load_etc_dump
|
2024-08-06 18:07:12 -04:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
DEFAULT_CONFIG_PATH = Path(get_etc_path(["_config.yaml"]))
|
|
|
|
|
CUSTOM_RULES_DOC_PATH = ROOT_DIR / REPO_DOCS_DIR / "custom-rules-management.md"
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
@root.group("custom-rules")
|
|
|
|
|
def custom_rules() -> None:
|
2024-08-06 18:07:12 -04:00
|
|
|
"""Commands for supporting custom rules."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_config_content() -> str:
|
|
|
|
|
"""Create the initial content for the _config.yaml file."""
|
|
|
|
|
# Base structure of the configuration
|
|
|
|
|
config_content = {
|
2025-07-01 15:20:55 +02:00
|
|
|
"rule_dirs": ["rules"],
|
|
|
|
|
"bbr_rules_dirs": ["rules_building_block"],
|
|
|
|
|
"directories": {
|
|
|
|
|
"action_dir": "actions",
|
|
|
|
|
"action_connector_dir": "action_connectors",
|
|
|
|
|
"exception_dir": "exceptions",
|
2024-08-06 18:07:12 -04:00
|
|
|
},
|
2025-07-01 15:20:55 +02:00
|
|
|
"files": {
|
|
|
|
|
"deprecated_rules": "etc/deprecated_rules.json",
|
|
|
|
|
"packages": "etc/packages.yaml",
|
|
|
|
|
"stack_schema_map": "etc/stack-schema-map.yaml",
|
|
|
|
|
"version_lock": "etc/version.lock.json",
|
2024-08-06 18:07:12 -04:00
|
|
|
},
|
2025-07-01 15:20:55 +02:00
|
|
|
"testing": {"config": "etc/test_config.yaml"},
|
2024-08-06 18:07:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return yaml.safe_dump(config_content, default_flow_style=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_test_config_content(enable_prebuilt_tests: bool) -> str:
|
|
|
|
|
"""Generate the content for the test_config.yaml with special content and references."""
|
|
|
|
|
|
|
|
|
|
def format_test_string(test_string: str, comment_char: str) -> str:
|
|
|
|
|
"""Generate a yaml formatted string with a comment character."""
|
|
|
|
|
return f"{comment_char} - {test_string}"
|
|
|
|
|
|
|
|
|
|
comment_char = "#" if enable_prebuilt_tests else ""
|
|
|
|
|
example_test_config_path = DEFAULT_CONFIG_PATH.parent.joinpath("example_test_config.yaml")
|
|
|
|
|
|
|
|
|
|
lines = [
|
|
|
|
|
"# For more details, refer to the example configuration:",
|
|
|
|
|
f"# {example_test_config_path}",
|
|
|
|
|
"# Define tests to explicitly bypass, with all others being run.",
|
|
|
|
|
"# To run all tests, set bypass to empty or leave this file commented out.",
|
|
|
|
|
"",
|
|
|
|
|
"unit_tests:",
|
|
|
|
|
" bypass:",
|
|
|
|
|
format_test_string("tests.test_gh_workflows.TestWorkflows.test_matrix_to_lock_version_defaults", comment_char),
|
|
|
|
|
format_test_string(
|
|
|
|
|
"tests.test_schemas.TestVersionLockSchema.test_version_lock_has_nested_previous", comment_char
|
|
|
|
|
),
|
|
|
|
|
format_test_string("tests.test_packages.TestRegistryPackage.test_registry_package_config", comment_char),
|
|
|
|
|
format_test_string("tests.test_all_rules.TestValidRules.test_schema_and_dupes", comment_char),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
@custom_rules.command("setup-config")
|
|
|
|
|
@click.argument("directory", type=Path)
|
|
|
|
|
@click.argument("kibana-version", type=str, default=load_etc_dump(["packages.yaml"])["package"]["name"])
|
|
|
|
|
@click.option("--overwrite", is_flag=True, help="Overwrite the existing _config.yaml file.")
|
2024-08-06 18:07:12 -04:00
|
|
|
@click.option(
|
|
|
|
|
"--enable-prebuilt-tests", "-e", is_flag=True, help="Enable all prebuilt tests instead of default subset."
|
|
|
|
|
)
|
2025-07-01 15:20:55 +02:00
|
|
|
def setup_config(directory: Path, kibana_version: str, overwrite: bool, enable_prebuilt_tests: bool) -> None:
|
2024-08-06 18:07:12 -04:00
|
|
|
"""Setup the custom rules configuration directory and files with defaults."""
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
config = directory / "_config.yaml"
|
2024-08-06 18:07:12 -04:00
|
|
|
if not overwrite and config.exists():
|
2025-07-01 15:20:55 +02:00
|
|
|
raise FileExistsError(f"{config} already exists. Use --overwrite to update")
|
2024-08-06 18:07:12 -04:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
etc_dir = directory / "etc"
|
|
|
|
|
test_config = etc_dir / "test_config.yaml"
|
|
|
|
|
package_config = etc_dir / "packages.yaml"
|
|
|
|
|
stack_schema_map_config = etc_dir / "stack-schema-map.yaml"
|
2024-08-06 18:07:12 -04:00
|
|
|
config_files = [
|
|
|
|
|
package_config,
|
|
|
|
|
stack_schema_map_config,
|
|
|
|
|
test_config,
|
|
|
|
|
config,
|
|
|
|
|
]
|
|
|
|
|
directories = [
|
2025-07-01 15:20:55 +02:00
|
|
|
directory / "actions",
|
|
|
|
|
directory / "action_connectors",
|
|
|
|
|
directory / "exceptions",
|
|
|
|
|
directory / "rules",
|
|
|
|
|
directory / "rules_building_block",
|
2024-08-06 18:07:12 -04:00
|
|
|
etc_dir,
|
|
|
|
|
]
|
|
|
|
|
version_files = [
|
2025-07-01 15:20:55 +02:00
|
|
|
etc_dir / "deprecated_rules.json",
|
|
|
|
|
etc_dir / "version.lock.json",
|
2024-08-06 18:07:12 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# Create directories
|
|
|
|
|
for dir_ in directories:
|
|
|
|
|
dir_.mkdir(parents=True, exist_ok=True)
|
2025-07-01 15:20:55 +02:00
|
|
|
click.echo(f"Created directory: {dir_}")
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
# Create version_files and populate with default content if applicable
|
|
|
|
|
for file_ in version_files:
|
2025-07-01 15:20:55 +02:00
|
|
|
_ = file_.write_text("{}")
|
|
|
|
|
click.echo(f"Created file with default content: {file_}")
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
# Create the stack-schema-map.yaml file
|
2025-07-01 15:20:55 +02:00
|
|
|
stack_schema_map_content = load_etc_dump(["stack-schema-map.yaml"])
|
2026-02-04 11:17:58 +01:00
|
|
|
latest_version = max(stack_schema_map_content.keys(), key=Version.parse)
|
2024-08-06 18:07:12 -04:00
|
|
|
latest_entry = {latest_version: stack_schema_map_content[latest_version]}
|
2025-07-01 15:20:55 +02:00
|
|
|
_ = stack_schema_map_config.write_text(yaml.safe_dump(latest_entry, default_flow_style=False))
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
# Create default packages.yaml
|
2025-07-01 15:20:55 +02:00
|
|
|
package_content = {"package": {"name": kibana_version}}
|
|
|
|
|
_ = package_config.write_text(yaml.safe_dump(package_content, default_flow_style=False))
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
# Create and configure test_config.yaml
|
2025-07-01 15:20:55 +02:00
|
|
|
_ = test_config.write_text(create_test_config_content(enable_prebuilt_tests))
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
# Create and configure _config.yaml
|
2025-07-01 15:20:55 +02:00
|
|
|
_ = config.write_text(create_config_content())
|
2024-08-06 18:07:12 -04:00
|
|
|
|
|
|
|
|
for file_ in config_files:
|
2025-07-01 15:20:55 +02:00
|
|
|
click.echo(f"Created file with default content: {file_}")
|
2024-08-06 18:07:12 -04:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
click.echo(
|
|
|
|
|
f"\n# For details on how to configure the _config.yaml file,\n"
|
|
|
|
|
f"# consult: {DEFAULT_CONFIG_PATH.resolve()}\n"
|
|
|
|
|
f"# or the docs: {CUSTOM_RULES_DOC_PATH.resolve()}"
|
|
|
|
|
)
|