Skip to content

Commit 637b056

Browse files
committed
fix(dynatrace): drill the documented JSON shapes, and require the tag selector
Two problems, one found in review and one worth more than it was given. The tag operations could run without an entity selector. All three tag tools declare `entitySelector` required, but the shared block field was only marked required for List Entities, so the block let a workflow reach those tools with an invalid configuration and let Dynatrace do the rejecting. My own structural auditor missed it because it only checked that *some* visible subBlock existed for a required param, not that the specific one was required — that check is now precise, and it confirms these three were the only instances across all 47 operations. The larger one: outputs were declaring `type: 'json'` for shapes the API reference documents in full. Thirty-five of them. The top-level entities were mapped properly, but nested payloads — a problem's evidence and impact analysis, a vulnerability's risk assessment and global counts, an attack's attacker, request, entry point and exploited vulnerability, a remediation item's assessment and mute state, the synthetic execution and failure records, the metric ingest error envelope, the DQL translation — were passed through as anonymous blobs. A downstream block could not reference `attacker.sourceIp` without knowing to guess it. All of those now carry their fields. What stays opaque is now only what genuinely is, and each says why in its description: a settings object's schema-defined value, an entity's type-dependent property bag and relationship keys, caller-supplied synthetic metadata, an audit log's JSON patch, the undocumented partial-success body of log ingestion, and the handful of security-detail shapes the reference names without expanding.
1 parent 3a8d2a6 commit 637b056

11 files changed

Lines changed: 786 additions & 51 deletions

File tree

apps/docs/content/docs/en/integrations/dynatrace.mdx

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ Read metric data points from Dynatrace using a metric selector, with optional en
222222
|`dimensionCountRatio` | number | Queried dimension tuples relative to the query limit |
223223
|`appliedOptionalFilters` | array | Optional filters Dynatrace applied to the query |
224224
|`dql` | json | DQL translation of the query, when available |
225+
|`status` | string | Whether the translation succeeded |
226+
|`query` | string | The equivalent DQL query |
225227
|`warnings` | array | Warnings for this metric |
226228
|`data` | array | Series of the metric, one per dimension tuple |
227229
|`dimensions` | array | Dimension values of the series |
@@ -291,8 +293,17 @@ Push custom metric data points into Dynatrace using the metric line protocol, on
291293
| --------- | ---- | ----------- |
292294
| `linesOk` | number | Number of accepted data points |
293295
| `linesInvalid` | number | Number of rejected data points |
294-
| `ingestError` | json | Details of the invalid lines, with the line number and reason for each |
296+
| `ingestError` | json | Details of the invalid lines |
297+
|`code` | number | Error code |
298+
|`message` | string | Error message |
299+
|`invalidLines` | array | The rejected lines |
300+
|`line` | number | Line number in the payload |
301+
|`error` | string | Why the line was rejected |
295302
| `warnings` | json | Warnings raised during ingestion, such as changed metric keys |
303+
|`message` | string | Warning message |
304+
|`changedMetricKeys` | array | Lines whose metric key Dynatrace rewrote |
305+
|`line` | number | Line number in the payload |
306+
|`warning` | string | What was changed |
296307

297308
### Dynatrace List Entities
298309

@@ -485,7 +496,7 @@ Push log events into Dynatrace. Accepts a single log event object or an array of
485496
| --------- | ---- | ----------- |
486497
| `accepted` | boolean | True when Dynatrace accepted every log event \(HTTP 204\) |
487498
| `statusCode` | number | HTTP status Dynatrace returned. 204 is full success, 200 is partial success |
488-
| `details` | json | Partial-success details, present only when some events were rejected |
499+
| `details` | json | Partial-success body, present only when some events were rejected. The reference does not document its shape, so it is passed through as-is |
489500

490501
### Dynatrace List SLOs
491502

@@ -613,7 +624,7 @@ Read the Dynatrace audit log — who changed which configuration, when, and whet
613624
|`timestamp` | number | Change timestamp in UTC milliseconds |
614625
|`success` | boolean | Whether the change succeeded |
615626
|`message` | string | Description of the change |
616-
|`patch` | json | JSON patch of the change |
627+
|`patch` | json | JSON patch describing the change. Its shape follows whatever settings object was edited, so it is dynamic |
617628
|`settingsSchemaId` | string | Settings schema ID \(dt.settings.schema_id\) |
618629
|`settingsScopeId` | string | Settings scope ID \(dt.settings.scope_id\) |
619630
|`settingsKey` | string | Settings key \(dt.settings.key\) |
@@ -920,7 +931,14 @@ Create a settings object — a maintenance window, alerting profile, management
920931
|`code` | number | Per-object HTTP status |
921932
|`objectId` | string | ID of the created object |
922933
|`writeError` | json | Validation error for this object, when it failed |
923-
|`invalidValue` | json | The value that was rejected |
934+
|`code` | number | Error code |
935+
|`message` | string | Error message |
936+
|`constraintViolations` | array | Which part of the value failed validation |
937+
|`location` | string | Where the violation was found |
938+
|`message` | string | What is wrong |
939+
|`parameterLocation` | string | HEADER, PATH, PAYLOAD_BODY, or QUERY |
940+
|`path` | string | Path to the offending field |
941+
|`invalidValue` | json | The value that was rejected. Mirrors the submitted schema-defined value, so the shape is dynamic |
924942
| `objectId` | string | ID of the created object, lifted from the first result |
925943

