From 165e3af3354709e9e60632e1b06bc45814f4376a Mon Sep 17 00:00:00 2001 From: Jacob Chung Date: Mon, 13 Oct 2025 17:16:43 -0700 Subject: [PATCH] refactor(core): migrate sts + ecr + ec2 + lambda + awserror --- package-lock.json | 502 ++++++++++++++++++ packages/core/package.json | 1 + .../src/shared/clients/codecatalystClient.ts | 7 +- .../src/shared/clients/ec2MetadataClient.ts | 103 ++-- packages/core/src/shared/clients/ecrClient.ts | 57 +- .../core/src/shared/clients/lambdaClient.ts | 13 +- packages/core/src/shared/clients/stsClient.ts | 57 +- packages/core/src/test/setupUtil.ts | 32 +- 8 files changed, 665 insertions(+), 107 deletions(-) diff --git a/package-lock.json b/package-lock.json index 16d97a48dfe..02616d4cebb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10086,6 +10086,507 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-ecr": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.693.0.tgz", + "integrity": "sha512-qBI06wo2VaQI/+Pb4GmZRVQMnXFr9B983nWWNhM6xzcYmfJKXbCW29syDVojiwp8/HPMOSqcKJzqIOqCWtN1Ug==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.693.0", + "@aws-sdk/client-sts": "3.693.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-node": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/client-sso": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.693.0.tgz", + "integrity": "sha512-QEynrBC26x6TG9ZMzApR/kZ3lmt4lEIs2D+cHuDxt6fDGzahBUsQFBwJqhizzsM97JJI5YvmJhmihoYjdSSaXA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.693.0.tgz", + "integrity": "sha512-UEDbYlYtK/e86OOMyFR4zEPyenIxDzO2DRdz3fwVW7RzZ94wfmSwBh/8skzPTuY1G7sI064cjHW0b0QG01Sdtg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-node": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/client-sts": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.693.0.tgz", + "integrity": "sha512-4S2y7VEtvdnjJX4JPl4kDQlslxXEZFnC50/UXVUYSt/AMc5A/GgspFNA5FVz4E3Gwpfobbf23hR2NBF8AGvYoQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.693.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-node": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/core": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.693.0.tgz", + "integrity": "sha512-v6Z/kWmLFqRLDPEwl9hJGhtTgIFHjZugSfF1Yqffdxf4n1AWgtHS7qSegakuMyN5pP4K2tvUD8qHJ+gGe2Bw2A==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/core": "^2.5.2", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.6", + "@smithy/signature-v4": "^4.2.2", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/util-middleware": "^3.0.9", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.693.0.tgz", + "integrity": "sha512-sL8MvwNJU7ZpD7/d2VVb3by1GknIJUxzTIgYtVkDVA/ojo+KRQSSHxcj0EWWXF5DTSh2Tm+LrEug3y1ZyKHsDA==", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/util-stream": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.693.0.tgz", + "integrity": "sha512-kvaa4mXhCCOuW7UQnBhYqYfgWmwy7WSBSDClutwSLPZvgrhYj2l16SD2lN4IfYdxARYMJJ1lFYp3/jJG/9Yk4Q==", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-env": "3.693.0", + "@aws-sdk/credential-provider-http": "3.693.0", + "@aws-sdk/credential-provider-process": "3.693.0", + "@aws-sdk/credential-provider-sso": "3.693.0", + "@aws-sdk/credential-provider-web-identity": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.693.0.tgz", + "integrity": "sha512-42WMsBjTNnjYxYuM3qD/Nq+8b7UdMopUq5OduMDxoM3mFTV6PXMMnfI4Z1TNnR4tYRvPXAnuNltF6xmjKbSJRA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.693.0", + "@aws-sdk/credential-provider-http": "3.693.0", + "@aws-sdk/credential-provider-ini": "3.693.0", + "@aws-sdk/credential-provider-process": "3.693.0", + "@aws-sdk/credential-provider-sso": "3.693.0", + "@aws-sdk/credential-provider-web-identity": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.693.0.tgz", + "integrity": "sha512-479UlJxY+BFjj3pJFYUNC0DCMrykuG7wBAXfsvZqQxKUa83DnH5Q1ID/N2hZLkxjGd4ZW0AC3lTOMxFelGzzpQ==", + "dependencies": { + "@aws-sdk/client-sso": "3.693.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/token-providers": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.693.0.tgz", + "integrity": "sha512-8LB210Pr6VeCiSb2hIra+sAH4KUBLyGaN50axHtIgufVK8jbKIctTZcVY5TO9Se+1107TsruzeXS7VeqVdJfFA==", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.693.0.tgz", + "integrity": "sha512-BCki6sAZ5jYwIN/t3ElCiwerHad69ipHwPsDCxJQyeiOnJ8HG+lEpnVIfrnI8A0fLQNSF3Gtx6ahfBpKiv1Oug==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/middleware-logger": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.693.0.tgz", + "integrity": "sha512-dXnXDPr+wIiJ1TLADACI1g9pkSB21KkMIko2u4CJ2JCBoxi5IqeTnVoa6YcC8GdFNVRl+PorZ3Zqfmf1EOTC6w==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.693.0.tgz", + "integrity": "sha512-0LDmM+VxXp0u3rG0xQRWD/q6Ubi7G8I44tBPahevD5CaiDZTkmNTrVUf0VEJgVe0iCKBppACMBDkLB0/ETqkFw==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.693.0.tgz", + "integrity": "sha512-/KUq/KEpFFbQmNmpp7SpAtFAdViquDfD2W0QcG07zYBfz9MwE2ig48ALynXm5sMpRmnG7sJXjdvPtTsSVPfkiw==", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@smithy/core": "^2.5.2", + "@smithy/protocol-http": "^4.1.6", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.693.0.tgz", + "integrity": "sha512-YLUkMsUY0GLW/nfwlZ69cy1u07EZRmsv8Z9m0qW317/EZaVx59hcvmcvb+W4bFqj5E8YImTjoGfE4cZ0F9mkyw==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/types": "^3.7.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.9", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/token-providers": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.693.0.tgz", + "integrity": "sha512-nDBTJMk1l/YmFULGfRbToOA2wjf+FkQT4dMgYCv+V9uSYsMzQj8A7Tha2dz9yv4vnQgYaEiErQ8d7HVyXcVEoA==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/util-endpoints": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.693.0.tgz", + "integrity": "sha512-eo4F6DRQ/kxS3gxJpLRv+aDNy76DxQJL5B3DPzpr9Vkq0ygVoi4GT5oIZLVaAVIJmi6k5qq9dLsYZfWLUxJJSg==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/types": "^3.7.0", + "@smithy/util-endpoints": "^2.1.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.693.0.tgz", + "integrity": "sha512-6EUfuKOujtddy18OLJUaXfKBgs+UcbZ6N/3QV4iOkubCUdeM1maIqs++B9bhCbWeaeF5ORizJw5FTwnyNjE/mw==", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/types": "^3.7.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.693.0.tgz", + "integrity": "sha512-td0OVX8m5ZKiXtecIDuzY3Y3UZIzvxEr57Hp21NOwieqKCG2UeyQWWeGPv0FQaU7dpTkvFmVNI+tx9iB8V/Nhg==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecr/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-glue": { "version": "3.852.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-glue/-/client-glue-3.852.0.tgz", @@ -37134,6 +37635,7 @@ "@aws-sdk/client-docdb": "<3.731.0", "@aws-sdk/client-docdb-elastic": "<3.731.0", "@aws-sdk/client-ec2": "<3.731.0", + "@aws-sdk/client-ecr": "~3.693.0", "@aws-sdk/client-ecs": "~3.693.0", "@aws-sdk/client-glue": "^3.852.0", "@aws-sdk/client-iam": "<3.731.0", diff --git a/packages/core/package.json b/packages/core/package.json index 2a232ec95fe..7b2545ebf26 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -593,6 +593,7 @@ "@aws-sdk/client-docdb": "<3.731.0", "@aws-sdk/client-docdb-elastic": "<3.731.0", "@aws-sdk/client-ec2": "<3.731.0", + "@aws-sdk/client-ecr": "~3.693.0", "@aws-sdk/client-ecs": "~3.693.0", "@aws-sdk/client-glue": "^3.852.0", "@aws-sdk/client-iam": "<3.731.0", diff --git a/packages/core/src/shared/clients/codecatalystClient.ts b/packages/core/src/shared/clients/codecatalystClient.ts index 45d123b36c4..b7618fe01b0 100644 --- a/packages/core/src/shared/clients/codecatalystClient.ts +++ b/packages/core/src/shared/clients/codecatalystClient.ts @@ -9,7 +9,6 @@ import * as vscode from 'vscode' import * as nls from 'vscode-nls' const localize = nls.loadMessageBundle() -import * as AWS from 'aws-sdk' import * as logger from '../logger/logger' import { CancellationError, Timeout, waitTimeout, waitUntil } from '../utilities/timeoutUtils' import { isUserCancelledError } from '../../shared/errors' @@ -841,18 +840,18 @@ class CodeCatalystClientInternal extends ClientWrapper { startAttempts++ await this.startDevEnvironment(args) } catch (e) { - const err = e as AWS.AWSError + const err = e as ServiceException // - ServiceQuotaExceededException: account billing limit reached // - ValidationException: "… creation has failed, cannot start" // - ConflictException: "Cannot start … because update process is still going on" // (can happen after "Update Dev Environment") - if (err.code === 'ServiceQuotaExceededException') { + if (err.name === 'ServiceQuotaExceededException') { throw new ToolkitError('Dev Environment failed: quota exceeded', { code: 'ServiceQuotaExceeded', cause: err, }) } - doLog('info', `devenv not started (${err.code}), waiting`) + doLog('info', `devenv not started (${err.name}), waiting`) // Continue retrying... } } else if (resp.status === 'STOPPING') { diff --git a/packages/core/src/shared/clients/ec2MetadataClient.ts b/packages/core/src/shared/clients/ec2MetadataClient.ts index 1db884efa27..72249efa6c9 100644 --- a/packages/core/src/shared/clients/ec2MetadataClient.ts +++ b/packages/core/src/shared/clients/ec2MetadataClient.ts @@ -5,8 +5,8 @@ import { getLogger } from '../logger/logger' import { ClassToInterfaceType } from '../utilities/tsUtils' -import { MetadataService } from 'aws-sdk' -import { ServiceException } from '@smithy/smithy-client' +import { httpRequest } from '@smithy/credential-provider-imds' +import { RequestOptions } from 'http' export interface IamInfo { Code: string @@ -22,8 +22,12 @@ export interface InstanceIdentity { export type Ec2MetadataClient = ClassToInterfaceType export class DefaultEc2MetadataClient { private static readonly metadataServiceTimeout: number = 500 + // AWS EC2 Instance Metadata Service (IMDS) constants + // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-v2-how-it-works.html + private static readonly metadataServiceHost: string = '169.254.169.254' + private static readonly tokenPath: string = '/latest/api/token' - public constructor(private metadata: MetadataService = DefaultEc2MetadataClient.getMetadataService()) {} + public constructor() {} public getInstanceIdentity(): Promise { return this.invoke('/latest/dynamic/instance-identity/document') @@ -33,52 +37,61 @@ export class DefaultEc2MetadataClient { return this.invoke('/latest/meta-data/iam/info') } - public invoke(path: string): Promise { - return new Promise((resolve, reject) => { - // fetchMetadataToken is private for some reason, but has the exact token functionality - // that we want out of the metadata service. - // https://github.com/aws/aws-sdk-js/blob/3333f8b49283f5bbff823ab8a8469acedb7fe3d5/lib/metadata_service.js#L116-L136 - ;(this.metadata as any).fetchMetadataToken((tokenErr: ServiceException, token: string) => { - let options - if (tokenErr) { - getLogger().warn( - 'Ec2MetadataClient failed to fetch token. If this is an EC2 environment, then Toolkit will fall back to IMDSv1: %s', - tokenErr - ) + public async invoke(path: string): Promise { + try { + // Try to get IMDSv2 token first + const token = await this.fetchMetadataToken() + const headers: Record = {} + if (token) { + headers['x-aws-ec2-metadata-token'] = token + } - // Fall back to IMDSv1 for legacy instances. - options = {} - } else { - options = { - // By attaching the token we force the use of IMDSv2. - // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-v2-how-it-works.html - headers: { 'x-aws-ec2-metadata-token': token }, - } - } + const response = await this.makeRequest(path, headers) + return JSON.parse(response.toString()) + } catch (tokenErr) { + getLogger().warn( + 'Ec2MetadataClient failed to fetch token. If this is an EC2 environment, then Toolkit will fall back to IMDSv1: %s', + tokenErr + ) - this.metadata.request(path, options, (err, response) => { - if (err) { - reject(err) - return - } - try { - const jsonResponse: T = JSON.parse(response) - resolve(jsonResponse) - } catch (e) { - reject(`Ec2MetadataClient: invalid response from "${path}": ${response}\nerror: ${e}`) - } - }) - }) - }) + // Fall back to IMDSv1 for legacy instances + try { + const response = await this.makeRequest(path, {}) + return JSON.parse(response.toString()) + } catch (err) { + throw new Error(`Ec2MetadataClient: failed to fetch "${path}": ${err}`) + } + } } - private static getMetadataService() { - return new MetadataService({ - httpOptions: { + private async fetchMetadataToken(): Promise { + try { + const options: RequestOptions = { + host: DefaultEc2MetadataClient.metadataServiceHost, + path: DefaultEc2MetadataClient.tokenPath, + method: 'PUT', + headers: { + 'x-aws-ec2-metadata-token-ttl-seconds': '21600', + }, timeout: DefaultEc2MetadataClient.metadataServiceTimeout, - connectTimeout: DefaultEc2MetadataClient.metadataServiceTimeout, - } as any, - // workaround for known bug: https://github.com/aws/aws-sdk-js/issues/3029 - }) + } + + const response = await httpRequest(options) + return response.toString() + } catch (err) { + return undefined + } + } + + private async makeRequest(path: string, headers: Record): Promise { + const options: RequestOptions = { + host: DefaultEc2MetadataClient.metadataServiceHost, + path, + method: 'GET', + headers, + timeout: DefaultEc2MetadataClient.metadataServiceTimeout, + } + + return httpRequest(options) } } diff --git a/packages/core/src/shared/clients/ecrClient.ts b/packages/core/src/shared/clients/ecrClient.ts index 1478d76751d..f5e03d4db7a 100644 --- a/packages/core/src/shared/clients/ecrClient.ts +++ b/packages/core/src/shared/clients/ecrClient.ts @@ -3,23 +3,31 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ECR } from 'aws-sdk' +import { + ECRClient, + DescribeImagesCommand, + DescribeRepositoriesCommand, + CreateRepositoryCommand, + DeleteRepositoryCommand, + BatchDeleteImageCommand, +} from '@aws-sdk/client-ecr' +import type { DescribeImagesRequest, DescribeRepositoriesRequest, Repository } from '@aws-sdk/client-ecr' import globals from '../extensionGlobals' import { AsyncCollection } from '../utilities/asyncCollection' import { pageableToCollection } from '../utilities/collectionUtils' import { assertHasProps, ClassToInterfaceType, isNonNullable, RequiredProps } from '../utilities/tsUtils' -export type EcrRepository = RequiredProps +export type EcrRepository = RequiredProps export type EcrClient = ClassToInterfaceType export class DefaultEcrClient { public constructor(public readonly regionCode: string) {} public async *describeTags(repositoryName: string): AsyncIterableIterator { - const sdkClient = await this.createSdkClient() - const request: ECR.DescribeImagesRequest = { repositoryName: repositoryName } + const sdkClient = this.createSdkClient() + const request: DescribeImagesRequest = { repositoryName: repositoryName } do { - const response = await sdkClient.describeImages(request).promise() + const response = await sdkClient.send(new DescribeImagesCommand(request)) if (response.imageDetails) { for (const item of response.imageDetails) { if (item.imageTags !== undefined) { @@ -34,13 +42,13 @@ export class DefaultEcrClient { } public async *describeRepositories(): AsyncIterableIterator { - const sdkClient = await this.createSdkClient() - const request: ECR.DescribeRepositoriesRequest = {} + const sdkClient = this.createSdkClient() + const request: DescribeRepositoriesRequest = {} do { - const response = await sdkClient.describeRepositories(request).promise() + const response = await sdkClient.send(new DescribeRepositoriesCommand(request)) if (response.repositories) { yield* response.repositories - .map((repo) => { + .map((repo: Repository) => { // If any of these are not present, the repo returned is not valid. repositoryUri/Arn // are both based on name, and it's not possible to not have a name if (!repo.repositoryArn || !repo.repositoryName || !repo.repositoryUri) { @@ -53,36 +61,43 @@ export class DefaultEcrClient { } } }) - .filter((item) => item !== undefined) as EcrRepository[] + .filter((item: EcrRepository | undefined) => item !== undefined) as EcrRepository[] } request.nextToken = response.nextToken } while (request.nextToken) } public listAllRepositories(): AsyncCollection { - const requester = async (req: ECR.DescribeRepositoriesRequest) => - (await this.createSdkClient()).describeRepositories(req).promise() + const requester = async (req: DescribeRepositoriesRequest) => + this.createSdkClient().send(new DescribeRepositoriesCommand(req)) const collection = pageableToCollection(requester, {}, 'nextToken', 'repositories') - return collection.filter(isNonNullable).map((list) => list.map((repo) => (assertHasProps(repo), repo))) + return collection + .filter(isNonNullable) + .map((list: Repository[]) => list.map((repo: Repository) => (assertHasProps(repo), repo))) } public async createRepository(repositoryName: string) { - const sdkClient = await this.createSdkClient() - return sdkClient.createRepository({ repositoryName: repositoryName }).promise() + const sdkClient = this.createSdkClient() + return sdkClient.send(new CreateRepositoryCommand({ repositoryName: repositoryName })) } public async deleteRepository(repositoryName: string): Promise { - const sdkClient = await this.createSdkClient() - await sdkClient.deleteRepository({ repositoryName: repositoryName }).promise() + const sdkClient = this.createSdkClient() + await sdkClient.send(new DeleteRepositoryCommand({ repositoryName: repositoryName })) } public async deleteTag(repositoryName: string, tag: string): Promise { - const sdkClient = await this.createSdkClient() - await sdkClient.batchDeleteImage({ repositoryName: repositoryName, imageIds: [{ imageTag: tag }] }).promise() + const sdkClient = this.createSdkClient() + await sdkClient.send( + new BatchDeleteImageCommand({ repositoryName: repositoryName, imageIds: [{ imageTag: tag }] }) + ) } - protected async createSdkClient(): Promise { - return await globals.sdkClientBuilder.createAwsService(ECR, undefined, this.regionCode) + protected createSdkClient(): ECRClient { + return globals.sdkClientBuilderV3.createAwsService({ + serviceClient: ECRClient, + clientOptions: { region: this.regionCode }, + }) } } diff --git a/packages/core/src/shared/clients/lambdaClient.ts b/packages/core/src/shared/clients/lambdaClient.ts index d6805bf4a25..fb73ce9c2d2 100644 --- a/packages/core/src/shared/clients/lambdaClient.ts +++ b/packages/core/src/shared/clients/lambdaClient.ts @@ -40,7 +40,6 @@ import { import { CancellationError } from '../utilities/timeoutUtils' import { fromSSO } from '@aws-sdk/credential-provider-sso' import { getIAMConnection } from '../../auth/utils' -import { WaiterConfiguration } from 'aws-sdk/lib/service' import { NodeHttpHandler } from '@smithy/node-http-handler' export type LambdaClient = ClassToInterfaceType @@ -301,11 +300,19 @@ export class DefaultLambdaClient { ) } - public async waitForActive(functionName: string, waiter?: WaiterConfiguration): Promise { + public async waitForActive( + functionName: string, + waiter?: { maxWaitTime?: number; minDelay?: number; maxDelay?: number } + ): Promise { const sdkClient = await this.createSdkClient() await waitUntilFunctionActiveV2( - { client: sdkClient, maxWaitTime: (waiter?.maxAttempts ?? 600) * (waiter?.delay ?? 1) }, + { + client: sdkClient, + maxWaitTime: waiter?.maxWaitTime ?? 600, + minDelay: waiter?.minDelay ?? 1, + maxDelay: waiter?.maxDelay ?? 120, + }, { FunctionName: functionName } ) } diff --git a/packages/core/src/shared/clients/stsClient.ts b/packages/core/src/shared/clients/stsClient.ts index 6cc01f57fa8..f3a225882a5 100644 --- a/packages/core/src/shared/clients/stsClient.ts +++ b/packages/core/src/shared/clients/stsClient.ts @@ -3,41 +3,60 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { STS } from 'aws-sdk' +import { STSClient, AssumeRoleCommand, GetCallerIdentityCommand } from '@aws-sdk/client-sts' +import type { AssumeRoleRequest, AssumeRoleResponse, GetCallerIdentityResponse } from '@aws-sdk/client-sts' +import { AwsCredentialIdentityProvider } from '@smithy/types' import { Credentials } from '@aws-sdk/types' import globals from '../extensionGlobals' import { ClassToInterfaceType } from '../utilities/tsUtils' -export type GetCallerIdentityResponse = STS.GetCallerIdentityResponse +export type { GetCallerIdentityResponse } export type StsClient = ClassToInterfaceType + +// Helper function to convert Credentials to AwsCredentialIdentityProvider +function toCredentialProvider(credentials: Credentials | AwsCredentialIdentityProvider): AwsCredentialIdentityProvider { + if (typeof credentials === 'function') { + return credentials + } + // Convert static credentials to provider function + return async () => credentials +} + export class DefaultStsClient { public constructor( public readonly regionCode: string, - private readonly credentials?: Credentials, + private readonly credentials?: Credentials | AwsCredentialIdentityProvider, private readonly endpointUrl?: string ) {} - public async assumeRole(request: STS.AssumeRoleRequest): Promise { - const sdkClient = await this.createSdkClient() - const response = await sdkClient.assumeRole(request).promise() + public async assumeRole(request: AssumeRoleRequest): Promise { + const sdkClient = this.createSdkClient() + const response = await sdkClient.send(new AssumeRoleCommand(request)) return response } - public async getCallerIdentity(): Promise { - const sdkClient = await this.createSdkClient() - const response = await sdkClient.getCallerIdentity().promise() + public async getCallerIdentity(): Promise { + const sdkClient = this.createSdkClient() + const response = await sdkClient.send(new GetCallerIdentityCommand({})) return response } - private async createSdkClient(): Promise { - return await globals.sdkClientBuilder.createAwsService( - STS, - { - credentials: this.credentials, - stsRegionalEndpoints: 'regional', - endpoint: this.endpointUrl, - }, - this.regionCode - ) + private createSdkClient(): STSClient { + const clientOptions: { region: string; endpoint?: string; credentials?: AwsCredentialIdentityProvider } = { + region: this.regionCode, + } + + if (this.endpointUrl) { + clientOptions.endpoint = this.endpointUrl + } + + if (this.credentials) { + clientOptions.credentials = toCredentialProvider(this.credentials) + } + + return globals.sdkClientBuilderV3.createAwsService({ + serviceClient: STSClient, + clientOptions, + }) } } diff --git a/packages/core/src/test/setupUtil.ts b/packages/core/src/test/setupUtil.ts index d0a4cd0b594..5e00b06ff5e 100644 --- a/packages/core/src/test/setupUtil.ts +++ b/packages/core/src/test/setupUtil.ts @@ -4,7 +4,8 @@ */ import { parse } from '@aws-sdk/util-arn-parser' -import { Lambda, STS } from 'aws-sdk' +import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda' +import { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts' import * as vscode from 'vscode' import { getLogger } from '../shared/logger' import { hasKey } from '../shared/utilities/tsUtils' @@ -135,13 +136,13 @@ export function patchObjectDescriptor, U extends k async function createLambdaClient(functionId: string) { if (!functionId.startsWith('arn:aws:lambda')) { - return Object.assign(new Lambda(), { isCrossAccount: false }) + return Object.assign(new LambdaClient({}), { isCrossAccount: false }) } - const sts = new STS() + const sts = new STSClient({}) const { region, accountId } = parse(functionId) - const identity = await sts.getCallerIdentity().promise() - const client = new Lambda({ region }) + const identity = await sts.send(new GetCallerIdentityCommand({})) + const client = new LambdaClient({ region }) return Object.assign(client, { isCrossAccount: identity.Account !== accountId }) } @@ -149,14 +150,15 @@ async function createLambdaClient(functionId: string) { export async function invokeLambda(id: string, request: unknown): Promise { const client = await createLambdaClient(id) const response = await client - .invoke({ - FunctionName: id, - // Setting this to `Tail` with cross account calls results in - // `AccessDeniedException: Cross-account log access is not allowed` - LogType: client.isCrossAccount ? 'None' : 'Tail', - Payload: JSON.stringify(request), - }) - .promise() + .send( + new InvokeCommand({ + FunctionName: id, + // Setting this to `Tail` with cross account calls results in + // `AccessDeniedException: Cross-account log access is not allowed` + LogType: client.isCrossAccount ? 'None' : 'Tail', + Payload: JSON.stringify(request), + }) + ) .catch((err) => { if (err instanceof Error) { err.message = maskArns(err.message) @@ -168,10 +170,10 @@ export async function invokeLambda(id: string, request: unknown): Promise