Skip to content

Commit 3b61141

Browse files
committed
Merge branch 'fix/cubic-ssm' into feat/aws-integration-batch
2 parents c3fbf21 + 0aff9e9 commit 3b61141

9 files changed

Lines changed: 91 additions & 12 deletions

File tree

‎apps/docs/content/docs/integrations/ssm.mdx‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ With AWS Systems Manager, you can:
2424

2525
In Sim, the Systems Manager integration is what lets an agent act on infrastructure rather than only report on it. Paired with CloudWatch or CloudTrail for detection, a workflow can investigate an alert, run a diagnostic command against the affected nodes, read the configuration behind the failure from Parameter Store, and kick off an Automation runbook to remediate — end to end, with every step logged in your run history.
2626

27-
Parameter Store decryption is opt-in: `Get Parameter` and `Get Parameters` leave `WithDecryption` off unless you explicitly enable it, so a SecureString stays encrypted by default. Written and decrypted values are masked in the block and are kept out of logs, traces, and error envelopes.
27+
Parameter Store decryption is opt-in: `Get Parameter`, `Get Parameters`, and `Get Parameters By Path` leave `WithDecryption` off unless you explicitly enable it, so a SecureString stays encrypted by default.
28+
29+
Be precise about what that protects. The value you supply to `Put Parameter` is masked in the block, is never echoed back in the result, and no parameter value ever appears in an error message. A value you read is different: once you enable decryption, the plaintext is ordinary block output. It flows to downstream blocks as intended, and it is also written to the run log and the execution trace like any other output. Enable decryption only on the steps that genuinely need the plaintext, and treat those run logs as secret material.
2830
{/* MANUAL-CONTENT-END */}
2931

3032

@@ -48,7 +50,7 @@ Run an SSM document on managed nodes with AWS Systems Manager Run Command
4850
| `accessKeyId` | string | Yes | AWS access key ID |
4951
| `secretAccessKey` | string | Yes | AWS secret access key |
5052
| `documentName` | string | Yes | Name of the SSM document to run \(e.g., AWS-RunShellScript\) |
51-
| `instanceIds` | json | No | Managed node IDs to target, as an array of strings \(e.g., \["i-0abc123"\]\). Provide instanceIds or targets |
53+
| `instanceIds` | json | No | Managed node IDs to target, as an array of strings \(e.g., \["i-0123456789abcdef0"\]\). Provide instanceIds or targets |
5254
| `targets` | json | No | Tag or resource-group targets, as an array of \{Key, Values\} objects. Provide instanceIds or targets |
5355
| `documentVersion` | string | No | Document version to run \($LATEST, $DEFAULT, or a version number\) |
5456
| `parameters` | json | No | Document parameters, as an object mapping each parameter name to an array of string values |
@@ -149,7 +151,7 @@ Read the output and status of a Run Command execution on one managed node
149151
| `accessKeyId` | string | Yes | AWS access key ID |
150152
| `secretAccessKey` | string | Yes | AWS secret access key |
151153
| `commandId` | string | Yes | ID of the command, as returned by ssm_send_command |
152-
| `instanceId` | string | Yes | Managed node the command ran on \(e.g., i-0abc123\) |
154+
| `instanceId` | string | Yes | Managed node the command ran on \(e.g., i-0123456789abcdef0\) |
153155
| `pluginName` | string | No | Name of the document plugin to read output for; required for documents with more than one plugin |
154156

155157
#### Output
@@ -185,7 +187,7 @@ Cancel an in-flight Run Command execution
185187
| `accessKeyId` | string | Yes | AWS access key ID |
186188
| `secretAccessKey` | string | Yes | AWS secret access key |
187189
| `commandId` | string | Yes | ID of the command to cancel, as returned by ssm_send_command |
188-
| `instanceIds` | json | No | Managed node IDs to cancel on, as an array of strings; omit to cancel on every targeted node |
190+
| `instanceIds` | array | No | Managed node IDs to cancel on \(e.g., \["i-0123456789abcdef0"\]\); omit to cancel on every targeted node |
189191

190192
#### Output
191193

@@ -379,7 +381,7 @@ List the patches reported for one managed node
379381
| `region` | string | Yes | AWS region \(e.g., us-east-1\) |
380382
| `accessKeyId` | string | Yes | AWS access key ID |
381383
| `secretAccessKey` | string | Yes | AWS secret access key |
382-
| `instanceId` | string | Yes | Managed node to report patches for \(e.g., i-0abc123\) |
384+
| `instanceId` | string | Yes | Managed node to report patches for \(e.g., i-0123456789abcdef0\) |
383385
| `filters` | json | No | Filters, as an array of \{Key, Values\} objects. Valid keys: Classification, KBId, Severity, State |
384386
| `maxResults` | number | No | Maximum number of patches to return \(10-100\) |
385387
| `nextToken` | string | No | Pagination token from a previous request |

‎apps/sim/lib/api/contracts/tools/aws/ssm-get-parameters-by-path.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ const RequestSchema = z.object({
3434
}),
3535
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
3636
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
37-
path: z.string().min(1, 'Parameter path is required').max(2048),
37+
path: z
38+
.string()
39+
.min(1, 'Parameter path is required')
40+
.max(2048)
41+
.startsWith('/', 'path must start with a forward slash (e.g., /prod/app)'),
3842
recursive: z.boolean().nullish(),
3943
withDecryption: z.boolean().nullish(),
4044
parameterFilters: z.array(ParameterStringFilterSchema).nullish(),