926944
### Dynatrace Update Settings Object
@@ -1012,8 +1030,17 @@ Trigger an on-demand batch execution of synthetic monitors, for gating a deploy
10121030
| `batchId` | string | ID of the batch, to poll with Get Synthetic Batch |
10131031
| `triggeredCount` | number | How many executions were triggered |
10141032
| `triggeringProblemsCount` | number | How many executions could not be triggered |
1015-
| `triggered` | json | Triggered executions, grouped by monitor with execution and location IDs |
1016-
| `triggeringProblemsDetails` | json | Why each untriggered execution failed to start |
1033+
| `triggered` | array | Triggered executions, grouped by monitor |
1034+
|`monitorId` | string | Monitor that was triggered |
1035+
|`executions` | array | One entry per location the monitor ran from |
1036+
|`executionId` | string | Execution ID |
1037+
|`locationId` | string | Location the execution ran from |
1038+
| `triggeringProblemsDetails` | array | Why each untriggered execution failed to start |
1039+
|`cause` | string | Why the execution could not be triggered |
1040+
|`details` | string | Detail behind the cause |
1041+
|`entityId` | string | Entity the problem relates to |
1042+
|`executionId` | string | Execution ID, when one was assigned |
1043+
|`locationId` | string | Location the execution targeted |
10171044

10181045
### Dynatrace Get Synthetic Batch
10191046

@@ -1038,10 +1065,29 @@ Get the status and failures of an on-demand synthetic batch execution. Poll it a
10381065
| `failedToExecuteCount` | number | Executions that never ran |
10391066
| `triggeredCount` | number | Executions triggered |
10401067
| `triggeringProblemsCount` | number | Executions that could not be triggered |
1041-
| `failedExecutions` | json | Failed executions with their error codes |
1042-
| `failedToExecute` | json | Executions that never started |
1043-
| `triggeringProblems` | json | Reasons executions could not be triggered |
1044-
| `metadata` | json | Metadata attached when the batch was triggered |
1068+
| `failedExecutions` | array | Executions that ran and failed |
1069+
|`errorCode` | string | Error code Dynatrace reported |
1070+
|`executionId` | string | Execution ID |
1071+
|`executionStage` | string | DATA_RETRIEVED, EXECUTED, NOT_TRIGGERED, TIMED_OUT, TRIGGERED, or WAITING |
1072+
|`executionTimestamp` | number | Execution time in UTC ms |
1073+
|`failureMessage` | string | Why the execution failed |
1074+
|`locationId` | string | Location the execution ran from |
1075+
|`monitorId` | string | Monitor that was executed |
1076+
| `failedToExecute` | array | Executions that never started |
1077+
|`errorCode` | string | Error code Dynatrace reported |
1078+
|`executionId` | string | Execution ID |
1079+
|`executionStage` | string | DATA_RETRIEVED, EXECUTED, NOT_TRIGGERED, TIMED_OUT, TRIGGERED, or WAITING |
1080+
|`executionTimestamp` | number | Execution time in UTC ms |
1081+
|`failureMessage` | string | Why the execution failed |
1082+
|`locationId` | string | Location the execution ran from |
1083+
|`monitorId` | string | Monitor that was executed |
1084+
| `triggeringProblems` | array | Reasons executions could not be triggered |
1085+
|`cause` | string | Why the execution could not be triggered |
1086+
|`details` | string | Detail behind the cause |
1087+
|`entityId` | string | Entity the problem relates to |
1088+
|`executionId` | string | Execution ID, when one was assigned |
1089+
|`locationId` | string | Location the execution targeted |
1090+
| `metadata` | json | Key-value metadata supplied when the batch was triggered. Keys are caller-defined, so the shape is dynamic |
10451091
| `userId` | string | Who triggered the batch |
10461092

10471093
### Dynatrace Get Problem Comment

apps/sim/blocks/blocks/dynatrace.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ const ENTITY_SELECTOR_OPERATIONS = [
5252
'dynatrace_delete_tag',
5353
]
5454

