Skip to content

add YAML schema and autocomplete snippet for detections #3612

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

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
90 changes: 90 additions & 0 deletions docs/yaml-spec/schema/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
### Objective

Enable schema validation and auto-completion for custom detection YAMLs within your forked repo, streamlining detection development and ensuring alignment with your own knowledge objects and detection standards.

### Motivation

The `contentctl new` CLI wrapper enforces strict keys and values, which can make it difficult to create meaningful detections tailored to your environment (e.g., macOS, GCP). This approach provides analysts with auto-complete functionality and dropdown options, making it easier to populate required fields and adapt detection logic to environment-specific assets.


| Step | Description |
| ---- | --------------------------------------------------------------------------------- |
| 1 | Create `.vscode/` folder to store project-specific editor settings |
| 2 | Add `schemas/detection.schema.json` for detection rule structure |
| 3 | Add `.vscode/settings.json` to link schema to detection YAML files |
| 4 | Install VSCode YAML Extension (Red Hat) for schema validation support |
| 5 | Create user snippet (`detection-snippets.code-snippets`) for a detection template |
| 6 | Test typing `newdetection` into a `.yml` file and validate schema enforcement |

#### Example Usage


https://github.com/user-attachments/assets/77ca2d9b-91f3-42a3-b34d-44fee325b892




### Setup Instructions

#### 1. Create the `.vscode/` Folder

* Open your local cloned detections repository in VSCode.
* Create a `.vscode/` folder at the root level:

```bash
mkdir .vscode
```
* Your folder structure should now include:

```
.vscode/
.github/
your_detections_repo/
README.md
```

#### 2. Add the Detection Schema

* Inside `.vscode/`, create a `schemas/` folder:

```bash
mkdir .vscode/schemas
```
* Add a file named `detection.schema.json` and populate it with your environment specifics.

#### 3. Link the Schema in VSCode Settings

* Under `.vscode/`, create `settings.json` and add:

```json
{
"yaml.schemas": {
"./.vscode/schemas/detection.schema.json": "path_to_where_your_detections_live/detections/cloud/*.yml"
}
}
```
* This applies the schema to any `.yml` files in the detections folder.

#### 4. Install the YAML Extension

* Open VSCode Extensions (`Ctrl+Shift+X`)
* Search for **YAML** by **Red Hat** and install it.
* This enables validation and autocomplete based on your schema.

#### 5. Create the Detection Template Snippet

* This will allow you to simply type `newdetection` in a new YAML file within your detections folder, and it will prepopulate this template for you. (Highly recommend to edit this as per your requirements)
* Enter `Cmd+Shift+P` in VScode
* Search for `Preferences: Configure User Snippets`
* Search for `New Global Snippets file`
* Name this file `detection-snippets.code-snippets`
* Or you can browse to the location on your local machine `/Users/<user>/Library/Application Support/Code/User/snippets`
* Add the `detection-snippets.code-snippets` to that location


#### 6. Test Your Setup

* Navigate to the detections folder and create a new YAML file.
* Type `newdetection` and use `Ctrl+Space` to trigger snippet suggestions.
* You should see schema validation and field descriptions by hovering over fields.

