@jupiterone/jupiterone-mcp 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +2 -2
  2. package/dist/client/graphql/mutations.js +13 -10
  3. package/dist/client/graphql/mutations.js.map +1 -1
  4. package/dist/client/graphql/queries.js +17 -14
  5. package/dist/client/graphql/queries.js.map +1 -1
  6. package/dist/client/jupiterone-client.d.ts +2 -0
  7. package/dist/client/jupiterone-client.d.ts.map +1 -1
  8. package/dist/client/jupiterone-client.js +33 -20
  9. package/dist/client/jupiterone-client.js.map +1 -1
  10. package/dist/client/services/account-service.js +8 -4
  11. package/dist/client/services/account-service.js.map +1 -1
  12. package/dist/client/services/alert-service.js +7 -3
  13. package/dist/client/services/alert-service.js.map +1 -1
  14. package/dist/client/services/dashboard-service.js +12 -8
  15. package/dist/client/services/dashboard-service.js.map +1 -1
  16. package/dist/client/services/integration-service.js +11 -7
  17. package/dist/client/services/integration-service.js.map +1 -1
  18. package/dist/client/services/j1ql-service.js +9 -5
  19. package/dist/client/services/j1ql-service.js.map +1 -1
  20. package/dist/client/services/rule-service.js +17 -13
  21. package/dist/client/services/rule-service.js.map +1 -1
  22. package/dist/generated/description-map.d.ts +2 -0
  23. package/dist/generated/description-map.d.ts.map +1 -0
  24. package/dist/generated/description-map.js +2107 -0
  25. package/dist/generated/description-map.js.map +1 -0
  26. package/dist/index.js +11 -12
  27. package/dist/index.js.map +1 -1
  28. package/dist/server/mcp-server.d.ts +4 -1
  29. package/dist/server/mcp-server.d.ts.map +1 -1
  30. package/dist/server/mcp-server.js +1505 -1366
  31. package/dist/server/mcp-server.js.map +1 -1
  32. package/dist/types/jupiterone.d.ts +3 -2
  33. package/dist/types/jupiterone.d.ts.map +1 -1
  34. package/dist/types/jupiterone.js +2 -1
  35. package/dist/utils/description-loader.js +8 -5
  36. package/dist/utils/description-loader.js.map +1 -1
  37. package/dist/utils/j1ql-validator.js +5 -1
  38. package/dist/utils/j1ql-validator.js.map +1 -1
  39. package/dist/utils/load-description.d.ts.map +1 -1
  40. package/dist/utils/load-description.js +7 -7
  41. package/dist/utils/load-description.js.map +1 -1
  42. package/package.json +5 -5
  43. package/dist/descriptions/create-dashboard-widget.md +0 -325
  44. package/dist/descriptions/create-dashboard.md +0 -12
  45. package/dist/descriptions/create-inline-question-rule.md +0 -374
  46. package/dist/descriptions/create-j1ql-from-natural-language.md +0 -7
  47. package/dist/descriptions/execute-j1ql-query.md +0 -379
  48. package/dist/descriptions/get-integration-definitions.md +0 -27
  49. package/dist/descriptions/get-integration-instances.md +0 -35
  50. package/dist/descriptions/list-alerts.md +0 -14
  51. package/dist/descriptions/list-rules.md +0 -53
  52. package/dist/descriptions/update-dashboard.md +0 -467
  53. package/dist/descriptions/update-inline-question-rule.md +0 -363
