chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamAddUserToGroupContract } from '@/lib/api/contracts/tools/aws/iam-add-user-to-group'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { addUserToGroup, createIAMClient } from '../utils'
const logger = createLogger('IAMAddUserToGroupAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamAddUserToGroupContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to add user to group:`, error)
return NextResponse.json(
{ error: `Failed to add user to group: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamAttachRolePolicyContract } from '@/lib/api/contracts/tools/aws/iam-attach-role-policy'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { attachRolePolicy, createIAMClient } from '../utils'
const logger = createLogger('IAMAttachRolePolicyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamAttachRolePolicyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to attach role policy:`, error)
return NextResponse.json(
{ error: `Failed to attach role policy: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamAttachUserPolicyContract } from '@/lib/api/contracts/tools/aws/iam-attach-user-policy'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { attachUserPolicy, createIAMClient } from '../utils'
const logger = createLogger('IAMAttachUserPolicyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamAttachUserPolicyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to attach user policy:`, error)
return NextResponse.json(
{ error: `Failed to attach user policy: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,51 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamCreateAccessKeyContract } from '@/lib/api/contracts/tools/aws/iam-create-access-key'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createAccessKey, createIAMClient } from '../utils'
const logger = createLogger('IAMCreateAccessKeyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamCreateAccessKeyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to create access key:`, error)
return NextResponse.json(
{ error: `Failed to create access key: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,58 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamCreateRoleContract } from '@/lib/api/contracts/tools/aws/iam-create-role'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, createRole } from '../utils'
const logger = createLogger('IAMCreateRoleAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamCreateRoleContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully created IAM role "${result.roleName}"`)
return NextResponse.json({
message: `Role "${result.roleName}" created successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to create IAM role:`, error)
return NextResponse.json(
{ error: `Failed to create IAM role: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,51 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamCreateUserContract } from '@/lib/api/contracts/tools/aws/iam-create-user'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, createUser } from '../utils'
const logger = createLogger('IAMCreateUserAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamCreateUserContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully created IAM user "${result.userName}"`)
return NextResponse.json({
message: `User "${result.userName}" created successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to create IAM user:`, error)
return NextResponse.json(
{ error: `Failed to create IAM user: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamDeleteAccessKeyContract } from '@/lib/api/contracts/tools/aws/iam-delete-access-key'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, deleteAccessKey } from '../utils'
const logger = createLogger('IAMDeleteAccessKeyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamDeleteAccessKeyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully deleted access key "${params.accessKeyIdToDelete}"`)
return NextResponse.json({ message: `Access key "${params.accessKeyIdToDelete}" deleted` })
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to delete access key:`, error)
return NextResponse.json(
{ error: `Failed to delete access key: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamDeleteRoleContract } from '@/lib/api/contracts/tools/aws/iam-delete-role'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, deleteRole } from '../utils'
const logger = createLogger('IAMDeleteRoleAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamDeleteRoleContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully deleted IAM role "${params.roleName}"`)
return NextResponse.json({ message: `Role "${params.roleName}" deleted successfully` })
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to delete IAM role:`, error)
return NextResponse.json(
{ error: `Failed to delete IAM role: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamDeleteUserContract } from '@/lib/api/contracts/tools/aws/iam-delete-user'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, deleteUser } from '../utils'
const logger = createLogger('IAMDeleteUserAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamDeleteUserContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully deleted IAM user "${params.userName}"`)
return NextResponse.json({ message: `User "${params.userName}" deleted successfully` })
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to delete IAM user:`, error)
return NextResponse.json(
{ error: `Failed to delete IAM user: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamDetachRolePolicyContract } from '@/lib/api/contracts/tools/aws/iam-detach-role-policy'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, detachRolePolicy } from '../utils'
const logger = createLogger('IAMDetachRolePolicyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamDetachRolePolicyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to detach role policy:`, error)
return NextResponse.json(
{ error: `Failed to detach role policy: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamDetachUserPolicyContract } from '@/lib/api/contracts/tools/aws/iam-detach-user-policy'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, detachUserPolicy } from '../utils'
const logger = createLogger('IAMDetachUserPolicyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamDetachUserPolicyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to detach user policy:`, error)
return NextResponse.json(
{ error: `Failed to detach user policy: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamGetRoleContract } from '@/lib/api/contracts/tools/aws/iam-get-role'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, getRole } from '../utils'
const logger = createLogger('IAMGetRoleAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamGetRoleContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully retrieved IAM role "${params.roleName}"`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to get IAM role:`, error)
return NextResponse.json(
{ error: `Failed to get IAM role: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamGetUserContract } from '@/lib/api/contracts/tools/aws/iam-get-user'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, getUser } from '../utils'
const logger = createLogger('IAMGetUserAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamGetUserContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully retrieved IAM user "${params.userName ?? 'caller'}"`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to get IAM user:`, error)
return NextResponse.json(
{ error: `Failed to get IAM user: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,54 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamListAttachedRolePoliciesContract } from '@/lib/api/contracts/tools/aws/iam-list-attached-role-policies'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, listAttachedRolePolicies } from '../utils'
const logger = createLogger('IAMListAttachedRolePoliciesAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamListAttachedRolePoliciesContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Listing policies attached to IAM role "${params.roleName}"`)
const client = createIAMClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await listAttachedRolePolicies(
client,
params.roleName,
params.pathPrefix,
params.maxItems,
params.marker
)
logger.info(`Found ${result.count} policies attached to role "${params.roleName}"`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to list attached role policies:`, error)
return NextResponse.json(
{ error: `Failed to list attached role policies: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,54 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamListAttachedUserPoliciesContract } from '@/lib/api/contracts/tools/aws/iam-list-attached-user-policies'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, listAttachedUserPolicies } from '../utils'
const logger = createLogger('IAMListAttachedUserPoliciesAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamListAttachedUserPoliciesContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Listing policies attached to IAM user "${params.userName}"`)
const client = createIAMClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await listAttachedUserPolicies(
client,
params.userName,
params.pathPrefix,
params.maxItems,
params.marker
)
logger.info(`Found ${result.count} policies attached to user "${params.userName}"`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to list attached user policies:`, error)
return NextResponse.json(
{ error: `Failed to list attached user policies: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamListGroupsContract } from '@/lib/api/contracts/tools/aws/iam-list-groups'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, listGroups } from '../utils'
const logger = createLogger('IAMListGroupsAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamListGroupsContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully listed ${result.count} IAM groups`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to list IAM groups:`, error)
return NextResponse.json(
{ error: `Failed to list IAM groups: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,55 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamListPoliciesContract } from '@/lib/api/contracts/tools/aws/iam-list-policies'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, listPolicies } from '../utils'
const logger = createLogger('IAMListPoliciesAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamListPoliciesContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully listed ${result.count} IAM policies`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to list IAM policies:`, error)
return NextResponse.json(
{ error: `Failed to list IAM policies: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamListRolesContract } from '@/lib/api/contracts/tools/aws/iam-list-roles'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, listRoles } from '../utils'
const logger = createLogger('IAMListRolesAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamListRolesContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully listed ${result.count} IAM roles`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to list IAM roles:`, error)
return NextResponse.json(
{ error: `Failed to list IAM roles: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamListUsersContract } from '@/lib/api/contracts/tools/aws/iam-list-users'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, listUsers } from '../utils'
const logger = createLogger('IAMListUsersAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamListUsersContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`Successfully listed ${result.count} IAM users`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to list IAM users:`, error)
return NextResponse.json(
{ error: `Failed to list IAM users: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamRemoveUserFromGroupContract } from '@/lib/api/contracts/tools/aws/iam-remove-user-from-group'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, removeUserFromGroup } from '../utils'
const logger = createLogger('IAMRemoveUserFromGroupAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamRemoveUserFromGroupContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`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(`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) {
logger.error(`Failed to remove user from group:`, error)
return NextResponse.json(
{ error: `Failed to remove user from group: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,57 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIamSimulatePrincipalPolicyContract } from '@/lib/api/contracts/tools/aws/iam-simulate-principal-policy'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIAMClient, simulatePrincipalPolicy } from '../utils'
const logger = createLogger('IAMSimulatePrincipalPolicyAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIamSimulatePrincipalPolicyContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(
`Simulating principal policy for "${params.policySourceArn}" on actions: ${params.actionNames}`
)
const client = createIAMClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await simulatePrincipalPolicy(
client,
params.policySourceArn,
params.actionNames,
params.resourceArns,
params.maxResults,
params.marker
)
logger.info(`Simulation complete: ${result.count} results`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error(`Failed to simulate principal policy:`, error)
return NextResponse.json(
{ error: `Failed to simulate principal policy: ${toError(error).message}` },
{ status: 500 }
)
}
})
+453
View File
@@ -0,0 +1,453 @@
import type {
AttachedPolicy,
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,
ListAttachedRolePoliciesCommand,
ListAttachedUserPoliciesCommand,
ListGroupsCommand,
ListPoliciesCommand,
ListRolesCommand,
ListUsersCommand,
RemoveUserFromGroupCommand,
SimulatePrincipalPolicyCommand,
} 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 | null) {
const command = new GetUserCommand(userName ? { 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)
}
export async function listAttachedRolePolicies(
client: IAMClient,
roleName: string,
pathPrefix?: string | null,
maxItems?: number | null,
marker?: string | null
) {
const command = new ListAttachedRolePoliciesCommand({
RoleName: roleName,
...(pathPrefix ? { PathPrefix: pathPrefix } : {}),
...(maxItems ? { MaxItems: maxItems } : {}),
...(marker ? { Marker: marker } : {}),
})
const response = await client.send(command)
const attachedPolicies = (response.AttachedPolicies ?? []).map((p: AttachedPolicy) => ({
policyName: p.PolicyName ?? '',
policyArn: p.PolicyArn ?? '',
}))
return {
attachedPolicies,
isTruncated: response.IsTruncated ?? false,
marker: response.Marker ?? null,
count: attachedPolicies.length,
}
}
export async function listAttachedUserPolicies(
client: IAMClient,
userName: string,
pathPrefix?: string | null,
maxItems?: number | null,
marker?: string | null
) {
const command = new ListAttachedUserPoliciesCommand({
UserName: userName,
...(pathPrefix ? { PathPrefix: pathPrefix } : {}),
...(maxItems ? { MaxItems: maxItems } : {}),
...(marker ? { Marker: marker } : {}),
})
const response = await client.send(command)
const attachedPolicies = (response.AttachedPolicies ?? []).map((p: AttachedPolicy) => ({
policyName: p.PolicyName ?? '',
policyArn: p.PolicyArn ?? '',
}))
return {
attachedPolicies,
isTruncated: response.IsTruncated ?? false,
marker: response.Marker ?? null,
count: attachedPolicies.length,
}
}
export async function simulatePrincipalPolicy(
client: IAMClient,
policySourceArn: string,
actionNames: string,
resourceArns?: string | null,
maxResults?: number | null,
marker?: string | null
) {
const actions = actionNames
.split(',')
.map((a) => a.trim())
.filter(Boolean)
const resources = resourceArns
? resourceArns
.split(',')
.map((r) => r.trim())
.filter(Boolean)
: ['*']
const command = new SimulatePrincipalPolicyCommand({
PolicySourceArn: policySourceArn,
ActionNames: actions,
ResourceArns: resources,
...(maxResults ? { MaxItems: maxResults } : {}),
...(marker ? { Marker: marker } : {}),
})
const response = await client.send(command)
const evaluationResults = (response.EvaluationResults ?? []).map((r) => ({
evalActionName: r.EvalActionName ?? '',
evalResourceName: r.EvalResourceName ?? '',
evalDecision: r.EvalDecision ?? '',
matchedStatements: (r.MatchedStatements ?? []).map((s) => ({
sourcePolicyId: s.SourcePolicyId ?? '',
sourcePolicyType: s.SourcePolicyType ?? '',
})),
missingContextValues: (r.MissingContextValues ?? []).map((v) => String(v)),
}))
return {
evaluationResults,
isTruncated: response.IsTruncated ?? false,
marker: response.Marker ?? null,
count: evaluationResults.length,
}
}