38 changes: 38 additions & 0 deletions docs/yaml-spec/schema/detection-snippets.code-snippets
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"New Detection YAML": {
"prefix": "newdetection",
"body": [
"name: ''",
"id: ''",
"version: ''",
"date: ''",
"author: ''",
"status: ''",
"type: ''",
"data_source:",
" - ''",
"description: ''",
"search: ''",
"how_to_implement: ''",
"known_false_positives: ''",
"references:",
" - ''",
"drilldown_searches:",
" - name: ''",
" search: ''",
" earliest_offset: ''",
" latest_offset: ''",
"tags:",
" analytic_story:",
" - ''",
" asset_type: ''",
" mitre_attack_id:",
" - ''",
" product:",
" - ''",
" security_domain: ''"
],
"description": "Updated minimal template for a new detection YAML file"
}
}
{
254 changes: 254 additions & 0 deletions docs/yaml-spec/schema/detection.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"author": {
"description": "Select the author email from allowed options.",
"enum": [
"<user1@<emailaddress>",
"<user2@<emailaddress>",
"<user3@<emailaddress>",
"<user4@<emailaddress>",
"<user5@<emailaddress>"
],
"type": "string"
},
"data_source": {
"description": "Select the relevant data sources for the rule.",
"items": {
"enum": [
"your_data_source_1",
"your_data_source_2",
"your_data_source_3",
"your_data_source_4",
"your_data_source_5",
"your_data_source_6",
"your_data_source_7",
"your_data_source_8",
"your_data_source_9",
"your_data_source_10",
"your_data_source_11"
],
"type": "string"
},
"type": "array"
},
"date": {
"description": "Enter the date in YYYY-MM-DD format.",
"format": "date",
"type": "string"
},
"description": {
"description": "Provide a description of what the detection rule does.",
"type": "string"
},
"drilldown_searches": {
"description": "Drilldown searches related to this rule.",
"items": {
"properties": {
"earliest_offset": {
"description": "Earliest time offset. '$info_min_time$'",
"type": "string"
},
"latest_offset": {
"description": "Latest time offset. '$info_max_time$'",
"type": "string"
},
"name": {
"description": "Name of the drilldown search. 'Click to see contributing events'",
"type": "string"
},
"search": {
"description": "SPL query for the drilldown. '%original_detection_search%'",
"type": "string"
}
},
"required": [
"name",
"search",
"earliest_offset",
"latest_offset"
],
"type": "object"
},
"type": "array"
},
"how_to_implement": {
"description": "Instructions on how to implement this detection rule. Ensure that the `YAMLRULENAME_filter` macro is available at the end of the SPL search. This macro is used to filter out known false positives.",
"type": "string"
},
"id": {
"description": "Enter a unique UUID.",
"type": "string"
},
"known_false_positives": {
"description": "Document any known false positives. Any references to JIRA tickets would go here",
"type": "string"
},
"name": {
"description": "Enter the name of the rule, matching the YAML file name all lowercase.",
"type": "string"
},
"references": {
"description": "Provide references (e.g., Runbook links).",
"items": {
"format": "uri",
"type": "string"
},
"type": "array"
},
"search": {
"description": "Provide the SPL (Search Processing Language) query for the rule.",
"type": "string"
},
"status": {
"description": "Define the status of the detection rule.",
"enum": [
"production",
"experimental",
"deprecated",
"validation"
],
"type": "string"
},
"tags": {
"description": "Metadata tags for the rule.",
"properties": {
"analytic_story": {
"description": "Relevant analytic stories.",
"items": {
"enum": [
"Example Stories",
"BlackMatter Ransomware",
"Suspicious GCP Storage Activities",
"Suspicious Okta Activity",
"Windows Registry Abuse",
"Threat Intelligence Brand Mentions Leaks and Exposure",
"Suspicious GCP Admin Activity",
"GitHub Evasion of Audit Controls",
"GitHub Account Abuse",
"Vault Credential Access and Secret Exposure",
"Log Source Disruption and Ingestion Gaps",
"GCP Firewall Tampering",
"Google Workspace External Sharing"
],
"type": "string"
},
"type": "array"
},
"asset_type": {
"description": "Asset type involved.",
"enum": [
"AWS Account",
"AWS EKS Kubernetes cluster",
"AWS Federated Account",
"AWS Instance",
"Account",
"Amazon EKS Kubernetes cluster",
"Amazon EKS Kubernetes cluster Pod",
"Amazon Elastic Container Registry",
"Azure Tenant",
"Azure AKS Kubernetes cluster",
"Azure Active Directory",
"CircleCI",
"Cloud Compute Instance",
"Cloud Instance",
"DNS Servers",
"Database Server",
"Domain Server",
"EC2 Snapshot",
"Endpoint",
"GCP",
"GCP Account",
"GCP GKE EKS Kubernetes cluster",
"GCP GKE Kubernetes cluster",
"GCP Kubernetes cluster",
"GCP Storage Bucket",
"GDrive",
"GSuite",
"GitHub",
"Google Cloud Platform tenant",
"Identity",
"Infrastructure",
"Instance",
"Kubernetes",
"Network",
"O365 Tenant",
"Okta Tenant",
"Proxy",
"S3 Bucket",
"Splunk Server",
"VPN Appliance",
"Web Server",
"Web Proxy",
"Web Application",
"Windows"
],
"type": "string"
},
"mitre_attack_id": {
"description": "Associated MITRE ATT&CK IDs.",
"items": {
"type": "string"
},
"type": "array"
},
"product": {
"description": "Product association.",
"items": {
"enum": [
"Splunk Enterprise Security",
"Splunk Cloud",
"Splunk Behavioral Analytics"
],
"type": "string"
},
"type": "array"
},
"security_domain": {
"description": "Security domain for the rule.",
"enum": [
"endpoint",
"network",
"identity",
"application",
"threat",
"access",
"audit"
],
"type": "string"
}
},
"type": "object"
},
"type": {
"description": "Specify the type of detection.",
"enum": [
"Anomaly",
"Correlation",
"Hunting",
"TTP",
"Baseline",
"Embedded"
],
"type": "string"
},
"version": {
"description": "Enter the version number (integer expected).",
"type": "string"
}
},
"required": [
"name",
"id",
"version",
"date",
"author",
"status",
"type",
"data_source",
"description",
"search"
],
"title": "Detection Rule Schema",
"type": "object"
}
5 changes: 5 additions & 0 deletions docs/yaml-spec/schema/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"yaml.schemas": {
"./.vscode/schemas/detection.schema.json": "path_to_where_you_keep_your/detections*.yml"
}
}