@@ -0,0 +1,2107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.descriptionMap = void 0;
4
+ /* AUTO-GENERATED — DO NOT EDIT MANUALLY */
5
+ exports.descriptionMap = {
6
+ "create-dashboard-widget.md": `# JupiterOne Create Dashboard Widget Tool
7
+
8
+ **Purpose**: Adds a new widget to a specified JupiterOne dashboard. This tool allows you to programmatically create visual widgets (such as pie charts, bar charts, tables, etc.) on any dashboard, using custom queries and configuration.
9
+
10
+ This tool should be used when:
11
+ - You want to add a new visualization to an existing dashboard
12
+ - You need to automate dashboard widget creation for reporting or monitoring
13
+ - You want to programmatically manage dashboard content
14
+
15
+ ## Required Parameters
16
+ - \`dashboardId\`: The ID of the dashboard to add the widget to
17
+ - \`input\`: The widget configuration object (CreateInsightsWidgetInput), including:
18
+ - \`title\`: Widget title
19
+ - \`description\`: Widget description (optional)
20
+ - \`type\`: Widget type (e.g., 'pie', 'bar', 'table', etc.)
21
+ - \`noResultMessage\`: Message to display when there are no results
22
+ - \`config\`: Widget configuration, including queries and settings
23
+
24
+ ## Supported Chart Types
25
+
26
+ The following values are supported for the \`type\` property when creating a widget:
27
+
28
+ \`\`\`typescript
29
+ export enum ChartType {
30
+ Area = 'area',
31
+ Bar = 'bar',
32
+ Graph = 'graph',
33
+ Line = 'line',
34
+ Matrix = 'matrix',
35
+ Number = 'number',
36
+ Pie = 'pie',
37
+ Table = 'table',
38
+ Status = 'status',
39
+ Markdown = 'markdown',
40
+ }
41
+ \`\`\`
42
+
43
+ ## Example Usage
44
+ \`\`\`json
45
+ {
46
+ "dashboardId": "95936c1a-468a-494f-b11d-b134ac9b9577",
47
+ "input": {
48
+ "title": "Example title",
49
+ "type": "pie",
50
+ "noResultMessage": "Message that shows when no results",
51
+ "config": {
52
+ "queries": [
53
+ {
54
+ "query": "FIND (aws_db_cluster_snapshot|aws_db_snapshot) as snapshot\n RETURN\n snapshot.tag.AccountName as name,\n sum(snapshot.allocatedStorage) * 0.02 as value",
55
+ "name": "Query 1"
56
+ }
57
+ ],
58
+ "settings": {
59
+ "pie": {
60
+ "customColors": {
61
+ "0": "#26A69A",
62
+ "1": "#3F51B5",
63
+ "2": "#D81B60",
64
+ "3": "#FF8F00",
65
+ "4": "#9575CD",
66
+ "5": "#8BC34A",
67
+ "6": "#039BE5"
68
+ },
69
+ "upwardTrendIsGood": true
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ \`\`\`
76
+
77
+ # Widget Options
78
+
79
+ When creating a dashboard, there are several options for widgets to choose from. This allows you to utilize the most impactful visual representation for your data. Below are the supported dashboard widgets, each with their own requirements and examples.
80
+
81
+ ---
82
+
83
+ # Chart Types and Example Queries
84
+
85
+ > **Note:**
86
+ > To enable trend functionality for a chart, set \`trendDataIsEnabled: true\` in the relevant chart type's settings (e.g., \`settings.pie.trendDataIsEnabled\`). You can also use keys like \`trendQueryResultsCount\` to control the number of trend data points, and \`upwardTrendIsGood\` to indicate if an upward trend is positive.
87
+
88
+ ## Number
89
+ The number chart visualization shows one large stat value. In the trend version of this chart you are able to track the value through a spark line to see if the result is getting larger or smaller over time.
90
+
91
+ ### Query Requirements
92
+ Expects only a single \`value\` in the returned query response.
93
+
94
+ ### Example Queries
95
+ **Trend:**
96
+ \`\`\`j1ql
97
+ FIND User AS u
98
+ RETURN count(u) AS value
99
+ \`\`\`
100
+ **Non-Trend:**
101
+ \`\`\`j1ql
102
+ FIND User AS u
103
+ RETURN count(u) AS value
104
+ \`\`\`
105
+
106
+ ---
107
+
108
+ ## Pie Chart
109
+ The pie chart displays values from one or more queries, as they relate to each other, in the form of slices of a pie. The arc length, area and central angle of a slice are all proportional to the slice's value, as it relates to the sum of all values. This type of chart is best used when you want a quick comparison of a small set of values in an aesthetically pleasing form. In the trend version of this chart you are able to track the value change of each slice value as well as the total value through a spark line to see if the data set is getting larger or smaller over time.
110
+
111
+ ### Query Requirements
112
+ Expects 2 or more pairs of \`name\` and numeric \`value\` properties.
113
+
114
+ ### Example Queries
115
+ **Trend:**
116
+ \`\`\`j1ql
117
+ FIND DataStore AS ds
118
+ THAT RELATES TO (Account|Service) AS a
119
+ RETURN
120
+ a.tag.AccountName AS name,
121
+ count(ds) AS value
122
+ \`\`\`
123
+ **Non-Trend 1:**
124
+ \`\`\`j1ql
125
+ FIND DataStore AS ds
126
+ THAT RELATES TO (Account|Service) AS a
127
+ RETURN
128
+ a.tag.AccountName AS name,
129
+ count(ds) AS value
130
+ \`\`\`
131
+ **Non-Trend 2:**
132
+ \`\`\`j1ql
133
+ FIND DataStore AS ds
134
+ THAT RELATES TO (Account|Service) AS a
135
+ RETURN
136
+ count(ds) AS value
137
+ \`\`\`
138
+
139
+ ---
140
+
141
+ ## Bar Chart
142
+ The bar chart visualization allows you to view categorical data to analyze your queries with a specified x and y axis. You are able to run multiple queries and visualize the bar chart in stacked format. This chart is best suited for categorizing your results. In the trend version of the chart you are able to visualize the value change of each categorical result through a %Change indicator and a reference category bar of the result value from the previous time period selected.
143
+
144
+ ### Query Requirements
145
+ Expects one or more \`x\` and \`y\` values.
146
+
147
+ ### Example Queries
148
+ **Trend:**
149
+ \`\`\`j1ql
150
+ FIND Person AS p
151
+ THAT IS User AS u
152
+ THAT opened PR
153
+ WITH state='OPEN' AS pr
154
+ RETURN
155
+ p.displayName AS x,
156
+ count(pr) AS y
157
+ ORDER BY y DESC
158
+ \`\`\`
159
+ **Non-Trend:**
160
+ \`\`\`j1ql
161
+ FIND Person AS p
162
+ THAT IS User AS u
163
+ THAT opened PR
164
+ WITH state='OPEN' AS pr
165
+ RETURN
166
+ p.displayName AS x,
167
+ count(pr) AS y
168
+ ORDER BY y DESC
169
+ LIMIT 5
170
+ \`\`\`
171
+
172
+ ---
173
+
174
+ ## Line Chart
175
+ The line chart is created by plotting a series of several points and connecting them with a straight line. This is best suited for data that has historical trend data enabled.
176
+
177
+ ### Query Requirements
178
+ Expects \`line\` and \`y\` values.
179
+
180
+ ### Example Queries
181
+ **Trend:**
182
+ \`\`\`j1ql
183
+ FIND Finding
184
+ WITH createdOn > date.now-7day AS f
185
+ RETURN
186
+ count(f) AS y,
187
+ f.numericSeverity AS line
188
+ \`\`\`
189
+ **Non-Trend:**
190
+ \`\`\`j1ql
191
+ FIND Finding
192
+ WITH createdOn > date.now-7day AS f
193
+ RETURN
194
+ f.createdOn AS x,
195
+ count(f) AS y,
196
+ f.numericSeverity AS line
197
+ \`\`\`
198
+
199
+ ---
200
+
201
+ ## Matrix Chart
202
+ The matrix chart is used for analyzing and displaying the relationship between data sets. The matrix diagram shows the relationship between two, three, or four groups of information.
203
+
204
+ ### Query Requirements
205
+ Expects \`x\` and \`y\` row and column names. Optional \`label\` to be shown in each cell. Any additional properties returned will be shown as key: value.
206
+
207
+ ### Example Queries
208
+ **Firewall matrix:**
209
+ \`\`\`j1ql
210
+ FIND Firewall AS row
211
+ THAT allows AS rel
212
+ Network AS col
213
+ RETURN
214
+ row.displayName AS x,
215
+ col.displayName AS y,
216
+ rel.egress AS egress,
217
+ rel.ingress AS ingress,
218
+ rel.fromPort as fromPort,
219
+ rel.toPort as toPort,
220
+ rel.ipProtocol AS label
221
+ \`\`\`
222
+
223
+ ---
224
+
225
+ ## Table
226
+ The tables chart present data in as close to raw form as possible. Tables are meant to be read, so they are ideal when you have data that cannot easily be presented visually, or when the data requires more specific attention.
227
+
228
+ ### Query Requirements
229
+ Note: This chart is currently limited to displaying 250 rows, and it does not handle pagination. It is recommended to use LIMIT and ORDER BY to sort and limit the results.
230
+
231
+ ### Example Queries
232
+ **Most recent people:**
233
+ \`\`\`j1ql
234
+ FIND Person AS p
235
+ RETURN
236
+ p.name AS Name,
237
+ p.email AS Email,
238
+ p.manager AS Manager
239
+ ORDER BY p._createdOn DESC
240
+ LIMIT 5
241
+ \`\`\`
242
+
243
+ ---
244
+
245
+ ## Graph Chart
246
+ The graph chart displays a tree graph of query results. This chart is best used to visualize specific relationships between entities.
247
+
248
+ ### Example Queries
249
+ **Most recent people:**
250
+ \`\`\`j1ql
251
+ FIND Person RETURN TREE
252
+ \`\`\`
253
+
254
+ ---
255
+
256
+ ## Status
257
+ The status chart displays a visual summary of correlating queries. This chart is best used to show positive or negative results based on if relationships are present in query results. This chart is best suited by multiple queries.
258
+
259
+ ### Example Queries
260
+ **Users passing security check:**
261
+ \`\`\`j1ql
262
+ Find Person as p
263
+ Return
264
+ p.email as id,
265
+ p.name as displayName,
266
+ p.acceptedSecurityPolicyOn,
267
+ p.backgroundCheck,
268
+ p.iconWebLink as iconWebLink
269
+ \`\`\`
270
+ \`\`\`j1ql
271
+ Find Person as p that owns Device as d
272
+ Return
273
+ p.email as id,
274
+ d.encrypted
275
+ \`\`\`
276
+ \`\`\`j1ql
277
+ Find Person as p that is User as u
278
+ Return
279
+ p.email as id,
280
+ count(u)
281
+ \`\`\`
282
+
283
+ ---
284
+
285
+ ## Area Chart
286
+ The area chart is a graph that combines a line chart and a bar chart to show changes in quantities over time. This chart requires the assets in the query to have relevant dates in their properties. For the best results, these charts can be generated by J1 Questions that have trend collection enabled. (This will soon be available straight from Insights.)
287
+
288
+ ### Query Requirements
289
+ Expects two or more \`x\` and \`y\` values.
290
+
291
+ ### Example Queries
292
+ **Top 5 most open PRs by Person:**
293
+ \`\`\`j1ql
294
+ FIND Person AS p
295
+ THAT IS User AS u
296
+ THAT opened PR
297
+ WITH state='OPEN' AS pr
298
+ RETURN
299
+ p.displayName AS x,
300
+ count(pr) AS y
301
+ ORDER BY y DESC
302
+ LIMIT 5
303
+ \`\`\`
304
+
305
+ ---
306
+
307
+ ## Markdown Chart
308
+ The markdown chart/widget allows you to display custom Markdown content directly on your dashboard. This is useful for adding documentation, instructions, or contextual information alongside your visualizations.
309
+
310
+ ### Query Requirements
311
+ - No queries are required for this widget type.
312
+ - The widget's settings must include a \`markdown.text\` property containing the Markdown content to display.
313
+
314
+ ### Example Configuration
315
+ **Simple Markdown widget:**
316
+ \`\`\`json
317
+ {
318
+ "type": "markdown",
319
+ "config": {
320
+ "queries": [],
321
+ "settings": {
322
+ "markdown": {
323
+ "text": "# test markdown here\nsome more content"
324
+ }
325
+ }
326
+ }
327
+ }
328
+ \`\`\`
329
+
330
+ ---
331
+ `,
332
+ "create-dashboard.md": `# Create Dashboard Tool
333
+
334
+ Creates a new dashboard in JupiterOne. This tool is simple and self-descriptive: provide a name and a type to create a dashboard. Unless specified otherwise, default to creating personal dashboards.
335
+ After creating a dashboard and all its widgets, you will typically want to call \`update-dashboard\` tool to set a layout favorable for the user, widgets should never be left at their default size.
336
+
337
+ ## Valid Dashboard Types
338
+ \`\`\`typescript
339
+ export enum DashboardType {
340
+ USER = 'User',
341
+ ACCOUNT = 'Account',
342
+ }
343
+ \`\`\``,
344
+ "create-inline-question-rule.md": `# JupiterOne Rule Creation Tool - Complete Guide
345
+
346
+ **Purpose**: Creates inline question-based alert rules in JupiterOne to monitor entities and trigger alerts based on specified conditions.
347
+
348
+ The first step in creating a rule is to identify the query you want to use in order to get the data you want to take action with. Use the \`execute-j1ql-query\` tool to find the correct query.
349
+
350
+ ## Key Requirements for Success
351
+
352
+ ### 1. Condition Format (Critical)
353
+
354
+ The \`condition\` parameter must use JupiterOne's specific array format:
355
+
356
+ - **Structure**: \`["LOGICAL_OPERATOR", [left_value, operator, right_value]]\`
357
+ - **Example**: \`["AND", ["queries.queryName.total", ">", 0]]\`
358
+ - **Supported operators**: \`>\`, \`<\`, \`>=\`, \`<=\`, \`=\`, \`!=\`
359
+ - **Logical operators**: \`"AND"\`, \`"OR"\`
360
+
361
+ ### 2. Operations Structure
362
+
363
+ The \`when\` clause should only contain:
364
+
365
+ - \`type\`: Always \`"FILTER"\`
366
+ - \`condition\`: The array format described above
367
+ - **Do NOT include**: \`version\`, \`specVersion\` (these belong at the rule level, not in the when clause)
368
+
369
+ ### 3. Query Naming Convention
370
+
371
+ - Query names in the \`queries\` array must match the references in conditions
372
+ - Example: If query name is \`"users"\`, reference it as \`"queries.users.total"\`
373
+ - **IMPORTANT**: Use \`"query0"\` as the standard query name for compatibility with existing patterns
374
+
375
+ ### 4. New Entity Detection
376
+
377
+ - Use \`triggerActionsOnNewEntitiesOnly: true\` to only alert on genuinely new entities
378
+ - This prevents re-alerting on existing entities every polling cycle
379
+ - Essential for "new user" or "new resource" type alerts
380
+
381
+ ### 5. Polling Intervals
382
+
383
+ - **Default**: Use \`"ONE_DAY"\` unless the user specifically requests a different interval
384
+ - **Available options**: \`"DISABLED"\`, \`"THIRTY_MINUTES"\`, \`"ONE_HOUR"\`, \`"FOUR_HOURS"\`, \`"EIGHT_HOURS"\`, \`"TWELVE_HOURS"\`, \`"ONE_DAY"\`, \`"ONE_WEEK"\`
385
+ - Only use more frequent intervals (like \`"THIRTY_MINUTES"\`) when explicitly requested or for time-sensitive security alerts
386
+
387
+ ### 6. Tags vs Labels (Important)
388
+
389
+ - **DEPRECATED**: The \`tags\` array field is deprecated and should always be set to an empty array \`[]\`
390
+ - **USE INSTEAD**: For tagging functionality, use the \`labels\` field with key-value pairs
391
+ - **Format**: \`labels: [{"labelName": "key", "labelValue": "value"}]\`
392
+ - **When users ask for tagging**: Always use the \`labels\` field to meet their needs
393
+ - **Note**: The \`tags\` field is still required in the schema for compatibility but should remain empty
394
+
395
+ ## Required Schema Fields
396
+
397
+ ### Complete Required Parameters for create-inline-question-rule
398
+
399
+ **CRITICAL**: All of these fields must be included for successful rule creation:
400
+
401
+ \`\`\`json
402
+ {
403
+ "name": "Rule Name",
404
+ "description": "Rule description",
405
+ "notifyOnFailure": true,
406
+ "triggerActionsOnNewEntitiesOnly": true,
407
+ "ignorePreviousResults": false,
408
+ "pollingInterval": "ONE_DAY",
409
+ "templates": {},
410
+ "outputs": ["alertLevel"],
411
+ "tags": [],
412
+ "labels": [
413
+ {"labelName": "environment", "labelValue": "production"},
414
+ {"labelName": "team", "labelValue": "security"}
415
+ ],
416
+ "queries": [
417
+ {
418
+ "query": "FIND Entity...",
419
+ "name": "query0",
420
+ "version": "v1",
421
+ "includeDeleted": false
422
+ }
423
+ ],
424
+ "operations": [
425
+ {
426
+ "when": {
427
+ "type": "FILTER",
428
+ "condition": ["AND", ["queries.query0.total", ">", 0]]
429
+ },
430
+ "actions": [...]
431
+ }
432
+ ]
433
+ }
434
+ \`\`\`
435
+
436
+ **Key Schema Requirements**:
437
+
438
+ - \`ignorePreviousResults\`: Must be included (typically \`false\`)
439
+ - \`templates\`: Must be included (use \`{}\` if empty)
440
+ - \`tags\`: Must be included but should always be empty \`[]\` (deprecated field)
441
+ - \`labels\`: Use this for actual tagging functionality with key-value pairs
442
+ - Query \`name\`: Use \`"query0"\` for primary query
443
+ - Query \`version\`: Include \`"v1"\` for compatibility
444
+ - Query \`includeDeleted\`: Must be explicitly set to \`false\`
445
+
446
+ ## Available Action Types
447
+
448
+ ### 1. SET_PROPERTY
449
+
450
+ Sets a property value on the alert (commonly used for alert severity levels).
451
+
452
+ **Configuration**:
453
+
454
+ \`\`\`json
455
+ {
456
+ "type": "SET_PROPERTY",
457
+ "targetProperty": "alertLevel",
458
+ "targetValue": "CRITICAL"
459
+ }
460
+ \`\`\`
461
+
462
+ **Common Values for alertLevel**: \`"LOW"\`, \`"MEDIUM"\`, \`"HIGH"\`, \`"CRITICAL"\`, \`"INFO"\`
463
+
464
+ ### 2. CREATE_ALERT
465
+
466
+ Creates a basic alert in JupiterOne.
467
+
468
+ **Configuration**:
469
+
470
+ \`\`\`json
471
+ {
472
+ "type": "CREATE_ALERT"
473
+ }
474
+ \`\`\`
475
+
476
+ **Note**: This is the most basic action and should almost always be included.
477
+
478
+ ### 3. SEND_EMAIL
479
+
480
+ Sends email notifications to specified recipients.
481
+
482
+ **Configuration**:
483
+
484
+ \`\`\`json
485
+ {
486
+ "type": "SEND_EMAIL",
487
+ "recipients": ["user1@company.com", "user2@company.com"],
488
+ "body": "Affected Items: <br><br>* {{queries.query0.data|mapProperty('displayName')|join('<br>* ')}}"
489
+ }
490
+ \`\`\`
491
+
492
+ **Required Information to Ask User**:
493
+
494
+ - Email addresses of recipients
495
+ - Custom email body content (if desired)
496
+
497
+ **Template Variables Available**:
498
+
499
+ - \`{{alertWebLink}}\` - Link to the alert in JupiterOne
500
+ - \`{{queries.queryName.data|mapProperty('fieldName')|join('separator')}}\` - Format query results
501
+
502
+ ### 4. TAG_ENTITIES
503
+
504
+ Adds or removes tags from entities that triggered the rule.
505
+
506
+ **Configuration**:
507
+
508
+ \`\`\`json
509
+ {
510
+ "type": "TAG_ENTITIES",
511
+ "entities": "{{queries.query0.data}}",
512
+ "tags": [
513
+ { "name": "existing tag to remove", "value": null },
514
+ { "name": "new tag", "value": "tag value" }
515
+ ]
516
+ }
517
+ \`\`\`
518
+
519
+ **Required Information to Ask User**:
520
+
521
+ - Tag names and values to add
522
+ - Tag names to remove (set value to \`null\`)
523
+
524
+ ### 5. SEND_SLACK_MESSAGE
525
+
526
+ Sends messages to Slack channels (requires Slack integration).
527
+
528
+ **Configuration**:
529
+
530
+ \`\`\`json
531
+ {
532
+ "integrationInstanceId": "d97d9127-c532-410a-bf0a-9ea93f66c3d2",
533
+ "type": "SEND_SLACK_MESSAGE",
534
+ "channels": ["#security-alerts", "#general"],
535
+ "body": "*Affected Items:* \n\n- {{queries.query0.data|mapProperty('displayName')|join('\n- ')}}"
536
+ }
537
+ \`\`\`
538
+
539
+ **Required Information to Ask User**:
540
+
541
+ - Slack channel names (with # prefix)
542
+ - Slack integration instance ID (may need to query available integrations)
543
+ - Custom message content (if desired)
544
+
545
+ ### 6. SEND_TO_S3
546
+
547
+ Sends alert data to an S3 bucket (requires AWS S3 integration).
548
+
549
+ **Configuration**:
550
+
551
+ \`\`\`json
552
+ {
553
+ "integrationInstanceId": "f89568b4-2a1b-4bd8-8abd-aee21270df75",
554
+ "type": "SEND_TO_S3",
555
+ "bucket": "security-alerts-bucket",
556
+ "region": "us-east-1",
557
+ "data": {
558
+ "description": "{{alertWebLink}}\n\n**Affected Items:**\n\n* {{queries.query0.data|mapProperty('displayName')|join('\n* ')}}"
559
+ }
560
+ }
561
+ \`\`\`
562
+
563
+ **Required Information to Ask User**:
564
+
565
+ - S3 bucket name
566
+ - AWS region
567
+ - S3 integration instance ID
568
+ - Data structure to send
569
+
570
+ ### 7. CREATE_JIRA_TICKET
571
+
572
+ Creates a Jira ticket for the alert (requires Jira integration).
573
+
574
+ **Configuration**:
575
+
576
+ \`\`\`json
577
+ {
578
+ "integrationInstanceId": "53a99eaa-18a5-45ef-b748-2de39d642a91",
579
+ "type": "CREATE_JIRA_TICKET",
580
+ "entityClass": "Finding",
581
+ "summary": "Security Alert: Critical Unencrypted Data Found",
582
+ "issueType": "Bug",
583
+ "project": "SEC",
584
+ "updateContentOnChanges": false,
585
+ "additionalFields": {
586
+ "description": {
587
+ "type": "doc",
588
+ "version": 1,
589
+ "content": [
590
+ {
591
+ "type": "paragraph",
592
+ "content": [
593
+ {
594
+ "type": "text",
595
+ "text": "{{alertWebLink}}\n\n**Affected Items:**\n\n* {{queries.query0.data|mapProperty('displayName')|join('\n* ')}}"
596
+ }
597
+ ]
598
+ }
599
+ ]
600
+ }
601
+ }
602
+ }
603
+ \`\`\`
604
+
605
+ **Required Information to Ask User**:
606
+
607
+ - Jira project key
608
+ - Issue type (Bug, Task, Story, etc.)
609
+ - Ticket summary/title
610
+ - Jira integration instance ID
611
+ - Additional fields as needed
612
+
613
+ **Common Entity Classes**: \`"Finding"\`, \`"Incident"\`, \`"Issue"\`
614
+
615
+ ## Template Variables and Formatting
616
+
617
+ ### Available Variables
618
+
619
+ - \`{{alertWebLink}}\` - Direct link to the alert in JupiterOne
620
+ - \`{{queries.queryName.data}}\` - Array of entities from the specified query
621
+ - \`{{queries.queryName.total}}\` - Count of entities from the query
622
+
623
+ ### Data Formatting
624
+
625
+ - \`|mapProperty('fieldName')\` - Extract specific field from each entity
626
+ - \`|join('separator')\` - Join array elements with specified separator
627
+ - Example: \`{{queries.users.data|mapProperty('displayName')|join(', ')}}\` - Creates comma-separated list of user names
628
+
629
+ ### Common Formatting Patterns
630
+
631
+ - **HTML list**: \`{{queries.query0.data|mapProperty('displayName')|join('<br>* ')}}\`
632
+ - **Markdown list**: \`{{queries.query0.data|mapProperty('displayName')|join('\n- ')}}\`
633
+ - **Simple list**: \`{{queries.query0.data|mapProperty('displayName')|join('\n* ')}}\`
634
+
635
+ ## Integration Dependencies
636
+
637
+ For actions requiring integrations, you may need to:
638
+
639
+ 1. Query available integration instances using \`get-integration-instances\`
640
+ 2. Ask the user which integration to use
641
+ 3. Use the integration's \`id\` as the \`integrationInstanceId\`
642
+
643
+ **Actions requiring integrations**:
644
+
645
+ - \`SEND_SLACK_MESSAGE\` (Slack integration)
646
+ - \`SEND_TO_S3\` (AWS S3 integration)
647
+ - \`CREATE_JIRA_TICKET\` (Jira integration)
648
+
649
+ ## Working Example Template
650
+
651
+ ### Complete Working Rule Structure
652
+
653
+ Based on confirmed working examples, use this template:
654
+
655
+ \`\`\`json
656
+ {
657
+ "name": "Your Rule Name",
658
+ "description": "Your rule description",
659
+ "notifyOnFailure": true,
660
+ "triggerActionsOnNewEntitiesOnly": true,
661
+ "ignorePreviousResults": false,
662
+ "pollingInterval": "ONE_DAY",
663
+ "templates": {},
664
+ "outputs": ["alertLevel"],
665
+ "tags": [],
666
+ "labels": [
667
+ { "labelName": "severity", "labelValue": "high" },
668
+ { "labelName": "category", "labelValue": "security" }
669
+ ],
670
+ "question": {
671
+ "queries": [
672
+ {
673
+ "query": "FIND Entity WITH condition",
674
+ "name": "query0",
675
+ "version": "v1",
676
+ "includeDeleted": false
677
+ }
678
+ ]
679
+ },
680
+ "operations": [
681
+ {
682
+ "when": {
683
+ "type": "FILTER",
684
+ "condition": ["AND", ["queries.query0.total", ">", 0]]
685
+ },
686
+ "actions": [
687
+ {
688
+ "type": "SET_PROPERTY",
689
+ "targetProperty": "alertLevel",
690
+ "targetValue": "CRITICAL"
691
+ },
692
+ {
693
+ "type": "CREATE_ALERT"
694
+ },
695
+ {
696
+ "type": "SEND_EMAIL",
697
+ "recipients": ["user@company.com"],
698
+ "body": "Affected Items: <br><br>* {{queries.query0.data|mapProperty('displayName')|join('<br>* ')}}"
699
+ }
700
+ ]
701
+ }
702
+ ]
703
+ }
704
+ \`\`\`
705
+
706
+ ## Common Patterns
707
+
708
+ ### New Entity Monitoring
709
+
710
+ \`\`\`json
711
+ {
712
+ "condition": ["AND", ["queries.query0.total", ">", 0]],
713
+ "triggerActionsOnNewEntitiesOnly": true
714
+ }
715
+ \`\`\`
716
+
717
+ ### Threshold-based Alerts
718
+
719
+ \`\`\`json
720
+ {
721
+ "condition": ["AND", ["queries.query0.total", ">=", 5]]
722
+ }
723
+ \`\`\`
724
+
725
+ ### Multi-action Rule Example
726
+
727
+ \`\`\`json
728
+ "actions": [
729
+ {"type": "SET_PROPERTY", "targetProperty": "alertLevel", "targetValue": "HIGH"},
730
+ {"type": "CREATE_ALERT"},
731
+ {"type": "SEND_EMAIL", "recipients": ["security@company.com"], "body": "Security issue detected: {{alertWebLink}}"},
732
+ {"type": "TAG_ENTITIES", "entities": "{{queries.query0.data}}", "tags": [{"name": "needs-review", "value": "true"}]}
733
+ ]
734
+ \`\`\`
735
+
736
+ ## Debugging Tips
737
+
738
+ - If you get "Invalid conjunction operator" errors, check the condition array format
739
+ - If you get "additional properties" errors, remove extra fields from the \`when\` clause
740
+ - If you get missing property errors, ensure all required schema fields are included
741
+ - **Always include**: \`ignorePreviousResults\`, \`templates\`, \`tags\`, query \`version\` and \`includeDeleted\`
742
+ - Always reference existing rules with \`get-rule-details\` to see working examples
743
+ - Test with simple conditions first, then add complexity
744
+ - Use \`"query0"\` as the standard query name for compatibility
745
+
746
+ ## Best Practices
747
+
748
+ - Use descriptive query names that match their purpose (but prefer \`"query0"\` for main query)
749
+ - Include relevant entity fields in \`outputs\` for alert context
750
+ - Set appropriate polling intervals (default to \`"ONE_DAY"\` unless specified)
751
+ - Use the \`labels\` field for rule organization and tagging (not the deprecated \`tags\` field)
752
+ - Use \`notifyOnFailure: true\` to catch rule execution issues
753
+ - Always include \`CREATE_ALERT\` action as a baseline
754
+ - Always include all required schema fields from the working template
755
+ - Ask users for specific details when configuring notification actions (emails, channels, etc.)
756
+ - When users request tagging functionality, use the \`labels\` field with key-value pairs
757
+
758
+ This format ensures reliable rule creation and helps avoid common pitfalls encountered during rule development.
759
+ `,
760
+ "create-j1ql-from-natural-language.md": `# JupiterOne Natural Language to J1QL Converter
761
+
762
+ **Purpose**: Converts natural language queries into JupiterOne Query Language (J1QL) syntax using AI-powered translation.
763
+ Unless the user gives a specific query to run, this should always be used for determing a query to use for any (but not exclusively) of the following:
764
+ - Queries for rules
765
+ - Queries for widgets
766
+ - Queries to answer a user's question regarding their data in jupiterone`,
767
+ "execute-j1ql-query.md": `# JupiterOne J1QL Query Executor
768
+
769
+ **Purpose**: Executes JupiterOne Query Language (J1QL) queries against your JupiterOne data and returns the results. This tool is used to directly run J1QL queries that have been created, either manually or through the natural language converter.
770
+
771
+ This tool should be used when:
772
+ - You need to validate the data of a query
773
+ - You need to get results from a previously generated query
774
+ - You want to test a query before using it in a rule or widget
775
+ - You need to analyze data directly using J1QL
776
+
777
+ The tool supports various query parameters including:
778
+ - Including/excluding deleted entities
779
+ - Returning row metadata
780
+ - Returning computed properties
781
+ - Applying scope filters
782
+ - Pagination using cursors
783
+
784
+ ### JupiterOne Query Language (J1QL) Quick Reference
785
+
786
+ > **IMPORTANT:** Always validate queries using this tool before creating rules or widgets. Start with discovery queries if unsure about data structure.
787
+
788
+ #### Core Concepts
789
+
790
+ **Entity and Relationship Structure**
791
+ - **Entities**: Assets in your environment with specific classes and types
792
+ - **Entity Class**: Always \`TitleCase\` (e.g., \`User\`, \`Host\`, \`Application\`)
793
+ - **Entity Type**: Always \`snake_case\` (e.g., \`aws_iam_user\`, \`github_user\`)
794
+ - **Relationships**: Connections between entities
795
+ - **Relationship Class**: Always \`ALLCAPS\` (e.g., \`HAS\`, \`USES\`, \`PROTECTS\`)
796
+ - **Default Returns**: Queries return the first entity after FIND unless explicitly modified with RETURN
797
+ - **Unified Entities**: Deduplicated repersentation of assets seen in JupiterOne have a \`_type: unified_entity\`
798
+
799
+ #### Unified Entities
800
+
801
+ Unified entities are the deduplicated "real-world" repersentation of data seen by JupiterOne. All Unified entities have a \`_type = unified_entity\`, and this is often the entity the user wants referenced.
802
+
803
+ Unified Entities currently supported:
804
+ - **UnifiedDevice**: Deduplicated representation of devices in the inventory
805
+ - **UnifiedIdentity**: Deduplicated representation of identities in the inventory
806
+ - **UnifiedVulnerability**: Deduplicated representation of vulnerabilities in the inventory
807
+
808
+ Unified entities typically also have additional enrichment making them valuable assets to search off of or reference back to. Unified entities only have relationships to the entities that they deduplicate, and you need to query off of their source components to get more context - for example a list of all devices related to users would look like:
809
+
810
+ \`\`\`
811
+ FIND UnifiedIdentity AS identity
812
+ THAT IS << User
813
+ THAT RELATES TO AS rel (Device|Host)
814
+ THAT IS >> UnifiedDevice AS device
815
+ RETURN identity.displayName, rel._class, device.displayName
816
+ \`\`\`
817
+
818
+ **IMPORTANT**: Whenever answering questions about entities that have a unified entity representation, answer the question in terms of unified entities.
819
+
820
+ #### MANDATORY Query Structure
821
+
822
+ \`\`\`
823
+ FIND <entity> [WITH <property_filter>] [AS <alias>]
824
+ [THAT <relationship> [<direction>] <entity> [WITH <property_filter>] [AS <alias>]]
825
+ [WHERE <condition>]
826
+ [RETURN <field_selection>]
827
+ [ORDER BY <field>]
828
+ [SKIP <number>]
829
+ [LIMIT <number>]
830
+ \`\`\`
831
+
832
+ #### ⚠️ CRITICAL SYNTAX RULES ⚠️ ALL QUERIES MUST ADHERE TO THESE RULES
833
+
834
+ 1. **Alias Placement**: Aliases MUST follow the WITH statement when filtering
835
+ ✅ \`FIND Device WITH name~='TEST' AS dev\`
836
+ ❌ \`FIND Device AS dev WITH name~='TEST'\`
837
+
838
+ 2. **String Values**: ALWAYS use single quotes for strings, NEVER double quotes
839
+ ✅ \`name ~= 'john'\`
840
+ ❌ \`name ~= "john"\`
841
+
842
+ 3. **WITH vs WHERE**: Use WITH for entity properties, WHERE only for relationship properties or cross-entity comparisons
843
+ ✅ \`FIND User WITH active = true\`
844
+ ✅ \`FIND User AS u THAT HAS Device AS d WHERE u.active = true AND d.platform = 'darwin'\`
845
+ ❌ \`FIND User WHERE active = true\`
846
+
847
+ 4. **LIMIT Usage**: ALWAYS include LIMIT (5-100) or use COUNT for discovery
848
+ ✅ \`FIND User LIMIT 50\`
849
+ ✅ \`FIND User AS u RETURN u._type, count(u)\`
850
+ ❌ \`FIND User\` (no limit specified)
851
+
852
+ 5. **Relationship Direction**: Direction arrows MUST follow the relationship verb
853
+ ✅ \`FIND User THAT HAS >> Device\`
854
+ ❌ \`FIND User THAT >> HAS Device\`
855
+
856
+ 6. **Optional Traversals**: Use parentheses and question mark
857
+ ✅ \`FIND User AS u (THAT IS Person AS p)?\`
858
+ ❌ \`FIND User AS u THAT IS? Person AS p\`
859
+
860
+ 7. **Using Aggregates For Discovery**: Alias COUNT and use ORDER BY
861
+ ✅ \`FIND * AS ent RETURN ent._class, COUNT(ent) AS cnt ORDER BY cnt DESC LIMIT 50\`
862
+ ❌ \`FIND * AS ent RETURN ent._class, COUNT(ent) LIMIT 50\`
863
+
864
+ #### Entity Selection
865
+
866
+ **Finding by class or type**:
867
+ \`\`\`j1ql
868
+ FIND User LIMIT 10 # Find entities with _class = 'User'
869
+ FIND aws_iam_user LIMIT 10 # Find entities with _type = 'aws_iam_user'
870
+ FIND * WITH _type='aws_instance' LIMIT 10 # Filter any entity by type
871
+ \`\`\`
872
+
873
+ **Finding multiple entity types**:
874
+ \`\`\`j1ql
875
+ FIND (User | Host) LIMIT 10 # Find entities with _class = 'User' OR _class = 'Host'
876
+ \`\`\`
877
+
878
+ #### Property Filtering (WITH)
879
+
880
+ **Basic property filtering**:
881
+ \`\`\`j1ql
882
+ FIND User WITH active = true LIMIT 10
883
+ FIND DataStore WITH encrypted = false LIMIT 10
884
+ \`\`\`
885
+
886
+ **WITH filtering with alias** (CORRECT ORDER):
887
+ \`\`\`j1ql
888
+ FIND User WITH active = true AS u LIMIT 10
889
+ FIND DataStore WITH encrypted = false AS ds LIMIT 10
890
+ \`\`\`
891
+
892
+ **WITH filtering with alias AND Advanced fiiltering** (CORRECT ORDER):
893
+ \`\`\`j1ql
894
+ FIND User WITH accountCount > 0 AS u RETURN u.displayName
895
+ FIND DataStore WITH name~='ROOT' OR name=/iam/i AS ds RETURN ds.name, ds.encrypted LIMIT 10
896
+ \`\`\`
897
+
898
+ **Multiple property filters**:
899
+ \`\`\`j1ql
900
+ FIND User WITH active = true AND mfaEnabled = false LIMIT 10
901
+ FIND Host WITH platform = 'darwin' OR platform = 'linux' LIMIT 10
902
+ \`\`\`
903
+
904
+ **Multiple value matching**:
905
+ \`\`\`j1ql
906
+ FIND Host WITH platform = ('darwin' OR 'linux') LIMIT 10
907
+ \`\`\`
908
+
909
+ **Property existence check**:
910
+ \`\`\`j1ql
911
+ FIND DataStore WITH encrypted = undefined LIMIT 10
912
+ \`\`\`
913
+
914
+ **Special character property names**:
915
+ \`\`\`j1ql
916
+ FIND Host WITH [tag.special-name] = 'value' LIMIT 10
917
+ \`\`\`
918
+
919
+ #### String Comparisons
920
+
921
+ J1QL comparison operators:
922
+ - \`=\` : equals (exact match)
923
+ - \`!=\` : not equals
924
+ - \`~=\` : contains
925
+ - \`^=\` : starts with
926
+ - \`$=\` : ends with
927
+ - \`!~=\` : does not contain
928
+ - \`!^=\` : does not start with
929
+ - \`!$=\` : does not end with
930
+
931
+ \`\`\`j1ql
932
+ FIND User WITH username ~= 'john' LIMIT 10
933
+ FIND Host WITH name ^= 'web' LIMIT 10
934
+ \`\`\`
935
+
936
+ #### Case-Insensitive Matching (Regex)
937
+
938
+ \`\`\`j1ql
939
+ FIND User WITH username=/john/ LIMIT 10 # Case-insensitive match
940
+ \`\`\`
941
+
942
+ #### Traversing Relationships (THAT)
943
+
944
+ ## Important: Don't assume relationship VERBS, either do discovery to determine the correct relationship or use the wild card relationship "THAT RELATES TO"
945
+
946
+ **Any relationship traversal (i.e. wildcard)**:
947
+ \`\`\`j1ql
948
+ FIND User THAT RELATES TO Application LIMIT 10
949
+ \`\`\`
950
+
951
+ **Basic traversal**:
952
+ \`\`\`j1ql
953
+ FIND User THAT HAS Device LIMIT 10
954
+ \`\`\`
955
+
956
+ **Multiple traversal steps**:
957
+ \`\`\`j1ql
958
+ FIND User THAT HAS Device THAT INSTALLED Application LIMIT 10
959
+ \`\`\`
960
+
961
+ **Multi-step traversal with filtering**:
962
+ \`\`\`j1ql
963
+ FIND User WITH active = true THAT HAS Device THAT INSTALLED Application WITH vendor = 'Microsoft' LIMIT 10
964
+ \`\`\`
965
+
966
+ **Multiple relationship types**:
967
+ \`\`\`j1ql
968
+ FIND HostAgent THAT (MONITORS|PROTECTS) Host LIMIT 10
969
+ \`\`\`
970
+
971
+ **Negating relationships**:
972
+ \`\`\`j1ql
973
+ FIND User THAT !HAS Device LIMIT 10 # Find users that don't have devices
974
+ \`\`\`
975
+
976
+ **Relationship direction** (arrows MUST follow relationship):
977
+ \`\`\`j1ql
978
+ FIND User THAT HAS >> Device LIMIT 10 # Direction from User to Device
979
+ FIND Device THAT HAS << User LIMIT 10 # Direction from User to Device
980
+ \`\`\`
981
+
982
+ #### Using Aliases (AS) - ALWAYS AFTER WITH CLAUSE
983
+
984
+ \`\`\`j1ql
985
+ FIND User WITH active = true AS u
986
+ THAT HAS AS relationship Device WITH platform = 'darwin' AS d
987
+ RETURN u._type, relationship._class, d._type, COUNT(relationship)
988
+ LIMIT 10
989
+ \`\`\`
990
+
991
+ #### Post-Traversal Filtering (WHERE) - ONLY FOR RELATIONSHIPS OR CROSS-ENTITY COMPARISON
992
+
993
+ **Example of filtering on relationship properties**
994
+ \`\`\`j1ql
995
+ FIND Firewall AS fw
996
+ THAT ALLOWS AS rule * AS n
997
+ WHERE rule.ingress = true
998
+ LIMIT 10
999
+ \`\`\`
1000
+
1001
+ \`\`\`j1ql
1002
+ FIND User AS u
1003
+ THAT HAS Device AS d
1004
+ WHERE u.active = true AND d.platform = 'darwin'
1005
+ LIMIT 10
1006
+ \`\`\`
1007
+
1008
+ #### Selecting Return Values (RETURN)
1009
+
1010
+ \`\`\`j1ql
1011
+ FIND User AS u
1012
+ THAT HAS Device AS d
1013
+ RETURN u.username, d.name
1014
+ LIMIT 10
1015
+ \`\`\`
1016
+
1017
+ Return all properties:
1018
+ \`\`\`j1ql
1019
+ FIND User AS u RETURN u.* LIMIT 10
1020
+ \`\`\`
1021
+
1022
+ #### Aggregation Functions (USE FOR DISCOVERY)
1023
+
1024
+ Available aggregations:
1025
+ - \`count(selector)\`
1026
+ - \`min(selector.field)\`
1027
+ - \`max(selector.field)\`
1028
+ - \`avg(selector.field)\`
1029
+ - \`sum(selector.field)\`
1030
+
1031
+ \`\`\`j1ql
1032
+ # Basic count
1033
+ FIND User AS u RETURN count(u)
1034
+
1035
+ # Group by with count
1036
+ FIND User AS u RETURN u._type, count(u)
1037
+
1038
+ # Multiple aggregations
1039
+ FIND Account AS acct THAT HAS User AS user
1040
+ RETURN acct.name, count(user), avg(user.lastLoginOn)
1041
+ \`\`\`
1042
+
1043
+ #### Date Comparisons
1044
+
1045
+ \`\`\`j1ql
1046
+ FIND User WITH createdOn > date.now - 7 days LIMIT 10
1047
+ \`\`\`
1048
+
1049
+ Supported units: \`hour(s)\`, \`day(s)\`, \`month(s)\`, \`year(s)\`
1050
+
1051
+ #### Math Operations
1052
+
1053
+ \`\`\`j1ql
1054
+ FIND aws_instance AS i
1055
+ RETURN i.name, i.memorySize * 0.001 AS memoryGB
1056
+ LIMIT 10
1057
+ \`\`\`
1058
+
1059
+ #### Sorting and Pagination
1060
+
1061
+ \`\`\`j1ql
1062
+ FIND User AS u
1063
+ ORDER BY u.username
1064
+ SKIP 10
1065
+ LIMIT 5
1066
+ \`\`\`
1067
+
1068
+ #### Optional Traversals (PROPER SYNTAX)
1069
+
1070
+ \`\`\`j1ql
1071
+ FIND User AS u
1072
+ (THAT IS Person AS p)?
1073
+ THAT HAS Device AS d
1074
+ LIMIT 10
1075
+ \`\`\`
1076
+
1077
+ Optional traversal with property access:
1078
+ \`\`\`j1ql
1079
+ FIND User AS u
1080
+ (THAT IS Person AS p)?
1081
+ THAT HAS Device AS d
1082
+ RETURN u.username, p.email, d.name
1083
+ LIMIT 10
1084
+ \`\`\`
1085
+
1086
+ #### Discovery Queries - ALWAYS START HERE
1087
+
1088
+ 1. **Find all entity classes**: \`FIND * AS e RETURN e._class, COUNT(e)\`
1089
+ 2. **Explore entity properties**: \`FIND EntityClass AS e RETURN e.* LIMIT 10\`
1090
+ 3. **Discover relationships**: \`FIND Entity1 THAT RELATES TO AS rel Entity2 RETURN rel._class\`
1091
+ 4. **Check property values**: \`FIND Entity AS e RETURN e.property, COUNT(e)\`
1092
+
1093
+ #### ⚠️ QUERY VALIDATION CHECKLIST ⚠️
1094
+
1095
+ Before running any J1QL query, verify:
1096
+
1097
+ 1. ✓ FIND statement specifies entity class or type
1098
+ 2. ✓ All string values use single quotes, not double quotes
1099
+ 3. ✓ Aliases are placed AFTER the WITH statement
1100
+ 4. ✓ All queries include either LIMIT or use COUNT aggregation
1101
+ 5. ✓ WITH is used for entity properties, WHERE only for relationship properties or cross-entity comparisons
1102
+ 6. ✓ Direction arrows (>> or <<) are placed after relationship verbs
1103
+ 7. ✓ Optional traversals use proper parentheses and question mark syntax
1104
+ 8. ✓ All aliases referenced in RETURN or WHERE are properly defined earlier
1105
+
1106
+ #### Most Common Errors (Quick Reference)
1107
+
1108
+ 1. **Missing quotes**: \`name = john\` → \`name = 'john'\`
1109
+ 2. **Wrong quotes**: \`name = "john"\` → \`name = 'john'\`
1110
+ 3. **Alias placement**: \`AS u WITH active = true\` → \`WITH active = true AS u\`
1111
+ 4. **WHERE needs alias**: \`WHERE active = true\` → \`AS u WHERE u.active = true\`
1112
+ 5. **Undefined alias**: \`FIND User RETURN u.name\` → \`FIND User AS u RETURN u.name\`
1113
+ 6. **No LIMIT**: Add \`LIMIT 100\` or use \`COUNT()\` to prevent timeouts
1114
+
1115
+ #### Common Patterns & Examples
1116
+
1117
+ **Security Queries**:
1118
+ - Unencrypted data: \`FIND DataStore WITH encrypted = false\`
1119
+ - Users without MFA: \`FIND User WITH mfaEnabled != true\`
1120
+ - Critical findings: \`FIND Finding WITH severity = "critical"\`
1121
+
1122
+ **Dashboard Queries**:
1123
+ - Pie chart: Return \`name\` and \`value\` pairs
1124
+ - Number chart: Return single \`value\`
1125
+ - Bar chart: Return \`x\` and \`y\` values
1126
+ - Table: Return named columns
1127
+
1128
+ **Rule Queries**:
1129
+ - New entities: Add time filter \`WITH _createdOn > date.now - 1 day\`
1130
+ - Always test with \`execute-j1ql-query\` first
1131
+ - Use condition: \`["AND", ["queries.query0.total", ">", 0]]\`
1132
+
1133
+ #### Best Practices
1134
+
1135
+ 1. **Always start with discovery** - Don't assume entity names or properties
1136
+ 2. **Test incrementally** - Build complex queries step by step
1137
+ 3. **Use this tool to validate** - Test every query before using in rules/widgets
1138
+ 4. **Check error suggestions** - The tool provides specific fixes for common issues
1139
+ 5. **Use proper syntax**:
1140
+ - Single quotes for strings
1141
+ - Alias AFTER WITH clause
1142
+ - LIMIT to prevent timeouts
1143
+ - Proper capitalization for classes
1144
+
1145
+ **Remember**: The execute-j1ql-query tool now provides enhanced error messages with specific suggestions. Always test queries here first!`,
1146
+ "get-integration-definitions.md": `# Get Integration Definitions Tool
1147
+
1148
+ Get all available integration definitions in your JupiterOne account. This tool returns a list of integration definitions that can be used to create integration instances. Integration definitions define the types of integrations available (like AWS, Azure, GitHub, etc.) and their configuration requirements. If a user is needing a specific integration instance id for something such as a rule action, you will want to start here and then use the \`get-integration-instances\` tool. Each integration definition will have a Name and a Title field, you should use this to identify which definition is correct for what the user is looking for. As an example, if the user wants to send a slack notification as a part of a rule action, you would want to pull all of the integration definitions and find any that have Slack in the name and/or title. If there are multiple, then clarify the differences to the user and allow them to guide you on which one is correct.
1149
+
1150
+ ## Parameters
1151
+ - \`cursor\` (optional): Pagination cursor to get the next page of results. Use the \`endCursor\` from a previous response's \`pageInfo\`. When you are needing to find a specific type of integration, you will want to query all of the available pages until there are no more left to query so you can select from the entire list.
1152
+ - \`includeConfig\` (optional): Whether to include configuration fields in the response. When true, returns detailed configuration schemas for each integration type. Typically this should be false or omitted entirely.
1153
+
1154
+ ## Example Usage
1155
+ Get all integration definitions without configuration details:
1156
+ \`\`\`json
1157
+ {}
1158
+ \`\`\`
1159
+
1160
+ Get all integration definitions with configuration fields:
1161
+ \`\`\`json
1162
+ {
1163
+ "includeConfig": true
1164
+ }
1165
+ \`\`\`
1166
+
1167
+ Get the next page of integration definitions using a cursor:
1168
+ \`\`\`json
1169
+ {
1170
+ "cursor": "cursor_here"
1171
+ }
1172
+ \`\`\``,
1173
+ "get-integration-instances.md": `# Get Integration Instances Tool
1174
+
1175
+ Get all integration instances in your JupiterOne account. This tool returns a list of configured integration instances, including their configuration, status, and recent job information. Integration instances are the actual configured connections to external services like AWS accounts, GitHub repositories, etc. Unless you have an integration definition id, you typically will not want to query this yet. To get an integration definition id, use the \`get-integration-definitions\` tool. If you need an integration instance id for another task (such as creating a rule action), ask the user which of the possible integrations they want you to use.
1176
+
1177
+ ## Parameters
1178
+ - \`definitionId\` (optional): Filter instances by a specific integration definition ID. Use this to get only instances of a particular integration type.
1179
+ - \`limit\` (optional): Maximum number of instances to return (between 1 and 1000).
1180
+
1181
+ ## Example Usage
1182
+ Get all integration instances:
1183
+ \`\`\`json
1184
+ {}
1185
+ \`\`\`
1186
+
1187
+ Get the first 10 integration instances:
1188
+ \`\`\`json
1189
+ {
1190
+ "limit": 10
1191
+ }
1192
+ \`\`\`
1193
+
1194
+ Get all instances of a specific integration type:
1195
+ \`\`\`json
1196
+ {
1197
+ "definitionId": "integration-definition-id-here"
1198
+ }
1199
+ \`\`\`
1200
+
1201
+ Get the first 5 instances of a specific integration type:
1202
+ \`\`\`json
1203
+ {
1204
+ "definitionId": "integration-definition-id-here",
1205
+ "limit": 5
1206
+ }
1207
+ \`\`\``,
1208
+ "list-alerts.md": `# List Alerts Tool
1209
+
1210
+ List all currently active alerts in your JupiterOne account. This tool returns a list of active alert instances, including their IDs, names, descriptions, levels, statuses, timestamps, and related rule information. You can optionally specify a limit to restrict the number of alerts returned. If a user is looking for configuration behind an alert, then list out the rules or get the details of the rule associated with an alert. If they are looking for alert data or then use this tool rather than listing rules.
1211
+
1212
+ ## Parameters
1213
+ - \`limit\` (optional): Maximum number of alerts to return (between 1 and 1000).
1214
+
1215
+ ## Example Usage
1216
+ Request the first 5 active alerts:
1217
+ \`\`\`json
1218
+ {
1219
+ "limit": 5
1220
+ }
1221
+ \`\`\``,
1222
+ "list-rules.md": `# List Rules Tool
1223
+
1224
+ List rules in your JupiterOne account using cursor pagination. This tool returns a page of rule instances, including their IDs, names, descriptions, versions, polling intervals, and other metadata. Use the cursor parameter to navigate through pages of results. This does not get alerts, but rather the configuration behind what may generate an alert, or other workflow action.
1225
+
1226
+ ## Parameters
1227
+ - \`limit\` (optional): Maximum number of rules to return per page (between 1 and 1000). Defaults to 100 if not specified.
1228
+ - \`cursor\` (optional): Pagination cursor to get the next page of results. Use the \`endCursor\` from a previous response's \`pageInfo\`. Omit this parameter to get the first page.
1229
+
1230
+ ## Example Usage
1231
+ Get the first page of rules (default page size):
1232
+ \`\`\`json
1233
+ {}
1234
+ \`\`\`
1235
+
1236
+ Get the first page with specific limit:
1237
+ \`\`\`json
1238
+ {
1239
+ "limit": 50
1240
+ }
1241
+ \`\`\`
1242
+
1243
+ Get the next page using a cursor:
1244
+ \`\`\`json
1245
+ {
1246
+ "limit": 50,
1247
+ "cursor": "cursor_value_from_previous_response"
1248
+ }
1249
+ \`\`\`
1250
+
1251
+ ## Response Format
1252
+ All responses include pagination information:
1253
+ \`\`\`json
1254
+ {
1255
+ "returned": 50,
1256
+ "rules": [...],
1257
+ "pageInfo": {
1258
+ "hasNextPage": true,
1259
+ "endCursor": "cursor_for_next_page"
1260
+ }
1261
+ }
1262
+ \`\`\`
1263
+
1264
+ - \`returned\`: Number of rules in this page
1265
+ - \`rules\`: Array of rule objects
1266
+ - \`pageInfo.hasNextPage\`: Whether there are more pages available
1267
+ - \`pageInfo.endCursor\`: Cursor to use for the next page (if \`hasNextPage\` is true)
1268
+
1269
+ ## Pagination Pattern
1270
+ To get all rules across multiple pages:
1271
+ 1. Call with no cursor to get the first page
1272
+ 2. Check if \`pageInfo.hasNextPage\` is true
1273
+ 3. If true, call again with \`cursor\` set to \`pageInfo.endCursor\`
1274
+ 4. Repeat until \`hasNextPage\` is false`,
1275
+ "update-dashboard.md": `Patch an existing dashboard's layout configuration. This tool is primarily used for modifying the layout of widgets on a dashboard after they have been created.
1276
+ You will always want to call this after creating a dashboard and all its widgets so you can give a favorable layout to the user. Widgets should always have a size specified.
1277
+ The layout configuration is organized by screen breakpoint sizes (xs, sm, md, lg, xl) and includes positioning information for each widget. Each layout item contains:
1278
+
1279
+ - \`i\`: Widget ID
1280
+ - \`x\`: X coordinate (horizontal position)
1281
+ - \`y\`: Y coordinate (vertical position)
1282
+ - \`w\`: Width in grid units
1283
+ - \`h\`: Height in grid units
1284
+ - \`moved\`: Whether the widget has been moved (should always be false)
1285
+ - \`static\`: Whether the widget position is fixed (should always be false)
1286
+
1287
+ Example layout configuration:
1288
+
1289
+ \`\`\`json
1290
+ {
1291
+ "xs": [],
1292
+ "sm": [],
1293
+ "md": [
1294
+ {
1295
+ "w": 5,
1296
+ "h": 2,
1297
+ "x": 0,
1298
+ "y": 0,
1299
+ "i": "widget-id-1",
1300
+ "moved": false,
1301
+ "static": false
1302
+ }
1303
+ ],
1304
+ "lg": [],
1305
+ "xl": []
1306
+ }
1307
+ \`\`\`
1308
+
1309
+ Here's an example layout that should be used for inspiration:
1310
+
1311
+ \`\`\`json
1312
+ "layouts": {
1313
+ "xs": [],
1314
+ "sm": [
1315
+ {
1316
+ "w": 1,
1317
+ "h": 1,
1318
+ "x": 0,
1319
+ "y": 0,
1320
+ "i": "cc1bb92b-736b-4b76-bb2a-4ffb3fb6db04"
1321
+ },
1322
+ {
1323
+ "w": 1,
1324
+ "h": 1,
1325
+ "x": 0,
1326
+ "y": 1,
1327
+ "i": "750ea929-fb31-46ef-b1d4-68c53b06e5a3"
1328
+ },
1329
+ {
1330
+ "w": 1,
1331
+ "h": 1,
1332
+ "x": 0,
1333
+ "y": 2,
1334
+ "i": "92507e3e-2c99-4089-b75a-ce97ad4743d5"
1335
+ },
1336
+ {
1337
+ "w": 2,
1338
+ "h": 2,
1339
+ "x": 0,
1340
+ "y": 3,
1341
+ "i": "f1535f10-a7ba-4c74-8ae6-d5be8c5655ee"
1342
+ },
1343
+ {
1344
+ "w": 1,
1345
+ "h": 1,
1346
+ "x": 0,
1347
+ "y": 7,
1348
+ "i": "29df3495-eea3-45a2-b779-788d92c8baa4"
1349
+ },
1350
+ {
1351
+ "w": 1,
1352
+ "h": 1,
1353
+ "x": 0,
1354
+ "y": 8,
1355
+ "i": "814000f8-9ffd-4ac3-90f8-26d321e9eba6"
1356
+ },
1357
+ {
1358
+ "w": 1,
1359
+ "h": 1,
1360
+ "x": 0,
1361
+ "y": 9,
1362
+ "i": "293fc7fd-eb34-4383-82b8-068b62ffdd61"
1363
+ },
1364
+ {
1365
+ "w": 1,
1366
+ "h": 1,
1367
+ "x": 0,
1368
+ "y": 10,
1369
+ "i": "b2e1c9b2-9da8-40d9-a068-9a6a4e0f2ed3"
1370
+ },
1371
+ {
1372
+ "w": 1,
1373
+ "h": 1,
1374
+ "x": 0,
1375
+ "y": 11,
1376
+ "i": "24bf65f6-e196-4e49-9e91-7d5bceb5c080"
1377
+ },
1378
+ {
1379
+ "w": 1,
1380
+ "h": 1,
1381
+ "x": 0,
1382
+ "y": 12,
1383
+ "i": "ce89d0fe-cd1d-4590-bffe-91c6f394ae4d"
1384
+ },
1385
+ {
1386
+ "w": 1,
1387
+ "h": 1,
1388
+ "x": 0,
1389
+ "y": 13,
1390
+ "i": "883dc4ba-6e75-44e6-8c42-8979c63c2a12"
1391
+ },
1392
+ {
1393
+ "w": 1,
1394
+ "h": 1,
1395
+ "x": 0,
1396
+ "y": 14,
1397
+ "i": "6ed5488a-0969-4cda-af4b-2ecb74b3963c"
1398
+ },
1399
+ {
1400
+ "w": 1,
1401
+ "h": 1,
1402
+ "x": 0,
1403
+ "y": 15,
1404
+ "i": "7a5c6998-df18-474c-be1c-5938a5e68943"
1405
+ },
1406
+ {
1407
+ "w": 1,
1408
+ "h": 1,
1409
+ "x": 0,
1410
+ "y": 16,
1411
+ "i": "3810193b-b6b6-428c-ab5c-48217d234ab4"
1412
+ },
1413
+ {
1414
+ "w": 1,
1415
+ "h": 1,
1416
+ "x": 0,
1417
+ "y": 17,
1418
+ "i": "f6a487a4-b385-421e-bfb8-03b1e651ce25"
1419
+ },
1420
+ {
1421
+ "w": 1,
1422
+ "h": 1,
1423
+ "x": 0,
1424
+ "y": 18,
1425
+ "i": "fd572af2-0df0-4d66-95e0-913cd79b973d"
1426
+ },
1427
+ {
1428
+ "w": 1,
1429
+ "h": 1,
1430
+ "x": 0,
1431
+ "y": 19,
1432
+ "i": "d1096b70-22fb-47d2-95d3-e1d63416d8e3"
1433
+ },
1434
+ {
1435
+ "w": 1,
1436
+ "h": 1,
1437
+ "x": 0,
1438
+ "y": 20,
1439
+ "i": "7d2e98b1-48cb-40bd-bef0-19e735c1fd3f"
1440
+ },
1441
+ {
1442
+ "w": 1,
1443
+ "h": 1,
1444
+ "x": 0,
1445
+ "y": 21,
1446
+ "i": "373a6c3e-77ee-4044-ba11-af176c813fb0"
1447
+ },
1448
+ {
1449
+ "w": 1,
1450
+ "h": 1,
1451
+ "x": 0,
1452
+ "y": 22,
1453
+ "i": "d679fc5e-ead3-4b7d-b650-559167edbeff"
1454
+ },
1455
+ {
1456
+ "w": 1,
1457
+ "h": 1,
1458
+ "x": 0,
1459
+ "y": 23,
1460
+ "i": "ce48c3e2-5ff9-42c6-85c3-e87ae9148762"
1461
+ },
1462
+ {
1463
+ "w": 1,
1464
+ "h": 1,
1465
+ "x": 0,
1466
+ "y": 24,
1467
+ "i": "384f066c-a4fe-4c26-b7cb-08f333cf9fac"
1468
+ },
1469
+ {
1470
+ "w": 1,
1471
+ "h": 1,
1472
+ "x": 0,
1473
+ "y": 25,
1474
+ "i": "b1caf3ba-4c6e-45aa-8def-e94f1d9e0e3c"
1475
+ },
1476
+ {
1477
+ "w": 1,
1478
+ "h": 1,
1479
+ "x": 0,
1480
+ "y": 26,
1481
+ "i": "c18dbb26-ecd1-4f19-ab9a-0de6980da2dc"
1482
+ },
1483
+ {
1484
+ "w": 1,
1485
+ "h": 1,
1486
+ "x": 0,
1487
+ "y": 27,
1488
+ "i": "450cc2ff-8f00-4311-b508-db8084df8725"
1489
+ },
1490
+ {
1491
+ "w": 2,
1492
+ "h": 2,
1493
+ "x": 0,
1494
+ "y": 5,
1495
+ "i": "befe345c-e392-40de-ad1b-97a38ac18503"
1496
+ },
1497
+ {
1498
+ "w": 1,
1499
+ "h": 1,
1500
+ "x": 0,
1501
+ "y": 28,
1502
+ "i": "e8f652ba-d3ac-4adb-a16e-f410af56414b"
1503
+ },
1504
+ {
1505
+ "w": 1,
1506
+ "h": 1,
1507
+ "x": 0,
1508
+ "y": 29,
1509
+ "i": "448f356d-d79f-47a2-a6ed-6ddf93d50f90"
1510
+ },
1511
+ {
1512
+ "w": 1,
1513
+ "h": 1,
1514
+ "x": 0,
1515
+ "y": 30,
1516
+ "i": "4d8ec87c-9a01-41eb-a659-bb9ad2afd283"
1517
+ },
1518
+ {
1519
+ "w": 1,
1520
+ "h": 1,
1521
+ "x": 0,
1522
+ "y": 31,
1523
+ "i": "6022a63e-38c0-42a4-bb9c-6a2c2e571da2"
1524
+ }
1525
+ ],
1526
+ "md": [],
1527
+ "lg": [
1528
+ {
1529
+ "w": 8,
1530
+ "h": 2,
1531
+ "x": 4,
1532
+ "y": 34,
1533
+ "i": "cc1bb92b-736b-4b76-bb2a-4ffb3fb6db04"
1534
+ },
1535
+ {
1536
+ "w": 12,
1537
+ "h": 2,
1538
+ "x": 0,
1539
+ "y": 9,
1540
+ "i": "750ea929-fb31-46ef-b1d4-68c53b06e5a3"
1541
+ },
1542
+ {
1543
+ "w": 12,
1544
+ "h": 1,
1545
+ "x": 0,
1546
+ "y": 8,
1547
+ "i": "92507e3e-2c99-4089-b75a-ce97ad4743d5"
1548
+ },
1549
+ {
1550
+ "w": 6,
1551
+ "h": 2,
1552
+ "x": 0,
1553
+ "y": 1,
1554
+ "i": "f1535f10-a7ba-4c74-8ae6-d5be8c5655ee"
1555
+ },
1556
+ {
1557
+ "w": 12,
1558
+ "h": 2,
1559
+ "x": 0,
1560
+ "y": 24,
1561
+ "i": "29df3495-eea3-45a2-b779-788d92c8baa4"
1562
+ },
1563
+ {
1564
+ "w": 12,
1565
+ "h": 2,
1566
+ "x": 0,
1567
+ "y": 29,
1568
+ "i": "814000f8-9ffd-4ac3-90f8-26d321e9eba6"
1569
+ },
1570
+ {
1571
+ "w": 4,
1572
+ "h": 2,
1573
+ "x": 0,
1574
+ "y": 18,
1575
+ "i": "293fc7fd-eb34-4383-82b8-068b62ffdd61"
1576
+ },
1577
+ {
1578
+ "w": 6,
1579
+ "h": 2,
1580
+ "x": 6,
1581
+ "y": 22,
1582
+ "i": "b2e1c9b2-9da8-40d9-a068-9a6a4e0f2ed3"
1583
+ },
1584
+ {
1585
+ "w": 12,
1586
+ "h": 2,
1587
+ "x": 0,
1588
+ "y": 15,
1589
+ "i": "24bf65f6-e196-4e49-9e91-7d5bceb5c080"
1590
+ },
1591
+ {
1592
+ "w": 12,
1593
+ "h": 1,
1594
+ "x": 0,
1595
+ "y": 33,
1596
+ "i": "ce89d0fe-cd1d-4590-bffe-91c6f394ae4d"
1597
+ },
1598
+ {
1599
+ "w": 6,
1600
+ "h": 2,
1601
+ "x": 6,
1602
+ "y": 20,
1603
+ "i": "883dc4ba-6e75-44e6-8c42-8979c63c2a12"
1604
+ },
1605
+ {
1606
+ "w": 6,
1607
+ "h": 2,
1608
+ "x": 0,
1609
+ "y": 22,
1610
+ "i": "6ed5488a-0969-4cda-af4b-2ecb74b3963c"
1611
+ },
1612
+ {
1613
+ "w": 6,
1614
+ "h": 2,
1615
+ "x": 6,
1616
+ "y": 31,
1617
+ "i": "7a5c6998-df18-474c-be1c-5938a5e68943"
1618
+ },
1619
+ {
1620
+ "w": 6,
1621
+ "h": 2,
1622
+ "x": 0,
1623
+ "y": 20,
1624
+ "i": "3810193b-b6b6-428c-ab5c-48217d234ab4"
1625
+ },
1626
+ {
1627
+ "w": 12,
1628
+ "h": 2,
1629
+ "x": 0,
1630
+ "y": 6,
1631
+ "i": "f6a487a4-b385-421e-bfb8-03b1e651ce25"
1632
+ },
1633
+ {
1634
+ "w": 6,
1635
+ "h": 2,
1636
+ "x": 6,
1637
+ "y": 3,
1638
+ "i": "fd572af2-0df0-4d66-95e0-913cd79b973d"
1639
+ },
1640
+ {
1641
+ "w": 7,
1642
+ "h": 2,
1643
+ "x": 5,
1644
+ "y": 11,
1645
+ "i": "d1096b70-22fb-47d2-95d3-e1d63416d8e3"
1646
+ },
1647
+ {
1648
+ "w": 12,
1649
+ "h": 1,
1650
+ "x": 0,
1651
+ "y": 5,
1652
+ "i": "7d2e98b1-48cb-40bd-bef0-19e735c1fd3f"
1653
+ },
1654
+ {
1655
+ "w": 6,
1656
+ "h": 2,
1657
+ "x": 0,
1658
+ "y": 3,
1659
+ "i": "373a6c3e-77ee-4044-ba11-af176c813fb0"
1660
+ },
1661
+ {
1662
+ "w": 8,
1663
+ "h": 2,
1664
+ "x": 4,
1665
+ "y": 18,
1666
+ "i": "d679fc5e-ead3-4b7d-b650-559167edbeff"
1667
+ },
1668
+ {
1669
+ "w": 6,
1670
+ "h": 2,
1671
+ "x": 0,
1672
+ "y": 31,
1673
+ "i": "ce48c3e2-5ff9-42c6-85c3-e87ae9148762"
1674
+ },
1675
+ {
1676
+ "w": 12,
1677
+ "h": 1,
1678
+ "x": 0,
1679
+ "y": 26,
1680
+ "i": "384f066c-a4fe-4c26-b7cb-08f333cf9fac"
1681
+ },
1682
+ {
1683
+ "w": 12,
1684
+ "h": 2,
1685
+ "x": 0,
1686
+ "y": 36,
1687
+ "i": "b1caf3ba-4c6e-45aa-8def-e94f1d9e0e3c"
1688
+ },
1689
+ {
1690
+ "w": 6,
1691
+ "h": 2,
1692
+ "x": 6,
1693
+ "y": 1,
1694
+ "i": "c18dbb26-ecd1-4f19-ab9a-0de6980da2dc"
1695
+ },
1696
+ {
1697
+ "w": 12,
1698
+ "h": 1,
1699
+ "x": 0,
1700
+ "y": 0,
1701
+ "i": "450cc2ff-8f00-4311-b508-db8084df8725"
1702
+ },
1703
+ {
1704
+ "w": 5,
1705
+ "h": 2,
1706
+ "x": 0,
1707
+ "y": 11,
1708
+ "i": "befe345c-e392-40de-ad1b-97a38ac18503"
1709
+ },
1710
+ {
1711
+ "w": 12,
1712
+ "h": 1,
1713
+ "x": 0,
1714
+ "y": 17,
1715
+ "i": "e8f652ba-d3ac-4adb-a16e-f410af56414b"
1716
+ },
1717
+ {
1718
+ "w": 12,
1719
+ "h": 2,
1720
+ "x": 0,
1721
+ "y": 13,
1722
+ "i": "448f356d-d79f-47a2-a6ed-6ddf93d50f90"
1723
+ },
1724
+ {
1725
+ "w": 4,
1726
+ "h": 2,
1727
+ "x": 0,
1728
+ "y": 34,
1729
+ "i": "4d8ec87c-9a01-41eb-a659-bb9ad2afd283"
1730
+ },
1731
+ {
1732
+ "w": 12,
1733
+ "h": 2,
1734
+ "x": 0,
1735
+ "y": 27,
1736
+ "i": "6022a63e-38c0-42a4-bb9c-6a2c2e571da2"
1737
+ }
1738
+ ],
1739
+ "xl": []
1740
+ }
1741
+ \`\`\`
1742
+ `,
1743
+ "update-inline-question-rule.md": `# JupiterOne Rule Update Tool - Complete Guide
1744
+
1745
+ **Purpose**: Updates existing inline question-based alert rules in JupiterOne. This tool modifies the configuration of an existing rule while preserving its identity and version history.
1746
+
1747
+ **Important**: Before updating a rule, use the \`get-rule-details\` tool to retrieve the current configuration. This ensures you have all required fields and can see what needs to be changed.
1748
+
1749
+ ## Key Requirements for Updates
1750
+
1751
+ ### 1. Required Fields for Updates
1752
+ When updating a rule, you must provide **ALL** fields, not just the ones you want to change. The update operation replaces the entire rule configuration, so missing fields will result in errors.
1753
+
1754
+ **Critical Required Fields**:
1755
+ - \`id\`: The existing rule ID (from \`get-rule-details\`)
1756
+ - \`version\`: The current version number (from \`get-rule-details\`)
1757
+ - \`specVersion\`: Usually 1
1758
+ - \`ignorePreviousResults\`: Must be included
1759
+ - \`templates\`: Must be included (use \`{}\` if empty)
1760
+ - \`tags\`: Must be included but should always be empty \`[]\` (deprecated)
1761
+ - \`labels\`: Use this for actual tagging functionality
1762
+ - \`resourceGroupId\`: Must be included (can be null)
1763
+ - \`remediationSteps\`: Must be included (can be null)
1764
+
1765
+ ### 2. Condition Format (Critical)
1766
+ The \`condition\` parameter must use JupiterOne's specific array format:
1767
+ - **Structure**: \`["LOGICAL_OPERATOR", [left_value, operator, right_value]]\`
1768
+ - **Example**: \`["AND", ["queries.queryName.total", ">", 0]]\`
1769
+ - **Supported operators**: \`>\`, \`<\`, \`>=\`, \`<=\`, \`=\`, \`!=\`
1770
+ - **Logical operators**: \`"AND"\`, \`"OR"\`
1771
+
1772
+ ### 3. Operations Structure
1773
+ The \`when\` clause should only contain:
1774
+ - \`type\`: Always \`"FILTER"\`
1775
+ - \`condition\`: The array format described above
1776
+ - **Do NOT include**: \`version\`, \`specVersion\` (these belong at the rule level, not in the when clause)
1777
+
1778
+ ### 4. Query Naming Convention
1779
+ - Query names in the \`queries\` array must match the references in conditions
1780
+ - Example: If query name is \`"users"\`, reference it as \`"queries.users.total"\`
1781
+ - **IMPORTANT**: Use \`"query0"\` as the standard query name for compatibility with existing patterns
1782
+
1783
+ ### 5. Version Management
1784
+ - The \`version\` field will be automatically incremented by JupiterOne
1785
+ - You must provide the current version number in your update request
1786
+ - Get the current version using \`get-rule-details\` before updating
1787
+
1788
+ ### 6. Tags vs Labels (Important)
1789
+ - **DEPRECATED**: The \`tags\` array field is deprecated and should always be set to an empty array \`[]\`
1790
+ - **USE INSTEAD**: For tagging functionality, use the \`labels\` field with key-value pairs
1791
+ - **Format**: \`labels: [{"labelName": "key", "labelValue": "value"}]\`
1792
+ - **When users ask for tagging**: Always use the \`labels\` field to meet their needs
1793
+ - **Note**: The \`tags\` field is still required in the schema for compatibility but should remain empty
1794
+
1795
+ ## Update Workflow
1796
+
1797
+ ### Step 1: Get Current Rule Configuration
1798
+ \`\`\`
1799
+ Use get-rule-details with the rule ID to get the current configuration
1800
+ \`\`\`
1801
+
1802
+ ### Step 2: Modify Required Fields
1803
+ Update only the fields you need to change while preserving all other required fields.
1804
+
1805
+ ### Step 3: Submit Update
1806
+ Use this tool with the complete configuration including your changes.
1807
+
1808
+ ## Required Schema Fields for Updates
1809
+
1810
+ ### Complete Required Parameters for update-inline-question-rule
1811
+ **CRITICAL**: All of these fields must be included for successful rule updates:
1812
+
1813
+ \`\`\`json
1814
+ {
1815
+ "id": "existing-rule-id",
1816
+ "name": "Updated Rule Name",
1817
+ "description": "Updated rule description",
1818
+ "notifyOnFailure": true,
1819
+ "triggerActionsOnNewEntitiesOnly": true,
1820
+ "ignorePreviousResults": false,
1821
+ "pollingInterval": "ONE_DAY",
1822
+ "specVersion": 1,
1823
+ "version": 2,
1824
+ "templates": {},
1825
+ "outputs": ["alertLevel"],
1826
+ "tags": [],
1827
+ "labels": [
1828
+ {"labelName": "environment", "labelValue": "production"},
1829
+ {"labelName": "team", "labelValue": "security"}
1830
+ ],
1831
+ "resourceGroupId": null,
1832
+ "remediationSteps": null,
1833
+ "question": {
1834
+ "queries": [
1835
+ {
1836
+ "query": "FIND Entity...",
1837
+ "name": "query0",
1838
+ "version": "v1",
1839
+ "includeDeleted": false
1840
+ }
1841
+ ]
1842
+ },
1843
+ "operations": [
1844
+ {
1845
+ "when": {
1846
+ "type": "FILTER",
1847
+ "condition": ["AND", ["queries.query0.total", ">", 0]]
1848
+ },
1849
+ "actions": [...]
1850
+ }
1851
+ ]
1852
+ }
1853
+ \`\`\`
1854
+
1855
+ **Key Update Requirements**:
1856
+ - \`id\`: Must match the existing rule ID
1857
+ - \`version\`: Must be the current version number from the existing rule
1858
+ - \`ignorePreviousResults\`: Must be included (typically \`false\`)
1859
+ - \`templates\`: Must be included (use \`{}\` if empty)
1860
+ - \`tags\`: Must be included but should always be empty \`[]\` (deprecated field)
1861
+ - \`labels\`: Use this for actual tagging functionality with key-value pairs
1862
+ - \`resourceGroupId\`: Must be included (can be null)
1863
+ - \`remediationSteps\`: Must be included (can be null)
1864
+ - Query \`name\`: Use \`"query0"\` for primary query
1865
+ - Query \`version\`: Include \`"v1"\` for compatibility
1866
+ - Query \`includeDeleted\`: Must be explicitly set to \`false\`
1867
+
1868
+ ## Available Action Types
1869
+
1870
+ ### 1. SET_PROPERTY
1871
+ Sets a property value on the alert (commonly used for alert severity levels).
1872
+
1873
+ **Configuration**:
1874
+ \`\`\`json
1875
+ {
1876
+ "type": "SET_PROPERTY",
1877
+ "targetProperty": "alertLevel",
1878
+ "targetValue": "CRITICAL"
1879
+ }
1880
+ \`\`\`
1881
+
1882
+ **Common Values for alertLevel**: \`"LOW"\`, \`"MEDIUM"\`, \`"HIGH"\`, \`"CRITICAL"\`, \`"INFO"\`
1883
+
1884
+ ### 2. CREATE_ALERT
1885
+ Creates a basic alert in JupiterOne.
1886
+
1887
+ **Configuration**:
1888
+ \`\`\`json
1889
+ {
1890
+ "type": "CREATE_ALERT"
1891
+ }
1892
+ \`\`\`
1893
+
1894
+ **Note**: This is the most basic action and should almost always be included.
1895
+
1896
+ ### 3. SEND_EMAIL
1897
+ Sends email notifications to specified recipients.
1898
+
1899
+ **Configuration**:
1900
+ \`\`\`json
1901
+ {
1902
+ "type": "SEND_EMAIL",
1903
+ "recipients": ["user1@company.com", "user2@company.com"],
1904
+ "body": "Affected Items: <br><br>* {{queries.query0.data|mapProperty('displayName')|join('<br>* ')}}"
1905
+ }
1906
+ \`\`\`
1907
+
1908
+ ### 4. TAG_ENTITIES
1909
+ Adds or removes tags from entities that triggered the rule.
1910
+
1911
+ **Configuration**:
1912
+ \`\`\`json
1913
+ {
1914
+ "type": "TAG_ENTITIES",
1915
+ "entities": "{{queries.query0.data}}",
1916
+ "tags": [
1917
+ {"name": "existing tag to remove", "value": null},
1918
+ {"name": "new tag", "value": "tag value"}
1919
+ ]
1920
+ }
1921
+ \`\`\`
1922
+
1923
+ ### 5. SEND_SLACK_MESSAGE
1924
+ Sends messages to Slack channels (requires Slack integration).
1925
+
1926
+ **Configuration**:
1927
+ \`\`\`json
1928
+ {
1929
+ "integrationInstanceId": "d97d9127-c532-410a-bf0a-9ea93f66c3d2",
1930
+ "type": "SEND_SLACK_MESSAGE",
1931
+ "channels": ["#security-alerts", "#general"],
1932
+ "body": "*Affected Items:* \n\n- {{queries.query0.data|mapProperty('displayName')|join('\n- ')}}"
1933
+ }
1934
+ \`\`\`
1935
+
1936
+ ### 6. SEND_TO_S3
1937
+ Sends alert data to an S3 bucket (requires AWS S3 integration).
1938
+
1939
+ **Configuration**:
1940
+ \`\`\`json
1941
+ {
1942
+ "integrationInstanceId": "f89568b4-2a1b-4bd8-8abd-aee21270df75",
1943
+ "type": "SEND_TO_S3",
1944
+ "bucket": "security-alerts-bucket",
1945
+ "region": "us-east-1",
1946
+ "data": {
1947
+ "description": "{{alertWebLink}}\n\n**Affected Items:**\n\n* {{queries.query0.data|mapProperty('displayName')|join('\n* ')}}"
1948
+ }
1949
+ }
1950
+ \`\`\`
1951
+
1952
+ ### 7. CREATE_JIRA_TICKET
1953
+ Creates a Jira ticket for the alert (requires Jira integration).
1954
+
1955
+ **Configuration**:
1956
+ \`\`\`json
1957
+ {
1958
+ "integrationInstanceId": "53a99eaa-18a5-45ef-b748-2de39d642a91",
1959
+ "type": "CREATE_JIRA_TICKET",
1960
+ "entityClass": "Finding",
1961
+ "summary": "Security Alert: Critical Unencrypted Data Found",
1962
+ "issueType": "Bug",
1963
+ "project": "SEC",
1964
+ "updateContentOnChanges": false,
1965
+ "additionalFields": {
1966
+ "description": {
1967
+ "type": "doc",
1968
+ "version": 1,
1969
+ "content": [
1970
+ {
1971
+ "type": "paragraph",
1972
+ "content": [
1973
+ {
1974
+ "type": "text",
1975
+ "text": "{{alertWebLink}}\n\n**Affected Items:**\n\n* {{queries.query0.data|mapProperty('displayName')|join('\n* ')}}"
1976
+ }
1977
+ ]
1978
+ }
1979
+ ]
1980
+ }
1981
+ }
1982
+ }
1983
+ \`\`\`
1984
+
1985
+ ## Template Variables and Formatting
1986
+
1987
+ ### Available Variables
1988
+ - \`{{alertWebLink}}\` - Direct link to the alert in JupiterOne
1989
+ - \`{{queries.queryName.data}}\` - Array of entities from the specified query
1990
+ - \`{{queries.queryName.total}}\` - Count of entities from the query
1991
+
1992
+ ### Data Formatting
1993
+ - \`|mapProperty('fieldName')\` - Extract specific field from each entity
1994
+ - \`|join('separator')\` - Join array elements with specified separator
1995
+ - Example: \`{{queries.users.data|mapProperty('displayName')|join(', ')}}\` - Creates comma-separated list of user names
1996
+
1997
+ ## Integration Dependencies
1998
+
1999
+ For actions requiring integrations, you may need to:
2000
+ 1. Query available integration instances using \`get-integration-instances\`
2001
+ 2. Ask the user which integration to use
2002
+ 3. Use the integration's \`id\` as the \`integrationInstanceId\`
2003
+
2004
+ **Actions requiring integrations**:
2005
+ - \`SEND_SLACK_MESSAGE\` (Slack integration)
2006
+ - \`SEND_TO_S3\` (AWS S3 integration)
2007
+ - \`CREATE_JIRA_TICKET\` (Jira integration)
2008
+
2009
+ ## Working Example Update
2010
+
2011
+ ### Complete Working Rule Update Structure
2012
+ \`\`\`json
2013
+ {
2014
+ "id": "12345678-1234-1234-1234-123456789abc",
2015
+ "name": "Updated Rule Name",
2016
+ "description": "Updated rule description",
2017
+ "notifyOnFailure": true,
2018
+ "triggerActionsOnNewEntitiesOnly": true,
2019
+ "ignorePreviousResults": false,
2020
+ "pollingInterval": "ONE_DAY",
2021
+ "specVersion": 1,
2022
+ "version": 3,
2023
+ "templates": {},
2024
+ "outputs": ["alertLevel"],
2025
+ "tags": [],
2026
+ "labels": [
2027
+ {"labelName": "severity", "labelValue": "high"},
2028
+ {"labelName": "category", "labelValue": "security"}
2029
+ ],
2030
+ "resourceGroupId": null,
2031
+ "remediationSteps": "1. Review the affected entities\n2. Apply security patches\n3. Update configurations",
2032
+ "question": {
2033
+ "queries": [
2034
+ {
2035
+ "query": "FIND Entity WITH condition",
2036
+ "name": "query0",
2037
+ "version": "v1",
2038
+ "includeDeleted": false
2039
+ }
2040
+ ]
2041
+ },
2042
+ "operations": [
2043
+ {
2044
+ "when": {
2045
+ "type": "FILTER",
2046
+ "condition": ["AND", ["queries.query0.total", ">", 0]]
2047
+ },
2048
+ "actions": [
2049
+ {
2050
+ "type": "SET_PROPERTY",
2051
+ "targetProperty": "alertLevel",
2052
+ "targetValue": "CRITICAL"
2053
+ },
2054
+ {
2055
+ "type": "CREATE_ALERT"
2056
+ },
2057
+ {
2058
+ "type": "SEND_EMAIL",
2059
+ "recipients": ["updated-user@company.com"],
2060
+ "body": "Updated notification: {{alertWebLink}}"
2061
+ }
2062
+ ]
2063
+ }
2064
+ ]
2065
+ }
2066
+ \`\`\`
2067
+
2068
+ ## Common Update Scenarios
2069
+
2070
+ ### 1. Changing Notification Recipients
2071
+ Update only the \`recipients\` array in the \`SEND_EMAIL\` action while preserving all other fields.
2072
+
2073
+ ### 2. Modifying Polling Interval
2074
+ Update the \`pollingInterval\` field while keeping all other configuration the same.
2075
+
2076
+ ### 3. Adding New Actions
2077
+ Add new actions to the \`actions\` array in the operations.
2078
+
2079
+ ### 4. Updating Query Logic
2080
+ Modify the \`query\` string in the queries array or adjust the \`condition\` in operations.
2081
+
2082
+ ### 5. Changing Labels
2083
+ Update the \`labels\` array to add, remove, or modify rule labels.
2084
+
2085
+ ## Debugging Tips
2086
+ - Always start by getting the current rule configuration with \`get-rule-details\`
2087
+ - Ensure the \`version\` number matches the current rule version
2088
+ - Include ALL required fields, even if they're not changing
2089
+ - If you get "Invalid conjunction operator" errors, check the condition array format
2090
+ - If you get "additional properties" errors, remove extra fields from the \`when\` clause
2091
+ - If you get missing property errors, ensure all required schema fields are included
2092
+ - **Always include**: \`id\`, \`version\`, \`ignorePreviousResults\`, \`templates\`, \`tags\`, \`labels\`, \`resourceGroupId\`, \`remediationSteps\`
2093
+ - Use \`"query0"\` as the standard query name for compatibility
2094
+
2095
+ ## Best Practices for Updates
2096
+ - Always retrieve the current rule configuration first using \`get-rule-details\`
2097
+ - Only modify the fields that actually need to change
2098
+ - Preserve the existing \`version\` number (it will be auto-incremented)
2099
+ - Use the \`labels\` field for rule organization and tagging (not the deprecated \`tags\` field)
2100
+ - Test rule changes with simple modifications first
2101
+ - Document changes in the \`description\` field if significant
2102
+ - When users request tagging functionality, use the \`labels\` field with key-value pairs
2103
+ - Always include \`CREATE_ALERT\` action as a baseline unless specifically removing it
2104
+
2105
+ This format ensures reliable rule updates and helps avoid common pitfalls encountered during rule modification.`
2106
+ };
2107
+ //# sourceMappingURL=description-map.js.map