55+
/**
56+
* Operations whose tool declares `entitySelector` as required. The tag endpoints
57+
* cannot run without one, so the block must not let them through empty.
58+
*/
59+
const ENTITY_SELECTOR_REQUIRED_OPERATIONS = [
60+
'dynatrace_list_entities',
61+
'dynatrace_list_tags',
62+
'dynatrace_add_tags',
63+
'dynatrace_delete_tag',
64+
]
65+
5566
/** Operations that take a problem ID. */
5667
const PROBLEM_ID_OPERATIONS = [
5768
'dynatrace_get_problem',
@@ -389,7 +400,7 @@ Return ONLY the selector string - no explanations, no surrounding quotes.`,
389400
title: 'Entity Selector',
390401
type: 'short-input',
391402
placeholder: 'type("HOST"),tag("env:prod")',
392-
required: { field: 'operation', value: 'dynatrace_list_entities' },
403+
required: { field: 'operation', value: ENTITY_SELECTOR_REQUIRED_OPERATIONS },
393404
condition: { field: 'operation', value: ENTITY_SELECTOR_OPERATIONS },
394405
wandConfig: {
395406
enabled: true,

apps/sim/tools/dynatrace/create_settings_object.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,31 @@ export const createSettingsObjectTool: ToolConfig<
127127
type: 'json',
128128
description: 'Validation error for this object, when it failed',
129129
nullable: true,
130+
properties: {
131+
code: { type: 'number', description: 'Error code' },
132+
message: { type: 'string', description: 'Error message' },
133+
constraintViolations: {
134+
type: 'array',
135+
description: 'Which part of the value failed validation',
136+
items: {
137+
type: 'object',
138+
properties: {
139+
location: { type: 'string', description: 'Where the violation was found' },
140+
message: { type: 'string', description: 'What is wrong' },
141+
parameterLocation: {
142+
type: 'string',
143+
description: 'HEADER, PATH, PAYLOAD_BODY, or QUERY',
144+
},
145+
path: { type: 'string', description: 'Path to the offending field' },
146+
},
147+
},
148+
},
149+
},
130150
},
131151
invalidValue: {
132152
type: 'json',
133-
description: 'The value that was rejected',
153+
description:
154+
'The value that was rejected. Mirrors the submitted schema-defined value, so the shape is dynamic',
134155
optional: true,
135156
},
136157
},

apps/sim/tools/dynatrace/execute_synthetic_monitors.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,39 @@ export const executeSyntheticMonitorsTool: ToolConfig<
137137
nullable: true,
138138
},
139139
triggered: {
140-
type: 'json',
141-
description: 'Triggered executions, grouped by monitor with execution and location IDs',
140+
type: 'array',
141+
description: 'Triggered executions, grouped by monitor',
142+
items: {
143+
type: 'object',
144+
properties: {
145+
monitorId: { type: 'string', description: 'Monitor that was triggered' },
146+
executions: {
147+
type: 'array',
148+
description: 'One entry per location the monitor ran from',
149+
items: {
150+
type: 'object',
151+
properties: {
152+
executionId: { type: 'string', description: 'Execution ID' },
153+
locationId: { type: 'string', description: 'Location the execution ran from' },
154+
},
155+
},
156+
},
157+
},
158+
},
142159
},
143160
triggeringProblemsDetails: {
144-
type: 'json',
161+
type: 'array',
145162
description: 'Why each untriggered execution failed to start',
163+
items: {
164+
type: 'object',
165+
properties: {
166+
cause: { type: 'string', description: 'Why the execution could not be triggered' },
167+
details: { type: 'string', description: 'Detail behind the cause' },
168+
entityId: { type: 'string', description: 'Entity the problem relates to' },
169+
executionId: { type: 'string', description: 'Execution ID, when one was assigned' },
170+
locationId: { type: 'string', description: 'Location the execution targeted' },
171+
},
172+
},
146173
},
147174
},
148175
}

apps/sim/tools/dynatrace/get_audit_logs.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,12 @@ export const getAuditLogsTool: ToolConfig<
129129
timestamp: { type: 'number', description: 'Change timestamp in UTC milliseconds' },
130130
success: { type: 'boolean', description: 'Whether the change succeeded' },
131131
message: { type: 'string', description: 'Description of the change', nullable: true },
132-
patch: { type: 'json', description: 'JSON patch of the change', nullable: true },
132+
patch: {
133+
type: 'json',
134+
description:
135+
'JSON patch describing the change. Its shape follows whatever settings object was edited, so it is dynamic',
136+
nullable: true,
137+
},
133138
settingsSchemaId: {
134139
type: 'string',
135140
description: 'Settings schema ID (dt.settings.schema_id)',

apps/sim/tools/dynatrace/get_synthetic_batch.ts

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,65 @@ export const getSyntheticBatchTool: ToolConfig<
102102
description: 'Executions that could not be triggered',
103103
nullable: true,
104104
},
105-
failedExecutions: { type: 'json', description: 'Failed executions with their error codes' },
106-
failedToExecute: { type: 'json', description: 'Executions that never started' },
107-
triggeringProblems: { type: 'json', description: 'Reasons executions could not be triggered' },
108-
metadata: { type: 'json', description: 'Metadata attached when the batch was triggered' },
105+
failedExecutions: {
106+
type: 'array',
107+
description: 'Executions that ran and failed',
108+
items: {
109+
type: 'object',
110+
properties: {
111+
errorCode: { type: 'string', description: 'Error code Dynatrace reported' },
112+
executionId: { type: 'string', description: 'Execution ID' },
113+
executionStage: {
114+
type: 'string',
115+
description:
116+
'DATA_RETRIEVED, EXECUTED, NOT_TRIGGERED, TIMED_OUT, TRIGGERED, or WAITING',
117+
},
118+
executionTimestamp: { type: 'number', description: 'Execution time in UTC ms' },
119+
failureMessage: { type: 'string', description: 'Why the execution failed' },
120+
locationId: { type: 'string', description: 'Location the execution ran from' },
121+
monitorId: { type: 'string', description: 'Monitor that was executed' },
122+
},
123+
},
124+
},
125+
failedToExecute: {
126+
type: 'array',
127+
description: 'Executions that never started',
128+
items: {
129+
type: 'object',
130+
properties: {
131+
errorCode: { type: 'string', description: 'Error code Dynatrace reported' },
132+
executionId: { type: 'string', description: 'Execution ID' },
133+
executionStage: {
134+
type: 'string',
135+
description:
136+
'DATA_RETRIEVED, EXECUTED, NOT_TRIGGERED, TIMED_OUT, TRIGGERED, or WAITING',
137+
},
138+
executionTimestamp: { type: 'number', description: 'Execution time in UTC ms' },
139+
failureMessage: { type: 'string', description: 'Why the execution failed' },
140+
locationId: { type: 'string', description: 'Location the execution ran from' },
141+
monitorId: { type: 'string', description: 'Monitor that was executed' },
142+
},
143+
},
144+
},
145+
triggeringProblems: {
146+
type: 'array',
147+
description: 'Reasons executions could not be triggered',
148+
items: {
149+
type: 'object',
150+
properties: {
151+
cause: { type: 'string', description: 'Why the execution could not be triggered' },
152+
details: { type: 'string', description: 'Detail behind the cause' },
153+
entityId: { type: 'string', description: 'Entity the problem relates to' },
154+
executionId: { type: 'string', description: 'Execution ID, when one was assigned' },
155+
locationId: { type: 'string', description: 'Location the execution targeted' },
156+
},
157+
},
158+
},
159+
metadata: {
160+
type: 'json',
161+
description:
162+
'Key-value metadata supplied when the batch was triggered. Keys are caller-defined, so the shape is dynamic',
163+
},
109164
userId: { type: 'string', description: 'Who triggered the batch', nullable: true },
110165
},
111166
}

apps/sim/tools/dynatrace/ingest_logs.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ export const ingestLogsTool: ToolConfig<DynatraceIngestLogsParams, DynatraceInge
8383
},
8484
details: {
8585
type: 'json',
86-
description: 'Partial-success details, present only when some events were rejected',
86+
description:
87+
'Partial-success body, present only when some events were rejected. The reference does not document its shape, so it is passed through as-is',
8788
nullable: true,
8889
},
8990
},

apps/sim/tools/dynatrace/ingest_metrics.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,42 @@ export const ingestMetricsTool: ToolConfig<
7474
},
7575
ingestError: {
7676
type: 'json',
77-
description: 'Details of the invalid lines, with the line number and reason for each',
77+
description: 'Details of the invalid lines',
7878
nullable: true,
79+
properties: {
80+
code: { type: 'number', description: 'Error code' },
81+
message: { type: 'string', description: 'Error message' },
82+
invalidLines: {
83+
type: 'array',
84+
description: 'The rejected lines',
85+
items: {
86+
type: 'object',
87+
properties: {
88+
line: { type: 'number', description: 'Line number in the payload' },
89+
error: { type: 'string', description: 'Why the line was rejected' },
90+
},
91+
},
92+
},
93+
},
7994
},
8095
warnings: {
8196
type: 'json',
8297
description: 'Warnings raised during ingestion, such as changed metric keys',
8398
nullable: true,
99+
properties: {
100+
message: { type: 'string', description: 'Warning message' },
101+
changedMetricKeys: {
102+
type: 'array',
103+
description: 'Lines whose metric key Dynatrace rewrote',
104+
items: {
105+
type: 'object',
106+
properties: {
107+
line: { type: 'number', description: 'Line number in the payload' },
108+
warning: { type: 'string', description: 'What was changed' },
109+
},
110+
},
111+
},
112+
},
84113
},
85114
},
86115
}

0 commit comments

Comments
 (0)