From b57464efff5a14e6d3ff088169e5aff488fb3cb2 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 16:09:00 -0700 Subject: [PATCH 1/4] feat(aws): add IAM and STS integrations --- apps/docs/components/icons.tsx | 18 + apps/docs/components/ui/icon-mapping.ts | 3 + apps/docs/content/docs/en/tools/iam.mdx | 443 ++++++++++++++ apps/docs/content/docs/en/tools/meta.json | 2 + apps/docs/content/docs/en/tools/sts.mdx | 128 ++++ .../integrations/data/icon-mapping.ts | 3 + .../integrations/data/integrations.json | 126 ++++ .../api/tools/iam/add-user-to-group/route.ts | 64 ++ .../api/tools/iam/attach-role-policy/route.ts | 62 ++ .../api/tools/iam/attach-user-policy/route.ts | 62 ++ .../api/tools/iam/create-access-key/route.ts | 62 ++ .../app/api/tools/iam/create-role/route.ts | 73 +++ .../app/api/tools/iam/create-user/route.ts | 63 ++ .../api/tools/iam/delete-access-key/route.ts | 60 ++ .../app/api/tools/iam/delete-role/route.ts | 59 ++ .../app/api/tools/iam/delete-user/route.ts | 59 ++ .../api/tools/iam/detach-role-policy/route.ts | 62 ++ .../api/tools/iam/detach-user-policy/route.ts | 62 ++ apps/sim/app/api/tools/iam/get-role/route.ts | 56 ++ apps/sim/app/api/tools/iam/get-user/route.ts | 56 ++ .../app/api/tools/iam/list-groups/route.ts | 61 ++ .../app/api/tools/iam/list-policies/route.ts | 70 +++ .../sim/app/api/tools/iam/list-roles/route.ts | 61 ++ .../sim/app/api/tools/iam/list-users/route.ts | 61 ++ .../tools/iam/remove-user-from-group/route.ts | 66 +++ apps/sim/app/api/tools/iam/utils.ts | 340 +++++++++++ .../app/api/tools/sts/assume-role/route.ts | 73 +++ .../tools/sts/get-access-key-info/route.ts | 63 ++ .../tools/sts/get-caller-identity/route.ts | 62 ++ .../api/tools/sts/get-session-token/route.ts | 70 +++ apps/sim/app/api/tools/sts/utils.ts | 94 +++ apps/sim/blocks/blocks/iam.ts | 553 ++++++++++++++++++ apps/sim/blocks/blocks/sts.ts | 235 ++++++++ apps/sim/blocks/registry.ts | 4 + apps/sim/components/icons.tsx | 18 + apps/sim/package.json | 2 + apps/sim/tools/iam/add_user_to_group.ts | 74 +++ apps/sim/tools/iam/attach_role_policy.ts | 75 +++ apps/sim/tools/iam/attach_user_policy.ts | 75 +++ apps/sim/tools/iam/create_access_key.ts | 81 +++ apps/sim/tools/iam/create_role.ts | 105 ++++ apps/sim/tools/iam/create_user.ts | 84 +++ apps/sim/tools/iam/delete_access_key.ts | 75 +++ apps/sim/tools/iam/delete_role.ts | 67 +++ apps/sim/tools/iam/delete_user.ts | 67 +++ apps/sim/tools/iam/detach_role_policy.ts | 75 +++ apps/sim/tools/iam/detach_user_policy.ts | 75 +++ apps/sim/tools/iam/get_role.ts | 101 ++++ apps/sim/tools/iam/get_user.ts | 93 +++ apps/sim/tools/iam/index.ts | 37 ++ apps/sim/tools/iam/list_groups.ts | 97 +++ apps/sim/tools/iam/list_policies.ts | 111 ++++ apps/sim/tools/iam/list_roles.ts | 97 +++ apps/sim/tools/iam/list_users.ts | 97 +++ apps/sim/tools/iam/remove_user_from_group.ts | 77 +++ apps/sim/tools/iam/types.ts | 275 +++++++++ apps/sim/tools/registry.ts | 48 ++ apps/sim/tools/sts/assume_role.ts | 118 ++++ apps/sim/tools/sts/get_access_key_info.ts | 70 +++ apps/sim/tools/sts/get_caller_identity.ts | 67 +++ apps/sim/tools/sts/get_session_token.ts | 88 +++ apps/sim/tools/sts/index.ts | 9 + apps/sim/tools/sts/types.ts | 67 +++ bun.lock | 264 +++++++++ 64 files changed, 5925 insertions(+) create mode 100644 apps/docs/content/docs/en/tools/iam.mdx create mode 100644 apps/docs/content/docs/en/tools/sts.mdx create mode 100644 apps/sim/app/api/tools/iam/add-user-to-group/route.ts create mode 100644 apps/sim/app/api/tools/iam/attach-role-policy/route.ts create mode 100644 apps/sim/app/api/tools/iam/attach-user-policy/route.ts create mode 100644 apps/sim/app/api/tools/iam/create-access-key/route.ts create mode 100644 apps/sim/app/api/tools/iam/create-role/route.ts create mode 100644 apps/sim/app/api/tools/iam/create-user/route.ts create mode 100644 apps/sim/app/api/tools/iam/delete-access-key/route.ts create mode 100644 apps/sim/app/api/tools/iam/delete-role/route.ts create mode 100644 apps/sim/app/api/tools/iam/delete-user/route.ts create mode 100644 apps/sim/app/api/tools/iam/detach-role-policy/route.ts create mode 100644 apps/sim/app/api/tools/iam/detach-user-policy/route.ts create mode 100644 apps/sim/app/api/tools/iam/get-role/route.ts create mode 100644 apps/sim/app/api/tools/iam/get-user/route.ts create mode 100644 apps/sim/app/api/tools/iam/list-groups/route.ts create mode 100644 apps/sim/app/api/tools/iam/list-policies/route.ts create mode 100644 apps/sim/app/api/tools/iam/list-roles/route.ts create mode 100644 apps/sim/app/api/tools/iam/list-users/route.ts create mode 100644 apps/sim/app/api/tools/iam/remove-user-from-group/route.ts create mode 100644 apps/sim/app/api/tools/iam/utils.ts create mode 100644 apps/sim/app/api/tools/sts/assume-role/route.ts create mode 100644 apps/sim/app/api/tools/sts/get-access-key-info/route.ts create mode 100644 apps/sim/app/api/tools/sts/get-caller-identity/route.ts create mode 100644 apps/sim/app/api/tools/sts/get-session-token/route.ts create mode 100644 apps/sim/app/api/tools/sts/utils.ts create mode 100644 apps/sim/blocks/blocks/iam.ts create mode 100644 apps/sim/blocks/blocks/sts.ts create mode 100644 apps/sim/tools/iam/add_user_to_group.ts create mode 100644 apps/sim/tools/iam/attach_role_policy.ts create mode 100644 apps/sim/tools/iam/attach_user_policy.ts create mode 100644 apps/sim/tools/iam/create_access_key.ts create mode 100644 apps/sim/tools/iam/create_role.ts create mode 100644 apps/sim/tools/iam/create_user.ts create mode 100644 apps/sim/tools/iam/delete_access_key.ts create mode 100644 apps/sim/tools/iam/delete_role.ts create mode 100644 apps/sim/tools/iam/delete_user.ts create mode 100644 apps/sim/tools/iam/detach_role_policy.ts create mode 100644 apps/sim/tools/iam/detach_user_policy.ts create mode 100644 apps/sim/tools/iam/get_role.ts create mode 100644 apps/sim/tools/iam/get_user.ts create mode 100644 apps/sim/tools/iam/index.ts create mode 100644 apps/sim/tools/iam/list_groups.ts create mode 100644 apps/sim/tools/iam/list_policies.ts create mode 100644 apps/sim/tools/iam/list_roles.ts create mode 100644 apps/sim/tools/iam/list_users.ts create mode 100644 apps/sim/tools/iam/remove_user_from_group.ts create mode 100644 apps/sim/tools/iam/types.ts create mode 100644 apps/sim/tools/sts/assume_role.ts create mode 100644 apps/sim/tools/sts/get_access_key_info.ts create mode 100644 apps/sim/tools/sts/get_caller_identity.ts create mode 100644 apps/sim/tools/sts/get_session_token.ts create mode 100644 apps/sim/tools/sts/index.ts create mode 100644 apps/sim/tools/sts/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index aab80fe0cbe..7508d0827cf 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4625,6 +4625,24 @@ export function DynamoDBIcon(props: SVGProps) { ) } +export function IAMIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} + export function SecretsManagerIcon(props: SVGProps) { return ( diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 4ed718ff7f6..7104301a0aa 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -89,6 +89,7 @@ import { HubspotIcon, HuggingFaceIcon, HunterIOIcon, + IAMIcon, ImageIcon, IncidentioIcon, InfisicalIcon, @@ -278,6 +279,7 @@ export const blockTypeToIconMap: Record = { hubspot: HubspotIcon, huggingface: HuggingFaceIcon, hunter: HunterIOIcon, + iam: IAMIcon, image_generator: ImageIcon, imap: MailServerIcon, incidentio: IncidentioIcon, @@ -356,6 +358,7 @@ export const blockTypeToIconMap: Record = { ssh: SshIcon, stagehand: StagehandIcon, stripe: StripeIcon, + sts: IAMIcon, stt_v2: STTIcon, supabase: SupabaseIcon, tailscale: TailscaleIcon, diff --git a/apps/docs/content/docs/en/tools/iam.mdx b/apps/docs/content/docs/en/tools/iam.mdx new file mode 100644 index 00000000000..5fd9263eadd --- /dev/null +++ b/apps/docs/content/docs/en/tools/iam.mdx @@ -0,0 +1,443 @@ +--- +title: AWS IAM +description: Manage AWS IAM users, roles, policies, and groups +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[AWS Identity and Access Management (IAM)](https://aws.amazon.com/iam/) is a web service that helps you securely control access to AWS resources. IAM lets you manage permissions that control which AWS resources users, groups, and roles can access. + +With AWS IAM, you can: + +- **Manage users**: Create and manage IAM users, assign them individual security credentials, and grant them permissions to access AWS services and resources +- **Create roles**: Define IAM roles with specific permissions that can be assumed by users, services, or applications for temporary access +- **Attach policies**: Assign managed policies to users and roles to define what actions they can perform on which resources +- **Organize with groups**: Create IAM groups to manage permissions for collections of users, simplifying access management at scale +- **Control access keys**: Generate and manage programmatic access key pairs for API and CLI access to AWS services + +In Sim, the AWS IAM integration allows your workflows to automate identity management tasks such as provisioning new users, assigning roles and permissions, managing group memberships, and rotating access keys. This is particularly useful for onboarding automation, security compliance workflows, access reviews, and incident response — enabling your agents to manage AWS access control programmatically. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate AWS Identity and Access Management into your workflow. Create and manage users, roles, policies, groups, and access keys. + + + +## Tools + +### `iam_list_users` + +List IAM users in your AWS account + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `pathPrefix` | string | No | Path prefix to filter users \(e.g., /division_abc/\) | +| `maxItems` | number | No | Maximum number of users to return \(1-1000, default 100\) | +| `marker` | string | No | Pagination marker from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `users` | json | List of IAM users with userName, userId, arn, path, and dates | +| `isTruncated` | boolean | Whether there are more results available | +| `marker` | string | Pagination marker for the next page of results | +| `count` | number | Number of users returned | + +### `iam_get_user` + +Get detailed information about an IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | The name of the IAM user to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `userName` | string | The name of the user | +| `userId` | string | The unique ID of the user | +| `arn` | string | The ARN of the user | +| `path` | string | The path to the user | +| `createDate` | string | Date the user was created | +| `passwordLastUsed` | string | Date the password was last used | +| `permissionsBoundaryArn` | string | ARN of the permissions boundary policy | +| `tags` | json | Tags attached to the user \(key, value pairs\) | + +### `iam_create_user` + +Create a new IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | Name for the new IAM user \(1-64 characters\) | +| `path` | string | No | Path for the user \(e.g., /division_abc/\), defaults to / | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `userName` | string | The name of the created user | +| `userId` | string | The unique ID of the created user | +| `arn` | string | The ARN of the created user | +| `path` | string | The path of the created user | +| `createDate` | string | Date the user was created | + +### `iam_delete_user` + +Delete an IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | The name of the IAM user to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_list_roles` + +List IAM roles in your AWS account + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `pathPrefix` | string | No | Path prefix to filter roles \(e.g., /application/\) | +| `maxItems` | number | No | Maximum number of roles to return \(1-1000, default 100\) | +| `marker` | string | No | Pagination marker from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `roles` | json | List of IAM roles with roleName, roleId, arn, path, and dates | +| `isTruncated` | boolean | Whether there are more results available | +| `marker` | string | Pagination marker for the next page of results | +| `count` | number | Number of roles returned | + +### `iam_get_role` + +Get detailed information about an IAM role + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `roleName` | string | Yes | The name of the IAM role to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `roleName` | string | The name of the role | +| `roleId` | string | The unique ID of the role | +| `arn` | string | The ARN of the role | +| `path` | string | The path to the role | +| `createDate` | string | Date the role was created | +| `description` | string | Description of the role | +| `maxSessionDuration` | number | Maximum session duration in seconds | +| `assumeRolePolicyDocument` | string | The trust policy document \(JSON\) | +| `roleLastUsedDate` | string | Date the role was last used | +| `roleLastUsedRegion` | string | AWS region where the role was last used | + +### `iam_create_role` + +Create a new IAM role with a trust policy + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `roleName` | string | Yes | Name for the new IAM role \(1-64 characters\) | +| `assumeRolePolicyDocument` | string | Yes | Trust policy JSON specifying who can assume this role | +| `description` | string | No | Description of the role | +| `path` | string | No | Path for the role \(e.g., /application/\), defaults to / | +| `maxSessionDuration` | number | No | Maximum session duration in seconds \(3600-43200, default 3600\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `roleName` | string | The name of the created role | +| `roleId` | string | The unique ID of the created role | +| `arn` | string | The ARN of the created role | +| `path` | string | The path of the created role | +| `createDate` | string | Date the role was created | + +### `iam_delete_role` + +Delete an IAM role + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `roleName` | string | Yes | The name of the IAM role to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_attach_user_policy` + +Attach a managed policy to an IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | The name of the IAM user | +| `policyArn` | string | Yes | The ARN of the managed policy to attach | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_detach_user_policy` + +Remove a managed policy from an IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | The name of the IAM user | +| `policyArn` | string | Yes | The ARN of the managed policy to detach | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_attach_role_policy` + +Attach a managed policy to an IAM role + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `roleName` | string | Yes | The name of the IAM role | +| `policyArn` | string | Yes | The ARN of the managed policy to attach | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_detach_role_policy` + +Remove a managed policy from an IAM role + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `roleName` | string | Yes | The name of the IAM role | +| `policyArn` | string | Yes | The ARN of the managed policy to detach | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_list_policies` + +List managed IAM policies + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `scope` | string | No | Filter by scope: All, AWS \(AWS-managed\), or Local \(customer-managed\) | +| `onlyAttached` | boolean | No | If true, only return policies attached to an entity | +| `pathPrefix` | string | No | Path prefix to filter policies | +| `maxItems` | number | No | Maximum number of policies to return \(1-1000, default 100\) | +| `marker` | string | No | Pagination marker from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `policies` | json | List of policies with policyName, arn, attachmentCount, and dates | +| `isTruncated` | boolean | Whether there are more results available | +| `marker` | string | Pagination marker for the next page of results | +| `count` | number | Number of policies returned | + +### `iam_create_access_key` + +Create a new access key pair for an IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | No | The IAM user to create the key for \(defaults to current user\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `accessKeyId` | string | The new access key ID | +| `secretAccessKey` | string | The new secret access key \(only shown once\) | +| `userName` | string | The user the key was created for | +| `status` | string | Status of the access key \(Active\) | +| `createDate` | string | Date the key was created | + +### `iam_delete_access_key` + +Delete an access key pair for an IAM user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `accessKeyIdToDelete` | string | Yes | The access key ID to delete | +| `userName` | string | No | The IAM user whose key to delete \(defaults to current user\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_list_groups` + +List IAM groups in your AWS account + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `pathPrefix` | string | No | Path prefix to filter groups | +| `maxItems` | number | No | Maximum number of groups to return \(1-1000, default 100\) | +| `marker` | string | No | Pagination marker from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `groups` | json | List of IAM groups with groupName, groupId, arn, and path | +| `isTruncated` | boolean | Whether there are more results available | +| `marker` | string | Pagination marker for the next page of results | +| `count` | number | Number of groups returned | + +### `iam_add_user_to_group` + +Add an IAM user to a group + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | The name of the IAM user | +| `groupName` | string | Yes | The name of the IAM group | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + +### `iam_remove_user_from_group` + +Remove an IAM user from a group + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `userName` | string | Yes | The name of the IAM user | +| `groupName` | string | Yes | The name of the IAM group | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index edded074639..d11a49bfd71 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -83,6 +83,7 @@ "hubspot", "huggingface", "hunter", + "iam", "image_generator", "imap", "incidentio", @@ -161,6 +162,7 @@ "ssh", "stagehand", "stripe", + "sts", "stt", "supabase", "table", diff --git a/apps/docs/content/docs/en/tools/sts.mdx b/apps/docs/content/docs/en/tools/sts.mdx new file mode 100644 index 00000000000..29fd0445e16 --- /dev/null +++ b/apps/docs/content/docs/en/tools/sts.mdx @@ -0,0 +1,128 @@ +--- +title: AWS STS +description: Connect to AWS Security Token Service +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[AWS Security Token Service (STS)](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html) is a web service that enables you to request temporary, limited-privilege credentials for AWS Identity and Access Management (IAM) users or for users that you authenticate (federated users). + +With AWS STS, you can: + +- **Assume IAM roles**: Request temporary credentials to access AWS resources across accounts or with elevated permissions +- **Verify identity**: Determine the AWS account, ARN, and user ID associated with the calling credentials +- **Generate session tokens**: Obtain temporary credentials with optional MFA protection for enhanced security +- **Audit access keys**: Look up the AWS account that owns a given access key for security investigations + +In Sim, the AWS STS integration allows your agents to manage temporary credentials as part of automated workflows. This is useful for cross-account access patterns, credential rotation, identity verification before sensitive operations, and security auditing. Agents can assume roles to interact with other AWS services, verify their own identity, or look up access key ownership without exposing long-lived credentials. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate AWS STS into the workflow. Assume roles, get temporary credentials, verify caller identity, and look up access key information. + + + +## Tools + +### `sts_assume_role` + +Assume an IAM role and receive temporary security credentials + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `roleArn` | string | Yes | ARN of the IAM role to assume | +| `roleSessionName` | string | Yes | Identifier for the assumed role session | +| `durationSeconds` | number | No | Duration of the session in seconds \(900-43200, default 3600\) | +| `externalId` | string | No | External ID for cross-account access | +| `serialNumber` | string | No | MFA device serial number or ARN | +| `tokenCode` | string | No | MFA token code \(6 digits\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `accessKeyId` | string | Temporary access key ID | +| `secretAccessKey` | string | Temporary secret access key | +| `sessionToken` | string | Temporary session token | +| `expiration` | string | Credential expiration timestamp | +| `assumedRoleArn` | string | ARN of the assumed role | +| `assumedRoleId` | string | Assumed role ID with session name | +| `packedPolicySize` | number | Percentage of allowed policy size used | + +### `sts_get_caller_identity` + +Get details about the IAM user or role whose credentials are used to call the API + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `account` | string | AWS account ID | +| `arn` | string | ARN of the calling entity | +| `userId` | string | Unique identifier of the calling entity | + +### `sts_get_session_token` + +Get temporary security credentials for an IAM user, optionally with MFA + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `durationSeconds` | number | No | Duration of the session in seconds \(900-129600, default 43200\) | +| `serialNumber` | string | No | MFA device serial number or ARN | +| `tokenCode` | string | No | MFA token code \(6 digits\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `accessKeyId` | string | Temporary access key ID | +| `secretAccessKey` | string | Temporary secret access key | +| `sessionToken` | string | Temporary session token | +| `expiration` | string | Credential expiration timestamp | + +### `sts_get_access_key_info` + +Get the AWS account ID associated with an access key + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `targetAccessKeyId` | string | Yes | The access key ID to look up | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `account` | string | AWS account ID that owns the access key | + + diff --git a/apps/sim/app/(landing)/integrations/data/icon-mapping.ts b/apps/sim/app/(landing)/integrations/data/icon-mapping.ts index 1b09e2c7bed..c30bb7431ed 100644 --- a/apps/sim/app/(landing)/integrations/data/icon-mapping.ts +++ b/apps/sim/app/(landing)/integrations/data/icon-mapping.ts @@ -89,6 +89,7 @@ import { HubspotIcon, HuggingFaceIcon, HunterIOIcon, + IAMIcon, ImageIcon, IncidentioIcon, InfisicalIcon, @@ -278,6 +279,7 @@ export const blockTypeToIconMap: Record = { hubspot: HubspotIcon, huggingface: HuggingFaceIcon, hunter: HunterIOIcon, + iam: IAMIcon, image_generator: ImageIcon, imap: MailServerIcon, incidentio: IncidentioIcon, @@ -356,6 +358,7 @@ export const blockTypeToIconMap: Record = { ssh: SshIcon, stagehand: StagehandIcon, stripe: StripeIcon, + sts: IAMIcon, stt_v2: STTIcon, supabase: SupabaseIcon, tailscale: TailscaleIcon, diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 6f31dc42571..757fd936781 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -1383,6 +1383,97 @@ "integrationTypes": ["crm", "sales"], "tags": ["sales-engagement", "enrichment"] }, + { + "type": "iam", + "slug": "aws-iam", + "name": "AWS IAM", + "description": "Manage AWS IAM users, roles, policies, and groups", + "longDescription": "Integrate AWS Identity and Access Management into your workflow. Create and manage users, roles, policies, groups, and access keys.", + "bgColor": "linear-gradient(45deg, #BD0816 0%, #FF5252 100%)", + "iconName": "IAMIcon", + "docsUrl": "https://docs.sim.ai/tools/iam", + "operations": [ + { + "name": "List Users", + "description": "List IAM users in your AWS account" + }, + { + "name": "Get User", + "description": "Get detailed information about an IAM user" + }, + { + "name": "Create User", + "description": "Create a new IAM user" + }, + { + "name": "Delete User", + "description": "Delete an IAM user" + }, + { + "name": "List Roles", + "description": "List IAM roles in your AWS account" + }, + { + "name": "Get Role", + "description": "Get detailed information about an IAM role" + }, + { + "name": "Create Role", + "description": "Create a new IAM role with a trust policy" + }, + { + "name": "Delete Role", + "description": "Delete an IAM role" + }, + { + "name": "Attach User Policy", + "description": "Attach a managed policy to an IAM user" + }, + { + "name": "Detach User Policy", + "description": "Remove a managed policy from an IAM user" + }, + { + "name": "Attach Role Policy", + "description": "Attach a managed policy to an IAM role" + }, + { + "name": "Detach Role Policy", + "description": "Remove a managed policy from an IAM role" + }, + { + "name": "List Policies", + "description": "List managed IAM policies" + }, + { + "name": "Create Access Key", + "description": "Create a new access key pair for an IAM user" + }, + { + "name": "Delete Access Key", + "description": "Delete an access key pair for an IAM user" + }, + { + "name": "List Groups", + "description": "List IAM groups in your AWS account" + }, + { + "name": "Add User to Group", + "description": "Add an IAM user to a group" + }, + { + "name": "Remove User from Group", + "description": "Remove an IAM user from a group" + } + ], + "operationCount": 18, + "triggers": [], + "triggerCount": 0, + "authType": "none", + "category": "tools", + "integrationTypes": ["developer-tools", "security"], + "tags": ["cloud", "identity"] + }, { "type": "secrets_manager", "slug": "aws-secrets-manager", @@ -1422,6 +1513,41 @@ "integrationTypes": ["developer-tools", "security"], "tags": ["cloud", "secrets-management"] }, + { + "type": "sts", + "slug": "aws-sts", + "name": "AWS STS", + "description": "Connect to AWS Security Token Service", + "longDescription": "Integrate AWS STS into the workflow. Assume roles, get temporary credentials, verify caller identity, and look up access key information.", + "bgColor": "linear-gradient(45deg, #BD0816 0%, #FF5252 100%)", + "iconName": "IAMIcon", + "docsUrl": "https://docs.sim.ai/tools/sts", + "operations": [ + { + "name": "Assume Role", + "description": "Assume an IAM role and receive temporary security credentials" + }, + { + "name": "Get Caller Identity", + "description": "Get details about the IAM user or role whose credentials are used to call the API" + }, + { + "name": "Get Session Token", + "description": "Get temporary security credentials for an IAM user, optionally with MFA" + }, + { + "name": "Get Access Key Info", + "description": "Get the AWS account ID associated with an access key" + } + ], + "operationCount": 4, + "triggers": [], + "triggerCount": 0, + "authType": "none", + "category": "tools", + "integrationTypes": ["security", "developer-tools"], + "tags": ["cloud"] + }, { "type": "textract_v2", "slug": "aws-textract", diff --git a/apps/sim/app/api/tools/iam/add-user-to-group/route.ts b/apps/sim/app/api/tools/iam/add-user-to-group/route.ts new file mode 100644 index 00000000000..88dc2e67501 --- /dev/null +++ b/apps/sim/app/api/tools/iam/add-user-to-group/route.ts @@ -0,0 +1,64 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { addUserToGroup, createIAMClient } from '../utils' + +const logger = createLogger('IAMAddUserToGroupAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), + groupName: z.string().min(1, 'Group name is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Adding user "${params.userName}" to group "${params.groupName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await addUserToGroup(client, params.userName, params.groupName) + logger.info( + `[${requestId}] Successfully added user "${params.userName}" to group "${params.groupName}"` + ) + return NextResponse.json({ + message: `User "${params.userName}" added to group "${params.groupName}"`, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to add user to group:`, error) + return NextResponse.json( + { error: `Failed to add user to group: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/attach-role-policy/route.ts b/apps/sim/app/api/tools/iam/attach-role-policy/route.ts new file mode 100644 index 00000000000..0360769c098 --- /dev/null +++ b/apps/sim/app/api/tools/iam/attach-role-policy/route.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { attachRolePolicy, createIAMClient } from '../utils' + +const logger = createLogger('IAMAttachRolePolicyAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + roleName: z.string().min(1, 'Role name is required'), + policyArn: z.string().min(1, 'Policy ARN is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Attaching policy to IAM role "${params.roleName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await attachRolePolicy(client, params.roleName, params.policyArn) + logger.info(`[${requestId}] Successfully attached policy to IAM role "${params.roleName}"`) + return NextResponse.json({ + message: `Policy "${params.policyArn}" attached to role "${params.roleName}"`, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to attach role policy:`, error) + return NextResponse.json( + { error: `Failed to attach role policy: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/attach-user-policy/route.ts b/apps/sim/app/api/tools/iam/attach-user-policy/route.ts new file mode 100644 index 00000000000..6ae4037ceb6 --- /dev/null +++ b/apps/sim/app/api/tools/iam/attach-user-policy/route.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { attachUserPolicy, createIAMClient } from '../utils' + +const logger = createLogger('IAMAttachUserPolicyAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), + policyArn: z.string().min(1, 'Policy ARN is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Attaching policy to IAM user "${params.userName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await attachUserPolicy(client, params.userName, params.policyArn) + logger.info(`[${requestId}] Successfully attached policy to IAM user "${params.userName}"`) + return NextResponse.json({ + message: `Policy "${params.policyArn}" attached to user "${params.userName}"`, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to attach user policy:`, error) + return NextResponse.json( + { error: `Failed to attach user policy: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/create-access-key/route.ts b/apps/sim/app/api/tools/iam/create-access-key/route.ts new file mode 100644 index 00000000000..f8a82d794b7 --- /dev/null +++ b/apps/sim/app/api/tools/iam/create-access-key/route.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createAccessKey, createIAMClient } from '../utils' + +const logger = createLogger('IAMCreateAccessKeyAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Creating IAM access key`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createAccessKey(client, params.userName) + logger.info(`[${requestId}] Successfully created access key for user "${result.userName}"`) + return NextResponse.json({ + message: `Access key created for user "${result.userName}"`, + ...result, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to create access key:`, error) + return NextResponse.json( + { error: `Failed to create access key: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/create-role/route.ts b/apps/sim/app/api/tools/iam/create-role/route.ts new file mode 100644 index 00000000000..0cd765c2012 --- /dev/null +++ b/apps/sim/app/api/tools/iam/create-role/route.ts @@ -0,0 +1,73 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, createRole } from '../utils' + +const logger = createLogger('IAMCreateRoleAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + roleName: z.string().min(1, 'Role name is required'), + assumeRolePolicyDocument: z.string().min(1, 'Assume role policy document is required'), + description: z.string().optional(), + path: z.string().optional(), + maxSessionDuration: z.number().min(3600).max(43200).optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Creating IAM role "${params.roleName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createRole( + client, + params.roleName, + params.assumeRolePolicyDocument, + params.description, + params.path, + params.maxSessionDuration + ) + logger.info(`[${requestId}] Successfully created IAM role "${result.roleName}"`) + return NextResponse.json({ + message: `Role "${result.roleName}" created successfully`, + ...result, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to create IAM role:`, error) + return NextResponse.json( + { error: `Failed to create IAM role: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/create-user/route.ts b/apps/sim/app/api/tools/iam/create-user/route.ts new file mode 100644 index 00000000000..42db82145fe --- /dev/null +++ b/apps/sim/app/api/tools/iam/create-user/route.ts @@ -0,0 +1,63 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, createUser } from '../utils' + +const logger = createLogger('IAMCreateUserAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), + path: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Creating IAM user "${params.userName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createUser(client, params.userName, params.path) + logger.info(`[${requestId}] Successfully created IAM user "${result.userName}"`) + return NextResponse.json({ + message: `User "${result.userName}" created successfully`, + ...result, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to create IAM user:`, error) + return NextResponse.json( + { error: `Failed to create IAM user: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/delete-access-key/route.ts b/apps/sim/app/api/tools/iam/delete-access-key/route.ts new file mode 100644 index 00000000000..65486f5e5fa --- /dev/null +++ b/apps/sim/app/api/tools/iam/delete-access-key/route.ts @@ -0,0 +1,60 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, deleteAccessKey } from '../utils' + +const logger = createLogger('IAMDeleteAccessKeyAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + accessKeyIdToDelete: z.string().min(1, 'Access key ID to delete is required'), + userName: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Deleting IAM access key "${params.accessKeyIdToDelete}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await deleteAccessKey(client, params.accessKeyIdToDelete, params.userName) + logger.info(`[${requestId}] Successfully deleted access key "${params.accessKeyIdToDelete}"`) + return NextResponse.json({ message: `Access key "${params.accessKeyIdToDelete}" deleted` }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to delete access key:`, error) + return NextResponse.json( + { error: `Failed to delete access key: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/delete-role/route.ts b/apps/sim/app/api/tools/iam/delete-role/route.ts new file mode 100644 index 00000000000..488bb300483 --- /dev/null +++ b/apps/sim/app/api/tools/iam/delete-role/route.ts @@ -0,0 +1,59 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, deleteRole } from '../utils' + +const logger = createLogger('IAMDeleteRoleAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + roleName: z.string().min(1, 'Role name is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Deleting IAM role "${params.roleName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await deleteRole(client, params.roleName) + logger.info(`[${requestId}] Successfully deleted IAM role "${params.roleName}"`) + return NextResponse.json({ message: `Role "${params.roleName}" deleted successfully` }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to delete IAM role:`, error) + return NextResponse.json( + { error: `Failed to delete IAM role: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/delete-user/route.ts b/apps/sim/app/api/tools/iam/delete-user/route.ts new file mode 100644 index 00000000000..5d6d9e980c9 --- /dev/null +++ b/apps/sim/app/api/tools/iam/delete-user/route.ts @@ -0,0 +1,59 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, deleteUser } from '../utils' + +const logger = createLogger('IAMDeleteUserAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Deleting IAM user "${params.userName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await deleteUser(client, params.userName) + logger.info(`[${requestId}] Successfully deleted IAM user "${params.userName}"`) + return NextResponse.json({ message: `User "${params.userName}" deleted successfully` }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to delete IAM user:`, error) + return NextResponse.json( + { error: `Failed to delete IAM user: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/detach-role-policy/route.ts b/apps/sim/app/api/tools/iam/detach-role-policy/route.ts new file mode 100644 index 00000000000..3e4af87dc98 --- /dev/null +++ b/apps/sim/app/api/tools/iam/detach-role-policy/route.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, detachRolePolicy } from '../utils' + +const logger = createLogger('IAMDetachRolePolicyAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + roleName: z.string().min(1, 'Role name is required'), + policyArn: z.string().min(1, 'Policy ARN is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Detaching policy from IAM role "${params.roleName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await detachRolePolicy(client, params.roleName, params.policyArn) + logger.info(`[${requestId}] Successfully detached policy from IAM role "${params.roleName}"`) + return NextResponse.json({ + message: `Policy "${params.policyArn}" detached from role "${params.roleName}"`, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to detach role policy:`, error) + return NextResponse.json( + { error: `Failed to detach role policy: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/detach-user-policy/route.ts b/apps/sim/app/api/tools/iam/detach-user-policy/route.ts new file mode 100644 index 00000000000..9972a2b78bb --- /dev/null +++ b/apps/sim/app/api/tools/iam/detach-user-policy/route.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, detachUserPolicy } from '../utils' + +const logger = createLogger('IAMDetachUserPolicyAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), + policyArn: z.string().min(1, 'Policy ARN is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Detaching policy from IAM user "${params.userName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await detachUserPolicy(client, params.userName, params.policyArn) + logger.info(`[${requestId}] Successfully detached policy from IAM user "${params.userName}"`) + return NextResponse.json({ + message: `Policy "${params.policyArn}" detached from user "${params.userName}"`, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to detach user policy:`, error) + return NextResponse.json( + { error: `Failed to detach user policy: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/get-role/route.ts b/apps/sim/app/api/tools/iam/get-role/route.ts new file mode 100644 index 00000000000..a7a0f20273b --- /dev/null +++ b/apps/sim/app/api/tools/iam/get-role/route.ts @@ -0,0 +1,56 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, getRole } from '../utils' + +const logger = createLogger('IAMGetRoleAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + roleName: z.string().min(1, 'Role name is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Getting IAM role "${params.roleName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getRole(client, params.roleName) + logger.info(`[${requestId}] Successfully retrieved IAM role "${params.roleName}"`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to get IAM role:`, error) + return NextResponse.json({ error: `Failed to get IAM role: ${errorMessage}` }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/iam/get-user/route.ts b/apps/sim/app/api/tools/iam/get-user/route.ts new file mode 100644 index 00000000000..148baf28834 --- /dev/null +++ b/apps/sim/app/api/tools/iam/get-user/route.ts @@ -0,0 +1,56 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, getUser } from '../utils' + +const logger = createLogger('IAMGetUserAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Getting IAM user "${params.userName}"`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getUser(client, params.userName) + logger.info(`[${requestId}] Successfully retrieved IAM user "${params.userName}"`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to get IAM user:`, error) + return NextResponse.json({ error: `Failed to get IAM user: ${errorMessage}` }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/iam/list-groups/route.ts b/apps/sim/app/api/tools/iam/list-groups/route.ts new file mode 100644 index 00000000000..6512f71f84a --- /dev/null +++ b/apps/sim/app/api/tools/iam/list-groups/route.ts @@ -0,0 +1,61 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, listGroups } from '../utils' + +const logger = createLogger('IAMListGroupsAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + pathPrefix: z.string().optional(), + maxItems: z.number().min(1).max(1000).optional(), + marker: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Listing IAM groups`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listGroups(client, params.pathPrefix, params.maxItems, params.marker) + logger.info(`[${requestId}] Successfully listed ${result.count} IAM groups`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to list IAM groups:`, error) + return NextResponse.json( + { error: `Failed to list IAM groups: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/list-policies/route.ts b/apps/sim/app/api/tools/iam/list-policies/route.ts new file mode 100644 index 00000000000..ecd2c892c94 --- /dev/null +++ b/apps/sim/app/api/tools/iam/list-policies/route.ts @@ -0,0 +1,70 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, listPolicies } from '../utils' + +const logger = createLogger('IAMListPoliciesAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + scope: z.string().optional(), + onlyAttached: z.boolean().optional(), + pathPrefix: z.string().optional(), + maxItems: z.number().min(1).max(1000).optional(), + marker: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Listing IAM policies`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listPolicies( + client, + params.scope, + params.onlyAttached, + params.pathPrefix, + params.maxItems, + params.marker + ) + logger.info(`[${requestId}] Successfully listed ${result.count} IAM policies`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to list IAM policies:`, error) + return NextResponse.json( + { error: `Failed to list IAM policies: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/list-roles/route.ts b/apps/sim/app/api/tools/iam/list-roles/route.ts new file mode 100644 index 00000000000..fac48e83475 --- /dev/null +++ b/apps/sim/app/api/tools/iam/list-roles/route.ts @@ -0,0 +1,61 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, listRoles } from '../utils' + +const logger = createLogger('IAMListRolesAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + pathPrefix: z.string().optional(), + maxItems: z.number().min(1).max(1000).optional(), + marker: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Listing IAM roles`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listRoles(client, params.pathPrefix, params.maxItems, params.marker) + logger.info(`[${requestId}] Successfully listed ${result.count} IAM roles`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to list IAM roles:`, error) + return NextResponse.json( + { error: `Failed to list IAM roles: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/list-users/route.ts b/apps/sim/app/api/tools/iam/list-users/route.ts new file mode 100644 index 00000000000..17668a8737c --- /dev/null +++ b/apps/sim/app/api/tools/iam/list-users/route.ts @@ -0,0 +1,61 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, listUsers } from '../utils' + +const logger = createLogger('IAMListUsersAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + pathPrefix: z.string().optional(), + maxItems: z.number().min(1).max(1000).optional(), + marker: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info(`[${requestId}] Listing IAM users`) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listUsers(client, params.pathPrefix, params.maxItems, params.marker) + logger.info(`[${requestId}] Successfully listed ${result.count} IAM users`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to list IAM users:`, error) + return NextResponse.json( + { error: `Failed to list IAM users: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/remove-user-from-group/route.ts b/apps/sim/app/api/tools/iam/remove-user-from-group/route.ts new file mode 100644 index 00000000000..d50c699e92e --- /dev/null +++ b/apps/sim/app/api/tools/iam/remove-user-from-group/route.ts @@ -0,0 +1,66 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createIAMClient, removeUserFromGroup } from '../utils' + +const logger = createLogger('IAMRemoveUserFromGroupAPI') + +const Schema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + userName: z.string().min(1, 'User name is required'), + groupName: z.string().min(1, 'Group name is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = Schema.parse(body) + + logger.info( + `[${requestId}] Removing user "${params.userName}" from group "${params.groupName}"` + ) + + const client = createIAMClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + await removeUserFromGroup(client, params.userName, params.groupName) + logger.info( + `[${requestId}] Successfully removed user "${params.userName}" from group "${params.groupName}"` + ) + return NextResponse.json({ + message: `User "${params.userName}" removed from group "${params.groupName}"`, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to remove user from group:`, error) + return NextResponse.json( + { error: `Failed to remove user from group: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/iam/utils.ts b/apps/sim/app/api/tools/iam/utils.ts new file mode 100644 index 00000000000..b711fc0c2ae --- /dev/null +++ b/apps/sim/app/api/tools/iam/utils.ts @@ -0,0 +1,340 @@ +import type { Group, Policy, PolicyScopeType, Role, User } from '@aws-sdk/client-iam' +import { + AddUserToGroupCommand, + AttachRolePolicyCommand, + AttachUserPolicyCommand, + CreateAccessKeyCommand, + CreateRoleCommand, + CreateUserCommand, + DeleteAccessKeyCommand, + DeleteRoleCommand, + DeleteUserCommand, + DetachRolePolicyCommand, + DetachUserPolicyCommand, + GetRoleCommand, + GetUserCommand, + IAMClient, + ListGroupsCommand, + ListPoliciesCommand, + ListRolesCommand, + ListUsersCommand, + RemoveUserFromGroupCommand, +} from '@aws-sdk/client-iam' +import type { IAMConnectionConfig } from '@/tools/iam/types' + +export function createIAMClient(config: IAMConnectionConfig): IAMClient { + return new IAMClient({ + region: config.region, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey, + }, + }) +} + +export async function listUsers( + client: IAMClient, + pathPrefix?: string | null, + maxItems?: number | null, + marker?: string | null +) { + const command = new ListUsersCommand({ + ...(pathPrefix ? { PathPrefix: pathPrefix } : {}), + ...(maxItems ? { MaxItems: maxItems } : {}), + ...(marker ? { Marker: marker } : {}), + }) + + const response = await client.send(command) + const users = (response.Users ?? []).map((user: User) => ({ + userName: user.UserName ?? '', + userId: user.UserId ?? '', + arn: user.Arn ?? '', + path: user.Path ?? '', + createDate: user.CreateDate?.toISOString() ?? null, + passwordLastUsed: user.PasswordLastUsed?.toISOString() ?? null, + })) + + return { + users, + isTruncated: response.IsTruncated ?? false, + marker: response.Marker ?? null, + count: users.length, + } +} + +export async function getUser(client: IAMClient, userName: string) { + const command = new GetUserCommand({ UserName: userName }) + const response = await client.send(command) + const user = response.User + + return { + userName: user?.UserName ?? '', + userId: user?.UserId ?? '', + arn: user?.Arn ?? '', + path: user?.Path ?? '', + createDate: user?.CreateDate?.toISOString() ?? null, + passwordLastUsed: user?.PasswordLastUsed?.toISOString() ?? null, + permissionsBoundaryArn: user?.PermissionsBoundary?.PermissionsBoundaryArn ?? null, + tags: user?.Tags?.map((t) => ({ key: t.Key ?? '', value: t.Value ?? '' })) ?? [], + } +} + +export async function createUser(client: IAMClient, userName: string, path?: string | null) { + const command = new CreateUserCommand({ + UserName: userName, + ...(path ? { Path: path } : {}), + }) + + const response = await client.send(command) + const user = response.User + + return { + userName: user?.UserName ?? '', + userId: user?.UserId ?? '', + arn: user?.Arn ?? '', + path: user?.Path ?? '', + createDate: user?.CreateDate?.toISOString() ?? null, + } +} + +export async function deleteUser(client: IAMClient, userName: string) { + const command = new DeleteUserCommand({ UserName: userName }) + await client.send(command) +} + +export async function listRoles( + client: IAMClient, + pathPrefix?: string | null, + maxItems?: number | null, + marker?: string | null +) { + const command = new ListRolesCommand({ + ...(pathPrefix ? { PathPrefix: pathPrefix } : {}), + ...(maxItems ? { MaxItems: maxItems } : {}), + ...(marker ? { Marker: marker } : {}), + }) + + const response = await client.send(command) + const roles = (response.Roles ?? []).map((role: Role) => ({ + roleName: role.RoleName ?? '', + roleId: role.RoleId ?? '', + arn: role.Arn ?? '', + path: role.Path ?? '', + createDate: role.CreateDate?.toISOString() ?? null, + description: role.Description ?? null, + maxSessionDuration: role.MaxSessionDuration ?? null, + })) + + return { + roles, + isTruncated: response.IsTruncated ?? false, + marker: response.Marker ?? null, + count: roles.length, + } +} + +export async function getRole(client: IAMClient, roleName: string) { + const command = new GetRoleCommand({ RoleName: roleName }) + const response = await client.send(command) + const role = response.Role + + let policyDocument: string | null = null + if (role?.AssumeRolePolicyDocument) { + try { + policyDocument = decodeURIComponent(role.AssumeRolePolicyDocument) + } catch { + policyDocument = role.AssumeRolePolicyDocument + } + } + + return { + roleName: role?.RoleName ?? '', + roleId: role?.RoleId ?? '', + arn: role?.Arn ?? '', + path: role?.Path ?? '', + createDate: role?.CreateDate?.toISOString() ?? null, + description: role?.Description ?? null, + maxSessionDuration: role?.MaxSessionDuration ?? null, + assumeRolePolicyDocument: policyDocument, + roleLastUsedDate: role?.RoleLastUsed?.LastUsedDate?.toISOString() ?? null, + roleLastUsedRegion: role?.RoleLastUsed?.Region ?? null, + } +} + +export async function createRole( + client: IAMClient, + roleName: string, + assumeRolePolicyDocument: string, + description?: string | null, + path?: string | null, + maxSessionDuration?: number | null +) { + const command = new CreateRoleCommand({ + RoleName: roleName, + AssumeRolePolicyDocument: assumeRolePolicyDocument, + ...(description ? { Description: description } : {}), + ...(path ? { Path: path } : {}), + ...(maxSessionDuration ? { MaxSessionDuration: maxSessionDuration } : {}), + }) + + const response = await client.send(command) + const role = response.Role + + return { + roleName: role?.RoleName ?? '', + roleId: role?.RoleId ?? '', + arn: role?.Arn ?? '', + path: role?.Path ?? '', + createDate: role?.CreateDate?.toISOString() ?? null, + } +} + +export async function deleteRole(client: IAMClient, roleName: string) { + const command = new DeleteRoleCommand({ RoleName: roleName }) + await client.send(command) +} + +export async function attachUserPolicy(client: IAMClient, userName: string, policyArn: string) { + const command = new AttachUserPolicyCommand({ + UserName: userName, + PolicyArn: policyArn, + }) + await client.send(command) +} + +export async function detachUserPolicy(client: IAMClient, userName: string, policyArn: string) { + const command = new DetachUserPolicyCommand({ + UserName: userName, + PolicyArn: policyArn, + }) + await client.send(command) +} + +export async function attachRolePolicy(client: IAMClient, roleName: string, policyArn: string) { + const command = new AttachRolePolicyCommand({ + RoleName: roleName, + PolicyArn: policyArn, + }) + await client.send(command) +} + +export async function detachRolePolicy(client: IAMClient, roleName: string, policyArn: string) { + const command = new DetachRolePolicyCommand({ + RoleName: roleName, + PolicyArn: policyArn, + }) + await client.send(command) +} + +export async function listPolicies( + client: IAMClient, + scope?: string | null, + onlyAttached?: boolean | null, + pathPrefix?: string | null, + maxItems?: number | null, + marker?: string | null +) { + const command = new ListPoliciesCommand({ + ...(scope ? { Scope: scope as PolicyScopeType } : {}), + ...(onlyAttached != null ? { OnlyAttached: onlyAttached } : {}), + ...(pathPrefix ? { PathPrefix: pathPrefix } : {}), + ...(maxItems ? { MaxItems: maxItems } : {}), + ...(marker ? { Marker: marker } : {}), + }) + + const response = await client.send(command) + const policies = (response.Policies ?? []).map((policy: Policy) => ({ + policyName: policy.PolicyName ?? '', + policyId: policy.PolicyId ?? '', + arn: policy.Arn ?? '', + path: policy.Path ?? '', + attachmentCount: policy.AttachmentCount ?? 0, + isAttachable: policy.IsAttachable ?? false, + createDate: policy.CreateDate?.toISOString() ?? null, + updateDate: policy.UpdateDate?.toISOString() ?? null, + description: policy.Description ?? null, + defaultVersionId: policy.DefaultVersionId ?? null, + permissionsBoundaryUsageCount: policy.PermissionsBoundaryUsageCount ?? 0, + })) + + return { + policies, + isTruncated: response.IsTruncated ?? false, + marker: response.Marker ?? null, + count: policies.length, + } +} + +export async function createAccessKey(client: IAMClient, userName?: string | null) { + const command = new CreateAccessKeyCommand({ + ...(userName ? { UserName: userName } : {}), + }) + + const response = await client.send(command) + const key = response.AccessKey + + return { + accessKeyId: key?.AccessKeyId ?? '', + secretAccessKey: key?.SecretAccessKey ?? '', + userName: key?.UserName ?? '', + status: key?.Status ?? '', + createDate: key?.CreateDate?.toISOString() ?? null, + } +} + +export async function deleteAccessKey( + client: IAMClient, + accessKeyIdToDelete: string, + userName?: string | null +) { + const command = new DeleteAccessKeyCommand({ + AccessKeyId: accessKeyIdToDelete, + ...(userName ? { UserName: userName } : {}), + }) + await client.send(command) +} + +export async function listGroups( + client: IAMClient, + pathPrefix?: string | null, + maxItems?: number | null, + marker?: string | null +) { + const command = new ListGroupsCommand({ + ...(pathPrefix ? { PathPrefix: pathPrefix } : {}), + ...(maxItems ? { MaxItems: maxItems } : {}), + ...(marker ? { Marker: marker } : {}), + }) + + const response = await client.send(command) + const groups = (response.Groups ?? []).map((group: Group) => ({ + groupName: group.GroupName ?? '', + groupId: group.GroupId ?? '', + arn: group.Arn ?? '', + path: group.Path ?? '', + createDate: group.CreateDate?.toISOString() ?? null, + })) + + return { + groups, + isTruncated: response.IsTruncated ?? false, + marker: response.Marker ?? null, + count: groups.length, + } +} + +export async function addUserToGroup(client: IAMClient, userName: string, groupName: string) { + const command = new AddUserToGroupCommand({ + UserName: userName, + GroupName: groupName, + }) + await client.send(command) +} + +export async function removeUserFromGroup(client: IAMClient, userName: string, groupName: string) { + const command = new RemoveUserFromGroupCommand({ + UserName: userName, + GroupName: groupName, + }) + await client.send(command) +} diff --git a/apps/sim/app/api/tools/sts/assume-role/route.ts b/apps/sim/app/api/tools/sts/assume-role/route.ts new file mode 100644 index 00000000000..d572bed3edb --- /dev/null +++ b/apps/sim/app/api/tools/sts/assume-role/route.ts @@ -0,0 +1,73 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { assumeRole, createSTSClient } from '../utils' + +const logger = createLogger('STSAssumeRoleAPI') + +const AssumeRoleSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + roleArn: z.string().min(1, 'Role ARN is required'), + roleSessionName: z.string().min(1, 'Role session name is required'), + durationSeconds: z.number().nullish(), + externalId: z.string().nullish(), + serialNumber: z.string().nullish(), + tokenCode: z.string().nullish(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = AssumeRoleSchema.parse(body) + + logger.info(`[${requestId}] Assuming role ${params.roleArn}`) + + const client = createSTSClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await assumeRole( + client, + params.roleArn, + params.roleSessionName, + params.durationSeconds, + params.externalId, + params.serialNumber, + params.tokenCode + ) + + logger.info(`[${requestId}] Role assumed successfully`) + + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to assume role:`, error) + + return NextResponse.json({ error: `Failed to assume role: ${errorMessage}` }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/sts/get-access-key-info/route.ts b/apps/sim/app/api/tools/sts/get-access-key-info/route.ts new file mode 100644 index 00000000000..2375aca7806 --- /dev/null +++ b/apps/sim/app/api/tools/sts/get-access-key-info/route.ts @@ -0,0 +1,63 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createSTSClient, getAccessKeyInfo } from '../utils' + +const logger = createLogger('STSGetAccessKeyInfoAPI') + +const GetAccessKeyInfoSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + targetAccessKeyId: z.string().min(1, 'Target access key ID is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = GetAccessKeyInfoSchema.parse(body) + + logger.info(`[${requestId}] Getting access key info for ${params.targetAccessKeyId}`) + + const client = createSTSClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getAccessKeyInfo(client, params.targetAccessKeyId) + + logger.info(`[${requestId}] Access key info retrieved successfully`) + + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to get access key info:`, error) + + return NextResponse.json( + { error: `Failed to get access key info: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/sts/get-caller-identity/route.ts b/apps/sim/app/api/tools/sts/get-caller-identity/route.ts new file mode 100644 index 00000000000..1cb5d263c06 --- /dev/null +++ b/apps/sim/app/api/tools/sts/get-caller-identity/route.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createSTSClient, getCallerIdentity } from '../utils' + +const logger = createLogger('STSGetCallerIdentityAPI') + +const GetCallerIdentitySchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = GetCallerIdentitySchema.parse(body) + + logger.info(`[${requestId}] Getting caller identity`) + + const client = createSTSClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getCallerIdentity(client) + + logger.info(`[${requestId}] Caller identity retrieved successfully`) + + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to get caller identity:`, error) + + return NextResponse.json( + { error: `Failed to get caller identity: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/sts/get-session-token/route.ts b/apps/sim/app/api/tools/sts/get-session-token/route.ts new file mode 100644 index 00000000000..098f154e340 --- /dev/null +++ b/apps/sim/app/api/tools/sts/get-session-token/route.ts @@ -0,0 +1,70 @@ +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateId } from '@/lib/core/utils/uuid' +import { createSTSClient, getSessionToken } from '../utils' + +const logger = createLogger('STSGetSessionTokenAPI') + +const GetSessionTokenSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + durationSeconds: z.number().nullish(), + serialNumber: z.string().nullish(), + tokenCode: z.string().nullish(), +}) + +export async function POST(request: NextRequest) { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const body = await request.json() + const params = GetSessionTokenSchema.parse(body) + + logger.info(`[${requestId}] Getting session token`) + + const client = createSTSClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getSessionToken( + client, + params.durationSeconds, + params.serialNumber, + params.tokenCode + ) + + logger.info(`[${requestId}] Session token retrieved successfully`) + + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { errors: error.errors }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] Failed to get session token:`, error) + + return NextResponse.json( + { error: `Failed to get session token: ${errorMessage}` }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/sts/utils.ts b/apps/sim/app/api/tools/sts/utils.ts new file mode 100644 index 00000000000..f674b7939ab --- /dev/null +++ b/apps/sim/app/api/tools/sts/utils.ts @@ -0,0 +1,94 @@ +import { + AssumeRoleCommand, + GetAccessKeyInfoCommand, + GetCallerIdentityCommand, + GetSessionTokenCommand, + STSClient, +} from '@aws-sdk/client-sts' +import type { STSConnectionConfig } from '@/tools/sts/types' + +export function createSTSClient(config: STSConnectionConfig): STSClient { + return new STSClient({ + region: config.region, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey, + }, + }) +} + +export async function assumeRole( + client: STSClient, + roleArn: string, + roleSessionName: string, + durationSeconds?: number | null, + externalId?: string | null, + serialNumber?: string | null, + tokenCode?: string | null +) { + const command = new AssumeRoleCommand({ + RoleArn: roleArn, + RoleSessionName: roleSessionName, + ...(durationSeconds ? { DurationSeconds: durationSeconds } : {}), + ...(externalId ? { ExternalId: externalId } : {}), + ...(serialNumber ? { SerialNumber: serialNumber } : {}), + ...(tokenCode ? { TokenCode: tokenCode } : {}), + }) + + const response = await client.send(command) + + return { + accessKeyId: response.Credentials?.AccessKeyId ?? '', + secretAccessKey: response.Credentials?.SecretAccessKey ?? '', + sessionToken: response.Credentials?.SessionToken ?? '', + expiration: response.Credentials?.Expiration?.toISOString() ?? null, + assumedRoleArn: response.AssumedRoleUser?.Arn ?? '', + assumedRoleId: response.AssumedRoleUser?.AssumedRoleId ?? '', + packedPolicySize: response.PackedPolicySize ?? null, + } +} + +export async function getCallerIdentity(client: STSClient) { + const command = new GetCallerIdentityCommand({}) + const response = await client.send(command) + + return { + account: response.Account ?? '', + arn: response.Arn ?? '', + userId: response.UserId ?? '', + } +} + +export async function getSessionToken( + client: STSClient, + durationSeconds?: number | null, + serialNumber?: string | null, + tokenCode?: string | null +) { + const command = new GetSessionTokenCommand({ + ...(durationSeconds ? { DurationSeconds: durationSeconds } : {}), + ...(serialNumber ? { SerialNumber: serialNumber } : {}), + ...(tokenCode ? { TokenCode: tokenCode } : {}), + }) + + const response = await client.send(command) + + return { + accessKeyId: response.Credentials?.AccessKeyId ?? '', + secretAccessKey: response.Credentials?.SecretAccessKey ?? '', + sessionToken: response.Credentials?.SessionToken ?? '', + expiration: response.Credentials?.Expiration?.toISOString() ?? null, + } +} + +export async function getAccessKeyInfo(client: STSClient, accessKeyId: string) { + const command = new GetAccessKeyInfoCommand({ + AccessKeyId: accessKeyId, + }) + + const response = await client.send(command) + + return { + account: response.Account ?? '', + } +} diff --git a/apps/sim/blocks/blocks/iam.ts b/apps/sim/blocks/blocks/iam.ts new file mode 100644 index 00000000000..51e682108ef --- /dev/null +++ b/apps/sim/blocks/blocks/iam.ts @@ -0,0 +1,553 @@ +import { IAMIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' +import type { IAMBaseResponse } from '@/tools/iam/types' + +export const IAMBlock: BlockConfig = { + type: 'iam', + name: 'AWS IAM', + description: 'Manage AWS IAM users, roles, policies, and groups', + longDescription: + 'Integrate AWS Identity and Access Management into your workflow. Create and manage users, roles, policies, groups, and access keys.', + docsLink: 'https://docs.sim.ai/tools/iam', + category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['cloud', 'identity'], + bgColor: 'linear-gradient(45deg, #BD0816 0%, #FF5252 100%)', + icon: IAMIcon, + authMode: AuthMode.ApiKey, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'List Users', id: 'list_users' }, + { label: 'Get User', id: 'get_user' }, + { label: 'Create User', id: 'create_user' }, + { label: 'Delete User', id: 'delete_user' }, + { label: 'List Roles', id: 'list_roles' }, + { label: 'Get Role', id: 'get_role' }, + { label: 'Create Role', id: 'create_role' }, + { label: 'Delete Role', id: 'delete_role' }, + { label: 'Attach User Policy', id: 'attach_user_policy' }, + { label: 'Detach User Policy', id: 'detach_user_policy' }, + { label: 'Attach Role Policy', id: 'attach_role_policy' }, + { label: 'Detach Role Policy', id: 'detach_role_policy' }, + { label: 'List Policies', id: 'list_policies' }, + { label: 'Create Access Key', id: 'create_access_key' }, + { label: 'Delete Access Key', id: 'delete_access_key' }, + { label: 'List Groups', id: 'list_groups' }, + { label: 'Add User to Group', id: 'add_user_to_group' }, + { label: 'Remove User from Group', id: 'remove_user_from_group' }, + ], + value: () => 'list_users', + }, + { + id: 'region', + title: 'AWS Region', + type: 'short-input', + placeholder: 'us-east-1', + required: true, + }, + { + id: 'accessKeyId', + title: 'AWS Access Key ID', + type: 'short-input', + placeholder: 'AKIA...', + password: true, + required: true, + }, + { + id: 'secretAccessKey', + title: 'AWS Secret Access Key', + type: 'short-input', + placeholder: 'Your secret access key', + password: true, + required: true, + }, + { + id: 'userName', + title: 'User Name', + type: 'short-input', + placeholder: 'my-iam-user', + condition: { + field: 'operation', + value: [ + 'get_user', + 'create_user', + 'delete_user', + 'attach_user_policy', + 'detach_user_policy', + 'create_access_key', + 'delete_access_key', + 'add_user_to_group', + 'remove_user_from_group', + ], + }, + required: { + field: 'operation', + value: [ + 'get_user', + 'create_user', + 'delete_user', + 'attach_user_policy', + 'detach_user_policy', + 'add_user_to_group', + 'remove_user_from_group', + ], + }, + }, + { + id: 'roleName', + title: 'Role Name', + type: 'short-input', + placeholder: 'my-iam-role', + condition: { + field: 'operation', + value: [ + 'get_role', + 'create_role', + 'delete_role', + 'attach_role_policy', + 'detach_role_policy', + ], + }, + required: { + field: 'operation', + value: [ + 'get_role', + 'create_role', + 'delete_role', + 'attach_role_policy', + 'detach_role_policy', + ], + }, + }, + { + id: 'policyArn', + title: 'Policy ARN', + type: 'short-input', + placeholder: 'arn:aws:iam::aws:policy/ReadOnlyAccess', + condition: { + field: 'operation', + value: [ + 'attach_user_policy', + 'detach_user_policy', + 'attach_role_policy', + 'detach_role_policy', + ], + }, + required: { + field: 'operation', + value: [ + 'attach_user_policy', + 'detach_user_policy', + 'attach_role_policy', + 'detach_role_policy', + ], + }, + }, + { + id: 'assumeRolePolicyDocument', + title: 'Trust Policy (JSON)', + type: 'code', + placeholder: + '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}', + condition: { field: 'operation', value: 'create_role' }, + required: { field: 'operation', value: 'create_role' }, + wandConfig: { + enabled: true, + prompt: + 'Generate an AWS IAM trust policy JSON document. The policy should use Version "2012-10-17" and contain a Statement array with Effect, Principal, and Action fields. Return ONLY the JSON - no explanations, no extra text.', + generationType: 'json-object', + }, + }, + { + id: 'groupName', + title: 'Group Name', + type: 'short-input', + placeholder: 'my-iam-group', + condition: { + field: 'operation', + value: ['add_user_to_group', 'remove_user_from_group'], + }, + required: { + field: 'operation', + value: ['add_user_to_group', 'remove_user_from_group'], + }, + }, + { + id: 'accessKeyIdToDelete', + title: 'Access Key ID to Delete', + type: 'short-input', + placeholder: 'AKIA...', + condition: { field: 'operation', value: 'delete_access_key' }, + required: { field: 'operation', value: 'delete_access_key' }, + }, + { + id: 'path', + title: 'Path', + type: 'short-input', + placeholder: '/division_abc/', + condition: { field: 'operation', value: ['create_user', 'create_role'] }, + required: false, + mode: 'advanced', + }, + { + id: 'description', + title: 'Description', + type: 'short-input', + placeholder: 'Role description', + condition: { field: 'operation', value: 'create_role' }, + required: false, + mode: 'advanced', + }, + { + id: 'maxSessionDuration', + title: 'Max Session Duration (seconds)', + type: 'short-input', + placeholder: '3600', + condition: { field: 'operation', value: 'create_role' }, + required: false, + mode: 'advanced', + }, + { + id: 'scope', + title: 'Policy Scope', + type: 'dropdown', + options: [ + { label: 'All', id: 'All' }, + { label: 'AWS Managed', id: 'AWS' }, + { label: 'Customer Managed', id: 'Local' }, + ], + value: () => 'All', + condition: { field: 'operation', value: 'list_policies' }, + required: false, + mode: 'advanced', + }, + { + id: 'onlyAttached', + title: 'Only Attached', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], + value: () => 'false', + condition: { field: 'operation', value: 'list_policies' }, + required: false, + mode: 'advanced', + }, + { + id: 'pathPrefix', + title: 'Path Prefix', + type: 'short-input', + placeholder: '/division_abc/', + condition: { + field: 'operation', + value: ['list_users', 'list_roles', 'list_policies', 'list_groups'], + }, + required: false, + mode: 'advanced', + }, + { + id: 'maxItems', + title: 'Max Items', + type: 'short-input', + placeholder: '100', + condition: { + field: 'operation', + value: ['list_users', 'list_roles', 'list_policies', 'list_groups'], + }, + required: false, + mode: 'advanced', + }, + { + id: 'marker', + title: 'Pagination Marker', + type: 'short-input', + placeholder: 'Pagination marker', + condition: { + field: 'operation', + value: ['list_users', 'list_roles', 'list_policies', 'list_groups'], + }, + required: false, + mode: 'advanced', + }, + ], + tools: { + access: [ + 'iam_list_users', + 'iam_get_user', + 'iam_create_user', + 'iam_delete_user', + 'iam_list_roles', + 'iam_get_role', + 'iam_create_role', + 'iam_delete_role', + 'iam_attach_user_policy', + 'iam_detach_user_policy', + 'iam_attach_role_policy', + 'iam_detach_role_policy', + 'iam_list_policies', + 'iam_create_access_key', + 'iam_delete_access_key', + 'iam_list_groups', + 'iam_add_user_to_group', + 'iam_remove_user_from_group', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'list_users': + return 'iam_list_users' + case 'get_user': + return 'iam_get_user' + case 'create_user': + return 'iam_create_user' + case 'delete_user': + return 'iam_delete_user' + case 'list_roles': + return 'iam_list_roles' + case 'get_role': + return 'iam_get_role' + case 'create_role': + return 'iam_create_role' + case 'delete_role': + return 'iam_delete_role' + case 'attach_user_policy': + return 'iam_attach_user_policy' + case 'detach_user_policy': + return 'iam_detach_user_policy' + case 'attach_role_policy': + return 'iam_attach_role_policy' + case 'detach_role_policy': + return 'iam_detach_role_policy' + case 'list_policies': + return 'iam_list_policies' + case 'create_access_key': + return 'iam_create_access_key' + case 'delete_access_key': + return 'iam_delete_access_key' + case 'list_groups': + return 'iam_list_groups' + case 'add_user_to_group': + return 'iam_add_user_to_group' + case 'remove_user_from_group': + return 'iam_remove_user_from_group' + default: + throw new Error(`Invalid IAM operation: ${params.operation}`) + } + }, + params: (params) => { + const { operation, maxItems, maxSessionDuration, onlyAttached, ...rest } = params + + const connectionConfig = { + region: rest.region, + accessKeyId: rest.accessKeyId, + secretAccessKey: rest.secretAccessKey, + } + + const result: Record = { ...connectionConfig } + + switch (operation) { + case 'list_users': + case 'list_roles': + case 'list_groups': + if (rest.pathPrefix) result.pathPrefix = rest.pathPrefix + if (maxItems) { + const parsed = Number.parseInt(String(maxItems), 10) + if (!Number.isNaN(parsed)) result.maxItems = parsed + } + if (rest.marker) result.marker = rest.marker + break + case 'get_user': + case 'delete_user': + result.userName = rest.userName + break + case 'create_user': + result.userName = rest.userName + if (rest.path) result.path = rest.path + break + case 'get_role': + case 'delete_role': + result.roleName = rest.roleName + break + case 'create_role': + result.roleName = rest.roleName + result.assumeRolePolicyDocument = rest.assumeRolePolicyDocument + if (rest.description) result.description = rest.description + if (rest.path) result.path = rest.path + if (maxSessionDuration) { + const parsed = Number.parseInt(String(maxSessionDuration), 10) + if (!Number.isNaN(parsed)) result.maxSessionDuration = parsed + } + break + case 'attach_user_policy': + case 'detach_user_policy': + result.userName = rest.userName + result.policyArn = rest.policyArn + break + case 'attach_role_policy': + case 'detach_role_policy': + result.roleName = rest.roleName + result.policyArn = rest.policyArn + break + case 'list_policies': + if (rest.scope) result.scope = rest.scope + if (onlyAttached === 'true' || onlyAttached === true) result.onlyAttached = true + if (rest.pathPrefix) result.pathPrefix = rest.pathPrefix + if (maxItems) { + const parsed = Number.parseInt(String(maxItems), 10) + if (!Number.isNaN(parsed)) result.maxItems = parsed + } + if (rest.marker) result.marker = rest.marker + break + case 'create_access_key': + if (rest.userName) result.userName = rest.userName + break + case 'delete_access_key': + result.accessKeyIdToDelete = rest.accessKeyIdToDelete + if (rest.userName) result.userName = rest.userName + break + case 'add_user_to_group': + case 'remove_user_from_group': + result.userName = rest.userName + result.groupName = rest.groupName + break + } + + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'IAM operation to perform' }, + region: { type: 'string', description: 'AWS region' }, + accessKeyId: { type: 'string', description: 'AWS access key ID' }, + secretAccessKey: { type: 'string', description: 'AWS secret access key' }, + userName: { type: 'string', description: 'IAM user name' }, + roleName: { type: 'string', description: 'IAM role name' }, + policyArn: { type: 'string', description: 'Policy ARN' }, + assumeRolePolicyDocument: { type: 'string', description: 'Trust policy JSON' }, + groupName: { type: 'string', description: 'IAM group name' }, + accessKeyIdToDelete: { type: 'string', description: 'Access key ID to delete' }, + path: { type: 'string', description: 'Resource path' }, + description: { type: 'string', description: 'Role description' }, + maxSessionDuration: { type: 'number', description: 'Max session duration in seconds' }, + scope: { type: 'string', description: 'Policy scope filter (All, AWS, Local)' }, + onlyAttached: { type: 'string', description: 'Only return attached policies' }, + pathPrefix: { type: 'string', description: 'Path prefix filter' }, + maxItems: { type: 'number', description: 'Maximum number of items to return' }, + marker: { type: 'string', description: 'Pagination marker' }, + }, + outputs: { + message: { + type: 'string', + description: 'Operation status message', + }, + users: { + type: 'json', + description: 'List of IAM users (userName, userId, arn, path, createDate, passwordLastUsed)', + }, + roles: { + type: 'json', + description: + 'List of IAM roles (roleName, roleId, arn, path, createDate, description, maxSessionDuration)', + }, + policies: { + type: 'json', + description: + 'List of IAM policies (policyName, policyId, arn, path, attachmentCount, isAttachable, createDate, updateDate)', + }, + groups: { + type: 'json', + description: 'List of IAM groups (groupName, groupId, arn, path, createDate)', + }, + userName: { + type: 'string', + description: 'User name', + }, + userId: { + type: 'string', + description: 'User ID', + }, + roleName: { + type: 'string', + description: 'Role name', + }, + roleId: { + type: 'string', + description: 'Role ID', + }, + arn: { + type: 'string', + description: 'Resource ARN', + }, + path: { + type: 'string', + description: 'Resource path', + }, + createDate: { + type: 'string', + description: 'Creation date', + }, + passwordLastUsed: { + type: 'string', + description: 'Date password was last used', + }, + permissionsBoundaryArn: { + type: 'string', + description: 'ARN of the permissions boundary policy', + }, + tags: { + type: 'json', + description: 'Tags attached to the resource (key, value pairs)', + }, + description: { + type: 'string', + description: 'Role description', + }, + maxSessionDuration: { + type: 'number', + description: 'Maximum session duration in seconds', + }, + assumeRolePolicyDocument: { + type: 'string', + description: 'Trust policy document (JSON)', + }, + roleLastUsedDate: { + type: 'string', + description: 'Date the role was last used', + }, + roleLastUsedRegion: { + type: 'string', + description: 'AWS region where the role was last used', + }, + accessKeyId: { + type: 'string', + description: 'Access key ID', + }, + secretAccessKey: { + type: 'string', + description: 'Secret access key (only shown once)', + }, + status: { + type: 'string', + description: 'Access key status', + }, + isTruncated: { + type: 'boolean', + description: 'Whether there are more results', + }, + marker: { + type: 'string', + description: 'Pagination marker', + }, + count: { + type: 'number', + description: 'Number of items returned', + }, + }, +} diff --git a/apps/sim/blocks/blocks/sts.ts b/apps/sim/blocks/blocks/sts.ts new file mode 100644 index 00000000000..29497ea7fe7 --- /dev/null +++ b/apps/sim/blocks/blocks/sts.ts @@ -0,0 +1,235 @@ +import { IAMIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' +import type { STSBaseResponse } from '@/tools/sts/types' + +export const STSBlock: BlockConfig = { + type: 'sts', + name: 'AWS STS', + description: 'Connect to AWS Security Token Service', + longDescription: + 'Integrate AWS STS into the workflow. Assume roles, get temporary credentials, verify caller identity, and look up access key information.', + docsLink: 'https://docs.sim.ai/tools/sts', + category: 'tools', + integrationType: IntegrationType.Security, + tags: ['cloud'], + authMode: AuthMode.ApiKey, + bgColor: 'linear-gradient(45deg, #BD0816 0%, #FF5252 100%)', + icon: IAMIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Assume Role', id: 'assume_role' }, + { label: 'Get Caller Identity', id: 'get_caller_identity' }, + { label: 'Get Session Token', id: 'get_session_token' }, + { label: 'Get Access Key Info', id: 'get_access_key_info' }, + ], + value: () => 'assume_role', + }, + { + id: 'region', + title: 'AWS Region', + type: 'short-input', + placeholder: 'us-east-1', + required: true, + }, + { + id: 'accessKeyId', + title: 'AWS Access Key ID', + type: 'short-input', + placeholder: 'AKIA...', + password: true, + required: true, + }, + { + id: 'secretAccessKey', + title: 'AWS Secret Access Key', + type: 'short-input', + placeholder: 'Your secret access key', + password: true, + required: true, + }, + { + id: 'roleArn', + title: 'Role ARN', + type: 'short-input', + placeholder: 'arn:aws:iam::123456789012:role/MyRole', + condition: { field: 'operation', value: 'assume_role' }, + required: { field: 'operation', value: 'assume_role' }, + }, + { + id: 'roleSessionName', + title: 'Session Name', + type: 'short-input', + placeholder: 'my-session', + condition: { field: 'operation', value: 'assume_role' }, + required: { field: 'operation', value: 'assume_role' }, + }, + { + id: 'durationSeconds', + title: 'Duration (Seconds)', + type: 'short-input', + placeholder: '3600', + condition: { field: 'operation', value: ['assume_role', 'get_session_token'] }, + required: false, + mode: 'advanced', + }, + { + id: 'externalId', + title: 'External ID', + type: 'short-input', + placeholder: 'External ID for cross-account access', + condition: { field: 'operation', value: 'assume_role' }, + required: false, + mode: 'advanced', + }, + { + id: 'serialNumber', + title: 'MFA Serial Number', + type: 'short-input', + placeholder: 'arn:aws:iam::123456789012:mfa/user', + condition: { field: 'operation', value: ['assume_role', 'get_session_token'] }, + required: false, + mode: 'advanced', + }, + { + id: 'tokenCode', + title: 'MFA Token Code', + type: 'short-input', + placeholder: '123456', + condition: { field: 'operation', value: ['assume_role', 'get_session_token'] }, + required: false, + mode: 'advanced', + }, + { + id: 'targetAccessKeyId', + title: 'Target Access Key ID', + type: 'short-input', + placeholder: 'AKIA...', + condition: { field: 'operation', value: 'get_access_key_info' }, + required: { field: 'operation', value: 'get_access_key_info' }, + }, + ], + tools: { + access: [ + 'sts_assume_role', + 'sts_get_caller_identity', + 'sts_get_session_token', + 'sts_get_access_key_info', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'assume_role': + return 'sts_assume_role' + case 'get_caller_identity': + return 'sts_get_caller_identity' + case 'get_session_token': + return 'sts_get_session_token' + case 'get_access_key_info': + return 'sts_get_access_key_info' + default: + throw new Error(`Invalid STS operation: ${params.operation}`) + } + }, + params: (params) => { + const { operation, durationSeconds, ...rest } = params + + const connectionConfig = { + region: rest.region, + accessKeyId: rest.accessKeyId, + secretAccessKey: rest.secretAccessKey, + } + + const result: Record = { ...connectionConfig } + + switch (operation) { + case 'assume_role': + result.roleArn = rest.roleArn + result.roleSessionName = rest.roleSessionName + if (durationSeconds) { + const parsed = Number.parseInt(String(durationSeconds), 10) + if (!Number.isNaN(parsed)) result.durationSeconds = parsed + } + if (rest.externalId) result.externalId = rest.externalId + if (rest.serialNumber) result.serialNumber = rest.serialNumber + if (rest.tokenCode) result.tokenCode = rest.tokenCode + break + case 'get_caller_identity': + break + case 'get_session_token': + if (durationSeconds) { + const parsed = Number.parseInt(String(durationSeconds), 10) + if (!Number.isNaN(parsed)) result.durationSeconds = parsed + } + if (rest.serialNumber) result.serialNumber = rest.serialNumber + if (rest.tokenCode) result.tokenCode = rest.tokenCode + break + case 'get_access_key_info': + result.targetAccessKeyId = rest.targetAccessKeyId + break + } + + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'STS operation to perform' }, + region: { type: 'string', description: 'AWS region' }, + accessKeyId: { type: 'string', description: 'AWS access key ID' }, + secretAccessKey: { type: 'string', description: 'AWS secret access key' }, + roleArn: { type: 'string', description: 'ARN of the role to assume' }, + roleSessionName: { type: 'string', description: 'Session name for the assumed role' }, + durationSeconds: { type: 'number', description: 'Session duration in seconds' }, + externalId: { type: 'string', description: 'External ID for cross-account access' }, + serialNumber: { type: 'string', description: 'MFA device serial number' }, + tokenCode: { type: 'string', description: 'MFA token code' }, + targetAccessKeyId: { type: 'string', description: 'Access key ID to look up' }, + }, + outputs: { + accessKeyId: { + type: 'string', + description: 'Temporary access key ID', + }, + secretAccessKey: { + type: 'string', + description: 'Temporary secret access key', + }, + sessionToken: { + type: 'string', + description: 'Temporary session token', + }, + expiration: { + type: 'string', + description: 'Credential expiration timestamp', + }, + assumedRoleArn: { + type: 'string', + description: 'ARN of the assumed role', + }, + assumedRoleId: { + type: 'string', + description: 'Assumed role ID with session name', + }, + account: { + type: 'string', + description: 'AWS account ID', + }, + arn: { + type: 'string', + description: 'ARN of the calling entity', + }, + userId: { + type: 'string', + description: 'Unique identifier of the calling entity', + }, + packedPolicySize: { + type: 'number', + description: 'Percentage of allowed policy size used', + }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index db351f7b24c..4ab0d88a16b 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -91,6 +91,7 @@ import { HubSpotBlock } from '@/blocks/blocks/hubspot' import { HuggingFaceBlock } from '@/blocks/blocks/huggingface' import { HumanInTheLoopBlock } from '@/blocks/blocks/human_in_the_loop' import { HunterBlock } from '@/blocks/blocks/hunter' +import { IAMBlock } from '@/blocks/blocks/iam' import { ImageGeneratorBlock } from '@/blocks/blocks/image_generator' import { ImapBlock } from '@/blocks/blocks/imap' import { IncidentioBlock } from '@/blocks/blocks/incidentio' @@ -185,6 +186,7 @@ import { StagehandBlock } from '@/blocks/blocks/stagehand' import { StartTriggerBlock } from '@/blocks/blocks/start_trigger' import { StarterBlock } from '@/blocks/blocks/starter' import { StripeBlock } from '@/blocks/blocks/stripe' +import { STSBlock } from '@/blocks/blocks/sts' import { SttBlock, SttV2Block } from '@/blocks/blocks/stt' import { SupabaseBlock } from '@/blocks/blocks/supabase' import { TableBlock } from '@/blocks/blocks/table' @@ -328,6 +330,7 @@ export const registry: Record = { huggingface: HuggingFaceBlock, human_in_the_loop: HumanInTheLoopBlock, hunter: HunterBlock, + iam: IAMBlock, image_generator: ImageGeneratorBlock, imap: ImapBlock, incidentio: IncidentioBlock, @@ -424,6 +427,7 @@ export const registry: Record = { secrets_manager: SecretsManagerBlock, sqs: SQSBlock, ssh: SSHBlock, + sts: STSBlock, stagehand: StagehandBlock, start_trigger: StartTriggerBlock, starter: StarterBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index aab80fe0cbe..7508d0827cf 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4625,6 +4625,24 @@ export function DynamoDBIcon(props: SVGProps) { ) } +export function IAMIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} + export function SecretsManagerIcon(props: SVGProps) { return ( diff --git a/apps/sim/package.json b/apps/sim/package.json index 0a8150656fe..20302951608 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -41,10 +41,12 @@ "@aws-sdk/client-cloudwatch": "3.940.0", "@aws-sdk/client-cloudwatch-logs": "3.940.0", "@aws-sdk/client-dynamodb": "3.940.0", + "@aws-sdk/client-iam": "3.1029.0", "@aws-sdk/client-rds-data": "3.940.0", "@aws-sdk/client-s3": "^3.779.0", "@aws-sdk/client-secrets-manager": "3.940.0", "@aws-sdk/client-sqs": "3.947.0", + "@aws-sdk/client-sts": "3.1029.0", "@aws-sdk/lib-dynamodb": "3.940.0", "@aws-sdk/s3-request-presigner": "^3.779.0", "@azure/communication-email": "1.0.0", diff --git a/apps/sim/tools/iam/add_user_to_group.ts b/apps/sim/tools/iam/add_user_to_group.ts new file mode 100644 index 00000000000..b1b32ed316f --- /dev/null +++ b/apps/sim/tools/iam/add_user_to_group.ts @@ -0,0 +1,74 @@ +import type { IAMAddUserToGroupParams, IAMGroupMembershipResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const addUserToGroupTool: ToolConfig = { + id: 'iam_add_user_to_group', + name: 'IAM Add User to Group', + description: 'Add an IAM user to a group', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM user', + }, + groupName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM group', + }, + }, + + request: { + url: '/api/tools/iam/add-user-to-group', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + groupName: params.groupName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to add user to group') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, +} diff --git a/apps/sim/tools/iam/attach_role_policy.ts b/apps/sim/tools/iam/attach_role_policy.ts new file mode 100644 index 00000000000..c5f7717b360 --- /dev/null +++ b/apps/sim/tools/iam/attach_role_policy.ts @@ -0,0 +1,75 @@ +import type { IAMAttachPolicyResponse, IAMAttachRolePolicyParams } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const attachRolePolicyTool: ToolConfig = + { + id: 'iam_attach_role_policy', + name: 'IAM Attach Role Policy', + description: 'Attach a managed policy to an IAM role', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + roleName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM role', + }, + policyArn: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ARN of the managed policy to attach', + }, + }, + + request: { + url: '/api/tools/iam/attach-role-policy', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + roleName: params.roleName, + policyArn: params.policyArn, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to attach policy to role') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, + } diff --git a/apps/sim/tools/iam/attach_user_policy.ts b/apps/sim/tools/iam/attach_user_policy.ts new file mode 100644 index 00000000000..c0e7b1903c9 --- /dev/null +++ b/apps/sim/tools/iam/attach_user_policy.ts @@ -0,0 +1,75 @@ +import type { IAMAttachPolicyResponse, IAMAttachUserPolicyParams } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const attachUserPolicyTool: ToolConfig = + { + id: 'iam_attach_user_policy', + name: 'IAM Attach User Policy', + description: 'Attach a managed policy to an IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM user', + }, + policyArn: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ARN of the managed policy to attach', + }, + }, + + request: { + url: '/api/tools/iam/attach-user-policy', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + policyArn: params.policyArn, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to attach policy to user') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, + } diff --git a/apps/sim/tools/iam/create_access_key.ts b/apps/sim/tools/iam/create_access_key.ts new file mode 100644 index 00000000000..f41115b00c5 --- /dev/null +++ b/apps/sim/tools/iam/create_access_key.ts @@ -0,0 +1,81 @@ +import type { IAMCreateAccessKeyParams, IAMCreateAccessKeyResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const createAccessKeyTool: ToolConfig = + { + id: 'iam_create_access_key', + name: 'IAM Create Access Key', + description: 'Create a new access key pair for an IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'The IAM user to create the key for (defaults to current user)', + }, + }, + + request: { + url: '/api/tools/iam/create-access-key', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create access key') + } + + return { + success: true, + output: { + message: data.message ?? '', + accessKeyId: data.accessKeyId ?? '', + secretAccessKey: data.secretAccessKey ?? '', + userName: data.userName ?? '', + status: data.status ?? '', + createDate: data.createDate ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + accessKeyId: { type: 'string', description: 'The new access key ID' }, + secretAccessKey: { + type: 'string', + description: 'The new secret access key (only shown once)', + }, + userName: { type: 'string', description: 'The user the key was created for' }, + status: { type: 'string', description: 'Status of the access key (Active)' }, + createDate: { type: 'string', description: 'Date the key was created', optional: true }, + }, + } diff --git a/apps/sim/tools/iam/create_role.ts b/apps/sim/tools/iam/create_role.ts new file mode 100644 index 00000000000..ff68ae73946 --- /dev/null +++ b/apps/sim/tools/iam/create_role.ts @@ -0,0 +1,105 @@ +import type { IAMCreateRoleParams, IAMCreateRoleResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const createRoleTool: ToolConfig = { + id: 'iam_create_role', + name: 'IAM Create Role', + description: 'Create a new IAM role with a trust policy', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + roleName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name for the new IAM role (1-64 characters)', + }, + assumeRolePolicyDocument: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Trust policy JSON specifying who can assume this role', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the role', + }, + path: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Path for the role (e.g., /application/), defaults to /', + }, + maxSessionDuration: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum session duration in seconds (3600-43200, default 3600)', + }, + }, + + request: { + url: '/api/tools/iam/create-role', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + roleName: params.roleName, + assumeRolePolicyDocument: params.assumeRolePolicyDocument, + description: params.description, + path: params.path, + maxSessionDuration: params.maxSessionDuration, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create IAM role') + } + + return { + success: true, + output: { + message: data.message ?? '', + roleName: data.roleName ?? '', + roleId: data.roleId ?? '', + arn: data.arn ?? '', + path: data.path ?? '', + createDate: data.createDate ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + roleName: { type: 'string', description: 'The name of the created role' }, + roleId: { type: 'string', description: 'The unique ID of the created role' }, + arn: { type: 'string', description: 'The ARN of the created role' }, + path: { type: 'string', description: 'The path of the created role' }, + createDate: { type: 'string', description: 'Date the role was created', optional: true }, + }, +} diff --git a/apps/sim/tools/iam/create_user.ts b/apps/sim/tools/iam/create_user.ts new file mode 100644 index 00000000000..4db9d8cbe84 --- /dev/null +++ b/apps/sim/tools/iam/create_user.ts @@ -0,0 +1,84 @@ +import type { IAMCreateUserParams, IAMCreateUserResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const createUserTool: ToolConfig = { + id: 'iam_create_user', + name: 'IAM Create User', + description: 'Create a new IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name for the new IAM user (1-64 characters)', + }, + path: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Path for the user (e.g., /division_abc/), defaults to /', + }, + }, + + request: { + url: '/api/tools/iam/create-user', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + path: params.path, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create IAM user') + } + + return { + success: true, + output: { + message: data.message ?? '', + userName: data.userName ?? '', + userId: data.userId ?? '', + arn: data.arn ?? '', + path: data.path ?? '', + createDate: data.createDate ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + userName: { type: 'string', description: 'The name of the created user' }, + userId: { type: 'string', description: 'The unique ID of the created user' }, + arn: { type: 'string', description: 'The ARN of the created user' }, + path: { type: 'string', description: 'The path of the created user' }, + createDate: { type: 'string', description: 'Date the user was created', optional: true }, + }, +} diff --git a/apps/sim/tools/iam/delete_access_key.ts b/apps/sim/tools/iam/delete_access_key.ts new file mode 100644 index 00000000000..07104e0c337 --- /dev/null +++ b/apps/sim/tools/iam/delete_access_key.ts @@ -0,0 +1,75 @@ +import type { IAMDeleteAccessKeyParams, IAMDeleteAccessKeyResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteAccessKeyTool: ToolConfig = + { + id: 'iam_delete_access_key', + name: 'IAM Delete Access Key', + description: 'Delete an access key pair for an IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + accessKeyIdToDelete: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The access key ID to delete', + }, + userName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'The IAM user whose key to delete (defaults to current user)', + }, + }, + + request: { + url: '/api/tools/iam/delete-access-key', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + accessKeyIdToDelete: params.accessKeyIdToDelete, + userName: params.userName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete access key') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, + } diff --git a/apps/sim/tools/iam/delete_role.ts b/apps/sim/tools/iam/delete_role.ts new file mode 100644 index 00000000000..e0b8656adba --- /dev/null +++ b/apps/sim/tools/iam/delete_role.ts @@ -0,0 +1,67 @@ +import type { IAMDeleteRoleParams, IAMDeleteRoleResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteRoleTool: ToolConfig = { + id: 'iam_delete_role', + name: 'IAM Delete Role', + description: 'Delete an IAM role', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + roleName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM role to delete', + }, + }, + + request: { + url: '/api/tools/iam/delete-role', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + roleName: params.roleName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete IAM role') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, +} diff --git a/apps/sim/tools/iam/delete_user.ts b/apps/sim/tools/iam/delete_user.ts new file mode 100644 index 00000000000..39e06dfeab0 --- /dev/null +++ b/apps/sim/tools/iam/delete_user.ts @@ -0,0 +1,67 @@ +import type { IAMDeleteUserParams, IAMDeleteUserResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteUserTool: ToolConfig = { + id: 'iam_delete_user', + name: 'IAM Delete User', + description: 'Delete an IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM user to delete', + }, + }, + + request: { + url: '/api/tools/iam/delete-user', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete IAM user') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, +} diff --git a/apps/sim/tools/iam/detach_role_policy.ts b/apps/sim/tools/iam/detach_role_policy.ts new file mode 100644 index 00000000000..9e7849aabed --- /dev/null +++ b/apps/sim/tools/iam/detach_role_policy.ts @@ -0,0 +1,75 @@ +import type { IAMDetachPolicyResponse, IAMDetachRolePolicyParams } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const detachRolePolicyTool: ToolConfig = + { + id: 'iam_detach_role_policy', + name: 'IAM Detach Role Policy', + description: 'Remove a managed policy from an IAM role', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + roleName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM role', + }, + policyArn: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ARN of the managed policy to detach', + }, + }, + + request: { + url: '/api/tools/iam/detach-role-policy', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + roleName: params.roleName, + policyArn: params.policyArn, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to detach policy from role') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, + } diff --git a/apps/sim/tools/iam/detach_user_policy.ts b/apps/sim/tools/iam/detach_user_policy.ts new file mode 100644 index 00000000000..8b1f6f855d9 --- /dev/null +++ b/apps/sim/tools/iam/detach_user_policy.ts @@ -0,0 +1,75 @@ +import type { IAMDetachPolicyResponse, IAMDetachUserPolicyParams } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const detachUserPolicyTool: ToolConfig = + { + id: 'iam_detach_user_policy', + name: 'IAM Detach User Policy', + description: 'Remove a managed policy from an IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM user', + }, + policyArn: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ARN of the managed policy to detach', + }, + }, + + request: { + url: '/api/tools/iam/detach-user-policy', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + policyArn: params.policyArn, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to detach policy from user') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, + } diff --git a/apps/sim/tools/iam/get_role.ts b/apps/sim/tools/iam/get_role.ts new file mode 100644 index 00000000000..d9064f319f0 --- /dev/null +++ b/apps/sim/tools/iam/get_role.ts @@ -0,0 +1,101 @@ +import type { IAMGetRoleParams, IAMGetRoleResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const getRoleTool: ToolConfig = { + id: 'iam_get_role', + name: 'IAM Get Role', + description: 'Get detailed information about an IAM role', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + roleName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM role to retrieve', + }, + }, + + request: { + url: '/api/tools/iam/get-role', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + roleName: params.roleName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get IAM role') + } + + return { + success: true, + output: { + roleName: data.roleName ?? '', + roleId: data.roleId ?? '', + arn: data.arn ?? '', + path: data.path ?? '', + createDate: data.createDate ?? null, + description: data.description ?? null, + maxSessionDuration: data.maxSessionDuration ?? null, + assumeRolePolicyDocument: data.assumeRolePolicyDocument ?? null, + roleLastUsedDate: data.roleLastUsedDate ?? null, + roleLastUsedRegion: data.roleLastUsedRegion ?? null, + }, + } + }, + + outputs: { + roleName: { type: 'string', description: 'The name of the role' }, + roleId: { type: 'string', description: 'The unique ID of the role' }, + arn: { type: 'string', description: 'The ARN of the role' }, + path: { type: 'string', description: 'The path to the role' }, + createDate: { type: 'string', description: 'Date the role was created', optional: true }, + description: { type: 'string', description: 'Description of the role', optional: true }, + maxSessionDuration: { + type: 'number', + description: 'Maximum session duration in seconds', + optional: true, + }, + assumeRolePolicyDocument: { + type: 'string', + description: 'The trust policy document (JSON)', + optional: true, + }, + roleLastUsedDate: { + type: 'string', + description: 'Date the role was last used', + optional: true, + }, + roleLastUsedRegion: { + type: 'string', + description: 'AWS region where the role was last used', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/iam/get_user.ts b/apps/sim/tools/iam/get_user.ts new file mode 100644 index 00000000000..2118e4001f5 --- /dev/null +++ b/apps/sim/tools/iam/get_user.ts @@ -0,0 +1,93 @@ +import type { IAMGetUserParams, IAMGetUserResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const getUserTool: ToolConfig = { + id: 'iam_get_user', + name: 'IAM Get User', + description: 'Get detailed information about an IAM user', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM user to retrieve', + }, + }, + + request: { + url: '/api/tools/iam/get-user', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get IAM user') + } + + return { + success: true, + output: { + userName: data.userName ?? '', + userId: data.userId ?? '', + arn: data.arn ?? '', + path: data.path ?? '', + createDate: data.createDate ?? null, + passwordLastUsed: data.passwordLastUsed ?? null, + permissionsBoundaryArn: data.permissionsBoundaryArn ?? null, + tags: data.tags ?? [], + }, + } + }, + + outputs: { + userName: { type: 'string', description: 'The name of the user' }, + userId: { type: 'string', description: 'The unique ID of the user' }, + arn: { type: 'string', description: 'The ARN of the user' }, + path: { type: 'string', description: 'The path to the user' }, + createDate: { type: 'string', description: 'Date the user was created', optional: true }, + passwordLastUsed: { + type: 'string', + description: 'Date the password was last used', + optional: true, + }, + permissionsBoundaryArn: { + type: 'string', + description: 'ARN of the permissions boundary policy', + optional: true, + }, + tags: { + type: 'json', + description: 'Tags attached to the user (key, value pairs)', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/iam/index.ts b/apps/sim/tools/iam/index.ts new file mode 100644 index 00000000000..bc2f9059c23 --- /dev/null +++ b/apps/sim/tools/iam/index.ts @@ -0,0 +1,37 @@ +import { addUserToGroupTool } from './add_user_to_group' +import { attachRolePolicyTool } from './attach_role_policy' +import { attachUserPolicyTool } from './attach_user_policy' +import { createAccessKeyTool } from './create_access_key' +import { createRoleTool } from './create_role' +import { createUserTool } from './create_user' +import { deleteAccessKeyTool } from './delete_access_key' +import { deleteRoleTool } from './delete_role' +import { deleteUserTool } from './delete_user' +import { detachRolePolicyTool } from './detach_role_policy' +import { detachUserPolicyTool } from './detach_user_policy' +import { getRoleTool } from './get_role' +import { getUserTool } from './get_user' +import { listGroupsTool } from './list_groups' +import { listPoliciesTool } from './list_policies' +import { listRolesTool } from './list_roles' +import { listUsersTool } from './list_users' +import { removeUserFromGroupTool } from './remove_user_from_group' + +export const iamListUsersTool = listUsersTool +export const iamGetUserTool = getUserTool +export const iamCreateUserTool = createUserTool +export const iamDeleteUserTool = deleteUserTool +export const iamListRolesTool = listRolesTool +export const iamGetRoleTool = getRoleTool +export const iamCreateRoleTool = createRoleTool +export const iamDeleteRoleTool = deleteRoleTool +export const iamAttachUserPolicyTool = attachUserPolicyTool +export const iamDetachUserPolicyTool = detachUserPolicyTool +export const iamAttachRolePolicyTool = attachRolePolicyTool +export const iamDetachRolePolicyTool = detachRolePolicyTool +export const iamListPoliciesTool = listPoliciesTool +export const iamCreateAccessKeyTool = createAccessKeyTool +export const iamDeleteAccessKeyTool = deleteAccessKeyTool +export const iamListGroupsTool = listGroupsTool +export const iamAddUserToGroupTool = addUserToGroupTool +export const iamRemoveUserFromGroupTool = removeUserFromGroupTool diff --git a/apps/sim/tools/iam/list_groups.ts b/apps/sim/tools/iam/list_groups.ts new file mode 100644 index 00000000000..7222a77b672 --- /dev/null +++ b/apps/sim/tools/iam/list_groups.ts @@ -0,0 +1,97 @@ +import type { IAMListGroupsParams, IAMListGroupsResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const listGroupsTool: ToolConfig = { + id: 'iam_list_groups', + name: 'IAM List Groups', + description: 'List IAM groups in your AWS account', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + pathPrefix: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Path prefix to filter groups', + }, + maxItems: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of groups to return (1-1000, default 100)', + }, + marker: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination marker from a previous request', + }, + }, + + request: { + url: '/api/tools/iam/list-groups', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + pathPrefix: params.pathPrefix, + maxItems: params.maxItems, + marker: params.marker, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list IAM groups') + } + + return { + success: true, + output: { + groups: data.groups ?? [], + isTruncated: data.isTruncated ?? false, + marker: data.marker ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + groups: { + type: 'json', + description: 'List of IAM groups with groupName, groupId, arn, and path', + }, + isTruncated: { + type: 'boolean', + description: 'Whether there are more results available', + }, + marker: { + type: 'string', + description: 'Pagination marker for the next page of results', + optional: true, + }, + count: { type: 'number', description: 'Number of groups returned' }, + }, +} diff --git a/apps/sim/tools/iam/list_policies.ts b/apps/sim/tools/iam/list_policies.ts new file mode 100644 index 00000000000..c45719e714b --- /dev/null +++ b/apps/sim/tools/iam/list_policies.ts @@ -0,0 +1,111 @@ +import type { IAMListPoliciesParams, IAMListPoliciesResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const listPoliciesTool: ToolConfig = { + id: 'iam_list_policies', + name: 'IAM List Policies', + description: 'List managed IAM policies', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + scope: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by scope: All, AWS (AWS-managed), or Local (customer-managed)', + }, + onlyAttached: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'If true, only return policies attached to an entity', + }, + pathPrefix: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Path prefix to filter policies', + }, + maxItems: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of policies to return (1-1000, default 100)', + }, + marker: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination marker from a previous request', + }, + }, + + request: { + url: '/api/tools/iam/list-policies', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + scope: params.scope, + onlyAttached: params.onlyAttached, + pathPrefix: params.pathPrefix, + maxItems: params.maxItems, + marker: params.marker, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list IAM policies') + } + + return { + success: true, + output: { + policies: data.policies ?? [], + isTruncated: data.isTruncated ?? false, + marker: data.marker ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + policies: { + type: 'json', + description: 'List of policies with policyName, arn, attachmentCount, and dates', + }, + isTruncated: { + type: 'boolean', + description: 'Whether there are more results available', + }, + marker: { + type: 'string', + description: 'Pagination marker for the next page of results', + optional: true, + }, + count: { type: 'number', description: 'Number of policies returned' }, + }, +} diff --git a/apps/sim/tools/iam/list_roles.ts b/apps/sim/tools/iam/list_roles.ts new file mode 100644 index 00000000000..14b740db8be --- /dev/null +++ b/apps/sim/tools/iam/list_roles.ts @@ -0,0 +1,97 @@ +import type { IAMListRolesParams, IAMListRolesResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const listRolesTool: ToolConfig = { + id: 'iam_list_roles', + name: 'IAM List Roles', + description: 'List IAM roles in your AWS account', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + pathPrefix: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Path prefix to filter roles (e.g., /application/)', + }, + maxItems: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of roles to return (1-1000, default 100)', + }, + marker: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination marker from a previous request', + }, + }, + + request: { + url: '/api/tools/iam/list-roles', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + pathPrefix: params.pathPrefix, + maxItems: params.maxItems, + marker: params.marker, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list IAM roles') + } + + return { + success: true, + output: { + roles: data.roles ?? [], + isTruncated: data.isTruncated ?? false, + marker: data.marker ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + roles: { + type: 'json', + description: 'List of IAM roles with roleName, roleId, arn, path, and dates', + }, + isTruncated: { + type: 'boolean', + description: 'Whether there are more results available', + }, + marker: { + type: 'string', + description: 'Pagination marker for the next page of results', + optional: true, + }, + count: { type: 'number', description: 'Number of roles returned' }, + }, +} diff --git a/apps/sim/tools/iam/list_users.ts b/apps/sim/tools/iam/list_users.ts new file mode 100644 index 00000000000..b912ce71370 --- /dev/null +++ b/apps/sim/tools/iam/list_users.ts @@ -0,0 +1,97 @@ +import type { IAMListUsersParams, IAMListUsersResponse } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const listUsersTool: ToolConfig = { + id: 'iam_list_users', + name: 'IAM List Users', + description: 'List IAM users in your AWS account', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + pathPrefix: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Path prefix to filter users (e.g., /division_abc/)', + }, + maxItems: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of users to return (1-1000, default 100)', + }, + marker: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination marker from a previous request', + }, + }, + + request: { + url: '/api/tools/iam/list-users', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + pathPrefix: params.pathPrefix, + maxItems: params.maxItems, + marker: params.marker, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list IAM users') + } + + return { + success: true, + output: { + users: data.users ?? [], + isTruncated: data.isTruncated ?? false, + marker: data.marker ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + users: { + type: 'json', + description: 'List of IAM users with userName, userId, arn, path, and dates', + }, + isTruncated: { + type: 'boolean', + description: 'Whether there are more results available', + }, + marker: { + type: 'string', + description: 'Pagination marker for the next page of results', + optional: true, + }, + count: { type: 'number', description: 'Number of users returned' }, + }, +} diff --git a/apps/sim/tools/iam/remove_user_from_group.ts b/apps/sim/tools/iam/remove_user_from_group.ts new file mode 100644 index 00000000000..fbafa477fe8 --- /dev/null +++ b/apps/sim/tools/iam/remove_user_from_group.ts @@ -0,0 +1,77 @@ +import type { IAMGroupMembershipResponse, IAMRemoveUserFromGroupParams } from '@/tools/iam/types' +import type { ToolConfig } from '@/tools/types' + +export const removeUserFromGroupTool: ToolConfig< + IAMRemoveUserFromGroupParams, + IAMGroupMembershipResponse +> = { + id: 'iam_remove_user_from_group', + name: 'IAM Remove User from Group', + description: 'Remove an IAM user from a group', + version: '1.0.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + userName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM user', + }, + groupName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the IAM group', + }, + }, + + request: { + url: '/api/tools/iam/remove-user-from-group', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + userName: params.userName, + groupName: params.groupName, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to remove user from group') + } + + return { + success: true, + output: { + message: data.message ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + }, +} diff --git a/apps/sim/tools/iam/types.ts b/apps/sim/tools/iam/types.ts new file mode 100644 index 00000000000..8c74710679f --- /dev/null +++ b/apps/sim/tools/iam/types.ts @@ -0,0 +1,275 @@ +import type { ToolResponse } from '@/tools/types' + +export interface IAMConnectionConfig { + region: string + accessKeyId: string + secretAccessKey: string +} + +export interface IAMListUsersParams extends IAMConnectionConfig { + pathPrefix?: string | null + maxItems?: number | null + marker?: string | null +} + +export interface IAMGetUserParams extends IAMConnectionConfig { + userName: string +} + +export interface IAMCreateUserParams extends IAMConnectionConfig { + userName: string + path?: string | null +} + +export interface IAMDeleteUserParams extends IAMConnectionConfig { + userName: string +} + +export interface IAMListRolesParams extends IAMConnectionConfig { + pathPrefix?: string | null + maxItems?: number | null + marker?: string | null +} + +export interface IAMGetRoleParams extends IAMConnectionConfig { + roleName: string +} + +export interface IAMCreateRoleParams extends IAMConnectionConfig { + roleName: string + assumeRolePolicyDocument: string + description?: string | null + path?: string | null + maxSessionDuration?: number | null +} + +export interface IAMDeleteRoleParams extends IAMConnectionConfig { + roleName: string +} + +export interface IAMAttachUserPolicyParams extends IAMConnectionConfig { + userName: string + policyArn: string +} + +export interface IAMDetachUserPolicyParams extends IAMConnectionConfig { + userName: string + policyArn: string +} + +export interface IAMAttachRolePolicyParams extends IAMConnectionConfig { + roleName: string + policyArn: string +} + +export interface IAMDetachRolePolicyParams extends IAMConnectionConfig { + roleName: string + policyArn: string +} + +export interface IAMListPoliciesParams extends IAMConnectionConfig { + scope?: string | null + onlyAttached?: boolean | null + pathPrefix?: string | null + maxItems?: number | null + marker?: string | null +} + +export interface IAMCreateAccessKeyParams extends IAMConnectionConfig { + userName?: string | null +} + +export interface IAMDeleteAccessKeyParams extends IAMConnectionConfig { + accessKeyIdToDelete: string + userName?: string | null +} + +export interface IAMListGroupsParams extends IAMConnectionConfig { + pathPrefix?: string | null + maxItems?: number | null + marker?: string | null +} + +export interface IAMAddUserToGroupParams extends IAMConnectionConfig { + userName: string + groupName: string +} + +export interface IAMRemoveUserFromGroupParams extends IAMConnectionConfig { + userName: string + groupName: string +} + +export interface IAMBaseResponse extends ToolResponse { + output: { message: string } + error?: string +} + +export interface IAMListUsersResponse extends ToolResponse { + output: { + users: Array<{ + userName: string + userId: string + arn: string + path: string + createDate: string | null + passwordLastUsed: string | null + }> + isTruncated: boolean + marker: string | null + count: number + } + error?: string +} + +export interface IAMGetUserResponse extends ToolResponse { + output: { + userName: string + userId: string + arn: string + path: string + createDate: string | null + passwordLastUsed: string | null + permissionsBoundaryArn: string | null + tags: Array<{ key: string; value: string }> + } + error?: string +} + +export interface IAMCreateUserResponse extends ToolResponse { + output: { + message: string + userName: string + userId: string + arn: string + path: string + createDate: string | null + } + error?: string +} + +export interface IAMDeleteUserResponse extends ToolResponse { + output: { message: string } + error?: string +} + +export interface IAMListRolesResponse extends ToolResponse { + output: { + roles: Array<{ + roleName: string + roleId: string + arn: string + path: string + createDate: string | null + description: string | null + maxSessionDuration: number | null + }> + isTruncated: boolean + marker: string | null + count: number + } + error?: string +} + +export interface IAMGetRoleResponse extends ToolResponse { + output: { + roleName: string + roleId: string + arn: string + path: string + createDate: string | null + description: string | null + maxSessionDuration: number | null + assumeRolePolicyDocument: string | null + roleLastUsedDate: string | null + roleLastUsedRegion: string | null + } + error?: string +} + +export interface IAMCreateRoleResponse extends ToolResponse { + output: { + message: string + roleName: string + roleId: string + arn: string + path: string + createDate: string | null + } + error?: string +} + +export interface IAMDeleteRoleResponse extends ToolResponse { + output: { message: string } + error?: string +} + +export interface IAMAttachPolicyResponse extends ToolResponse { + output: { message: string } + error?: string +} + +export interface IAMDetachPolicyResponse extends ToolResponse { + output: { message: string } + error?: string +} + +export interface IAMListPoliciesResponse extends ToolResponse { + output: { + policies: Array<{ + policyName: string + policyId: string + arn: string + path: string + attachmentCount: number + isAttachable: boolean + createDate: string | null + updateDate: string | null + description: string | null + defaultVersionId: string | null + permissionsBoundaryUsageCount: number + }> + isTruncated: boolean + marker: string | null + count: number + } + error?: string +} + +export interface IAMCreateAccessKeyResponse extends ToolResponse { + output: { + message: string + accessKeyId: string + secretAccessKey: string + userName: string + status: string + createDate: string | null + } + error?: string +} + +export interface IAMDeleteAccessKeyResponse extends ToolResponse { + output: { message: string } + error?: string +} + +export interface IAMListGroupsResponse extends ToolResponse { + output: { + groups: Array<{ + groupName: string + groupId: string + arn: string + path: string + createDate: string | null + }> + isTruncated: boolean + marker: string | null + count: number + } + error?: string +} + +export interface IAMGroupMembershipResponse extends ToolResponse { + output: { message: string } + error?: string +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 6737fc16557..a90264d546f 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -1169,6 +1169,26 @@ import { hunterEmailFinderTool, hunterEmailVerifierTool, } from '@/tools/hunter' +import { + iamAddUserToGroupTool, + iamAttachRolePolicyTool, + iamAttachUserPolicyTool, + iamCreateAccessKeyTool, + iamCreateRoleTool, + iamCreateUserTool, + iamDeleteAccessKeyTool, + iamDeleteRoleTool, + iamDeleteUserTool, + iamDetachRolePolicyTool, + iamDetachUserPolicyTool, + iamGetRoleTool, + iamGetUserTool, + iamListGroupsTool, + iamListPoliciesTool, + iamListRolesTool, + iamListUsersTool, + iamRemoveUserFromGroupTool, +} from '@/tools/iam' import { incidentioActionsListTool, incidentioActionsShowTool, @@ -2430,6 +2450,12 @@ import { stripeUpdateSubscriptionTool, stripeVoidInvoiceTool, } from '@/tools/stripe' +import { + stsAssumeRoleTool, + stsGetAccessKeyInfoTool, + stsGetCallerIdentityTool, + stsGetSessionTokenTool, +} from '@/tools/sts' import { assemblyaiSttTool, assemblyaiSttV2Tool, @@ -4900,6 +4926,24 @@ export const tools: Record = { hunter_email_verifier: hunterEmailVerifierTool, hunter_companies_find: hunterCompaniesFindTool, hunter_email_count: hunterEmailCountTool, + iam_list_users: iamListUsersTool, + iam_get_user: iamGetUserTool, + iam_create_user: iamCreateUserTool, + iam_delete_user: iamDeleteUserTool, + iam_list_roles: iamListRolesTool, + iam_get_role: iamGetRoleTool, + iam_create_role: iamCreateRoleTool, + iam_delete_role: iamDeleteRoleTool, + iam_attach_user_policy: iamAttachUserPolicyTool, + iam_detach_user_policy: iamDetachUserPolicyTool, + iam_attach_role_policy: iamAttachRolePolicyTool, + iam_detach_role_policy: iamDetachRolePolicyTool, + iam_list_policies: iamListPoliciesTool, + iam_create_access_key: iamCreateAccessKeyTool, + iam_delete_access_key: iamDeleteAccessKeyTool, + iam_list_groups: iamListGroupsTool, + iam_add_user_to_group: iamAddUserToGroupTool, + iam_remove_user_from_group: iamRemoveUserFromGroupTool, incidentio_incidents_list: incidentioIncidentsListTool, incidentio_incidents_create: incidentioIncidentsCreateTool, incidentio_incidents_show: incidentioIncidentsShowTool, @@ -5071,6 +5115,10 @@ export const tools: Record = { salesforce_describe_object: salesforceDescribeObjectTool, salesforce_list_objects: salesforceListObjectsTool, sqs_send: sqsSendTool, + sts_assume_role: stsAssumeRoleTool, + sts_get_caller_identity: stsGetCallerIdentityTool, + sts_get_session_token: stsGetSessionTokenTool, + sts_get_access_key_info: stsGetAccessKeyInfoTool, table_create: tableCreateTool, table_list: tableListTool, table_insert_row: tableInsertRowTool, diff --git a/apps/sim/tools/sts/assume_role.ts b/apps/sim/tools/sts/assume_role.ts new file mode 100644 index 00000000000..608ffd4c7d7 --- /dev/null +++ b/apps/sim/tools/sts/assume_role.ts @@ -0,0 +1,118 @@ +import type { STSAssumeRoleParams, STSAssumeRoleResponse } from '@/tools/sts/types' +import type { ToolConfig } from '@/tools/types' + +export const assumeRoleTool: ToolConfig = { + id: 'sts_assume_role', + name: 'STS Assume Role', + description: 'Assume an IAM role and receive temporary security credentials', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + roleArn: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ARN of the IAM role to assume', + }, + roleSessionName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Identifier for the assumed role session', + }, + durationSeconds: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Duration of the session in seconds (900-43200, default 3600)', + }, + externalId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'External ID for cross-account access', + }, + serialNumber: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'MFA device serial number or ARN', + }, + tokenCode: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'MFA token code (6 digits)', + }, + }, + + request: { + url: '/api/tools/sts/assume-role', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + roleArn: params.roleArn, + roleSessionName: params.roleSessionName, + durationSeconds: params.durationSeconds, + externalId: params.externalId, + serialNumber: params.serialNumber, + tokenCode: params.tokenCode, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to assume role') + } + + return { + success: true, + output: { + accessKeyId: data.accessKeyId ?? '', + secretAccessKey: data.secretAccessKey ?? '', + sessionToken: data.sessionToken ?? '', + expiration: data.expiration ?? null, + assumedRoleArn: data.assumedRoleArn ?? '', + assumedRoleId: data.assumedRoleId ?? '', + packedPolicySize: data.packedPolicySize ?? null, + }, + } + }, + + outputs: { + accessKeyId: { type: 'string', description: 'Temporary access key ID' }, + secretAccessKey: { type: 'string', description: 'Temporary secret access key' }, + sessionToken: { type: 'string', description: 'Temporary session token' }, + expiration: { type: 'string', description: 'Credential expiration timestamp' }, + assumedRoleArn: { type: 'string', description: 'ARN of the assumed role' }, + assumedRoleId: { type: 'string', description: 'Assumed role ID with session name' }, + packedPolicySize: { + type: 'number', + description: 'Percentage of allowed policy size used', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/sts/get_access_key_info.ts b/apps/sim/tools/sts/get_access_key_info.ts new file mode 100644 index 00000000000..327710415a7 --- /dev/null +++ b/apps/sim/tools/sts/get_access_key_info.ts @@ -0,0 +1,70 @@ +import type { STSGetAccessKeyInfoParams, STSGetAccessKeyInfoResponse } from '@/tools/sts/types' +import type { ToolConfig } from '@/tools/types' + +export const getAccessKeyInfoTool: ToolConfig< + STSGetAccessKeyInfoParams, + STSGetAccessKeyInfoResponse +> = { + id: 'sts_get_access_key_info', + name: 'STS Get Access Key Info', + description: 'Get the AWS account ID associated with an access key', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + targetAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The access key ID to look up', + }, + }, + + request: { + url: '/api/tools/sts/get-access-key-info', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + targetAccessKeyId: params.targetAccessKeyId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get access key info') + } + + return { + success: true, + output: { + account: data.account ?? '', + }, + } + }, + + outputs: { + account: { type: 'string', description: 'AWS account ID that owns the access key' }, + }, +} diff --git a/apps/sim/tools/sts/get_caller_identity.ts b/apps/sim/tools/sts/get_caller_identity.ts new file mode 100644 index 00000000000..469746f1f37 --- /dev/null +++ b/apps/sim/tools/sts/get_caller_identity.ts @@ -0,0 +1,67 @@ +import type { STSGetCallerIdentityParams, STSGetCallerIdentityResponse } from '@/tools/sts/types' +import type { ToolConfig } from '@/tools/types' + +export const getCallerIdentityTool: ToolConfig< + STSGetCallerIdentityParams, + STSGetCallerIdentityResponse +> = { + id: 'sts_get_caller_identity', + name: 'STS Get Caller Identity', + description: 'Get details about the IAM user or role whose credentials are used to call the API', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + }, + + request: { + url: '/api/tools/sts/get-caller-identity', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get caller identity') + } + + return { + success: true, + output: { + account: data.account ?? '', + arn: data.arn ?? '', + userId: data.userId ?? '', + }, + } + }, + + outputs: { + account: { type: 'string', description: 'AWS account ID' }, + arn: { type: 'string', description: 'ARN of the calling entity' }, + userId: { type: 'string', description: 'Unique identifier of the calling entity' }, + }, +} diff --git a/apps/sim/tools/sts/get_session_token.ts b/apps/sim/tools/sts/get_session_token.ts new file mode 100644 index 00000000000..0550467a56e --- /dev/null +++ b/apps/sim/tools/sts/get_session_token.ts @@ -0,0 +1,88 @@ +import type { STSGetSessionTokenParams, STSGetSessionTokenResponse } from '@/tools/sts/types' +import type { ToolConfig } from '@/tools/types' + +export const getSessionTokenTool: ToolConfig = + { + id: 'sts_get_session_token', + name: 'STS Get Session Token', + description: 'Get temporary security credentials for an IAM user, optionally with MFA', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + durationSeconds: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Duration of the session in seconds (900-129600, default 43200)', + }, + serialNumber: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'MFA device serial number or ARN', + }, + tokenCode: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'MFA token code (6 digits)', + }, + }, + + request: { + url: '/api/tools/sts/get-session-token', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + durationSeconds: params.durationSeconds, + serialNumber: params.serialNumber, + tokenCode: params.tokenCode, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get session token') + } + + return { + success: true, + output: { + accessKeyId: data.accessKeyId ?? '', + secretAccessKey: data.secretAccessKey ?? '', + sessionToken: data.sessionToken ?? '', + expiration: data.expiration ?? null, + }, + } + }, + + outputs: { + accessKeyId: { type: 'string', description: 'Temporary access key ID' }, + secretAccessKey: { type: 'string', description: 'Temporary secret access key' }, + sessionToken: { type: 'string', description: 'Temporary session token' }, + expiration: { type: 'string', description: 'Credential expiration timestamp' }, + }, + } diff --git a/apps/sim/tools/sts/index.ts b/apps/sim/tools/sts/index.ts new file mode 100644 index 00000000000..6aef12734b8 --- /dev/null +++ b/apps/sim/tools/sts/index.ts @@ -0,0 +1,9 @@ +import { assumeRoleTool } from './assume_role' +import { getAccessKeyInfoTool } from './get_access_key_info' +import { getCallerIdentityTool } from './get_caller_identity' +import { getSessionTokenTool } from './get_session_token' + +export const stsAssumeRoleTool = assumeRoleTool +export const stsGetCallerIdentityTool = getCallerIdentityTool +export const stsGetSessionTokenTool = getSessionTokenTool +export const stsGetAccessKeyInfoTool = getAccessKeyInfoTool diff --git a/apps/sim/tools/sts/types.ts b/apps/sim/tools/sts/types.ts new file mode 100644 index 00000000000..8da375eacbc --- /dev/null +++ b/apps/sim/tools/sts/types.ts @@ -0,0 +1,67 @@ +import type { ToolResponse } from '@/tools/types' + +export interface STSConnectionConfig { + region: string + accessKeyId: string + secretAccessKey: string +} + +export interface STSAssumeRoleParams extends STSConnectionConfig { + roleArn: string + roleSessionName: string + durationSeconds?: number | null + externalId?: string | null + serialNumber?: string | null + tokenCode?: string | null +} + +export interface STSGetCallerIdentityParams extends STSConnectionConfig {} + +export interface STSGetSessionTokenParams extends STSConnectionConfig { + durationSeconds?: number | null + serialNumber?: string | null + tokenCode?: string | null +} + +export interface STSGetAccessKeyInfoParams extends STSConnectionConfig { + targetAccessKeyId: string +} + +export interface STSAssumeRoleResponse extends ToolResponse { + output: { + accessKeyId: string + secretAccessKey: string + sessionToken: string + expiration: string | null + assumedRoleArn: string + assumedRoleId: string + packedPolicySize: number | null + } +} + +export interface STSGetCallerIdentityResponse extends ToolResponse { + output: { + account: string + arn: string + userId: string + } +} + +export interface STSGetSessionTokenResponse extends ToolResponse { + output: { + accessKeyId: string + secretAccessKey: string + sessionToken: string + expiration: string | null + } +} + +export interface STSGetAccessKeyInfoResponse extends ToolResponse { + output: { + account: string + } +} + +export interface STSBaseResponse extends ToolResponse { + output: { message: string } +} diff --git a/bun.lock b/bun.lock index b071c71851b..064a7f2f0f6 100644 --- a/bun.lock +++ b/bun.lock @@ -64,10 +64,12 @@ "@aws-sdk/client-cloudwatch": "3.940.0", "@aws-sdk/client-cloudwatch-logs": "3.940.0", "@aws-sdk/client-dynamodb": "3.940.0", + "@aws-sdk/client-iam": "3.1029.0", "@aws-sdk/client-rds-data": "3.940.0", "@aws-sdk/client-s3": "^3.779.0", "@aws-sdk/client-secrets-manager": "3.940.0", "@aws-sdk/client-sqs": "3.947.0", + "@aws-sdk/client-sts": "3.1029.0", "@aws-sdk/lib-dynamodb": "3.940.0", "@aws-sdk/s3-request-presigner": "^3.779.0", "@azure/communication-email": "1.0.0", @@ -426,6 +428,8 @@ "@aws-sdk/client-dynamodb": ["@aws-sdk/client-dynamodb@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-endpoint-discovery": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-u2sXsNJazJbuHeWICvsj6RvNyJh3isedEfPvB21jK/kxcriK+dE/izlKC2cyxUjERCmku0zTFNzY9FhrLbYHjQ=="], + "@aws-sdk/client-iam": ["@aws-sdk/client-iam@3.1029.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/credential-provider-node": "^3.972.30", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "@smithy/util-waiter": "^4.2.15", "tslib": "^2.6.2" } }, "sha512-v/5wWvrX3fveCP5UQ4qTCvvD9KCQ3dpnY6uEOCGpkAigli+xzEixl8xNQDCRi9G3KyrhvGaeE2SEfuuoCHX+gw=="], + "@aws-sdk/client-rds-data": ["@aws-sdk/client-rds-data@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-68NH61MvS48CVPfzBNCPdCG4KnNjM+Uj/3DSw7rT9PJvdML9ARS4M2Uqco9POPw+Aj20KBumsEUd6FMVcYBXAA=="], "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.1015.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.24", "@aws-sdk/credential-provider-node": "^3.972.25", "@aws-sdk/middleware-bucket-endpoint": "^3.972.8", "@aws-sdk/middleware-expect-continue": "^3.972.8", "@aws-sdk/middleware-flexible-checksums": "^3.974.4", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-location-constraint": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-sdk-s3": "^3.972.24", "@aws-sdk/middleware-ssec": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/region-config-resolver": "^3.972.9", "@aws-sdk/signature-v4-multi-region": "^3.996.12", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.11", "@smithy/config-resolver": "^4.4.13", "@smithy/core": "^3.23.12", "@smithy/eventstream-serde-browser": "^4.2.12", "@smithy/eventstream-serde-config-resolver": "^4.3.12", "@smithy/eventstream-serde-node": "^4.2.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-blob-browser": "^4.2.13", "@smithy/hash-node": "^4.2.12", "@smithy/hash-stream-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/md5-js": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-retry": "^4.4.44", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.43", "@smithy/util-defaults-mode-node": "^4.2.47", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/util-waiter": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-yo+Y+/fq5/E684SynTRO+VA3a+98MeE/hs7J52XpNI5SchOCSrLhLtcDKVASlGhHQdNLGLzblRgps1OZaf8sbA=="], @@ -438,6 +442,8 @@ "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="], + "@aws-sdk/client-sts": ["@aws-sdk/client-sts@3.1029.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/credential-provider-node": "^3.972.30", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-9C2WAs0ECcQvaQWRBetVGjxlvNpVpNWTwIuf3oA106JOtb2EjxJ2s4JQQUPCiCH1qP9HzZ3Zf9MDEEJox0HT4Q=="], + "@aws-sdk/core": ["@aws-sdk/core@3.973.26", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.16", "@smithy/core": "^3.23.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ=="], "@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.972.5", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-2VbTstbjKdT+yKi8m7b3a9CiVac+pL/IY2PHJwsaGkkHmuuqkJZIErPck1h6P3T9ghQMLSdMPyW6Qp7Di5swFg=="], @@ -4004,6 +4010,72 @@ "@aws-sdk/client-dynamodb/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + "@aws-sdk/client-iam/@aws-sdk/core": ["@aws-sdk/core@3.973.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@aws-sdk/xml-builder": "^3.972.17", "@smithy/core": "^3.23.14", "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/signature-v4": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-CUZ5m8hwMCH6OYI4Li/WgMfIEx10Q2PLI9Y3XOUTPGZJ53aZ0007jCv+X/ywsaERyKPdw5MRZWk877roQksQ4A=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.30", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.25", "@aws-sdk/credential-provider-http": "^3.972.27", "@aws-sdk/credential-provider-ini": "^3.972.29", "@aws-sdk/credential-provider-process": "^3.972.25", "@aws-sdk/credential-provider-sso": "^3.972.29", "@aws-sdk/credential-provider-web-identity": "^3.972.29", "@aws-sdk/types": "^3.973.7", "@smithy/credential-provider-imds": "^4.2.13", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-FMnAnWxc8PG+ZrZ2OBKzY4luCUJhe9CG0B9YwYr4pzrYGLXBS2rl+UoUvjGbAwiptxRL6hyA3lFn03Bv1TLqTw=="], + + "@aws-sdk/client-iam/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-je5vRdNw4SkuTnmRbFZLdye4sQ0faLt8kwka5wnnSU30q1mHO4X+idGEJOOE+Tn1ME7Oryn05xxkDvIb3UaLaQ=="], + + "@aws-sdk/client-iam/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-HsVgDrruhqI28RkaXALm8grJ7Agc1wF6Et0xh6pom8NdO2VdO/SD9U/tPwUjewwK/pVoka+EShBxyCvgsPCtog=="], + + "@aws-sdk/client-iam/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-RVQQbq5orQ/GHUnXvqEOj2HHPBJm+mM+ySwZKS5UaLBwra5ugRtiH09PLUoOZRl7a1YzaOzXSuGbn9iD5j60WQ=="], + + "@aws-sdk/client-iam/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@smithy/core": "^3.23.14", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/util-retry": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-f/sIRzuTfEjg6NsbMYvye2VsmnQoNgntntleQyx5uGacUYzszbfIlO3GcI6G6daWUmTm0IDZc11qMHWwF0o0mQ=="], + + "@aws-sdk/client-iam/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/config-resolver": "^4.4.14", "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-6Q8B1dcx6BBqUTY1Mc/eROKA0FImEEY5VPSd6AGPEUf0ErjExz4snVqa9kNJSoVDV1rKaNf3qrWojgcKW+SdDg=="], + + "@aws-sdk/client-iam/@aws-sdk/types": ["@aws-sdk/types@3.973.7", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-reXRwoJ6CfChoqAsBszUYajAF8Z2LRE+CRcKocvFSMpIiLOtYU3aJ9trmn6VVPAzbbY5LXF+FfmUslbXk1SYFg=="], + + "@aws-sdk/client-iam/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.6", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-endpoints": "^3.3.4", "tslib": "^2.6.2" } }, "sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg=="], + + "@aws-sdk/client-iam/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-sn/LMzTbGjYqCCF24390WxPd6hkpoSptiUn5DzVp4cD71yqw+yGEGm1YCxyEoPXyc8qciM8UzLJcZBFslxo5Uw=="], + + "@aws-sdk/client-iam/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.15", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/types": "^3.973.7", "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-fYn3s9PtKdgQkczGZCFMgkNEe8aq1JCVbnRqjqN9RSVW43xn2RV9xdcZ3z01a48Jpkuh/xCmBKJxdLOo4Ozg7w=="], + + "@aws-sdk/client-iam/@smithy/config-resolver": ["@smithy/config-resolver@4.4.14", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-N55f8mPEccpzKetUagdvmAy8oohf0J5cuj9jLI1TaSceRlq0pJsIZepY3kmAXAhyxqXPV6hDerDQhqQPKWgAoQ=="], + + "@aws-sdk/client-iam/@smithy/core": ["@smithy/core@3.23.14", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.13", "@smithy/util-stream": "^4.5.22", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-vJ0IhpZxZAkFYOegMKSrxw7ujhhT2pass/1UEcZ4kfl5srTAqtPU5I7MdYQoreVas3204ykCiNhY1o7Xlz6Yyg=="], + + "@aws-sdk/client-iam/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.16", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/querystring-builder": "^4.2.13", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-nYDRUIvNd4mFmuXraRWt6w5UsZTNqtj4hXJA/iiOD4tuseIdLP9Lq38teH/SZTcIFCa2f+27o7hYpIsWktJKEQ=="], + + "@aws-sdk/client-iam/@smithy/hash-node": ["@smithy/hash-node@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4/oy9h0jjmY80a2gOIo75iLl8TOPhmtx4E2Hz+PfMjvx/vLtGY4TMU/35WRyH2JHPfT5CVB38u4JRow7gnmzJA=="], + + "@aws-sdk/client-iam/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-jvC0RB/8BLj2SMIkY0Npl425IdnxZJxInpZJbu563zIRnVjpDMXevU3VMCRSabaLB0kf/eFIOusdGstrLJ8IDg=="], + + "@aws-sdk/client-iam/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-IPMLm/LE4AZwu6qiE8Rr8vJsWhs9AtOdySRXrOM7xnvclp77Tyh7hMs/FRrMf26kgIe67vFJXXOSmVxS7oKeig=="], + + "@aws-sdk/client-iam/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.29", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/middleware-serde": "^4.2.17", "@smithy/node-config-provider": "^4.3.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-middleware": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-R9Q/58U+qBiSARGWbAbFLczECg/RmysRksX6Q8BaQEpt75I7LI6WGDZnjuC9GXSGKljEbA7N118LhGaMbfrTXw=="], + + "@aws-sdk/client-iam/@smithy/middleware-retry": ["@smithy/middleware-retry@4.5.1", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/node-config-provider": "^4.3.13", "@smithy/protocol-http": "^5.3.13", "@smithy/service-error-classification": "^4.2.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.1", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-/zY+Gp7Qj2D2hVm3irkCyONER7E9MiX3cUUm/k2ZmhkzZkrPgwVS4aJ5NriZUEN/M0D1hhjrgjUmX04HhRwdWA=="], + + "@aws-sdk/client-iam/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.17", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-0T2mcaM6v9W1xku86Dk0bEW7aEseG6KenFkPK98XNw0ZhOqOiD1MrMsdnQw9QsL3/Oa85T53iSMlm0SZdSuIEQ=="], + + "@aws-sdk/client-iam/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-g72jN/sGDLyTanrCLH9fhg3oysO3f7tQa6eWWsMyn2BiYNCgjF24n4/I9wff/5XidFvjj9ilipAoQrurTUrLvw=="], + + "@aws-sdk/client-iam/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.13", "", { "dependencies": { "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-iGxQ04DsKXLckbgnX4ipElrOTk+IHgTyu0q0WssZfYhDm9CQWHmu6cOeI5wmWRxpXbBDhIIfXMWz5tPEtcVqbw=="], + + "@aws-sdk/client-iam/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.2", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/querystring-builder": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-/oD7u8M0oj2ZTFw7GkuuHWpIxtWdLlnyNkbrWcyVYhd5RJNDuczdkb0wfnQICyNFrVPlr8YHOhamjNy3zidhmA=="], + + "@aws-sdk/client-iam/@smithy/protocol-http": ["@smithy/protocol-http@5.3.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-+HsmuJUF4u8POo6s8/a2Yb/AQ5t/YgLovCuHF9oxbocqv+SZ6gd8lC2duBFiCA/vFHoHQhoq7QjqJqZC6xOxxg=="], + + "@aws-sdk/client-iam/@smithy/smithy-client": ["@smithy/smithy-client@4.12.9", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-stack": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/util-stream": "^4.5.22", "tslib": "^2.6.2" } }, "sha512-ovaLEcTU5olSeHcRXcxV6viaKtpkHZumn6Ps0yn7dRf2rRSfy794vpjOtrWDO0d1auDSvAqxO+lyhERSXQ03EQ=="], + + "@aws-sdk/client-iam/@smithy/types": ["@smithy/types@4.14.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ=="], + + "@aws-sdk/client-iam/@smithy/url-parser": ["@smithy/url-parser@4.2.13", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-2G03yoboIRZlZze2+PT4GZEjgwQsJjUgn6iTsvxA02bVceHR6vp4Cuk7TUnPFWKF+ffNUk3kj4COwkENS2K3vw=="], + + "@aws-sdk/client-iam/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.45", "", { "dependencies": { "@smithy/property-provider": "^4.2.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-ag9sWc6/nWZAuK3Wm9KlFJUnRkXLrXn33RFjIAmCTFThqLHY+7wCst10BGq56FxslsDrjhSie46c8OULS+BiIw=="], + + "@aws-sdk/client-iam/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.49", "", { "dependencies": { "@smithy/config-resolver": "^4.4.14", "@smithy/credential-provider-imds": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-jlN6vHwE8gY5AfiFBavtD3QtCX2f7lM3BKkz7nFKSNfFR5nXLXLg6sqXTJEEyDwtxbztIDBQCfjsGVXlIru2lQ=="], + + "@aws-sdk/client-iam/@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-BKoR/ubPp9KNKFxPpg1J28N1+bgu8NGAtJblBP7yHy8yQPBWhIAv9+l92SlQLpolGm71CVO+btB60gTgzT0wog=="], + + "@aws-sdk/client-iam/@smithy/util-middleware": ["@smithy/util-middleware@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-GTooyrlmRTqvUen4eK7/K1p6kryF7bnDfq6XsAbIsf2mo51B/utaH+XThY6dKgNCWzMAaH/+OLmqaBuLhLWRow=="], + + "@aws-sdk/client-iam/@smithy/util-retry": ["@smithy/util-retry@4.3.1", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-FwmicpgWOkP5kZUjN3y+3JIom8NLGqSAJBeoIgK0rIToI817TEBHCrd0A2qGeKQlgDeP+Jzn4i0H/NLAXGy9uQ=="], + + "@aws-sdk/client-iam/@smithy/util-waiter": ["@smithy/util-waiter@4.2.15", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-oUt9o7n8hBv3BL56sLSneL0XeigZSuem0Hr78JaoK33D9oKieyCvVP8eTSe3j7g2mm/S1DvzxKieG7JEWNJUNg=="], + "@aws-sdk/client-rds-data/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], @@ -4204,6 +4276,70 @@ "@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + "@aws-sdk/client-sts/@aws-sdk/core": ["@aws-sdk/core@3.973.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@aws-sdk/xml-builder": "^3.972.17", "@smithy/core": "^3.23.14", "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/signature-v4": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-CUZ5m8hwMCH6OYI4Li/WgMfIEx10Q2PLI9Y3XOUTPGZJ53aZ0007jCv+X/ywsaERyKPdw5MRZWk877roQksQ4A=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.30", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.25", "@aws-sdk/credential-provider-http": "^3.972.27", "@aws-sdk/credential-provider-ini": "^3.972.29", "@aws-sdk/credential-provider-process": "^3.972.25", "@aws-sdk/credential-provider-sso": "^3.972.29", "@aws-sdk/credential-provider-web-identity": "^3.972.29", "@aws-sdk/types": "^3.973.7", "@smithy/credential-provider-imds": "^4.2.13", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-FMnAnWxc8PG+ZrZ2OBKzY4luCUJhe9CG0B9YwYr4pzrYGLXBS2rl+UoUvjGbAwiptxRL6hyA3lFn03Bv1TLqTw=="], + + "@aws-sdk/client-sts/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-je5vRdNw4SkuTnmRbFZLdye4sQ0faLt8kwka5wnnSU30q1mHO4X+idGEJOOE+Tn1ME7Oryn05xxkDvIb3UaLaQ=="], + + "@aws-sdk/client-sts/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-HsVgDrruhqI28RkaXALm8grJ7Agc1wF6Et0xh6pom8NdO2VdO/SD9U/tPwUjewwK/pVoka+EShBxyCvgsPCtog=="], + + "@aws-sdk/client-sts/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-RVQQbq5orQ/GHUnXvqEOj2HHPBJm+mM+ySwZKS5UaLBwra5ugRtiH09PLUoOZRl7a1YzaOzXSuGbn9iD5j60WQ=="], + + "@aws-sdk/client-sts/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@smithy/core": "^3.23.14", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/util-retry": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-f/sIRzuTfEjg6NsbMYvye2VsmnQoNgntntleQyx5uGacUYzszbfIlO3GcI6G6daWUmTm0IDZc11qMHWwF0o0mQ=="], + + "@aws-sdk/client-sts/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/config-resolver": "^4.4.14", "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-6Q8B1dcx6BBqUTY1Mc/eROKA0FImEEY5VPSd6AGPEUf0ErjExz4snVqa9kNJSoVDV1rKaNf3qrWojgcKW+SdDg=="], + + "@aws-sdk/client-sts/@aws-sdk/types": ["@aws-sdk/types@3.973.7", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-reXRwoJ6CfChoqAsBszUYajAF8Z2LRE+CRcKocvFSMpIiLOtYU3aJ9trmn6VVPAzbbY5LXF+FfmUslbXk1SYFg=="], + + "@aws-sdk/client-sts/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.6", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-endpoints": "^3.3.4", "tslib": "^2.6.2" } }, "sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg=="], + + "@aws-sdk/client-sts/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-sn/LMzTbGjYqCCF24390WxPd6hkpoSptiUn5DzVp4cD71yqw+yGEGm1YCxyEoPXyc8qciM8UzLJcZBFslxo5Uw=="], + + "@aws-sdk/client-sts/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.15", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/types": "^3.973.7", "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-fYn3s9PtKdgQkczGZCFMgkNEe8aq1JCVbnRqjqN9RSVW43xn2RV9xdcZ3z01a48Jpkuh/xCmBKJxdLOo4Ozg7w=="], + + "@aws-sdk/client-sts/@smithy/config-resolver": ["@smithy/config-resolver@4.4.14", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-N55f8mPEccpzKetUagdvmAy8oohf0J5cuj9jLI1TaSceRlq0pJsIZepY3kmAXAhyxqXPV6hDerDQhqQPKWgAoQ=="], + + "@aws-sdk/client-sts/@smithy/core": ["@smithy/core@3.23.14", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.13", "@smithy/util-stream": "^4.5.22", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-vJ0IhpZxZAkFYOegMKSrxw7ujhhT2pass/1UEcZ4kfl5srTAqtPU5I7MdYQoreVas3204ykCiNhY1o7Xlz6Yyg=="], + + "@aws-sdk/client-sts/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.16", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/querystring-builder": "^4.2.13", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-nYDRUIvNd4mFmuXraRWt6w5UsZTNqtj4hXJA/iiOD4tuseIdLP9Lq38teH/SZTcIFCa2f+27o7hYpIsWktJKEQ=="], + + "@aws-sdk/client-sts/@smithy/hash-node": ["@smithy/hash-node@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4/oy9h0jjmY80a2gOIo75iLl8TOPhmtx4E2Hz+PfMjvx/vLtGY4TMU/35WRyH2JHPfT5CVB38u4JRow7gnmzJA=="], + + "@aws-sdk/client-sts/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-jvC0RB/8BLj2SMIkY0Npl425IdnxZJxInpZJbu563zIRnVjpDMXevU3VMCRSabaLB0kf/eFIOusdGstrLJ8IDg=="], + + "@aws-sdk/client-sts/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-IPMLm/LE4AZwu6qiE8Rr8vJsWhs9AtOdySRXrOM7xnvclp77Tyh7hMs/FRrMf26kgIe67vFJXXOSmVxS7oKeig=="], + + "@aws-sdk/client-sts/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.29", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/middleware-serde": "^4.2.17", "@smithy/node-config-provider": "^4.3.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-middleware": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-R9Q/58U+qBiSARGWbAbFLczECg/RmysRksX6Q8BaQEpt75I7LI6WGDZnjuC9GXSGKljEbA7N118LhGaMbfrTXw=="], + + "@aws-sdk/client-sts/@smithy/middleware-retry": ["@smithy/middleware-retry@4.5.1", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/node-config-provider": "^4.3.13", "@smithy/protocol-http": "^5.3.13", "@smithy/service-error-classification": "^4.2.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.1", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-/zY+Gp7Qj2D2hVm3irkCyONER7E9MiX3cUUm/k2ZmhkzZkrPgwVS4aJ5NriZUEN/M0D1hhjrgjUmX04HhRwdWA=="], + + "@aws-sdk/client-sts/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.17", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-0T2mcaM6v9W1xku86Dk0bEW7aEseG6KenFkPK98XNw0ZhOqOiD1MrMsdnQw9QsL3/Oa85T53iSMlm0SZdSuIEQ=="], + + "@aws-sdk/client-sts/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-g72jN/sGDLyTanrCLH9fhg3oysO3f7tQa6eWWsMyn2BiYNCgjF24n4/I9wff/5XidFvjj9ilipAoQrurTUrLvw=="], + + "@aws-sdk/client-sts/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.13", "", { "dependencies": { "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-iGxQ04DsKXLckbgnX4ipElrOTk+IHgTyu0q0WssZfYhDm9CQWHmu6cOeI5wmWRxpXbBDhIIfXMWz5tPEtcVqbw=="], + + "@aws-sdk/client-sts/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.2", "", { "dependencies": { "@smithy/protocol-http": "^5.3.13", "@smithy/querystring-builder": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-/oD7u8M0oj2ZTFw7GkuuHWpIxtWdLlnyNkbrWcyVYhd5RJNDuczdkb0wfnQICyNFrVPlr8YHOhamjNy3zidhmA=="], + + "@aws-sdk/client-sts/@smithy/protocol-http": ["@smithy/protocol-http@5.3.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-+HsmuJUF4u8POo6s8/a2Yb/AQ5t/YgLovCuHF9oxbocqv+SZ6gd8lC2duBFiCA/vFHoHQhoq7QjqJqZC6xOxxg=="], + + "@aws-sdk/client-sts/@smithy/smithy-client": ["@smithy/smithy-client@4.12.9", "", { "dependencies": { "@smithy/core": "^3.23.14", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-stack": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/util-stream": "^4.5.22", "tslib": "^2.6.2" } }, "sha512-ovaLEcTU5olSeHcRXcxV6viaKtpkHZumn6Ps0yn7dRf2rRSfy794vpjOtrWDO0d1auDSvAqxO+lyhERSXQ03EQ=="], + + "@aws-sdk/client-sts/@smithy/types": ["@smithy/types@4.14.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ=="], + + "@aws-sdk/client-sts/@smithy/url-parser": ["@smithy/url-parser@4.2.13", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-2G03yoboIRZlZze2+PT4GZEjgwQsJjUgn6iTsvxA02bVceHR6vp4Cuk7TUnPFWKF+ffNUk3kj4COwkENS2K3vw=="], + + "@aws-sdk/client-sts/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.45", "", { "dependencies": { "@smithy/property-provider": "^4.2.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-ag9sWc6/nWZAuK3Wm9KlFJUnRkXLrXn33RFjIAmCTFThqLHY+7wCst10BGq56FxslsDrjhSie46c8OULS+BiIw=="], + + "@aws-sdk/client-sts/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.49", "", { "dependencies": { "@smithy/config-resolver": "^4.4.14", "@smithy/credential-provider-imds": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-jlN6vHwE8gY5AfiFBavtD3QtCX2f7lM3BKkz7nFKSNfFR5nXLXLg6sqXTJEEyDwtxbztIDBQCfjsGVXlIru2lQ=="], + + "@aws-sdk/client-sts/@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-BKoR/ubPp9KNKFxPpg1J28N1+bgu8NGAtJblBP7yHy8yQPBWhIAv9+l92SlQLpolGm71CVO+btB60gTgzT0wog=="], + + "@aws-sdk/client-sts/@smithy/util-middleware": ["@smithy/util-middleware@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-GTooyrlmRTqvUen4eK7/K1p6kryF7bnDfq6XsAbIsf2mo51B/utaH+XThY6dKgNCWzMAaH/+OLmqaBuLhLWRow=="], + + "@aws-sdk/client-sts/@smithy/util-retry": ["@smithy/util-retry@4.3.1", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-FwmicpgWOkP5kZUjN3y+3JIom8NLGqSAJBeoIgK0rIToI817TEBHCrd0A2qGeKQlgDeP+Jzn4i0H/NLAXGy9uQ=="], + "@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.18", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.26", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.9", "@aws-sdk/middleware-user-agent": "^3.972.28", "@aws-sdk/region-config-resolver": "^3.972.10", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.14", "@smithy/config-resolver": "^4.4.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], @@ -4934,6 +5070,56 @@ "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + "@aws-sdk/client-iam/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.17", "", { "dependencies": { "@smithy/types": "^4.14.0", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg=="], + + "@aws-sdk/client-iam/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-iam/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.13", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.13", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-YpYSyM0vMDwKbHD/JA7bVOF6kToVRpa+FM5ateEVRpsTNu564g1muBlkTubXhSKKYXInhpADF46FPyrZcTLpXg=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.25", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-6QfI0wv4jpG5CrdO/AO0JfZ2ux+tKwJPrUwmvxXF50vI5KIypKVGNF6b4vlkYEnKumDTI1NX2zUBi8JoU5QU3A=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.27", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/property-provider": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/util-stream": "^4.5.22", "tslib": "^2.6.2" } }, "sha512-3V3Usj9Gs93h865DqN4M2NWJhC5kXU9BvZskfN3+69omuYlE3TZxOEcVQtBGLOloJB7BVfJKXVLqeNhOzHqSlQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/credential-provider-env": "^3.972.25", "@aws-sdk/credential-provider-http": "^3.972.27", "@aws-sdk/credential-provider-login": "^3.972.29", "@aws-sdk/credential-provider-process": "^3.972.25", "@aws-sdk/credential-provider-sso": "^3.972.29", "@aws-sdk/credential-provider-web-identity": "^3.972.29", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/credential-provider-imds": "^4.2.13", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-SiBuAnXecCbT/OpAf3vqyI/AVE3mTaYr9ShXLybxZiPLBiPCCOIWSGAtYYGQWMRvobBTiqOewaB+wcgMMZI2Aw=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.25", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-HR7ynNRdNhNsdVCOCegy1HsfsRzozCOPtD3RzzT1JouuaHobWyRfJzCBue/3jP7gECHt+kQyZUvwg/cYLWurNQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/token-providers": "3.1026.0", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-HWv4SEq3jZDYPlwryZVef97+U8CxxRos5mK8sgGO1dQaFZpV5giZLzqGE5hkDmh2csYcBO2uf5XHjPTpZcJlig=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-PdMBza1WEKEUPFEmMGCfnU2RYCz9MskU2e8JxjyUOsMKku7j9YaDKvbDi2dzC0ihFoM6ods2SbhfAAro+Gwlew=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.8", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw=="], + + "@aws-sdk/client-iam/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.22", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew=="], + + "@aws-sdk/client-iam/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ=="], + + "@aws-sdk/client-iam/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.8", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw=="], + + "@aws-sdk/client-iam/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0" } }, "sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw=="], + + "@aws-sdk/client-iam/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-iam/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.8", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw=="], + + "@aws-sdk/client-iam/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ=="], + + "@aws-sdk/client-iam/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.22", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew=="], + + "@aws-sdk/client-iam/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-hqW3Q4P+CDzUyQ87GrboGMeD7XYNMOF+CuTwu936UQRB/zeYn3jys8C3w+wMkDfY7CyyyVwZQ5cNFoG0x1pYmA=="], + + "@aws-sdk/client-iam/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-iam/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ=="], + + "@aws-sdk/client-iam/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-iam/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0" } }, "sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw=="], + "@aws-sdk/client-rds-data/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], @@ -5012,6 +5198,56 @@ "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + "@aws-sdk/client-sts/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.17", "", { "dependencies": { "@smithy/types": "^4.14.0", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg=="], + + "@aws-sdk/client-sts/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-sts/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.13", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.13", "@smithy/types": "^4.14.0", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.13", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-YpYSyM0vMDwKbHD/JA7bVOF6kToVRpa+FM5ateEVRpsTNu564g1muBlkTubXhSKKYXInhpADF46FPyrZcTLpXg=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.25", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-6QfI0wv4jpG5CrdO/AO0JfZ2ux+tKwJPrUwmvxXF50vI5KIypKVGNF6b4vlkYEnKumDTI1NX2zUBi8JoU5QU3A=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.27", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/property-provider": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/util-stream": "^4.5.22", "tslib": "^2.6.2" } }, "sha512-3V3Usj9Gs93h865DqN4M2NWJhC5kXU9BvZskfN3+69omuYlE3TZxOEcVQtBGLOloJB7BVfJKXVLqeNhOzHqSlQ=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/credential-provider-env": "^3.972.25", "@aws-sdk/credential-provider-http": "^3.972.27", "@aws-sdk/credential-provider-login": "^3.972.29", "@aws-sdk/credential-provider-process": "^3.972.25", "@aws-sdk/credential-provider-sso": "^3.972.29", "@aws-sdk/credential-provider-web-identity": "^3.972.29", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/credential-provider-imds": "^4.2.13", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-SiBuAnXecCbT/OpAf3vqyI/AVE3mTaYr9ShXLybxZiPLBiPCCOIWSGAtYYGQWMRvobBTiqOewaB+wcgMMZI2Aw=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.25", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-HR7ynNRdNhNsdVCOCegy1HsfsRzozCOPtD3RzzT1JouuaHobWyRfJzCBue/3jP7gECHt+kQyZUvwg/cYLWurNQ=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/token-providers": "3.1026.0", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-HWv4SEq3jZDYPlwryZVef97+U8CxxRos5mK8sgGO1dQaFZpV5giZLzqGE5hkDmh2csYcBO2uf5XHjPTpZcJlig=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-PdMBza1WEKEUPFEmMGCfnU2RYCz9MskU2e8JxjyUOsMKku7j9YaDKvbDi2dzC0ihFoM6ods2SbhfAAro+Gwlew=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.8", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw=="], + + "@aws-sdk/client-sts/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.22", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew=="], + + "@aws-sdk/client-sts/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ=="], + + "@aws-sdk/client-sts/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.8", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw=="], + + "@aws-sdk/client-sts/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0" } }, "sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw=="], + + "@aws-sdk/client-sts/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-sts/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.8", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw=="], + + "@aws-sdk/client-sts/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ=="], + + "@aws-sdk/client-sts/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.22", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew=="], + + "@aws-sdk/client-sts/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-hqW3Q4P+CDzUyQ87GrboGMeD7XYNMOF+CuTwu936UQRB/zeYn3jys8C3w+wMkDfY7CyyyVwZQ5cNFoG0x1pYmA=="], + + "@aws-sdk/client-sts/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-sts/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.13", "@smithy/property-provider": "^4.2.13", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ=="], + + "@aws-sdk/client-sts/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ=="], + + "@aws-sdk/client-sts/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.13", "", { "dependencies": { "@smithy/types": "^4.14.0" } }, "sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw=="], + "@aws-sdk/lib-dynamodb/@aws-sdk/core/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], "@aws-sdk/lib-dynamodb/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], @@ -5568,6 +5804,20 @@ "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], + "@aws-sdk/client-iam/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.22", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-OGOslTbOlxXexKMqhxCEbBQbUIfuhGxU5UXw3Fm56ypXHvrXH4aTt/xb5Y884LOoteP1QST1lVZzHfcTnWhiPQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.19", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.19", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1026.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-Ieq/HiRrbEtrYP387Nes0XlR7H1pJiJOZKv+QyQzMYpvTiDs0VKy2ZB3E2Zf+aFovWmeE7lRE4lXyF7dYM6GgA=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.19", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q=="], + "@aws-sdk/client-rds-data/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], @@ -5620,6 +5870,20 @@ "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + "@aws-sdk/client-sts/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.22", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.16", "@smithy/node-http-handler": "^4.5.2", "@smithy/types": "^4.14.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.29", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/protocol-http": "^5.3.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-OGOslTbOlxXexKMqhxCEbBQbUIfuhGxU5UXw3Fm56ypXHvrXH4aTt/xb5Y884LOoteP1QST1lVZzHfcTnWhiPQ=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.19", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.19", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1026.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.27", "@aws-sdk/nested-clients": "^3.996.19", "@aws-sdk/types": "^3.973.7", "@smithy/property-provider": "^4.2.13", "@smithy/shared-ini-file-loader": "^4.4.8", "@smithy/types": "^4.14.0", "tslib": "^2.6.2" } }, "sha512-Ieq/HiRrbEtrYP387Nes0XlR7H1pJiJOZKv+QyQzMYpvTiDs0VKy2ZB3E2Zf+aFovWmeE7lRE4lXyF7dYM6GgA=="], + + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.19", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.27", "@aws-sdk/middleware-host-header": "^3.972.9", "@aws-sdk/middleware-logger": "^3.972.9", "@aws-sdk/middleware-recursion-detection": "^3.972.10", "@aws-sdk/middleware-user-agent": "^3.972.29", "@aws-sdk/region-config-resolver": "^3.972.11", "@aws-sdk/types": "^3.973.7", "@aws-sdk/util-endpoints": "^3.996.6", "@aws-sdk/util-user-agent-browser": "^3.972.9", "@aws-sdk/util-user-agent-node": "^3.973.15", "@smithy/config-resolver": "^4.4.14", "@smithy/core": "^3.23.14", "@smithy/fetch-http-handler": "^5.3.16", "@smithy/hash-node": "^4.2.13", "@smithy/invalid-dependency": "^4.2.13", "@smithy/middleware-content-length": "^4.2.13", "@smithy/middleware-endpoint": "^4.4.29", "@smithy/middleware-retry": "^4.5.0", "@smithy/middleware-serde": "^4.2.17", "@smithy/middleware-stack": "^4.2.13", "@smithy/node-config-provider": "^4.3.13", "@smithy/node-http-handler": "^4.5.2", "@smithy/protocol-http": "^5.3.13", "@smithy/smithy-client": "^4.12.9", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.45", "@smithy/util-defaults-mode-node": "^4.2.49", "@smithy/util-endpoints": "^3.3.4", "@smithy/util-middleware": "^4.2.13", "@smithy/util-retry": "^4.3.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q=="], + "@aws-sdk/lib-dynamodb/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "@aws-sdk/lib-dynamodb/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], From d548e120a3d3c9e854a22c2a40e7c663268d78ff Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 16:25:38 -0700 Subject: [PATCH 2/4] fix(sts): address PR review comments - Fix CrowdStrike tags to include "security" (unintended removal) - Standardize STS tool versions to '1.0.0' (matching IAM convention) - Add range validation to durationSeconds in Zod schemas Co-Authored-By: Claude Opus 4.6 --- apps/docs/components/icons.tsx | 18 ++++++++++++++++++ apps/docs/components/ui/icon-mapping.ts | 3 ++- .../integrations/data/integrations.json | 2 +- .../sim/app/api/tools/sts/assume-role/route.ts | 2 +- .../api/tools/sts/get-session-token/route.ts | 2 +- apps/sim/blocks/blocks/sts.ts | 4 ++-- apps/sim/components/icons.tsx | 18 ++++++++++++++++++ apps/sim/tools/sts/assume_role.ts | 2 +- apps/sim/tools/sts/get_access_key_info.ts | 2 +- apps/sim/tools/sts/get_caller_identity.ts | 2 +- apps/sim/tools/sts/get_session_token.ts | 2 +- 11 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 7508d0827cf..f2542de601d 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4643,6 +4643,24 @@ export function IAMIcon(props: SVGProps) { ) } +export function STSIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} + export function SecretsManagerIcon(props: SVGProps) { return ( diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 7104301a0aa..ef9d49a1141 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -164,6 +164,7 @@ import { SmtpIcon, SQSIcon, SshIcon, + STSIcon, STTIcon, StagehandIcon, StripeIcon, @@ -358,7 +359,7 @@ export const blockTypeToIconMap: Record = { ssh: SshIcon, stagehand: StagehandIcon, stripe: StripeIcon, - sts: IAMIcon, + sts: STSIcon, stt_v2: STTIcon, supabase: SupabaseIcon, tailscale: TailscaleIcon, diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 757fd936781..a64c4629993 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -2567,7 +2567,7 @@ "authType": "none", "category": "tools", "integrationTypes": ["security", "analytics", "developer-tools"], - "tags": ["identity", "monitoring"] + "tags": ["identity", "monitoring", "security"] }, { "type": "cursor_v2", diff --git a/apps/sim/app/api/tools/sts/assume-role/route.ts b/apps/sim/app/api/tools/sts/assume-role/route.ts index d572bed3edb..4903eb8e8e2 100644 --- a/apps/sim/app/api/tools/sts/assume-role/route.ts +++ b/apps/sim/app/api/tools/sts/assume-role/route.ts @@ -13,7 +13,7 @@ const AssumeRoleSchema = z.object({ secretAccessKey: z.string().min(1, 'AWS secret access key is required'), roleArn: z.string().min(1, 'Role ARN is required'), roleSessionName: z.string().min(1, 'Role session name is required'), - durationSeconds: z.number().nullish(), + durationSeconds: z.number().int().min(900).max(43200).nullish(), externalId: z.string().nullish(), serialNumber: z.string().nullish(), tokenCode: z.string().nullish(), diff --git a/apps/sim/app/api/tools/sts/get-session-token/route.ts b/apps/sim/app/api/tools/sts/get-session-token/route.ts index 098f154e340..05fb77bcb32 100644 --- a/apps/sim/app/api/tools/sts/get-session-token/route.ts +++ b/apps/sim/app/api/tools/sts/get-session-token/route.ts @@ -11,7 +11,7 @@ const GetSessionTokenSchema = z.object({ region: z.string().min(1, 'AWS region is required'), accessKeyId: z.string().min(1, 'AWS access key ID is required'), secretAccessKey: z.string().min(1, 'AWS secret access key is required'), - durationSeconds: z.number().nullish(), + durationSeconds: z.number().int().min(900).max(129600).nullish(), serialNumber: z.string().nullish(), tokenCode: z.string().nullish(), }) diff --git a/apps/sim/blocks/blocks/sts.ts b/apps/sim/blocks/blocks/sts.ts index 29497ea7fe7..2f7608010be 100644 --- a/apps/sim/blocks/blocks/sts.ts +++ b/apps/sim/blocks/blocks/sts.ts @@ -1,4 +1,4 @@ -import { IAMIcon } from '@/components/icons' +import { STSIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode, IntegrationType } from '@/blocks/types' import type { STSBaseResponse } from '@/tools/sts/types' @@ -15,7 +15,7 @@ export const STSBlock: BlockConfig = { tags: ['cloud'], authMode: AuthMode.ApiKey, bgColor: 'linear-gradient(45deg, #BD0816 0%, #FF5252 100%)', - icon: IAMIcon, + icon: STSIcon, subBlocks: [ { id: 'operation', diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 7508d0827cf..f2542de601d 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4643,6 +4643,24 @@ export function IAMIcon(props: SVGProps) { ) } +export function STSIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} + export function SecretsManagerIcon(props: SVGProps) { return ( diff --git a/apps/sim/tools/sts/assume_role.ts b/apps/sim/tools/sts/assume_role.ts index 608ffd4c7d7..838a911595f 100644 --- a/apps/sim/tools/sts/assume_role.ts +++ b/apps/sim/tools/sts/assume_role.ts @@ -5,7 +5,7 @@ export const assumeRoleTool: ToolConfig Date: Mon, 13 Apr 2026 16:26:42 -0700 Subject: [PATCH 3/4] icon --- apps/sim/app/(landing)/integrations/data/icon-mapping.ts | 3 ++- apps/sim/app/(landing)/integrations/data/integrations.json | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/(landing)/integrations/data/icon-mapping.ts b/apps/sim/app/(landing)/integrations/data/icon-mapping.ts index c30bb7431ed..1eb1d47659e 100644 --- a/apps/sim/app/(landing)/integrations/data/icon-mapping.ts +++ b/apps/sim/app/(landing)/integrations/data/icon-mapping.ts @@ -164,6 +164,7 @@ import { SmtpIcon, SQSIcon, SshIcon, + STSIcon, STTIcon, StagehandIcon, StripeIcon, @@ -358,7 +359,7 @@ export const blockTypeToIconMap: Record = { ssh: SshIcon, stagehand: StagehandIcon, stripe: StripeIcon, - sts: IAMIcon, + sts: STSIcon, stt_v2: STTIcon, supabase: SupabaseIcon, tailscale: TailscaleIcon, diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index a64c4629993..1903537dc19 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -1520,7 +1520,7 @@ "description": "Connect to AWS Security Token Service", "longDescription": "Integrate AWS STS into the workflow. Assume roles, get temporary credentials, verify caller identity, and look up access key information.", "bgColor": "linear-gradient(45deg, #BD0816 0%, #FF5252 100%)", - "iconName": "IAMIcon", + "iconName": "STSIcon", "docsUrl": "https://docs.sim.ai/tools/sts", "operations": [ { @@ -2567,7 +2567,7 @@ "authType": "none", "category": "tools", "integrationTypes": ["security", "analytics", "developer-tools"], - "tags": ["identity", "monitoring", "security"] + "tags": ["identity", "monitoring"] }, { "type": "cursor_v2", From 64acaa66b2fc1001ada864b908c7e151abb10661 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 16:29:52 -0700 Subject: [PATCH 4/4] lint --- apps/docs/components/icons.tsx | 2 +- apps/sim/components/icons.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index f2542de601d..bde3013c6a2 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4654,7 +4654,7 @@ export function STSIcon(props: SVGProps) { diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index f2542de601d..bde3013c6a2 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4654,7 +4654,7 @@ export function STSIcon(props: SVGProps) {