@aws/nx-plugin 1.0.0-rc.44 → 1.0.0-rc.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/generators.json +6 -0
  2. package/package.json +1 -1
  3. package/src/agentcore-gateway/files/cedar/policies/README.md +9 -0
  4. package/src/agentcore-gateway/files/cedar/policies/permit-all.cedar +15 -0
  5. package/src/agentcore-gateway/generator.js +12 -5
  6. package/src/agentcore-gateway/generator.js.map +1 -1
  7. package/src/agentcore-gateway/schema.d.js.map +1 -1
  8. package/src/agentcore-gateway/schema.d.ts +1 -1
  9. package/src/agentcore-gateway/schema.json +3 -2
  10. package/src/mcp-server/tools/general-guidance.js +1 -1
  11. package/src/mcp-server/tools/general-guidance.js.map +1 -1
  12. package/src/preset/__snapshots__/generator.spec.ts.snap +5 -2
  13. package/src/py/agent/gateway-connection/generator.js +1 -1
  14. package/src/py/agent/gateway-connection/generator.js.map +1 -1
  15. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +16 -0
  16. package/src/py/rdb/files/Dockerfile.create-db-user.template +4 -0
  17. package/src/py/rdb/files/Dockerfile.migration.template +4 -0
  18. package/src/sdk/ts.d.ts +2 -0
  19. package/src/sdk/ts.js +2 -0
  20. package/src/sdk/ts.js.map +1 -1
  21. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +5 -1
  22. package/src/ts/agent/files/deploy/Dockerfile.template +5 -1
  23. package/src/ts/agent/gateway-connection/generator.js +1 -1
  24. package/src/ts/agent/gateway-connection/generator.js.map +1 -1
  25. package/src/ts/agent/generator.js +6 -0
  26. package/src/ts/agent/generator.js.map +1 -1
  27. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +982 -0
  28. package/src/ts/dcr-proxy/generator.d.ts +10 -0
  29. package/src/ts/dcr-proxy/generator.js +98 -0
  30. package/src/ts/dcr-proxy/generator.js.map +1 -0
  31. package/src/ts/dcr-proxy/schema.d.js +6 -0
  32. package/src/ts/dcr-proxy/schema.d.js.map +1 -0
  33. package/src/ts/dcr-proxy/schema.d.ts +13 -0
  34. package/src/ts/dcr-proxy/schema.json +44 -0
  35. package/src/ts/mcp-server/files/Dockerfile.template +5 -1
  36. package/src/ts/mcp-server/generator.js +1 -0
  37. package/src/ts/mcp-server/generator.js.map +1 -1
  38. package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +2 -2
  39. package/src/ts/nx-plugin/files/mcp-server/resources/GENERAL_GUIDANCE.md.template +1 -1
  40. package/src/ts/nx-plugin/files/mcp-server/utils.ts.template +1 -1
  41. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +7 -0
  42. package/src/ts/rdb/files/Dockerfile.template +7 -0
  43. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +4 -4
  44. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +1 -0
  45. package/src/utils/agent-core-constructs/agent-core-constructs.js +2 -0
  46. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  47. package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +38 -3
  48. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +13 -3
  49. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +22 -1
  50. package/src/utils/commands.js +1 -1
  51. package/src/utils/commands.js.map +1 -1
  52. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.d.ts +38 -0
  53. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js +93 -0
  54. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js.map +1 -0
  55. package/src/utils/dcr-proxy-constructs/files/cdk/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.ts.template +227 -0
  56. package/src/utils/dcr-proxy-constructs/files/project/src/handlers/authorization-server-metadata.ts.template +39 -0
  57. package/src/utils/dcr-proxy-constructs/files/project/src/handlers/authorize.ts.template +26 -0
  58. package/src/utils/dcr-proxy-constructs/files/project/src/handlers/mcp-proxy.ts.template +89 -0
  59. package/src/utils/dcr-proxy-constructs/files/project/src/handlers/protected-resource-metadata.ts.template +13 -0
  60. package/src/utils/dcr-proxy-constructs/files/project/src/handlers/register.ts.template +70 -0
  61. package/src/utils/dcr-proxy-constructs/files/project/src/handlers/token.ts.template +75 -0
  62. package/src/utils/dcr-proxy-constructs/files/terraform/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.tf.template +410 -0
  63. package/src/utils/docker.d.ts +4 -3
  64. package/src/utils/docker.js +11 -7
  65. package/src/utils/docker.js.map +1 -1
  66. package/src/utils/format.d.ts +1 -1
  67. package/src/utils/format.js +3 -2
  68. package/src/utils/format.js.map +1 -1
  69. package/src/utils/init.js +4 -0
  70. package/src/utils/init.js.map +1 -1
  71. package/src/utils/versions.d.ts +3 -1
  72. package/src/utils/versions.js +4 -0
  73. package/src/utils/versions.js.map +1 -1
