Community
Questions Library
Docs
Blog
Events
Swag
Github
Slack
JupiterOne
Discussions
Release Notes
Contact Us
JupiterOne Alert Rule Schema - AskJ1 Community
<main> <article class="userContent"> <p>A rule uses the results of one or more queries to execute one or more actions.<br> The basic alert workflows are described here:<br><a rel="nofollow" href="https://support.jupiterone.io/hc/en-us/articles/360022720474-6-9-Alerts-and-Alert-Rules">JupiterOne Alert Rule configuration documentation</a>.<br> You can also directly edit the JSON that defines a rule for more advanced<br> workflow execution.</p> <h2 data-id="configuring-a-rule">Configuring a Rule</h2> <ol><li>Navigate to the JupiterOne alert rule configuration page<br> (<a href="https://apps.us.jupiterone.io/alerts/rules)" rel="nofollow">https://apps.us.jupiterone.io/alerts/rules)</a></li> <li>Click <strong>Create Rule</strong></li> <li>Click <strong>Advanced Editor (JSON)</strong> to open the advanced rule editor.</li> </ol><p>JSON Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "unencrypted-critical-data-stores", "description": "Unencrypted data store with classification label of 'critical' or 'sensitive' or 'confidential' or 'restricted'", "version": 1, "specVersion": 1, "pollingInterval": "ONE_DAY", "question": { "queries": [ { "name": "query0", "query": "Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true", "version": "v1" } ] }, "operations": [ { "when": { "type": "FILTER", "condition": "{{queries.query0.total > 0}}" }, "actions": [ { "type": "CREATE_ALERT" } ] } ], "outputs": ["queries.query0.total", "alertLevel"] } </pre> <p>You can also configure rules to include deleted data in the results. For<br> example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0"> // ... "question": { "queries": [ { "name": "query0", "query": "Find DataStore with classification='critical' and encrypted=false as d return d.tag.AccountName as Account, d.displayName as UnencryptedDataStores, d._type as Type, d.encrypted as Encrypted", "version": "v1", "includeDeleted": true }, { "name": "query1", "query": "...", "version": "v1", "includeDeleted": false }, { "name": "query2", "query": "...", "version": "v1" } ] }, // ... } </pre> <h2 data-id="rule-properties">Rule Properties</h2> <p>| Property | Type | Description |<br> | ------------------ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code> | Auto-generated, globally unique ID of each rule. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">version</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">number</code> | Current version of the rule. Incremented each time the rule is updated. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code> | Name of the rule, which is unique to each account. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code> | Optional description of the rule. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">specVersion</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">number</code> | Rule evaluation version in the case of breaking changes. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">pollingInterval</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PollingInterval</code> | Optional frequency of automated rule evaluation. Defaults to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_DAY</code>. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">question</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Question</code> | Contains properties related to queries used in the rule evaluation. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionId</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code> | A known unique ID for a question in the question library. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">operations</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperation[]</code> | Actions that are executed when a corresponding condition is met. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">templates</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">object</code> | Optional key/value pairs of template name to template. |<br> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">outputs</code> | <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string[]</code> | Names of properties that can be used throughout the rule evaluation process and will be included in each record of a rule evaluation (for example, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queries.query0.total</code>). |<br></p> <h3 data-id="type-pollinginterval">Type: PollingInterval</h3> <p>Enumeration of the scheduled frequencies on which rules will automatically be evaluated.<br> Possible values are <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DISABLED</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">THIRTY_MINUTES</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_HOUR</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FOUR_HOURS</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">EIGHT_HOURS</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">TWELVE_HOURS</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_DAY</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_WEEK</code>.</p> <h3 data-id="type-ruleoperation">Type: RuleOperation</h3> <p>A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperation</code> is a single <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">condition</code> and series of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">action</code>s that are<br> executed when the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">condition</code> is met.</p> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">when</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperationCondition\|RuleOperationCondition[]</code></td> <td>Type of conditional used to determine whether the associated actions should be executed.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">actions</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperationAction[]</code></td> <td>Actions that should be executed when the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">when</code> conditions have been met.</td> </tr></tbody></table><h3 data-id="type-question">Type: Question</h3> <p>A Question contains a collection of named queries that should be executed during<br> the rule evaluation process and whose responses can be used in any<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperation</code>.</p> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queries</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">QuestionQuery[]</code></td> <td>The collection of queries that are used during the rule evaluation.</td> </tr></tbody></table><h3 data-id="type-questionquery">Type: QuestionQuery</h3> <p>A named query that should be executed during the rule evaluation process and<br> whose responses can be used in any <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperation</code>.</p> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Optional name to assign the query that will be used when referencing query data in <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperation</code>s. If not provided, the query name is automatically assigned based on the index in the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queries</code> array (for example, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">query0</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">query1</code>).</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">query</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>JupiterOne query to execute.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">version</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>JupiterOne query language execution version (for example, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">v1</code>).</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">includeDeleted</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">boolean</code></td> <td>Whether deleted data should be considered for the specific query (defaults to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">false</code>).</td> </tr></tbody></table><h3 data-id="type-ruleoperationcondition">Type: RuleOperationCondition</h3> <p>The condition that determines whether the associated actions should be executed.<br> The type of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperationCondition</code> is determined using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code> property.</p> <h4 data-id="type-filterruleoperationcondition">Type: FilterRuleOperationCondition</h4> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation condition type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FILTER</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">condition</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Template condition (for example, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{{queries.query0.total > 0}}</code>).</td> </tr></tbody></table><h3 data-id="type-ruleoperationaction">Type: RuleOperationAction</h3> <p>Action that is executed when a corresponding condition is met. The type of<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperationAction</code> is determined using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code> property.</p> <hr></hr><p></p> <h4 data-id="action-set-property">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SET_PROPERTY</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Includes a property that can be used in rule evaluation input.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SET_PROPERTY.</code> | |</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">targetProperty</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Property to include in the evaluation input. | |</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">targetValue</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">number | string | boolean</code></td> <td>Property to include in the evaluation input.</td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SET_PROPERTY", "targetProperty": "alertLevel", "targetValue": "CRITICAL" } </pre> <hr></hr><p></p> <h4 data-id="action-create-alert">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">CREATE_ALERT</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Creates a JupiterOne alert that is visible in J1 Alerts.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">CREATE_ALERT</code></td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "CREATE_ALERT" } </pre> <hr></hr><p></p> <h4 data-id="action-send-email">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_EMAIL</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Sends an email to a list of recipients with details related to alerts that are<br> created during the rule evaluation.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_EMAIL</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">recipients</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string[]</code></td> <td>Email addresses of the recipients of this alert.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">body</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Optional additional body information of the email.</td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", "body": "Number of items above threshold: {{queries.query0.total}}", "recipients": ["recipient@example.com"] } </pre> <h6 data-id="multiple-queries-in-a-rule">Multiple Queries in a Rule</h6> <p>You can pass multiple queries into an alert rule that allows each query to output its results into the same, single alert.</p> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Note the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">when</code> condition in the example below will invoke actions if either query returns results.</p> </div></blockquote> <p>This example shows multiple queries sending out an email alert to multiple recipients:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Multiple Queries in a Rule", "description": "", "version": 1, "specVersion": 1, "pollingInterval": "ONE_WEEK", "templates": { "tempMap": "Project: {{item.Project}}, ProjectFindings: {{item.ProjectFindings}}, RepoFindings: {{item.RepoFindings}}" }, "outputs": [ "alertLevel" ], "question": { "queries": [ { "name": "query0", "query": "Find CodeRepo THAT RELATES TO Project with repoName!=undefined as p THAT HAS Finding as f RETURN p.repoName as Project, count(f) as ProjectFindings", "version": "v1", "includeDeleted": false }, { "name": "query1", "query": "Find Project with repoName!=undefined THAT RELATES TO CodeRepo as p THAT HAS Finding as f RETURN p.displayName as Project, count(f) as RepoFindings", "version": "v1", "includeDeleted": false } ] }, "operations": [ { "when": { "type": "FILTER", "specVersion": 1, "condition": [ "OR", [ "queries.query0.total", ">", 0 ], [ "queries.query1.total", ">", 0 ] ] }, "actions": [ { "targetValue": "INFO", "type": "SET_PROPERTY", "targetProperty": "alertLevel" }, { "type": "CREATE_ALERT" }, { "type": "SEND_EMAIL", "body": "Affected Items: <br><br>* {{ queries.query0.data | mapTemplate('tempMap') | join('<br>* ') }} / <br>* {{ queries.query1.data | mapTemplate('tempMap') | join('<br>* ') }}", "recipients": [ "person1@example.com", "person2@example.com", "person3@example.com" ] } ] } ], "tags": [] } </pre> <hr></hr><p></p> <h4 data-id="action-create-jira-ticket">Action <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">CREATE_JIRA_TICKET</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Creates a Jira ticket using a specific JupiterOne Jira integration<br> configuration.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">CREATE_JIRA_TICKET.</code></td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integrationInstanceId</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> of the JupiterOne Jira integration that should be used to create the ticket.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityClass</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">class</code> of the new ticket entity that should be created in JupiterOne. (for example,<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Vulnerability</code>)</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">project</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The unique Jira project ID that the ticket is created in.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">summary</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Summary of the Jira ticket. Used as the ticket title.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">issueType</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The Jira issue type (for example, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Task</code>).</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">additionalFields</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">object</code></td> <td>Optional additional fields that are passed directly to the Jira API. (see table below for details)</td> </tr></tbody></table><h4 data-id="jira-description-field">Jira Description Field</h4> <p>The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code> field can have a raw string value or be passed as depicted in<br> these examples as Jira<br><a rel="nofollow" href="https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/">ADF</a>.<br><strong>NOTE</strong>: string in either the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">text</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code> keys supports markdown<br> syntax.</p> <h4 data-id="other-custom-additional-fields">Other/custom Additional Fields</h4> <p>Fields passed into <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">additionalFields</code> will be passed directly to the Jira API<br> and as such should match the required input format of each field type.<br> This table outlines some of the common field types and their value formats.<br> Please use the<br><a rel="nofollow" href="https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-fields/">Official Jira Rest API</a><br> for more information.</p> <table><thead><tr><th>Field Type Label</th> <th>Schema Type</th> <th>Input Format</th> <th>Example</th> </tr></thead><tbody><tr><td>Text</td> <td>textfield</td> <td>String value</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"Value of Field"</code></td> </tr><tr><td>Number</td> <td>number</td> <td>Number value</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">2</code></td> </tr><tr><td>Select</td> <td>select</td> <td>Object with value key</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{ "value": "Select Option Label"}</code></td> </tr><tr><td>MultiSelect</td> <td>multiselect</td> <td>Array of string values</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">["Option 1", "Option 2"]</code></td> </tr><tr><td>MultiCheckBoxes</td> <td>multicheckboxes</td> <td>Array of Objects with value keys</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">[{ "value": "Option 1" }, { "value": "Option 2"}]</code></td> </tr><tr><td>UserPicker</td> <td>userpicker</td> <td>Object with accountId</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{ "accountId": "userInternalId" }</code></td> </tr><tr><td>MultiUserPicker</td> <td>multiuserpicker</td> <td>Array of Objects with accountId keys</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">[{ "accountId": "user1InternalId" }, { "accountId": "user2InternalId"}]</code></td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "CREATE_JIRA_TICKET", "integrationInstanceId": "<JIRA_INTEGRATION_INSTANCE_ID>", "entityClass": "Vulnerability", "project": "81198", "summary": "Ticket summary", "issueType": "Task", "additionalFields": { "custom_text": "field_value", "custom_number": 2, "custom_select": { "value": "Select Option Label" }, "custom_multi_select": ["Option 1", "Option 2"], "custom_multi_checkboxes": [ { "value": "Option 1" }, { "value": "Option 2" } ], "custom_user_picker": { "accountId": "usersInternalId" }, "custom_multi_user_picker": [ { "accountId": "user1InternalId" }, { "accountId": "user2InternalId" } ], "description": { "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Jira description here! **Full Markdown Supported Text**" } ] } ] } } } </pre> <p>This example shows multiple queries sending results to Jira to create a single<br> Jira issue:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Multiple Queries in a Rule to Jira Example", "description": "Multiple queries can be composed into a Jira Alert", "version": 1, "specVersion": 1, "pollingInterval": "ONE_DAY", "templates": { "projectInfo": "Project: {{item.Project}}, ProjectFindings: {{item.ProjectFindings}}, RepoFindings: {{item.RepoFindings}}" }, "outputs": [ "alertLevel" ], "question": { "queries": [ { "name": "query0", "query": "Find CodeRepo THAT RELATES TO Project with repoName!=undefined as p THAT HAS Finding as f RETURN p.repoName as Project, count(f) as ProjectFindings", "version": "v1", "includeDeleted": false }, { "name": "query1", "query": "Find Project with repoName!=undefined THAT RELATES TO CodeRepo as p THAT HAS Finding as f RETURN p.displayName as Project, count(f) as RepoFindings", "version": "v1", "includeDeleted": false } ] }, "operations": [ { "when": { "type": "FILTER", "specVersion": 1, "condition": [ "OR", [ "queries.query0.total", ">", 0 ], [ "queries.query1.total", ">", 0 ] ] }, "actions": [ { "targetValue": "INFO", "type": "SET_PROPERTY", "targetProperty": "alertLevel" }, { "type": "CREATE_ALERT", }, { "summary": ": {{queries.query0.total}}", "issueType": "Task", "entityClass": "Finding", "integrationInstanceId": "<JIRA_INTEGRATION_INSTANCE_ID>", "additionalFields": { "description": { "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "{{alertWebLink}}\n\n**Affected Items:**\n\n* {{ queries.query0.data | mapTemplate('projectInfo') | join('\n* ') }} \n\n***************\n\n {{ queries.query1.data | mapTemplate('projectInfo') | join('\n* ') }}" } ] } ] } }, "project": "CT", "type": "CREATE_JIRA_TICKET" } ] } ], "tags": [] } </pre> <p>If your query returns multiple results, you can run a second query using the<br> results of the first query to create a Jira ticket for each item in the first<br> query results. You do this by<br><a rel="nofollow" href="##configuring-a-rule">editing the advanced JSON of the alert rule</a> to use the<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FOR_EACH_ITEM</code> action type.</p> <p>It is not recommended that you use this action type if your results sizes are very large.<br> This example limits the number of possible Jira tickets created to a maximum of 100, and sends an email when the limit is exceeded.</p> <p>For example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Unencrypted critical data stores", "description": "", "specVersion": 1, "pollingInterval": "ONE_WEEK", "question": { "queries": [ { "name": "query0", "query": "Find DataStore with classification='critical' and encrypted=false", "version": "v1", "includeDeleted": false } ] }, "operations": [ { "when": { "type": "FILTER", "specVersion": 1, "condition": ["AND", ["queries.query0.total", ">", 0], ["queries.query0.total", "<=", 100]] }, "actions": [ { "type": "SET_PROPERTY", "targetValue": "CRITICAL", "targetProperty": "alertLevel" }, { "type": "CREATE_ALERT" }, { "itemRef": "obj", "type": "FOR_EACH_ITEM", "items": "{{queries.query0.data}}", "actions": [ { "type": "CREATE_JIRA_TICKET", "summary": "{{alertRuleDescription}}", "issueType": "", "entityClass": "{{ obj.entity._type | join(',') }}", "integrationInstanceId": "{{ obj.entity._integrationInstanceId }}", "additionalFields": { "description": { "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "{{alertWebLink}}\n\n**Affected Items:**\n\n* {{obj.properties.webLink}}" } ] } ] } }, "project": "{{param.MySpecialProject}}" } ] } ] }, { "when": { "type": "FILTER", "specVersion": 1, "condition": ["queries.query0.total", ">", 100] }, "actions": [ { "type": "SET_PROPERTY", "targetValue": "CRITICAL", "targetProperty": "alertLevel" }, { "type": "CREATE_ALERT" }, { "type": "SEND_EMAIL", "body": "The alert rule {{alertRuleName}} has {{queries.query0.total}} results. Please review the results in the JupiterOne app: {{alertWebLink}}.", "recipients": ["emergency@example.com"], } ] } ], "outputs": ["alertLevel"], "templates": {} } </pre> <hr></hr><p></p> <h4 data-id="action-for-each-item">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FOR_EACH_ITEM</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Runs a set of actions for each item in a list. This list can be query results, or a composed list of items.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FOR_EACH_ITEM</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">itemRef</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Optional name of the item reference to use in the templates. Defaults to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">item</code></td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">items</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The list of items to iterate over. Can be a template (see example).</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">actions</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">array</code></td> <td>The actions to run for each item.</td> </tr></tbody></table><p>Examples:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">// will call POST <a href="https://example.com" rel="nofollow">https://example.com</a> with the body { "name": "John Doe", "webLink": "<a href="https://apps.<region>.jupiterone.io/asset/reference/link" rel="nofollow">https://apps.<region>.jupiterone.io/asset/reference/link</a>" } // for each user in the query results, e.g. `Find User` { "type": "FOR_EACH_ITEM", "itemRef": "user", "items": "{{queries.query0.data}}", "actions": [ { "type": "WEBHOOK", "method": "POST", "url": "<a href="https://example.com" rel="nofollow">https://example.com</a>", "body": { "name": "{{user.properties.name}}", "webLink": "{{user.properties.webLink}}" }, } ] } </pre> <hr></hr><p></p> <h4 data-id="action-jupiterone-query">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JUPITERONE_QUERY</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Runs a JupiterOne query and stores the results on the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queries</code> template parameter with a given <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code>.<br> It is recommended that you only use this action within a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FOR_EACH_ITEM</code> action.<br> Including it in normal <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">operations</code> actions is not recommended, as you can retrieve results you want with the normal <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">question</code> queries.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JUPITERONE_QUERY</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">query</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The JupiterOne query to run.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The name of the query result to store.</td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">// { "type": "FOR_EACH_ITEM", "itemRef": "user", "items": "{{queries.query0.data}}", "actions": [ // JUPITERONE_QUERY actions always run first in order to enable the use of the results in the templates // of other actions in a FOR_EACH_ITEM action { "type": "JUPITERONE_QUERY", "query": "Find Account with email='{{user.properties.email}}'", "name": "accountsOwnedByUserQuery" }, { "type": "WEBHOOK", "method": "POST", "url": "<a href="https://example.com" rel="nofollow">https://example.com</a>", "body": { "name": "{{user.properties.displayName}}", "accounts": "{{queries.accountsOwnedByUserQuery.data | mapProperty('displayName')}}" } } ] } </pre> <hr></hr><p></p> <h4 data-id="action-send-slack-message">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_SLACK_MESSAGE</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Sends a Slack message to a given Slack webhook URL.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integrationInstanceId</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> of the JupiterOne Jira integration used to create the ticket.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_SLACK_MESSAGE</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">channels</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>A string or list of strings beginning with a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">#</code> to denote Slack channels to send to.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">webhookUrl</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Webhook URL for the account/channel that this message should be delivered to.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">severity</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Optional severity of this alert that determined the color of the message shown in Slack.</td> </tr></tbody></table><p><strong>NOTE</strong>: By default, the color of the alert in Slack is derived from the value<br> of the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">alertLevel</code> that is created in a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SET_PROPERTY</code> action. You can override<br> the color of the alert using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">severity</code> property.</p> <p>Example:</p> <p>After you have configured the integration, copy the integration ID from the<br> integration instance page, which looks similar to<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">d1549f40-b9fd-447a-bec5-4360c9ca7e8c</code>.</p> <ol><li>Configure a rule with the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_SLACK_MESSAGE</code> action and specify the<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integrationInstanceId</code> with the unique identifier of the integration and<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">channels</code> denoting the destinations. The following is an example alert rule<br> configuration with the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_SLACK_MESSAGE</code> action:</li> </ol><p><strong>NOTE</strong>: For the JupiterOne Slack bot to deliver messages to a private Slack<br> channel, the JupiterOne Slack bot must be a member of that private channel.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Critical Data Stores Not Encrypted", "description": "Sends a alert to Slack when a critical data store that is not encrypted is found.", "specVersion": 1, "pollingInterval": "ONE_DAY", "templates": { "slackBody": "JupiterOne Account: {{item.displayName}}\n\n" }, "question": { "queries": [ { "name": "query0", "query": "Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true", "version": "v1" } ] }, "operations": [ { "when": { "type": "FILTER", "specVersion": 1, "condition": "{{queries.query0.total > 0}}" }, "actions": [ { "targetValue": "HIGH", "type": "SET_PROPERTY", "targetProperty": "alertLevel" }, { "type": "CREATE_ALERT" }, { "integrationInstanceId": "<SLACK_INTEGRATION_INSTANCE_ID>", "channels": ["#random"], "type": "SEND_SLACK_MESSAGE", "body": "{{ queries.query0.data | mapTemplate('slackBody') | join(' ') }}" } ] } ], "outputs": ["queries.query0.total", "alertLevel"] } </pre> <hr></hr><p></p> <h4 data-id="action-webhook">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">WEBHOOK</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Sends an HTTP request to a given endpoint.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">WEBHOOK</code></td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">endpoint</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Webhook endpoint to send the request to.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">method</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>HTTP method to use when making the request Allowed values: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">POST</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PUT</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">GET</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">HEAD</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PATCH</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DELETE</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">body</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">object</code></td> <td>Optional body data to include in the request. Can only be used with <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">POST</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PUT</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PATCH</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">headers</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">object</code></td> <td>Optional HTTP headers to include in the request.</td> </tr></tbody></table><h4 data-id="webhook-reference-variables">Webhook Reference Variables</h4> <p>You can reference the following variables via a template pattern (such as<br><em>{{alertLevel}}</em>) inside the webhook action:</p> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">alertLevel</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Level of severity of the rule.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">alertRuleName</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Name of the alert rule.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">alertRuleId</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Identifier for the alert in the J1 platform.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">alertRuleDescription</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Description saved in the rule.</td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "WEBHOOK", "method": "POST", "body": { "myApiPayload": " {{alertLevel}} alert has been triggered: {{alertRuleName}} " }, "headers": { "Authorization": "Bearer abc123" } } </pre> <h5 data-id="tines-trigger">Tines Trigger</h5> <p>If you opt to use a Tines alert action when you create a rule, J1 creates a<br> webhook with the Tines URL you provided and pushes the data to that endpoint.<br> You can use any of the <a rel="nofollow" href="https://www.tines.com/api/actions/create">Tines APIs</a> to<br> configure the webhook action.</p> <p><img src="https://us.v-cdn.net/6035534/uploads/O1URGNNZV0GR/tines-webhook.gif" alt="" class="embedImage-img importedEmbed-img"></img></p> <hr></hr><p></p> <h4 data-id="action-publish-sns-message">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PUBLISH_SNS_MESSAGE</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Publishes a message to the specified SNS topic.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">PUBLISH_SNS_MESSAGE</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integrationInstanceId</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The ID of the AWS integration instance to use. The integration role must have <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">sns:Publish</code> permission.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">topicArn</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The ARN of the SNS topic to publish the message to.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">data</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">object</code></td> <td>User-provided data to include in the message. See <a rel="nofollow" href="#operationtemplating">Operation Templating</a> for details on using variable data.</td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "PUBLISH_SNS_MESSAGE", "integrationInstanceId": "<AWS_INTEGRATION_INSTANCE_ID>", "topicArn": "arn:aws:sns:<REGION>:arn:aws:sns:<ACCOUNT_ID>:<SNS_TOPIC_NAME>", "data": { "query0Data": "{{queries.query0.data}}", "anotherCustomProperty": true } } </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">!!! Note: </pre> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">data</code> is stringified in the payload. For example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ Sns: { Message: '{"data":{"query0Data": ..., "anotherCustomProperty": true}}'; } } </pre> <hr></hr><p></p> <h4 data-id="action-send-sqs-message">Action: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_SQS_MESSAGE</code></h4> <blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Publishes a message to the specified SQS queue.</p> </div></blockquote> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>Rule operation action type: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">SEND_SQS_MESSAGE</code>.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integrationInstanceId</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The ID of the AWS integration instance to use. The integration role must have <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">sqs:SendMessage</code> permission.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queueUrl</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">string</code></td> <td>The URL of the SQS queue to publish the message to.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">data</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">object</code></td> <td>User-provided data to include in the message. See <a rel="nofollow" href="#operationtemplating">Operation Templating</a> for details on using variable data.</td> </tr></tbody></table><p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_SQS_MESSAGE", "integrationInstanceId": "<AWS_INTEGRATION_INSTANCE_ID>", "queueUrl": "<a href="https://sqs.<REGION>.amazonaws.com/<ACCOUNT_ID>/<SQS_QUEUE_NAME&gt" rel="nofollow">https://sqs.<REGION>.amazonaws.com/<ACCOUNT_ID>/<SQS_QUEUE_NAME&gt</a>;", "data": { "query0Data": "{{queries.query0.data}}", "anotherCustomProperty": true } } </pre> <p>!!! warning <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">data</code> is stringified in the payload. For example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ body: '{"data":{"query0Data": ..., "anotherCustomProperty": true}}'; } </pre> <h2 data-id="operation-templating">Operation Templating</h2> <p>You can use templates inside any property under the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">operations</code> property on a<br> rule. The templates can contain a JavaScript-like syntax that automatically have<br> input variables injected for usage.</p> <p>For example, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FilterRuleOperationCondition</code>s are often used with rules as the<br> condition for whether rule actions should be executed. You can use query<br> response data inside of the rule conditions:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "operations": [ { "when": { "type": "FILTER", // Use the `.total` property from query named `query0`. "condition": "{{queries.query0.total > 0}}" }, "actions": [ { "type": "CREATE_ALERT" } ] } ] } </pre> <p>You can use data from query results inside of rule operations by referencing the<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">query.query0.data</code> property and custom templating transforms. For example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "lambda-function-settings-check-runtime-nodejs610", "description": "Node.js 6.10 is end of life (EOL) and should no longer be used.", "specVersion": 1, "pollingInterval": "ONE_DAY", "templates": { // The email template that we will use later "emailBody": "({{itemIndex+1}} of {{itemCount}}) [{{item.account}}] Function Name: {{item.functionName}}<br>" }, "question": { "queries": [ { "name": "query0", "query": "Find aws_lambda_function with runtime='nodejs6.10' as f return f.name as functionName, f.version as version, f.tag.AccountName as account, f.tag.Project as project order by account", "version": "v1" } ] }, "operations": [ { "when": { "type": "FILTER", "specVersion": 1, "condition": "{{queries.query0.total > 0}}" }, "actions": [ { "targetValue": "HIGH", "type": "SET_PROPERTY", "targetProperty": "alertLevel" }, { "type": "CREATE_ALERT" }, { "type": "SEND_EMAIL", // Reference the `query0` data and include it in a template "body": "Affected Functions: <br><br>{{ queries.query0.data | mapTemplate('emailBody') | join(' ') }}", "recipients": ["person1@example.com"] } ] } ], "outputs": ["queries.query0.total", "alertLevel"] } </pre> <h2 data-id="rule-evaluation-templating-language">Rule Evaluation Templating Language</h2> <p>You can create a template in any <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">RuleOperation</code> using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{{...}}</code> syntax.<br> Inside the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{{...}}</code> is a JavaScript-like language that allows for powerful rule<br> evaluation functionality. Additionally, if the template contains exactly one<br> expression and nothing else, the original type of the computed value is<br> preserved. If multiple expressions are used, the entire value is casted to a<br> string.</p> <p>The following is an example where the type <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">boolean</code> is preserved because there<br> is only a single expression:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{{true}} </pre> <p>The following is an example where the entire value would be cast to a string<br> because it contains multiple expressions:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{{age + 10}} is my age and my name is {{firstName + " " + lastName}} </pre> <p>All templating expressions support references to<br><a rel="nofollow" href="#parametersinrules">account parameters</a>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">My name is {{param.myFirstName}} and I am {{age}} </pre> <h3 data-id="unary-operators">Unary Operators</h3> <table><thead><tr><th>Operation</th> <th align="center">Symbol</th> </tr></thead><tbody><tr><td>Negate</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">!</code></td> </tr></tbody></table><h3 data-id="binary-operators">Binary Operators</h3> <table><thead><tr><th>Operation</th> <th align="center">Symbol</th> </tr></thead><tbody><tr><td>Add, Concat</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">+</code></td> </tr><tr><td>Subtract</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">-</code></td> </tr><tr><td>Multiply</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">*</code></td> </tr><tr><td>Divide</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/</code></td> </tr><tr><td>Divide and floor</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">//</code></td> </tr><tr><td>Modulus</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">%</code></td> </tr><tr><td>Power of</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">^</code></td> </tr><tr><td>Logical AND</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">&&</code></td> </tr><tr><td>Logical OR</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">| |</code></td> </tr></tbody></table><h3 data-id="comparisons">Comparisons</h3> <table><thead><tr><th>Comparison</th> <th align="center">Symbol</th> </tr></thead><tbody><tr><td>Equal</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">==</code></td> </tr><tr><td>Not equal</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">!=</code></td> </tr><tr><td>Greater than</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">></code></td> </tr><tr><td>Greater than or equal</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">>=</code></td> </tr><tr><td>Less than</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0"><</code></td> </tr><tr><td>Less than or equal</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0"><=</code></td> </tr><tr><td>Element in array or string</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">in</code></td> </tr></tbody></table><h3 data-id="ternary-operator">Ternary operator</h3> <table><thead><tr><th>Expression</th> <th>Result</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"" ? "Full" : "Empty"</code></td> <td>Empty</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"foo" in "foobar" ? "Yes" : "No"</code></td> <td>Yes</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{agent: "Archer"}.agent ?: "Kane"</code></td> <td>Archer</td> </tr></tbody></table><h3 data-id="native-types">Native Types</h3> <table><thead><tr><th>Type</th> <th align="center">Examples</th> </tr></thead><tbody><tr><td>Booleans</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">true</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">false</code></td> </tr><tr><td>Strings</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"Hello \"user\""</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'Hey there!'</code></td> </tr><tr><td>Numerics</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">6</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">-7.2</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">5</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">-3.14159</code></td> </tr><tr><td>Objects</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">{hello: "world!"}</code></td> </tr><tr><td>Arrays</td> <td align="center"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">['hello', 'world!']</code></td> </tr></tbody></table><h3 data-id="groups">Groups</h3> <p>Grouping operations with parentheses:</p> <table><thead><tr><th>Expression</th> <th>Result</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">(83 + 1) / 2</code></td> <td>42</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">1 < 3 && (4 > 2 || 2 > 4)</code></td> <td>true</td> </tr></tbody></table><h2 data-id="custom-templating-transforms">Custom Templating Transforms</h2> <p>Some custom transforms are exposed in the rule templating language. These are<br> functions that perform actions on an input, and can be chained together to<br> accomplish some powerful actions.</p> <h4 data-id="maptemplate-templatename-string-custom-transform"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapTemplate(templateName: string)</code> Custom Transform</h4> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapTemplate</code> is separates and reuses templates inside of a rule. The transform<br> expects a single array and the first argument should be a string whose value<br> matches a template in rule <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">templates</code> object.</p> <p>The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapTemplate</code> transform exposes additional input variable to the template:</p> <table><thead><tr><th>Property</th> <th>Type</th> <th>Description</th> </tr></thead><tbody><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">item</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">any</code></td> <td>The individual item of this iteration.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">itemCount</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">number</code></td> <td>The total count of items in the array.</td> </tr><tr><td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">itemIndex</code></td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">number</code></td> <td>The index of the current <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">item</code> in the array</td> </tr></tbody></table><p>!!! note The properties that are accessible on the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">item</code> property are pulled<br> from the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">properties</code> object and the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entity</code> object if the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">item</code> matches the<br> schema for an entity.</p> <p>Example operation:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", // Reference the `query0` data and include it in a template "body": "{{ queries.query0.data | mapTemplate('emailBody') | join(' ') }}", "recipients": ["person1@example.com"] } </pre> <p>Example <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">templates</code>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "emailBody": "({{itemIndex+1}} of {{itemCount}}) [{{item.account}}] Function Name: {{item.somePropertyOnItem}}<br>" } </pre> <h4 data-id="mapproperty-properties-string-custom-transform"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapProperty(...properties: string)</code> Custom Transform</h4> <p>Allows for mapping individual properties from an array. You can supply a single<br> or multiple properties. The properties that are accessible are pulled from the<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">properties</code> object and the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entity</code> object if the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">item</code> matches the schema for<br> an entity. If the array that is being evaluated with <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapProperty</code> matches the<br> schema of an entity, the the rule evaluator attempts to pull properties passed<br> to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapProperty</code> from the entity properties.</p> <p>Example query data:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "query": "FIND Person", "data": [ { "id": "", "entity": { "_createdOn": 1234 // ... }, "properties": { "firstName": "Jon" // ... } }, { "id": "", "entity": { "_createdOn": 12345 // ... }, "properties": { "firstName": "Jane" // ... } } ] } </pre> <p>This is an example of accessing <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">properties</code> data using <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapProperty</code> and the<br> above data:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", // This would return: `Jon,Jane` "body": "{{ queries.query0.data | mapProperty('firstName') | join}}", "recipients": ["person1@example.com"] } </pre> <p>This is an example accessing <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entity</code> data using <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapProperty</code> and the above<br> data:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", // This would return: `1234,12345` "body": "{{ queries.query0.data | mapProperty('_createdOn') | join}}", "recipients": ["person1@example.com"] } </pre> <h4 data-id="merge-data-array-custom-transform"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">merge(...data: array)</code> Custom Transform</h4> <p>Allows for merging 1 or more arrays together to create a new array of the<br> combined results. This transform does not perform any deduplication; all<br> elements of the input arrays are present in the output. This is usually used to<br> combine the results of two or more J1QL queries into a common set of query<br> results.</p> <p>Example query configuration:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "queries": [ { "query": "Find User with name ~=\"first.last\" as a RETURN a.displayName as DisplayName", "name": "query0", "version": "v1", "includeDeleted": false }, { "query": "Find User with name ~=\"firstLast\" as b RETURN b.displayName as DisplayName", "name": "query1", "version": "v1", "includeDeleted": false } ] } </pre> <p>This is an example of merging the results of these two queries together, and<br> getting the number of deduplicated total results.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", "body": "Total Query Results: {{ queries.query0.data | merge(queries.query1.data) | uniquePropertyValues('displayName') | length}}", "recipients": ["person1@example.com"] } </pre> <h4 data-id="join-separator-string-custom-transform"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">join(separator?: string)</code> Custom Transform</h4> <p>This function is similar to the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Array.prototype.join</code> function in JavaScript.<br> It returns a new string by concatenating all of the elements in an array. If the<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">separator</code>argument is not passed to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">join</code>, the array elements are separated by<br> a comma, by default.</p> <p>This transform is often used with <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapTemplate</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">mapProperty</code>.</p> <p>Example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", "body": "{{ queries.query0.data | mapTemplate('emailBody') | join(' ') }}", "recipients": ["person1@example.com"] } </pre> <p>Example of default if no <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">separator</code> is passed to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">join</code>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", "body": "{{ queries.query0.data | mapTemplate('emailBody') | join }}", "recipients": ["person1@example.com"] } </pre> <h4 data-id="uniquepropertyvalues-propertyname-string-custom-transform"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">uniquePropertyValues(propertyName: string)</code> Custom Transform</h4> <p>Creates a set of unique values for the given property name. The transform will<br> pull all properties from the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entity</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">properties</code> sub-properties to the top<br> level to try to access the passed in <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">propertyName</code>.</p> <p>Example query data:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "query": "FIND Person", "data": [ { "id": "1", "entity": { "_createdOn": 1234 // ... }, "properties": { "firstName": "Jon" // ... } }, { "id": "2", "entity": { "_createdOn": 12345 // ... }, "properties": { "firstName": "Jane" // ... } }, { "id": "3", "entity": { "_createdOn": 5555 // ... }, "properties": { "firstName": "Jon" // ... } }, ] } </pre> <p>This is an example of accessing deduplicating a property of an array of<br> entities:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", // This would return: ["Jon","Jane"] "body": "{{ queries.query0.data | uniquePropertyValues('firstName') }}", "recipients": ["person1@example.com"] } </pre> <h3 data-id="common-templating-examples">Common Templating Examples</h3> <p>Merging multiple query results to generate a unique set of values for a given<br> property printed on a new line</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{{ queries.query0.data | merge(queries.query1.data) | uniquePropertyValues('firstName') | join('\n') }} // Will display something like: // // firstName1 // firstName2 // ... </pre> <p>Using a template to display multiple properties from a set of query results</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">// In the templates definition { "myTemplateName": "Property1: {{item.propertyName1}} - Property2: {{item.propertyName2}}" } // In your rule action {{ queries.query0.data | mapProperty('propertyName1', 'propertyName2') | mapTemplate('myTemplateName') | join('\n') }} // Will display something like: // Property1: value1 - Property2 - value2 // Property1: value3 - Property2 - value4 // ... </pre> <p>Filtering a set of query results to a specific name and using a template for extra propoerties</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">// In the templates definition { "myTemplateName": "Property1: {{item.name}} - Property2: {{item.id}}" } // In your rule action {{ queries.query0.data[.name == 'repository1'] | mapProperty('name', 'id') | mapTemplate('myTemplateName') | join('\n') }} // Will display something like: // repository1 - anIdForEntity1 // repository1 - anIdForEntity2 // repository1 - anIdForEntity3 // ... </pre> <h2 data-id="filtering-collections">Filtering Collections</h2> <p>Collections, or arrays of objects, can be filtered by including a filter<br> expression in brackets. Properties of each collection can be referenced by<br> prefixing them with a leading dot. The result will be an array of the objects<br> for which the filter expression resulted in a truthy value.</p> <p>Example context:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ employees: [ {first: 'Sterling', last: 'Archer', age: 36}, {first: 'Malory', last: 'Archer', age: 75}, {first: 'Lana', last: 'Kane', age: 33}, {first: 'Cyril', last: 'Figgis', age: 45}, {first: 'Cheryl', last: 'Tunt', age: 28} ], retireAge: 62 } </pre> <table><thead><tr><th align="left">Expression</th> <th align="left">Result</th> </tr></thead><tbody><tr><td align="left">employees[.first == 'Sterling']</td> <td align="left">[{first: 'Sterling', last: 'Archer', age: 36}]</td> </tr><tr><td align="left">employees[.last == 'Tu' + 'nt'].first</td> <td align="left">Cheryl</td> </tr><tr><td align="left">employees[.age >= 30 && .age < 40]</td> <td align="left">[{first: 'Sterling', last: 'Archer', age: 36},{first: 'Lana', last: 'Kane', age: 33}]</td> </tr><tr><td align="left">employees[.age >= 30 && .age < 40][.age < 35]</td> <td align="left">[{first: 'Lana', last: 'Kane', age: 33}]</td> </tr><tr><td align="left">employees[.age >= retireAge].first</td> <td align="left">Malory</td> </tr></tbody></table><h2 data-id="parameters-in-rules">Parameters in Rules</h2> <p>Rules support reference to parameter values stored at the account-level. These<br> parameters simplify the task of referencing long, sensitive, or widely reused<br> values in rules or queries. For example, the following action trigger is nearly<br> identical to <a rel="nofollow" href="#actionwebhook">the slack webhook</a> example:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "WEBHOOK", "method": "POST", "body": { "name": "Jon" }, "headers": { "Authorization": "Bearer {{param.SlackAuthToken}}" } } </pre> <p>This showcases a primary use case of parameter storage: a value that is long,<br> not human-readable, and may represent a sensitive value which should not be<br> leaked in the configuration.</p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">param.SlackAuthToken</code> invokes a parameter stored at the account level, which is<br> referenced when the rule is evaluated. These parameters are always referenced<br> with the preceding token <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">param.</code>. The subsequent string (without special<br> characters) identifies the name of a parameter.</p> <p>Parameters are supported anywhere that<br><a rel="nofollow" href="#operationtemplating">Operation Templating</a> is supported, and the value of a<br> parameter can be any type of <a rel="nofollow" href="#nativetypes">native type</a> with the <strong>exclusion of<br> objects</strong>, which support comparison <em>against</em> parameters but cannot be the<br> contents of a parameter. Additionally, parameters can store lists of native<br> types, and template expressions can invoke parameter lists similarly to examples<br> above. For example, <a rel="nofollow" href="#actionsend_email">using the email example</a>, we can<br> parameterize the recipient list:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "SEND_EMAIL", "body": "{{ queries.query0.data | mapTemplate('emailBody') | join(' ') }}", // a stored list of email strings: "recipients": "{{param.alertEmailRecipientList}}" } </pre> <p>For more info on JupiterOne parameters,<br><a rel="nofollow" href="https://jupiterone.vanillacommunities.com/kb/articles/850-jupiterone-parameter-service">reference the documentation</a>.</p> </article> </main>