# Using JQ in Cortex

[JQ](https://stedolan.github.io/jq/) is a lightweight, flexible command-line JSON processor that allows users to do arbitrary JSON manipulations.

Cortex leverages JQ within CQL to enable complex queries, including queries on YAML files. For instance:

```
jq(custom("foo"), ".property | length")
```

The above query would cycle through the `foo` object and retrieve the length of all `.property` components. This type of query is often used on Kubernetes resources.

### JQ and datatypes

JQ can provide additional flexibility around data types. For instance, let's say you have a string associated with a numerical value in your Custom Data.

```
x-cortex-custom-metadata:
  my-key:
    line: "100"
```

If you wanted to query on the line value as a number rather than string, the following JQ functionality could be used within CQL:

```
jq(custom("my-key"), ".line | tonumber") > 99
```

This would result in the respective entity passing this CQL check.

### JQ examples

The following examples demonstrate ways you could use JQ in Cortex:

#### Use JQ to implement conditional logic for selecting file paths dynamically

```
git.fileContents(jq(custom("git"), "if . != null then .[\"dockerfile-path\"] else \"Dockerfile\" end
```

This checks if custom git data exists, uses the custom dockerfile path if present, or falls back to the default "Dockerfile" path.

#### Accessing properties with special characters

Use bracket notation to access JSON properties containing dots, slashes, or other special characters:

```
jq(k8s.spec().firstOrNull().selector.matchLabels, ".[\"app.kubernetes.io/instance\"]")
```

#### Handling null values

Prevent errors by checking for null values before accessing properties:

```
jq(custom("data-key"), 'if .retryConfigurations != null then .retryConfigurations | map(.retryAttemptTime) else "Not Found" end')
```

For Scorecard rules, you can use a similar approach:

```
custom("retry-circuit-breaker") != null
```

#### Wildcard pattern matching

Find packages containing specific strings using the matches() function:

```
jq(custom("data-source").packages.filter((package)=>package.packageName.matches(".*<string-text-here>.*")).map((package) => package.packageVersion), ".")
```

#### Finding team members by role

Filter team members by role using JQ:

```
jq(entity.descriptor().info.`x-cortex-team`.members, "map(select(.role == \"engineering-manager\")) | .[].name")
```

#### Handling complex YAML structures

When working with complex YAML files like GitLab CI configurations:

```
jq(git.fileContents('gitlab-ci.yaml').split(' ').filter((section) => section.matchesIn('NODE_VERSION:')).firstOrNull(), '.variables.NODE_VERSION')
```

#### Extract the scheme of an AWS load balancer for resource metadata

```
jq(aws.details(), ".resources[0].Scheme")
```

Or, for nested metadata:

```
jq(aws.details(), ".resources[0].metadata.Scheme")
```

#### Extracting version from pom.xml file

This query extracts the version number from a Maven pom.xml file. You might use this to automate dependency version checks:

```
jq(jq(git.fileContents("pom.xml").split("<version>"),".[1]").split("</version>"), ".[0]")
```

#### Display a parent entity name in a CQL report

This query would allow you to display a parent entity name value, rather than an array, in a CQL report:

```
jq(entity.parents().map((parentEntity) => parentEntity.parents.map((parentEntity) => parentEntity.name)), ".[0]")
```