@@ -0,0 +1,13 @@
1
+ import type { APIGatewayProxyHandlerV2 } from 'aws-lambda';
2
+
3
+ export const handler: APIGatewayProxyHandlerV2 = async (event) => {
4
+ const proxyUrl = `https://${event.requestContext.domainName}`;
5
+ return {
6
+ statusCode: 200,
7
+ headers: { 'content-type': 'application/json' },
8
+ body: JSON.stringify({
9
+ resource: `${proxyUrl}/mcp`,
10
+ authorization_servers: [proxyUrl],
11
+ }),
12
+ };
13
+ };
@@ -0,0 +1,70 @@
1
+ import type {
2
+ APIGatewayProxyHandlerV2,
3
+ APIGatewayProxyStructuredResultV2,
4
+ } from 'aws-lambda';
5
+
6
+ const COGNITO_CLIENT_ID = process.env.COGNITO_CLIENT_ID!;
7
+
8
+ interface RegisterRequest {
9
+ redirect_uris?: unknown;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ function jsonResponse(
14
+ statusCode: number,
15
+ body: unknown,
16
+ ): APIGatewayProxyStructuredResultV2 {
17
+ return {
18
+ statusCode,
19
+ headers: { 'content-type': 'application/json' },
20
+ body: JSON.stringify(body),
21
+ };
22
+ }
23
+
24
+ export const handler: APIGatewayProxyHandlerV2 = async (event) => {
25
+ if (!event.body) {
26
+ return jsonResponse(400, {
27
+ error: 'invalid_client_metadata',
28
+ error_description: 'request body is required',
29
+ });
30
+ }
31
+
32
+ let req: RegisterRequest;
33
+ try {
34
+ req = JSON.parse(event.body) as RegisterRequest;
35
+ } catch {
36
+ return jsonResponse(400, {
37
+ error: 'invalid_client_metadata',
38
+ error_description: 'request body must be valid JSON',
39
+ });
40
+ }
41
+
42
+ const redirectUris = req.redirect_uris;
43
+ if (!Array.isArray(redirectUris) || redirectUris.length === 0) {
44
+ return jsonResponse(400, {
45
+ error: 'invalid_redirect_uri',
46
+ error_description: 'redirect_uris is required and must be a non-empty array',
47
+ });
48
+ }
49
+
50
+ // The proxy fronts a single Cognito App Client, so Cognito performs the
51
+ // authoritative check: any redirect_uri forwarded to the Hosted UI must be
52
+ // registered as a callback URL on that App Client. The proxy only validates
53
+ // the request shape here and passes the URIs through unchanged.
54
+ for (const uri of redirectUris) {
55
+ if (typeof uri !== 'string') {
56
+ return jsonResponse(400, {
57
+ error: 'invalid_redirect_uri',
58
+ error_description: 'each redirect_uri must be a string',
59
+ });
60
+ }
61
+ }
62
+
63
+ return jsonResponse(201, {
64
+ client_id: COGNITO_CLIENT_ID,
65
+ redirect_uris: redirectUris,
66
+ token_endpoint_auth_method: 'none',
67
+ grant_types: ['authorization_code', 'refresh_token'],
68
+ response_types: ['code'],
69
+ });
70
+ };
@@ -0,0 +1,75 @@
1
+ import type { APIGatewayProxyHandlerV2 } from 'aws-lambda';
2
+ import {
3
+ SecretsManagerClient,
4
+ GetSecretValueCommand,
5
+ } from '@aws-sdk/client-secrets-manager';
6
+
7
+ const COGNITO_HOSTED_UI_BASE = process.env.COGNITO_HOSTED_UI_BASE!;
8
+ const COGNITO_CLIENT_ID = process.env.COGNITO_CLIENT_ID!;
9
+ const COGNITO_CLIENT_SECRET_ARN = process.env.COGNITO_CLIENT_SECRET_ARN!;
10
+ const COGNITO_REGION = process.env.COGNITO_REGION!;
11
+
12
+ const sm = new SecretsManagerClient({ region: COGNITO_REGION });
13
+ let cachedSecret: string | undefined;
14
+
15
+ async function getClientSecret(): Promise<string> {
16
+ if (cachedSecret) return cachedSecret;
17
+ const res = await sm.send(
18
+ new GetSecretValueCommand({ SecretId: COGNITO_CLIENT_SECRET_ARN }),
19
+ );
20
+ if (!res.SecretString) {
21
+ throw new Error('client_secret missing in Secrets Manager');
22
+ }
23
+ cachedSecret = res.SecretString;
24
+ return cachedSecret;
25
+ }
26
+
27
+ export const handler: APIGatewayProxyHandlerV2 = async (event) => {
28
+ if (!event.body) {
29
+ return {
30
+ statusCode: 400,
31
+ headers: { 'content-type': 'application/json' },
32
+ body: JSON.stringify({
33
+ error: 'invalid_request',
34
+ error_description: 'request body is required',
35
+ }),
36
+ };
37
+ }
38
+
39
+ const rawBody = event.isBase64Encoded
40
+ ? Buffer.from(event.body, 'base64').toString('utf-8')
41
+ : event.body;
42
+
43
+ const params = new URLSearchParams(rawBody);
44
+
45
+ // Always force the real Cognito client_id and inject the server-side secret.
46
+ // DCR returned the same client_id to every caller, but we re-assert here
47
+ // to keep client_id/secret consistent regardless of what the caller sent.
48
+ params.set('client_id', COGNITO_CLIENT_ID);
49
+ params.set('client_secret', await getClientSecret());
50
+
51
+ // Cognito does not understand RFC 8707 `resource`; some MCP clients send it
52
+ // and Cognito has been observed to reject the exchange when present.
53
+ params.delete('resource');
54
+
55
+ const res = await fetch(`${COGNITO_HOSTED_UI_BASE}/oauth2/token`, {
56
+ method: 'POST',
57
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
58
+ body: params.toString(),
59
+ });
60
+
61
+ const responseBody = await res.text();
62
+ console.log('[token]', {
63
+ grant_type: params.get('grant_type'),
64
+ status: res.status,
65
+ ...(res.ok ? {} : { body: responseBody }),
66
+ });
67
+
68
+ return {
69
+ statusCode: res.status,
70
+ headers: {
71
+ 'content-type': res.headers.get('content-type') ?? 'application/json',
72
+ },
73
+ body: responseBody,
74
+ };
75
+ };
@@ -0,0 +1,410 @@
1
+ # OAuth Dynamic Client Registration (DCR) proxy for Amazon Cognito.
2
+ #
3
+ # Lets MCP clients (Claude Code, Kiro CLI, MCP Inspector, ...) authenticate
4
+ # against an Amazon Cognito User Pool while keeping the Hosted UI flow intact,
5
+ # supporting RFC 7591 Dynamic Client Registration, and never exposing the
6
+ # Cognito App Client secret to the client.
7
+
8
+ terraform {
9
+ required_providers {
10
+ aws = {
11
+ source = "hashicorp/aws"
12
+ version = "<%- awsProviderVersion %>"
13
+ }
14
+ archive = {
15
+ source = "hashicorp/archive"
16
+ version = "<%- archiveProviderVersion %>"
17
+ }
18
+ }
19
+ }
20
+
21
+ # Cognito configuration (injected by the caller)
22
+ variable "user_pool_id" {
23
+ description = "Cognito User Pool id (e.g. us-east-1_abc123)"
24
+ type = string
25
+ }
26
+
27
+ variable "user_pool_client_id" {
28
+ description = "Cognito User Pool App Client id"
29
+ type = string
30
+ }
31
+
32
+ variable "cognito_client_secret_arn" {
33
+ description = "ARN of the Secrets Manager secret holding the Cognito App Client secret. The token handler reads this at runtime; the secret is never exposed to the client."
34
+ type = string
35
+ }
36
+
37
+ variable "cognito_hosted_ui_base" {
38
+ description = "Base URL of the Cognito Hosted UI domain, without a trailing slash (e.g. https://my-domain.auth.us-east-1.amazoncognito.com)"
39
+ type = string
40
+ }
41
+
42
+ variable "upstream_url" {
43
+ description = "Full URL of the upstream MCP server. The proxy forwards /mcp requests to this URL and rewrites the upstream WWW-Authenticate header."
44
+ type = string
45
+ }
46
+
47
+ variable "env" {
48
+ description = "Additional environment variables applied to all proxy Lambda functions"
49
+ type = map(string)
50
+ default = {}
51
+ }
52
+
53
+ # CORS Configuration (passed to the core http-api module)
54
+ variable "cors_allow_headers" {
55
+ description = "List of allowed headers for CORS"
56
+ type = list(string)
57
+ default = ["authorization", "content-type", "mcp-protocol-version"]
58
+ }
59
+
60
+ variable "cors_allow_methods" {
61
+ description = "List of allowed HTTP methods for CORS"
62
+ type = list(string)
63
+ default = ["GET", "POST", "DELETE", "OPTIONS"]
64
+ }
65
+
66
+ variable "cors_allow_origins" {
67
+ description = "List of allowed origins for CORS"
68
+ type = list(string)
69
+ default = ["*"]
70
+ }
71
+
72
+ variable "asset_bucket_name" {
73
+ description = "Name of the shared asset S3 bucket used to stage the Lambda deployment zips. Instantiate the `core/asset-bucket` module once per deployment and pass its `bucket_name` output here."
74
+ type = string
75
+ }
76
+
77
+ variable "mcp_proxy_timeout" {
78
+ description = "Timeout (seconds) applied to the MCP proxy Lambda. Defaults to 29 (the API Gateway HTTP API integration limit)."
79
+ type = number
80
+ default = 29
81
+ }
82
+
83
+ variable "mcp_proxy_memory_size" {
84
+ description = "Memory size (MB) for the MCP proxy Lambda"
85
+ type = number
86
+ default = 512
87
+ }
88
+
89
+ variable "tags" {
90
+ description = "Tags to apply to all resources"
91
+ type = map(string)
92
+ default = {}
93
+ }
94
+
95
+ data "aws_region" "current" {}
96
+ data "aws_caller_identity" "current" {}
97
+
98
+ # The Cognito App Client secret, referenced by ARN so the token handler's role
99
+ # can be scoped to read exactly this secret.
100
+ data "aws_secretsmanager_secret" "cognito_client_secret" {
101
+ arn = var.cognito_client_secret_arn
102
+ }
103
+
104
+ resource "random_string" "suffix" {
105
+ length = 8
106
+ special = false
107
+ upper = false
108
+ }
109
+
110
+ locals {
111
+ aws_account_id = data.aws_caller_identity.current.account_id
112
+ aws_region = data.aws_region.current.region
113
+
114
+ base_env = merge({
115
+ COGNITO_CLIENT_ID = var.user_pool_client_id
116
+ COGNITO_CLIENT_SECRET_ARN = var.cognito_client_secret_arn
117
+ COGNITO_ISSUER = "https://cognito-idp.${local.aws_region}.amazonaws.com/${var.user_pool_id}"
118
+ COGNITO_HOSTED_UI_BASE = var.cognito_hosted_ui_base
119
+ COGNITO_REGION = local.aws_region
120
+ }, var.env)
121
+
122
+ # Workspace-root-relative bundle output directory per handler
123
+ handler_bundle_dirs = {
124
+ "protected-resource-metadata" = "<%- bundlePathsFromRoot['protected-resource-metadata'] %>"
125
+ "authorization-server-metadata" = "<%- bundlePathsFromRoot['authorization-server-metadata'] %>"
126
+ "register" = "<%- bundlePathsFromRoot['register'] %>"
127
+ "authorize" = "<%- bundlePathsFromRoot['authorize'] %>"
128
+ "token" = "<%- bundlePathsFromRoot['token'] %>" #checkov:skip=CKV_SECRET_6:Value is a Lambda bundle output path, not a secret
129
+ "mcp-proxy" = "<%- bundlePathsFromRoot['mcp-proxy'] %>"
130
+ }
131
+
132
+ # Handlers deployed with the standard configuration (timeout 10s, mem 256).
133
+ # mcp-proxy is deployed separately since its env/timeout/memory differ.
134
+ standard_handlers = {
135
+ for name, dir in local.handler_bundle_dirs : name => dir if name != "mcp-proxy"
136
+ }
137
+ }
138
+
139
+ # Package each handler's rolldown bundle into a deployment zip
140
+ data "archive_file" "handler_zip" {
141
+ for_each = local.handler_bundle_dirs
142
+
143
+ type = "zip"
144
+ source_dir = "${path.module}/../../../../../../../${each.value}"
145
+ output_path = "${path.module}/../../../../../../../dist/packages/common/terraform/dcr-proxies/<%- nameKebabCase %>/${each.key}/lambda.zip"
146
+ }
147
+
148
+ resource "aws_s3_object" "handler_zip" {
149
+ for_each = local.handler_bundle_dirs
150
+
151
+ bucket = var.asset_bucket_name
152
+ key = "dcr-proxies/<%- nameKebabCase %>/${each.key}/${data.archive_file.handler_zip[each.key].output_sha256}.zip"
153
+ source = data.archive_file.handler_zip[each.key].output_path
154
+ source_hash = data.archive_file.handler_zip[each.key].output_base64sha256
155
+ etag = data.archive_file.handler_zip[each.key].output_md5
156
+ }
157
+
158
+ # Shared execution role for handlers that do not read the client secret
159
+ resource "aws_iam_role" "proxy" {
160
+ name = "<%- nameKebabCase %>-proxy-${random_string.suffix.result}"
161
+
162
+ assume_role_policy = jsonencode({
163
+ Version = "2012-10-17"
164
+ Statement = [{
165
+ Effect = "Allow"
166
+ Principal = { Service = "lambda.amazonaws.com" }
167
+ Action = "sts:AssumeRole"
168
+ }]
169
+ })
170
+
171
+ tags = var.tags
172
+ }
173
+
174
+ # Dedicated role for the token handler, additionally granted read access to the
175
+ # Cognito App Client secret only.
176
+ resource "aws_iam_role" "token" {
177
+ name = "<%- nameKebabCase %>-token-${random_string.suffix.result}"
178
+
179
+ assume_role_policy = jsonencode({
180
+ Version = "2012-10-17"
181
+ Statement = [{
182
+ Effect = "Allow"
183
+ Principal = { Service = "lambda.amazonaws.com" }
184
+ Action = "sts:AssumeRole"
185
+ }]
186
+ })
187
+
188
+ tags = var.tags
189
+ }
190
+
191
+ resource "aws_iam_role_policy_attachment" "proxy_basic" {
192
+ role = aws_iam_role.proxy.name
193
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
194
+ }
195
+
196
+ resource "aws_iam_role_policy_attachment" "proxy_xray" {
197
+ role = aws_iam_role.proxy.name
198
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
199
+ }
200
+
201
+ resource "aws_iam_role_policy_attachment" "token_basic" {
202
+ role = aws_iam_role.token.name
203
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
204
+ }
205
+
206
+ resource "aws_iam_role_policy_attachment" "token_xray" {
207
+ role = aws_iam_role.token.name
208
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
209
+ }
210
+
211
+ resource "aws_iam_role_policy" "token_secret_read" {
212
+ name = "<%- nameKebabCase %>-token-secret-read-${random_string.suffix.result}"
213
+ role = aws_iam_role.token.id
214
+
215
+ policy = jsonencode({
216
+ Version = "2012-10-17"
217
+ Statement = [{
218
+ Effect = "Allow"
219
+ Action = ["secretsmanager:GetSecretValue"]
220
+ Resource = [data.aws_secretsmanager_secret.cognito_client_secret.arn]
221
+ }]
222
+ })
223
+ }
224
+
225
+ # Standard handler Lambda functions
226
+ resource "aws_lambda_function" "standard" {
227
+ #checkov:skip=CKV_AWS_117:Lambda does not need to be in a VPC for this use case
228
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this use case
229
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
230
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
231
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
232
+ for_each = local.standard_handlers
233
+
234
+ s3_bucket = aws_s3_object.handler_zip[each.key].bucket
235
+ s3_key = aws_s3_object.handler_zip[each.key].key
236
+ function_name = "<%- nameKebabCase %>-${each.key}-${random_string.suffix.result}"
237
+ role = each.key == "token" ? aws_iam_role.token.arn : aws_iam_role.proxy.arn
238
+ handler = "index.handler"
239
+ runtime = "nodejs22.x"
240
+ architectures = ["arm64"]
241
+ source_code_hash = data.archive_file.handler_zip[each.key].output_base64sha256
242
+ timeout = 10
243
+ memory_size = 256
244
+
245
+ tracing_config {
246
+ mode = "Active"
247
+ }
248
+
249
+ environment {
250
+ variables = local.base_env
251
+ }
252
+
253
+ tags = var.tags
254
+ }
255
+
256
+ # MCP proxy Lambda function (extended env, timeout and memory)
257
+ resource "aws_lambda_function" "mcp_proxy" {
258
+ #checkov:skip=CKV_AWS_117:Lambda does not need to be in a VPC for this use case
259
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this use case
260
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
261
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
262
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
263
+ s3_bucket = aws_s3_object.handler_zip["mcp-proxy"].bucket
264
+ s3_key = aws_s3_object.handler_zip["mcp-proxy"].key
265
+ function_name = "<%- nameKebabCase %>-mcp-proxy-${random_string.suffix.result}"
266
+ role = aws_iam_role.proxy.arn
267
+ handler = "index.handler"
268
+ runtime = "nodejs22.x"
269
+ architectures = ["arm64"]
270
+ source_code_hash = data.archive_file.handler_zip["mcp-proxy"].output_base64sha256
271
+ timeout = var.mcp_proxy_timeout
272
+ memory_size = var.mcp_proxy_memory_size
273
+
274
+ tracing_config {
275
+ mode = "Active"
276
+ }
277
+
278
+ environment {
279
+ variables = merge(local.base_env, {
280
+ UPSTREAM_URL = var.upstream_url
281
+ PROXY_METADATA_URL = "${module.http_api.api_endpoint}/.well-known/oauth-protected-resource"
282
+ })
283
+ }
284
+
285
+ tags = var.tags
286
+ }
287
+
288
+ # HTTP API Gateway (shared core module)
289
+ module "http_api" {
290
+ source = "../../../core/api/http-api"
291
+
292
+ api_name = "<%- nameKebabCase %>-mcp-auth-proxy-${random_string.suffix.result}"
293
+ api_description = "MCP-compatible OAuth proxy for Amazon Cognito"
294
+ stage_name = "$default"
295
+ stage_auto_deploy = true
296
+ cors_allow_headers = var.cors_allow_headers
297
+ cors_allow_methods = var.cors_allow_methods
298
+ cors_allow_origins = var.cors_allow_origins
299
+
300
+ tags = var.tags
301
+ }
302
+
303
+ # Integrations
304
+ resource "aws_apigatewayv2_integration" "standard" {
305
+ for_each = local.standard_handlers
306
+
307
+ api_id = module.http_api.api_id
308
+ integration_type = "AWS_PROXY"
309
+ integration_uri = aws_lambda_function.standard[each.key].invoke_arn
310
+ payload_format_version = "2.0"
311
+ timeout_milliseconds = 30000
312
+ }
313
+
314
+ resource "aws_apigatewayv2_integration" "mcp_proxy" {
315
+ api_id = module.http_api.api_id
316
+ integration_type = "AWS_PROXY"
317
+ integration_uri = aws_lambda_function.mcp_proxy.invoke_arn
318
+ payload_format_version = "2.0"
319
+ timeout_milliseconds = 29000
320
+ }
321
+
322
+ # Routes. jwks_uri/issuer are handled by Cognito; the proxy hosts the OAuth
323
+ # metadata, authorize, token and registration endpoints plus the /mcp proxy.
324
+ locals {
325
+ routes = {
326
+ "GET /.well-known/oauth-protected-resource" = "protected-resource-metadata"
327
+ "GET /.well-known/oauth-authorization-server" = "authorization-server-metadata"
328
+ "GET /.well-known/openid-configuration" = "authorization-server-metadata"
329
+ "POST /register" = "register"
330
+ "GET /authorize" = "authorize"
331
+ "POST /oauth/token" = "token"
332
+ }
333
+ }
334
+
335
+ # OAuth discovery, registration and authorization endpoints are part of the
336
+ # public DCR/OAuth flow and must be reachable without prior authorization.
337
+ resource "aws_apigatewayv2_route" "standard" {
338
+ #checkov:skip=CKV_AWS_309:Public OAuth/DCR endpoints must be accessible without authorization
339
+ for_each = local.routes
340
+
341
+ api_id = module.http_api.api_id
342
+ route_key = each.key
343
+ target = "integrations/${aws_apigatewayv2_integration.standard[each.value].id}"
344
+ authorization_type = "NONE"
345
+ }
346
+
347
+ # The /mcp route enforces authorization at the upstream MCP server, so the
348
+ # proxy route itself is intentionally left open.
349
+ resource "aws_apigatewayv2_route" "mcp_proxy" {
350
+ #checkov:skip=CKV_AWS_309:Authorization is enforced by the upstream MCP server, not this proxy route
351
+ api_id = module.http_api.api_id
352
+ route_key = "ANY /mcp"
353
+ target = "integrations/${aws_apigatewayv2_integration.mcp_proxy.id}"
354
+ authorization_type = "NONE"
355
+ }
356
+
357
+ # Permissions for API Gateway to invoke each Lambda
358
+ resource "aws_lambda_permission" "standard" {
359
+ for_each = local.standard_handlers
360
+
361
+ statement_id = "AllowAPIGatewayInvoke"
362
+ action = "lambda:InvokeFunction"
363
+ function_name = aws_lambda_function.standard[each.key].function_name
364
+ principal = "apigateway.amazonaws.com"
365
+ source_arn = "${module.http_api.api_execution_arn}/*/*"
366
+ }
367
+
368
+ resource "aws_lambda_permission" "mcp_proxy" {
369
+ statement_id = "AllowAPIGatewayInvoke"
370
+ action = "lambda:InvokeFunction"
371
+ function_name = aws_lambda_function.mcp_proxy.function_name
372
+ principal = "apigateway.amazonaws.com"
373
+ source_arn = "${module.http_api.api_execution_arn}/*/*"
374
+ }
375
+
376
+ # Outputs
377
+ output "proxy_url" {
378
+ description = "Base URL of the DCR proxy"
379
+ value = module.http_api.api_endpoint
380
+ }
381
+
382
+ output "mcp_url" {
383
+ description = "MCP endpoint proxied to the upstream server"
384
+ value = "${module.http_api.api_endpoint}/mcp"
385
+ }
386
+
387
+ output "metadata_url" {
388
+ description = "OAuth protected-resource metadata URL"
389
+ value = "${module.http_api.api_endpoint}/.well-known/oauth-protected-resource"
390
+ }
391
+
392
+ output "auth_server_metadata_url" {
393
+ description = "OAuth authorization-server metadata URL"
394
+ value = "${module.http_api.api_endpoint}/.well-known/oauth-authorization-server"
395
+ }
396
+
397
+ output "token_endpoint" {
398
+ description = "OAuth token endpoint"
399
+ value = "${module.http_api.api_endpoint}/oauth/token"
400
+ }
401
+
402
+ output "registration_endpoint" {
403
+ description = "Dynamic Client Registration endpoint"
404
+ value = "${module.http_api.api_endpoint}/register"
405
+ }
406
+
407
+ output "api_id" {
408
+ description = "ID of the HTTP API Gateway"
409
+ value = module.http_api.api_id
410
+ }
@@ -27,8 +27,9 @@ export interface DockerScanTargetOptions {
27
27
  readonly imageTags: string[];
28
28
  }
29
29
  /**
30
- * Add a cacheable Trivy scan target for the images built by a docker target,
31
- * wire it under the aggregate \`trivy\` target, and make \`build\` depend on it.
30
+ * Add a cacheable Trivy scan target for the images built by a docker target
31
+ * and wire it under the aggregate \`trivy\` target. The scan is not part of
32
+ * \`build\` — run \`nx run-many --target trivy\` (the root \`trivy\` script) in CI.
32
33
  *
33
34
  * The scan target depends on the docker target and declares the project source
34
35
  * as its inputs, so an unchanged image is never re-scanned (a cache hit skips
@@ -36,7 +37,7 @@ export interface DockerScanTargetOptions {
36
37
  * \`dist/<projectRoot>/trivy/<scan-key>\` (kept out of any Docker build context)
37
38
  * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative
38
39
  * bind mount, so the same commands work under both docker and finch. The scan
39
- * fails the build (exit code 1) on HIGH/CRITICAL vulnerabilities.
40
+ * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.
40
41
  *
41
42
  * A \`.trivyignore\` is vended at the project root (kept if it already exists)
42
43
  * for suppressing findings.
@@ -7,12 +7,13 @@ import { addDependencyToTargetIfNotPresent } from "./nx.js";
7
7
  import { CONTAINER_VERSIONS } from "./versions.js";
8
8
  const TRIVY_IGNORE_FILE = '.trivyignore';
9
9
  const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to
10
- # suppress it during the image scan run on build.
10
+ # suppress it during the image scan (\`nx run-many --target trivy\`).
11
11
  # https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids
12
12
  `;
13
13
  /**
14
- * Add a cacheable Trivy scan target for the images built by a docker target,
15
- * wire it under the aggregate \`trivy\` target, and make \`build\` depend on it.
14
+ * Add a cacheable Trivy scan target for the images built by a docker target
15
+ * and wire it under the aggregate \`trivy\` target. The scan is not part of
16
+ * \`build\` — run \`nx run-many --target trivy\` (the root \`trivy\` script) in CI.
16
17
  *
17
18
  * The scan target depends on the docker target and declares the project source
18
19
  * as its inputs, so an unchanged image is never re-scanned (a cache hit skips
@@ -20,7 +21,7 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
20
21
  * \`dist/<projectRoot>/trivy/<scan-key>\` (kept out of any Docker build context)
21
22
  * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative
22
23
  * bind mount, so the same commands work under both docker and finch. The scan
23
- * fails the build (exit code 1) on HIGH/CRITICAL vulnerabilities.
24
+ * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.
24
25
  *
25
26
  * A \`.trivyignore\` is vended at the project root (kept if it already exists)
26
27
  * for suppressing findings.
@@ -70,12 +71,15 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
70
71
  dockerTargetName
71
72
  ]
72
73
  };
73
- // Aggregate per-component scan targets under a single `trivy` target, and
74
- // make `build` run the scan.
74
+ // Aggregate per-component scan targets under a single `trivy` target. The
75
+ // scan is intentionally NOT wired into `build`: image scanning is slow and
76
+ // its result depends on the ever-changing vulnerability database (a scan
77
+ // that passes today can fail tomorrow when a new CVE is published), so
78
+ // coupling it to `build` would make local and CI builds non-deterministic.
79
+ // Run `nx run-many --target trivy` (the root `trivy` script) in CI instead.
75
80
  if (trivyTargetName !== 'trivy') {
76
81
  addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);
77
82
  }
78
- addDependencyToTargetIfNotPresent(project, 'build', 'trivy');
79
83
  };
80
84
 
81
85
  //# sourceMappingURL=docker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/docker.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n} from '@nx/devkit';\nimport { FsCommands } from './fs';\nimport { addDependencyToTargetIfNotPresent } from './nx';\nimport { CONTAINER_VERSIONS } from './versions';\n\nconst TRIVY_IGNORE_FILE = '.trivyignore';\n\nconst TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to\n# suppress it during the image scan run on build.\n# https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids\n`;\n\nexport interface DockerScanTargetOptions {\n /**\n * Project configuration to add the scan target to (mutated in place).\n */\n readonly project: ProjectConfiguration;\n /**\n * Container engine command to invoke (\\`docker\\` or \\`finch\\`).\n */\n readonly containerEngine: string;\n /**\n * Name of the scan target to add, e.g. \\`my-agent-trivy\\`.\n */\n readonly trivyTargetName: string;\n /**\n * Name of the docker target that builds the image(s) to scan. The scan\n * target depends on it.\n */\n readonly dockerTargetName: string;\n /**\n * Tags of the images built by the docker target which should be scanned.\n */\n readonly imageTags: string[];\n}\n\n/**\n * Add a cacheable Trivy scan target for the images built by a docker target,\n * wire it under the aggregate \\`trivy\\` target, and make \\`build\\` depend on it.\n *\n * The scan target depends on the docker target and declares the project source\n * as its inputs, so an unchanged image is never re-scanned (a cache hit skips\n * the scan entirely). Each image is saved to a tarball under\n * \\`dist/<projectRoot>/trivy/<scan-key>\\` (kept out of any Docker build context)\n * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative\n * bind mount, so the same commands work under both docker and finch. The scan\n * fails the build (exit code 1) on HIGH/CRITICAL vulnerabilities.\n *\n * A \\`.trivyignore\\` is vended at the project root (kept if it already exists)\n * for suppressing findings.\n */\nexport const addDockerScanTarget = (\n tree: Tree,\n options: DockerScanTargetOptions,\n): void => {\n const { project, containerEngine, trivyTargetName, dockerTargetName } =\n options;\n const { imageTags } = options;\n const projectRoot = project.root;\n\n const ignoreFilePath = joinPathFragments(projectRoot, TRIVY_IGNORE_FILE);\n if (!tree.exists(ignoreFilePath)) {\n tree.write(ignoreFilePath, TRIVY_IGNORE_CONTENTS);\n }\n\n // Stage scan artifacts in a directory unique to this scan target so that\n // sibling targets in the same project (e.g. multiple agents) don't clobber\n // each other's tarballs when run in parallel. The first image tag is unique\n // per target, so it makes a stable, collision-free key.\n const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');\n const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);\n const trivyImage = `public.ecr.aws/aquasecurity/trivy:${CONTAINER_VERSIONS.trivy}`;\n\n const fs = new FsCommands(tree);\n const commands = [\n fs.rm(scanDir),\n fs.mkdir(scanDir),\n fs.cp(ignoreFilePath, joinPathFragments(scanDir, TRIVY_IGNORE_FILE)),\n ];\n\n imageTags.forEach((imageTag, index) => {\n const tarName = `image-${index}.tar`;\n commands.push(\n `${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`,\n `${containerEngine} run --rm -v \"./${scanDir}\":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`,\n );\n });\n\n project.targets ??= {};\n project.targets[trivyTargetName] = {\n cache: true,\n // The scanned image is fully determined by the project source, so caching\n // on the source ensures an unchanged image is never re-scanned.\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/${scanDir}`],\n executor: 'nx:run-commands',\n options: {\n commands,\n parallel: false,\n },\n dependsOn: [dockerTargetName],\n };\n\n // Aggregate per-component scan targets under a single `trivy` target, and\n // make `build` run the scan.\n if (trivyTargetName !== 'trivy') {\n addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);\n }\n addDependencyToTargetIfNotPresent(project, 'build', 'trivy');\n};\n"],"names":["joinPathFragments","FsCommands","addDependencyToTargetIfNotPresent","CONTAINER_VERSIONS","TRIVY_IGNORE_FILE","TRIVY_IGNORE_CONTENTS","addDockerScanTarget","tree","options","project","containerEngine","trivyTargetName","dockerTargetName","imageTags","projectRoot","root","ignoreFilePath","exists","write","scanKey","replace","scanDir","trivyImage","trivy","fs","commands","rm","mkdir","cp","forEach","imageTag","index","tarName","push","targets","cache","inputs","outputs","executor","parallel","dependsOn"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAASC,UAAU,QAAQ,UAAO;AAClC,SAASC,iCAAiC,QAAQ,UAAO;AACzD,SAASC,kBAAkB,QAAQ,gBAAa;AAEhD,MAAMC,oBAAoB;AAE1B,MAAMC,wBAAwB,CAAC;;;AAG/B,CAAC;AA0BD;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,eAAe,EAAEC,eAAe,EAAEC,gBAAgB,EAAE,GACnEJ;IACF,MAAM,EAAEK,SAAS,EAAE,GAAGL;IACtB,MAAMM,cAAcL,QAAQM,IAAI;IAEhC,MAAMC,iBAAiBhB,kBAAkBc,aAAaV;IACtD,IAAI,CAACG,KAAKU,MAAM,CAACD,iBAAiB;QAChCT,KAAKW,KAAK,CAACF,gBAAgBX;IAC7B;IAEA,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,wDAAwD;IACxD,MAAMc,UAAUN,SAAS,CAAC,EAAE,CAACO,OAAO,CAAC,kBAAkB;IACvD,MAAMC,UAAUrB,kBAAkB,QAAQc,aAAa,SAASK;IAChE,MAAMG,aAAa,CAAC,kCAAkC,EAAEnB,mBAAmBoB,KAAK,EAAE;IAElF,MAAMC,KAAK,IAAIvB,WAAWM;IAC1B,MAAMkB,WAAW;QACfD,GAAGE,EAAE,CAACL;QACNG,GAAGG,KAAK,CAACN;QACTG,GAAGI,EAAE,CAACZ,gBAAgBhB,kBAAkBqB,SAASjB;KAClD;IAEDS,UAAUgB,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,UAAU,CAAC,MAAM,EAAED,MAAM,IAAI,CAAC;QACpCN,SAASQ,IAAI,CACX,GAAGvB,gBAAgB,SAAS,EAAEV,kBAAkBqB,SAASW,SAAS,CAAC,EAAEF,UAAU,EAC/E,GAAGpB,gBAAgB,gBAAgB,EAAEW,QAAQ,QAAQ,EAAEC,WAAW,qBAAqB,EAAEU,QAAQ,oBAAoB,EAAE5B,kBAAkB,yFAAyF,CAAC;IAEvO;IAEAK,QAAQyB,OAAO,KAAK,CAAC;IACrBzB,QAAQyB,OAAO,CAACvB,gBAAgB,GAAG;QACjCwB,OAAO;QACP,0EAA0E;QAC1E,gEAAgE;QAChEC,QAAQ;YAAC;YAAW;SAAc;QAClCC,SAAS;YAAC,CAAC,gBAAgB,EAAEhB,SAAS;SAAC;QACvCiB,UAAU;QACV9B,SAAS;YACPiB;YACAc,UAAU;QACZ;QACAC,WAAW;YAAC5B;SAAiB;IAC/B;IAEA,0EAA0E;IAC1E,6BAA6B;IAC7B,IAAID,oBAAoB,SAAS;QAC/BT,kCAAkCO,SAAS,SAASE;IACtD;IACAT,kCAAkCO,SAAS,SAAS;AACtD,EAAE"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/docker.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n} from '@nx/devkit';\nimport { FsCommands } from './fs';\nimport { addDependencyToTargetIfNotPresent } from './nx';\nimport { CONTAINER_VERSIONS } from './versions';\n\nconst TRIVY_IGNORE_FILE = '.trivyignore';\n\nconst TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to\n# suppress it during the image scan (\\`nx run-many --target trivy\\`).\n# https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids\n`;\n\nexport interface DockerScanTargetOptions {\n /**\n * Project configuration to add the scan target to (mutated in place).\n */\n readonly project: ProjectConfiguration;\n /**\n * Container engine command to invoke (\\`docker\\` or \\`finch\\`).\n */\n readonly containerEngine: string;\n /**\n * Name of the scan target to add, e.g. \\`my-agent-trivy\\`.\n */\n readonly trivyTargetName: string;\n /**\n * Name of the docker target that builds the image(s) to scan. The scan\n * target depends on it.\n */\n readonly dockerTargetName: string;\n /**\n * Tags of the images built by the docker target which should be scanned.\n */\n readonly imageTags: string[];\n}\n\n/**\n * Add a cacheable Trivy scan target for the images built by a docker target\n * and wire it under the aggregate \\`trivy\\` target. The scan is not part of\n * \\`build\\` run \\`nx run-many --target trivy\\` (the root \\`trivy\\` script) in CI.\n *\n * The scan target depends on the docker target and declares the project source\n * as its inputs, so an unchanged image is never re-scanned (a cache hit skips\n * the scan entirely). Each image is saved to a tarball under\n * \\`dist/<projectRoot>/trivy/<scan-key>\\` (kept out of any Docker build context)\n * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative\n * bind mount, so the same commands work under both docker and finch. The scan\n * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.\n *\n * A \\`.trivyignore\\` is vended at the project root (kept if it already exists)\n * for suppressing findings.\n */\nexport const addDockerScanTarget = (\n tree: Tree,\n options: DockerScanTargetOptions,\n): void => {\n const { project, containerEngine, trivyTargetName, dockerTargetName } =\n options;\n const { imageTags } = options;\n const projectRoot = project.root;\n\n const ignoreFilePath = joinPathFragments(projectRoot, TRIVY_IGNORE_FILE);\n if (!tree.exists(ignoreFilePath)) {\n tree.write(ignoreFilePath, TRIVY_IGNORE_CONTENTS);\n }\n\n // Stage scan artifacts in a directory unique to this scan target so that\n // sibling targets in the same project (e.g. multiple agents) don't clobber\n // each other's tarballs when run in parallel. The first image tag is unique\n // per target, so it makes a stable, collision-free key.\n const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');\n const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);\n const trivyImage = `public.ecr.aws/aquasecurity/trivy:${CONTAINER_VERSIONS.trivy}`;\n\n const fs = new FsCommands(tree);\n const commands = [\n fs.rm(scanDir),\n fs.mkdir(scanDir),\n fs.cp(ignoreFilePath, joinPathFragments(scanDir, TRIVY_IGNORE_FILE)),\n ];\n\n imageTags.forEach((imageTag, index) => {\n const tarName = `image-${index}.tar`;\n commands.push(\n `${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`,\n `${containerEngine} run --rm -v \"./${scanDir}\":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`,\n );\n });\n\n project.targets ??= {};\n project.targets[trivyTargetName] = {\n cache: true,\n // The scanned image is fully determined by the project source, so caching\n // on the source ensures an unchanged image is never re-scanned.\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/${scanDir}`],\n executor: 'nx:run-commands',\n options: {\n commands,\n parallel: false,\n },\n dependsOn: [dockerTargetName],\n };\n\n // Aggregate per-component scan targets under a single `trivy` target. The\n // scan is intentionally NOT wired into `build`: image scanning is slow and\n // its result depends on the ever-changing vulnerability database (a scan\n // that passes today can fail tomorrow when a new CVE is published), so\n // coupling it to `build` would make local and CI builds non-deterministic.\n // Run `nx run-many --target trivy` (the root `trivy` script) in CI instead.\n if (trivyTargetName !== 'trivy') {\n addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);\n }\n};\n"],"names":["joinPathFragments","FsCommands","addDependencyToTargetIfNotPresent","CONTAINER_VERSIONS","TRIVY_IGNORE_FILE","TRIVY_IGNORE_CONTENTS","addDockerScanTarget","tree","options","project","containerEngine","trivyTargetName","dockerTargetName","imageTags","projectRoot","root","ignoreFilePath","exists","write","scanKey","replace","scanDir","trivyImage","trivy","fs","commands","rm","mkdir","cp","forEach","imageTag","index","tarName","push","targets","cache","inputs","outputs","executor","parallel","dependsOn"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAASC,UAAU,QAAQ,UAAO;AAClC,SAASC,iCAAiC,QAAQ,UAAO;AACzD,SAASC,kBAAkB,QAAQ,gBAAa;AAEhD,MAAMC,oBAAoB;AAE1B,MAAMC,wBAAwB,CAAC;;;AAG/B,CAAC;AA0BD;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,eAAe,EAAEC,eAAe,EAAEC,gBAAgB,EAAE,GACnEJ;IACF,MAAM,EAAEK,SAAS,EAAE,GAAGL;IACtB,MAAMM,cAAcL,QAAQM,IAAI;IAEhC,MAAMC,iBAAiBhB,kBAAkBc,aAAaV;IACtD,IAAI,CAACG,KAAKU,MAAM,CAACD,iBAAiB;QAChCT,KAAKW,KAAK,CAACF,gBAAgBX;IAC7B;IAEA,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,wDAAwD;IACxD,MAAMc,UAAUN,SAAS,CAAC,EAAE,CAACO,OAAO,CAAC,kBAAkB;IACvD,MAAMC,UAAUrB,kBAAkB,QAAQc,aAAa,SAASK;IAChE,MAAMG,aAAa,CAAC,kCAAkC,EAAEnB,mBAAmBoB,KAAK,EAAE;IAElF,MAAMC,KAAK,IAAIvB,WAAWM;IAC1B,MAAMkB,WAAW;QACfD,GAAGE,EAAE,CAACL;QACNG,GAAGG,KAAK,CAACN;QACTG,GAAGI,EAAE,CAACZ,gBAAgBhB,kBAAkBqB,SAASjB;KAClD;IAEDS,UAAUgB,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,UAAU,CAAC,MAAM,EAAED,MAAM,IAAI,CAAC;QACpCN,SAASQ,IAAI,CACX,GAAGvB,gBAAgB,SAAS,EAAEV,kBAAkBqB,SAASW,SAAS,CAAC,EAAEF,UAAU,EAC/E,GAAGpB,gBAAgB,gBAAgB,EAAEW,QAAQ,QAAQ,EAAEC,WAAW,qBAAqB,EAAEU,QAAQ,oBAAoB,EAAE5B,kBAAkB,yFAAyF,CAAC;IAEvO;IAEAK,QAAQyB,OAAO,KAAK,CAAC;IACrBzB,QAAQyB,OAAO,CAACvB,gBAAgB,GAAG;QACjCwB,OAAO;QACP,0EAA0E;QAC1E,gEAAgE;QAChEC,QAAQ;YAAC;YAAW;SAAc;QAClCC,SAAS;YAAC,CAAC,gBAAgB,EAAEhB,SAAS;SAAC;QACvCiB,UAAU;QACV9B,SAAS;YACPiB;YACAc,UAAU;QACZ;QACAC,WAAW;YAAC5B;SAAiB;IAC/B;IAEA,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAID,oBAAoB,SAAS;QAC/BT,kCAAkCO,SAAS,SAASE;IACtD;AACF,EAAE"}