# Query Language

The query language used by the rule service is a LISP style language: `(<operator> <args>...)`.

## Operators

The following are the operators

| Operator   | Syntax                       | Description                             |
| ---------- | ---------------------------- | --------------------------------------- |
| `eq`       | `(eq left right)`            | Equality comparison                     |
| `contains` | `(contains needle haystack)` | Text contains search (case-insensitive) |
| `matches`  | `(matches pattern target)`   | Regex pattern matching                  |
| `any`      | `(any needle expr)`          | Value search in JSON objects            |
| `and`      | `(and expr1 expr2 ...)`      | Logical AND                             |
| `or`       | `(or expr1 expr2 ...)`       | Logical OR                              |
| `not`      | `(not expr)`                 | Logical NOT                             |

### Equality (`eq`)

Compares two values for exact equality.

```javascript
(eq $.name "s3-encryption")
(eq $.type "security")
(eq $.version "1.0.0")
(eq $.annotations.stable true)
```

### Contains (`contains`)

Searches for text within a field (case-insensitive).

```javascript
(contains "aws" $.name)
(contains "s3" $.resource)
(contains "prod" $.metadata.environment)
```

### Matches (`matches`)

Uses regex patterns for matching.

```javascript
(matches /aws_.*/i $.resource)
(matches /^s3-.*/ $.name)
(matches /prod|staging/ $.environment)
```

**Regex Flags:**

* `i` - Case insensitive
* `g` - Global match
* `m` - Multiline

### Any (`any`)

Searches for a specific value within JSON data structures.

```javascript
(any "prod" $.metadata)
(any "CIS" $.classification)
(any "encryption" $.body.config)
(any "enabled" $.annotations)
```

### AND (`and`)

All conditions must be true.

```javascript
(and (eq $.type "security") (contains "aws" $.resource))
(and
  (eq $.iacLanguage "terraform")
  (any "prod" $.metadata)
  (not (contains "deprecated" $.name))
)
```

### OR (`or`)

At least one condition must be true.

```javascript
(or (contains "aws" $.resource) (contains "azure" $.resource))
(or (eq $.name "rule1") (eq $.name "rule2") (eq $.name "rule3"))
```

### NOT (`not`)

Negates a condition.

```javascript
(not (contains "test" $.name))
(not (any "deprecated" $.metadata))
(not (eq $.environment "dev"))
```

## Fields

Each object has fields that can be referenced.

| Field                        | Description                | Example                                            |
| ---------------------------- | -------------------------- | -------------------------------------------------- |
| `finding.name`               | Rule name                  | `(eq finding.name "s3-encryption")`                |
| `finding.shortName`          | Rule short name            | `(contains "s3" finding.shortName)`                |
| `finding.type`               | Rule type                  | `(eq finding.type "security")`                     |
| `finding.version`            | Rule version               | `(eq finding.version "1.0.0")`                     |
| `finding.iacLanguage`        | IaC language               | `(eq finding.iacLanguage "terraform")`             |
| `finding.metadata`           | Rule metadata              | `(any "prod" finding.metadata)`                    |
| `finding.body`               | Rule body content          | `(contains "aws_s3_bucket" finding.body)`          |
| `finding.annotations`        | Rule annotations           | `(eq finding.annotations.stable true)`             |
| `finding.classification`     | Rule classifications       | `(any "CIS" finding.classification)`               |
| `channel.name`               | Channel name               | `(eq channel.name "security-channel")`             |
| `channel.query`              | Channel query              | `(contains "security" channel.query)`              |
| `channel.filters`            | Channel filters            | `(contains "prod" channel.filters)`                |
| `channel.accountId`          | Channel account ID         | `(eq channel.accountId "account-123")`             |
| `classification.name`        | Classification name        | `(eq classification.name "CIS")`                   |
| `classification.parent`      | Parent classification      | `(eq classification.parent "Security")`            |
| `classification.shortName`   | Classification short name  | `(contains "CIS" classification.shortName)`        |
| `classification.description` | Classification description | `(contains "security" classification.description)` |
| `classification.annotations` | Classification annotations | `(eq classification.annotations.stable true)`      |

Note: There is also a `$` object which represents "this" and changes behavior based on what is being returned. If executed against rules then it is a `finding`, if executed against channels it is a `channel`, and if executed against classifications then it is a `classification`.

## Data Types

| Type        | Syntax            | Example           |
| ----------- | ----------------- | ----------------- |
| **String**  | `"text"`          | `"aws_s3_bucket"` |
| **Number**  | `123` or `-42.5`  | `1` or `1000.0`   |
| **Boolean** | `true` or `false` | `true`            |
| **Null**    | `null`            | `null`            |
| **Regex**   | `/pattern/flags`  | `/aws_.*/i`       |

### String Escaping

* Use `\"` for quotes: `"He said \"Hello\""`
* Use `\\` for backslashes: `"path\\to\\file"`

### Regex Escaping

* Use `\/` for forward slashes: `/path\/to\/file/`
* Use `\\` for backslashes: `/path\\to\\file/`

## Common Patterns

### Find Rules by Resource Type

```javascript
(contains "aws_s3_bucket" $.resource)
(matches /aws_.*_bucket/i $.resource)
```

### Exclude Test/Deprecated Rules

```javascript
(not (any "test" $.metadata))
(not (contains "deprecated" $.name))
(not (any "deprecated" $.metadata))
```

Note: The positive can also be used in a filter.

### Complex Filtering

```javascript
(and
  (eq finding.type "security")
  (not (any "deprecated" finding.metadata.annotations))
  (any "prod" finding.metadata)
  (contains "aws" finding.metadata.annotations["resource"])
)
```

## Troubleshooting

### Common Issues

1. **Query Syntax Errors**
   * Ensure all parentheses are balanced
   * Use proper string escaping
   * Check operator argument counts
2. **Field Not Found**
   * Unknown fields default to `$.body` search
   * Use dot notation for nested fields
   * Check field names in the reference table
3. **Regex Issues**
   * Use proper escaping for special characters
   * Add flags like `i` for case-insensitive matching
   * Test regex patterns separately
4. **`any()` Function Issues**

   * **Error**: `any() requires exactly 2 args`
   * **Solution**: Use `(any needle field)` for single values, or use `OR` for multiple values

   ```javascript
   // ❌ WRONG: Too many arguments
   (any "s3" "ec2" "rds" $.services)  // Error: requires 2 args

   // ✅ CORRECT: Single value search
   (any "prod" $.metadata)

   // ✅ CORRECT: Multiple values using OR
   (or (any "prod" $.metadata) (any "staging" $.metadata))
   ```

   * **Memory Errors**: Complex JSON searches can cause out-of-memory
   * **Solution**: Break complex queries into smaller parts or use alternatives like `contains`
5. **Performance Considerations**
   * Use specific field references when possible
   * Avoid overly complex nested queries
   * Consider using `contains` over `any` for simple text searches
   * Be cautious with `any` on very large JSON structures

### Debugging Tips

1. **Start Simple**: Begin with basic queries and add complexity gradually
2. **Test Components**: Test individual parts of complex queries
3. **Use Examples**: Reference the examples in this guide
4. **Check Syntax**: Ensure proper S-Expression syntax