‎apps/sim/lib/internal/ssm/execute-tool.test.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,39 @@ describe('executeSsmTool', () => {
214214
expect(mockOperations.executeSsmGetCommandInvocation).not.toHaveBeenCalled()
215215
})
216216

217+
it('rejects a hierarchy path without the leading slash AWS requires', async () => {
218+
const response = await executeSsmTool(
219+
createRequest({
220+
toolId: 'ssm_get_parameters_by_path',
221+
input: { ...CONNECTION, path: 'prod/app' },
222+
})
223+
)
224+
225+
expect(response.status).toBe(400)
226+
await expect(response.json()).resolves.toMatchObject({
227+
details: expect.arrayContaining([
228+
expect.objectContaining({
229+
message: 'path must start with a forward slash (e.g., /prod/app)',
230+
}),
231+
]),
232+
})
233+
expect(mockOperations.executeSsmGetParametersByPath).not.toHaveBeenCalled()
234+
})
235+
236+
it('accepts a hierarchy path that starts with a slash', async () => {
237+
mockOperations.executeSsmGetParametersByPath.mockResolvedValue({ parameters: [] })
238+
239+
const response = await executeSsmTool(
240+
createRequest({
241+
toolId: 'ssm_get_parameters_by_path',
242+
input: { ...CONNECTION, path: '/prod/app' },
243+
})
244+
)
245+
246+
expect(response.status).toBe(200)
247+
expect(mockOperations.executeSsmGetParametersByPath).toHaveBeenCalled()
248+
})
249+
217250
it('rejects an unsupported tool id', async () => {
218251
const response = await executeSsmTool(createRequest({ toolId: 'ssm_not_a_tool' }))
219252

‎apps/sim/tools/generated/tool-metadata.ts‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it } from 'vitest'
5+
import { awsSsmCancelCommandContract } from '@/lib/api/contracts/tools/aws/ssm-cancel-command'
6+
import { createUserToolSchema } from '@/tools/params'
7+
import { cancelCommandTool } from '@/tools/ssm/cancel_command'
8+
9+
const COMMAND_ID = '11111111-2222-3333-4444-555555555555'
10+
const INSTANCE_ID = 'i-0123456789abcdef0'
11+
12+
const CONNECTION = {
13+
region: 'us-east-1',
14+
accessKeyId: 'access-key',
15+
secretAccessKey: 'secret-key',
16+
}
17+
18+
describe('ssm_cancel_command published schema', () => {
19+
const schema = createUserToolSchema(cancelCommandTool)
20+
21+
it('advertises instanceIds as an array of strings, not an object', () => {
22+
expect(schema.properties.instanceIds).toMatchObject({
23+
type: 'array',
24+
items: { type: 'string' },
25+
maxItems: 50,
26+
})
27+
})
28+
29+
it('accepts a request shaped the way the published schema advertises', () => {
30+
const parsed = awsSsmCancelCommandContract.body?.safeParse({
31+
...CONNECTION,
32+
commandId: COMMAND_ID,
33+
instanceIds: [INSTANCE_ID],
34+
})
35+
36+
expect(parsed?.success).toBe(true)
37+
})
38+
})

‎apps/sim/tools/ssm/cancel_command.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ export const cancelCommandTool: InternalToolConfig<
3636
description: 'ID of the command to cancel, as returned by ssm_send_command',
3737
},
3838
instanceIds: {
39-
type: 'json',
39+
type: 'array',
4040
required: false,
4141
visibility: 'user-or-llm',
42+
maxItems: 50,
43+
items: { type: 'string' },
4244
description:
43-
'Managed node IDs to cancel on, as an array of strings; omit to cancel on every targeted node',
45+
'Managed node IDs to cancel on (e.g., ["i-0123456789abcdef0"]); omit to cancel on every targeted node',
4446
},
4547
},
4648

‎apps/sim/tools/ssm/describe_instance_patches.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const describeInstancePatchesTool: InternalToolConfig<
3636
type: 'string',
3737
required: true,
3838
visibility: 'user-or-llm',
39-
description: 'Managed node to report patches for (e.g., i-0abc123)',
39+
description: 'Managed node to report patches for (e.g., i-0123456789abcdef0)',
4040
},
4141
filters: {
4242
type: 'json',

‎apps/sim/tools/ssm/get_command_invocation.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const getCommandInvocationTool: InternalToolConfig<
4242
type: 'string',
4343
required: true,
4444
visibility: 'user-or-llm',
45-
description: 'Managed node the command ran on (e.g., i-0abc123)',
45+
description: 'Managed node the command ran on (e.g., i-0123456789abcdef0)',
4646
},
4747
pluginName: {
4848
type: 'string',

‎apps/sim/tools/ssm/send_command.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const sendCommandTool: InternalToolConfig<SsmSendCommandParams, SsmSendCo
3737
required: false,
3838
visibility: 'user-or-llm',
3939
description:
40-
'Managed node IDs to target, as an array of strings (e.g., ["i-0abc123"]). Provide instanceIds or targets',
40+
'Managed node IDs to target, as an array of strings (e.g., ["i-0123456789abcdef0"]). Provide instanceIds or targets',
4141
},
4242
targets: {
4343
type: 'json',

0 commit comments

Comments
 (0)