diff --git a/.changeset/weak-actors-pretend.md b/.changeset/weak-actors-pretend.md new file mode 100644 index 0000000..e3ba503 --- /dev/null +++ b/.changeset/weak-actors-pretend.md @@ -0,0 +1,5 @@ +--- +'@mirohq/cloud-data-import': minor +--- + +Add tag support diff --git a/package-lock.json b/package-lock.json index 2d8c742..e8d085a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mirohq/cloud-data-import", - "version": "0.9.0", + "version": "0.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mirohq/cloud-data-import", - "version": "0.9.0", + "version": "0.10.0", "license": "MIT", "dependencies": { "@aws-sdk/client-athena": "^3.621.0", @@ -26,6 +26,7 @@ "@aws-sdk/client-rds": "^3.658.1", "@aws-sdk/client-redshift": "3.654.0", "@aws-sdk/client-resource-explorer-2": "^3.662.0", + "@aws-sdk/client-resource-groups-tagging-api": "3.669.0", "@aws-sdk/client-route-53": "^3.624.0", "@aws-sdk/client-s3": "^3.621.0", "@aws-sdk/client-sns": "^3.621.0", @@ -3001,6 +3002,514 @@ } } }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-resource-groups-tagging-api/-/client-resource-groups-tagging-api-3.669.0.tgz", + "integrity": "sha512-Z1NugpGINC3+YCONX7EFDWJQe1vgIXNoE3RCDH7cR7Wzsqa9ka5qUgEerN0KW4CI/16WHvoZPGbz2f1548tKGw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.669.0", + "@aws-sdk/client-sts": "3.669.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.669.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@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.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/client-sso": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.669.0.tgz", + "integrity": "sha512-WNpfNYIHzehLv98F+KolJglXNjJOTbOvIbSZ2XAnebVLmXCWeEEd1r4dIH0oI2dHtLbQ/h3uqaeQhsVQjLAxpw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@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.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.669.0.tgz", + "integrity": "sha512-E7uYOS3Axhe36Zeq6iLC9kjF1mMEyCQ4fXud11h22rbjq7PFUtN2Omekrch37eUx3BFj1jMePnuTnT98t5LWnw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.669.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@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.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.669.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/client-sts": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.669.0.tgz", + "integrity": "sha512-1XdOBtHKCVxVkEDiy+oktJNSsySj3ADyh58KpHaqgvCQKV3vmfkr0YO5dG4kqq+TflNwdfl1YgMuOUiCulOWeQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.669.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.669.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.669.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", + "@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.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/core": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.667.0.tgz", + "integrity": "sha512-pMcDVI7Tmdsc8R3sDv0Omj/4iRParGY+uJtAfF669WnZfDfaBQaix2Mq7+Mu08vdjqO9K3gicFvjk9S1VLmOKA==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.667.0.tgz", + "integrity": "sha512-zZbrkkaPc54WXm+QAnpuv0LPNfsts0HPPd+oCECGs7IQRaFsGj187cwvPg9RMWDFZqpm64MdBDoA8OQHsqzYCw==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.667.0.tgz", + "integrity": "sha512-sjtybFfERZWiqTY7fswBxKQLvUkiCucOWyqh3IaPo/4nE1PXRnaZCVG0+kRBPrYIxWqiVwytvZzMJy8sVZcG0A==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-stream": "^3.1.9", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.669.0.tgz", + "integrity": "sha512-YHhfH7w29BmMPnOK0BrBhEy2IRFRSRGSCyz3jtqpG883CZ2Lxan/AzaJDfKRdz350KPgbMMBwbPkIrqNIsg8iw==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-env": "3.667.0", + "@aws-sdk/credential-provider-http": "3.667.0", + "@aws-sdk/credential-provider-process": "3.667.0", + "@aws-sdk/credential-provider-sso": "3.669.0", + "@aws-sdk/credential-provider-web-identity": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.669.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.669.0.tgz", + "integrity": "sha512-O506azQcq6N1gnDX870MXXL9LHlhX0k6BlLMM6IDClxVDnlNkK3+n2cAEKSy8HwZJcRlekcsKz/AS2CxjPY+fg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.667.0", + "@aws-sdk/credential-provider-http": "3.667.0", + "@aws-sdk/credential-provider-ini": "3.669.0", + "@aws-sdk/credential-provider-process": "3.667.0", + "@aws-sdk/credential-provider-sso": "3.669.0", + "@aws-sdk/credential-provider-web-identity": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.667.0.tgz", + "integrity": "sha512-HZHnvop32fKgsNHkdhVaul7UzQ25sEc0j9yqA4bjhtbk0ECl42kj3f1pJ+ZU/YD9ut8lMJs/vVqiOdNThVdeBw==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.669.0.tgz", + "integrity": "sha512-HvpMJQ8xZuEGjadARVOfORPZx4U23PC5Jf6Fj+/NWK4VxEXhvf8J037fvGp3xRds5wUeuBBbhWX+Cbt0lbLCwQ==", + "dependencies": { + "@aws-sdk/client-sso": "3.669.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/token-providers": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.667.0.tgz", + "integrity": "sha512-t8CFlZMD/1p/8Cli3rvRiTJpjr/8BO64gw166AHgFZYSN2h95L2l1tcW0jpsc3PprA32nLg1iQVKYt4WGM4ugw==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.667.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.667.0.tgz", + "integrity": "sha512-Z7fIAMQnPegs7JjAQvlOeWXwpMRfegh5eCoIP6VLJIeR6DLfYKbP35JBtt98R6DXslrN2RsbTogjbxPEDQfw1w==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/middleware-logger": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.667.0.tgz", + "integrity": "sha512-PtTRNpNm/5c746jRgZCNg4X9xEJIwggkGJrF0GP9AB1ANg4pc/sF2Fvn1NtqPe9wtQ2stunJprnm5WkCHN7QiA==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.667.0.tgz", + "integrity": "sha512-U5glWD3ehFohzpUpopLtmqAlDurGWo2wRGPNgi4SwhWU7UDt6LS7E/UvJjqC0CUrjlzOw+my2A+Ncf+fisMhxQ==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.669.0.tgz", + "integrity": "sha512-K8ScPi45zjJrj5Y2gRqVsvKKQCQbvQBfYGcBw9ZOx9TTavH80bOCBjWg/GFnvs4f37tqVc1wMN2oGvcTF6HveQ==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.667.0.tgz", + "integrity": "sha512-iNr+JhhA902JMKHG9IwT9YdaEx6KGl6vjAL5BRNeOjfj4cZYMog6Lz/IlfOAltMtT0w88DAHDEFrBd2uO0l2eg==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/token-providers": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.667.0.tgz", + "integrity": "sha512-ZecJlG8p6D4UTYlBHwOWX6nknVtw/OBJ3yPXTSajBjhUlj9lE2xvejI8gl4rqkyLXk7z3bki+KR4tATbMaM9yg==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.667.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/types": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.667.0.tgz", + "integrity": "sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg==", + "dependencies": { + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/util-endpoints": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.667.0.tgz", + "integrity": "sha512-X22SYDAuQJWnkF1/q17pkX3nGw5XMD9YEUbmt87vUnRq7iyJ3JOpl6UKOBeUBaL838wA5yzdbinmCITJ/VZ1QA==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", + "@smithy/util-endpoints": "^2.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.667.0.tgz", + "integrity": "sha512-y1pKlNzNpxzddM0QSnfIfIbi3Z9LTag1VDjYyZRbEGGSVip2J00qKsET+979nRezWMyJgw5GPBQR3Y+rN+jh0Q==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-resource-groups-tagging-api/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.669.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.669.0.tgz", + "integrity": "sha512-9jxCYrgggy2xd44ZASqI7AMiRVaSiFp+06Kg8BQSU0ijKpBJlwcsqIS8pDT/n6LxuOw2eV5ipvM2C0r1iKzrGA==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.669.0", + "@aws-sdk/types": "3.667.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.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-route-53": { "version": "3.654.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-route-53/-/client-route-53-3.654.0.tgz", @@ -5762,15 +6271,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.7.tgz", - "integrity": "sha512-goqMjX+IoVEnHZjYuzu8xwoZjoteMiLXsPHuXPBkWsGwu0o9c3nTjqkUlP1Ez/V8E501aOU7CJ3INk8mQcW2gw==", + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.8.tgz", + "integrity": "sha512-x4qWk7p/a4dcf7Vxb2MODIf4OIcqNbK182WxRvZ/3oKPrf/6Fdic5sSElhO1UtXpWKBazWfqg0ZEK9xN1DsuHA==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.4", - "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-retry": "^3.0.23", "@smithy/middleware-serde": "^3.0.7", "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-middleware": "^3.0.7", @@ -5988,14 +6497,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.22.tgz", - "integrity": "sha512-svEN7O2Tf7BoaBkPzX/8AE2Bv7p16d9/ulFAD1Gmn5g19iMqNk1WIkMxAY7SpB9/tVtUwKx0NaIsBRl88gumZA==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.23.tgz", + "integrity": "sha512-x9PbGXxkcXIpm6L26qRSCC+eaYcHwybRmqU8LO/WM2RRlW0g8lz6FIiKbKgGvHuoK3dLZRiQVSQJveiCzwnA5A==", "dependencies": { "@smithy/node-config-provider": "^3.1.8", "@smithy/protocol-http": "^4.1.4", "@smithy/service-error-classification": "^3.0.7", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "@smithy/util-middleware": "^3.0.7", "@smithy/util-retry": "^3.0.7", @@ -6150,9 +6659,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.3.6.tgz", - "integrity": "sha512-qdH+mvDHgq1ss6mocyIl2/VjlWXew7pGwZQydwYJczEc22HZyX3k8yVPV9aZsbYbssHPvMDRA5rfBDrjQUbIIw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.0.tgz", + "integrity": "sha512-nOfJ1nVQsxiP6srKt43r2My0Gp5PLWCW2ASqUioxIiGmu6d32v4Nekidiv5qOmmtzIrmaD+ADX5SKHUuhReeBQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.4", "@smithy/middleware-stack": "^3.0.7", @@ -6242,12 +6751,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.22.tgz", - "integrity": "sha512-WKzUxNsOun5ETwEOrvooXeI1mZ8tjDTOcN4oruELWHhEYDgQYWwxZupURVyovcv+h5DyQT/DzK5nm4ZoR/Tw5Q==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.23.tgz", + "integrity": "sha512-Y07qslyRtXDP/C5aWKqxTPBl4YxplEELG3xRrz2dnAQ6Lq/FgNrcKWmV561nNaZmFH+EzeGOX3ZRMbU8p1T6Nw==", "dependencies": { "@smithy/property-provider": "^3.1.7", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -6257,15 +6766,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.22.tgz", - "integrity": "sha512-hUsciOmAq8fsGwqg4+pJfNRmrhfqMH4Y9UeGcgeUl88kPAoYANFATJqCND+O4nUvwp5TzsYwGpqpcBKyA8LUUg==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.23.tgz", + "integrity": "sha512-9Y4WH7f0vnDGuHUa4lGX9e2p+sMwODibsceSV6rfkZOvMC+BY3StB2LdO1NHafpsyHJLpwAgChxQ38tFyd6vkg==", "dependencies": { "@smithy/config-resolver": "^3.0.9", "@smithy/credential-provider-imds": "^3.2.4", "@smithy/node-config-provider": "^3.1.8", "@smithy/property-provider": "^3.1.7", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, diff --git a/package.json b/package.json index 4dc7c54..4971429 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "@aws-sdk/client-rds": "^3.658.1", "@aws-sdk/client-redshift": "3.654.0", "@aws-sdk/client-resource-explorer-2": "^3.662.0", + "@aws-sdk/client-resource-groups-tagging-api": "3.669.0", "@aws-sdk/client-route-53": "^3.624.0", "@aws-sdk/client-s3": "^3.621.0", "@aws-sdk/client-sns": "^3.621.0", diff --git a/src/aws-app/main.ts b/src/aws-app/main.ts index e62f8ce..7f42ea7 100644 --- a/src/aws-app/main.ts +++ b/src/aws-app/main.ts @@ -52,6 +52,11 @@ export default async () => { return {...acc, ...resources} }, {}) + // aggregate tags + const tags = result.reduce((acc, {tags}) => { + return {...acc, ...tags} + }, {}) + // aggregate errors const errors = result.reduce((acc, {errors}) => { return [...acc, ...errors] @@ -62,7 +67,8 @@ export default async () => { provider: 'aws', docVersion: '0.1.0', resources: config.raw ? resources : {}, - processed: await getProcessedData(resources), + processed: await getProcessedData(resources, tags), + tags: tags, errors, metadata: { account: await getAwsAccountId(credentials), diff --git a/src/aws-app/process/getPlacementData.ts b/src/aws-app/process/getPlacementData.ts index 3377282..f604edf 100644 --- a/src/aws-app/process/getPlacementData.ts +++ b/src/aws-app/process/getPlacementData.ts @@ -27,6 +27,7 @@ export const getResourcePlacementData = (arnInfo: ARNInfo, resource: ResourceDes availabilityZones: [], subnets: [], securityGroups: [], + tags: {}, } // Athena Named Queries @@ -319,9 +320,7 @@ export const getPlacementData = (resources: Resources): PlacementData => { continue } - const data = getResourcePlacementData(arnInfo, resource) - - placementData[arn] = data + placementData[arn] = getResourcePlacementData(arnInfo, resource) } return placementData diff --git a/src/aws-app/process/index.ts b/src/aws-app/process/index.ts index 9e410c3..f5438ab 100644 --- a/src/aws-app/process/index.ts +++ b/src/aws-app/process/index.ts @@ -1,27 +1,42 @@ -import type {ProcessedData, Resources} from '@/types' +import type {ProcessedData, Resources, ResourceTags} from '@/types' import {getPlacementData} from './getPlacementData' import {getProcessedResources} from './resources' import {getProcessedContainers} from './containers' import {ProcessingErrorManager} from './utils/ProcessingErrorManager' -export const getProcessedData = (resources: Resources): ProcessedData => { +export const getProcessedData = (resources: Resources, resourceTags: ResourceTags): ProcessedData => { const processingErrorsManager = new ProcessingErrorManager() // Get the placement data which is a simplified version of the resources focusing on the location of the resources const placementData = getPlacementData(resources) // Calculate the containers, connections and resources - const processedResources = getProcessedResources(placementData) + const processedResources = getProcessedResources(placementData, resourceTags) const containers = getProcessedContainers(placementData, resources, processingErrorsManager) // Log all collected errors processingErrorsManager.render() + // Tag values + let possibleTagValues: {[key: string]: string[]} = {} + for (const [_arn, tags] of Object.entries(resourceTags)) { + for (const [key, value] of Object.entries(tags)) { + if (!possibleTagValues[key]) { + possibleTagValues[key] = [] + } + + if (value && !possibleTagValues[key].includes(value)) { + possibleTagValues[key].push(value) + } + } + } + // Return the processed data return { resources: processedResources, connections: [], containers, + tags: possibleTagValues, } } diff --git a/src/aws-app/process/resources/processResources.ts b/src/aws-app/process/resources/processResources.ts index ca8c5b7..2a0e63b 100644 --- a/src/aws-app/process/resources/processResources.ts +++ b/src/aws-app/process/resources/processResources.ts @@ -1,6 +1,7 @@ import {PlacementData, ProcessedResources} from '../types' +import {ResourceTags} from '@/types' -export const getProcessedResources = (placementData: PlacementData): ProcessedResources => { +export const getProcessedResources = (placementData: PlacementData, tags: ResourceTags): ProcessedResources => { const processedResources = {} as ProcessedResources for (const [arn, {name, service, type, variant}] of Object.entries(placementData)) { @@ -9,6 +10,7 @@ export const getProcessedResources = (placementData: PlacementData): ProcessedRe processedResources[arn] = { name, type: unifiedType, + tags: tags[arn] ?? {}, } } diff --git a/src/aws-app/process/types.ts b/src/aws-app/process/types.ts index 5afab3a..872ce1b 100644 --- a/src/aws-app/process/types.ts +++ b/src/aws-app/process/types.ts @@ -11,6 +11,7 @@ export type ResourcePlacementData = { availabilityZones: string[] subnets: string[] securityGroups: string[] + tags: {[key: string]: number} } export type PlacementData = { diff --git a/src/scanners/common/createGlobalScanner.ts b/src/scanners/common/createGlobalScanner.ts index ada26da..ce8c67d 100644 --- a/src/scanners/common/createGlobalScanner.ts +++ b/src/scanners/common/createGlobalScanner.ts @@ -5,11 +5,14 @@ import { Credentials, ScannerLifecycleHook, RateLimiter, + ResourceTags, } from '@/types' import {CreateGlobalScannerFunction, GetRateLimiterFunction} from '@/scanners/types' +import {fetchTags} from '@/scanners/common/fetchTags' type GlobalScanResult = { resources: Resources + tags: ResourceTags error: Error | null } @@ -18,6 +21,7 @@ async function performGlobalScan( scanFunction: GlobalScanFunction, credentials: Credentials, rateLimiter: RateLimiter, + tagsRateLimiter: RateLimiter, hooks: ScannerLifecycleHook[], ): Promise> { try { @@ -27,17 +31,20 @@ async function performGlobalScan( // Perform scan const resources = await scanFunction(credentials, rateLimiter) + // Fetch tags + const tags = await fetchTags(credentials, tagsRateLimiter) + // onComplete hook hooks.forEach((hook) => hook.onComplete?.(resources, service)) // Return resources - return {resources, error: null} + return {resources, tags, error: null} } catch (error) { // onError hook hooks.forEach((hook) => hook.onError?.(error as Error, service)) // Return error - return {resources: {} as Resources, error: error as Error} + return {resources: {} as Resources, tags: {}, error: error as Error} } } @@ -47,19 +54,28 @@ export const createGlobalScanner: CreateGlobalScannerFunction = { return async () => { - const {credentials, getRateLimiter, hooks} = options + const {credentials, getRateLimiter, tagsRateLimiter, hooks} = options // Perform global scan const rateLimiter = getRateLimiter(service) - const {resources, error} = await performGlobalScan(service, scanFunction, credentials, rateLimiter, hooks) + const {resources, tags, error} = await performGlobalScan( + service, + scanFunction, + credentials, + rateLimiter, + tagsRateLimiter, + hooks, + ) // Return resources and errors return { resources, + tags, errors: error ? [{service, message: error.message}] : [], } } diff --git a/src/scanners/common/createRegionalScanner.ts b/src/scanners/common/createRegionalScanner.ts index 103a935..da3d579 100644 --- a/src/scanners/common/createRegionalScanner.ts +++ b/src/scanners/common/createRegionalScanner.ts @@ -6,12 +6,15 @@ import { Credentials, ScannerLifecycleHook, RateLimiter, + ResourceTags, } from '@/types' import {CreateRegionalScannerFunction, GetRateLimiterFunction} from '@/scanners/types' +import {fetchTags} from '@/scanners/common/fetchTags' type RegionScanResult = { region: string resources: Resources | null + tags?: ResourceTags error: Error | null } @@ -21,6 +24,7 @@ async function scanRegion( region: string, credentials: Credentials, rateLimiter: RateLimiter, + tagsRateLimiter: RateLimiter, hooks: ScannerLifecycleHook[], ): Promise> { try { @@ -30,11 +34,14 @@ async function scanRegion( // Perform scan const resources = await scanFunction(credentials, rateLimiter, region) + // Fetch tags + const tags = await fetchTags(credentials, tagsRateLimiter) + // onComplete hook hooks.forEach((hook) => hook.onComplete?.(resources, service, region)) // Return resources - return {region, resources, error: null} + return {region, resources, tags, error: null} } catch (error) { // onError hook hooks.forEach((hook) => hook.onError?.(error as Error, service, region)) @@ -51,17 +58,18 @@ export const createRegionalScanner: CreateRegionalScannerFunction = { return async () => { - const {credentials, getRateLimiter, hooks} = options + const {credentials, getRateLimiter, tagsRateLimiter, hooks} = options // Scan each region in parallel const scanResults = await Promise.all( regions.map((region) => { const rateLimiter = getRateLimiter(service, region) - return scanRegion(service, scanFunction, region, credentials, rateLimiter, hooks) + return scanRegion(service, scanFunction, region, credentials, rateLimiter, tagsRateLimiter, hooks) }), ) @@ -73,6 +81,14 @@ export const createRegionalScanner: CreateRegionalScannerFunction = ) + // Aggregate resource tags + const tags = scanResults.reduce((acc, {tags}) => { + if (tags) { + Object.assign(acc, tags) + } + return acc + }, {} as ResourceTags) + // Extract errors const errors: ScannerError[] = scanResults .map(({region, error}) => { @@ -81,6 +97,6 @@ export const createRegionalScanner: CreateRegionalScannerFunction = => { + const client = new ResourceGroupsTaggingAPIClient({credentials}) + const tagResult: Record> = {} + + try { + let paginationToken: string | undefined = undefined + + do { + const command: GetResourcesCommand = new GetResourcesCommand({ + PaginationToken: paginationToken, + }) + + const response = await rateLimiter.throttle(() => client.send(command)) + paginationToken = response.PaginationToken + + for (const resourceData of response.ResourceTagMappingList ?? []) { + for (const tagData of resourceData.Tags ?? []) { + if (!resourceData.ResourceARN || !tagData.Key) { + continue + } + + if (!tagResult[resourceData.ResourceARN]) { + tagResult[resourceData.ResourceARN] = {} + } + + tagResult[resourceData.ResourceARN][tagData.Key] = tagData.Value + } + } + } while (paginationToken) + } catch (error) { + console.error('Error fetching tag resources:', error) + } + + return tagResult +} diff --git a/src/scanners/getAwsScanners.ts b/src/scanners/getAwsScanners.ts index a5fc317..0d9a514 100644 --- a/src/scanners/getAwsScanners.ts +++ b/src/scanners/getAwsScanners.ts @@ -53,9 +53,12 @@ export const getAwsScanners = ({ regions, shouldIncludeGlobalServices, }: GetAwsScannersArguments): Scanner[] => { + const tagsRateLimiter = getRateLimiter('resource-groups-tagging') + const options = { credentials, getRateLimiter, + tagsRateLimiter, hooks: hooks || [], } diff --git a/src/scanners/types.ts b/src/scanners/types.ts index f45ace7..4f74816 100644 --- a/src/scanners/types.ts +++ b/src/scanners/types.ts @@ -16,6 +16,7 @@ interface CreateScannerOptions { credentials: Credentials hooks: ScannerLifecycleHook[] getRateLimiter: GetRateLimiterFunction + tagsRateLimiter: RateLimiter } export type CreateRegionalScannerFunction = ( diff --git a/src/types.ts b/src/types.ts index 675cc8c..6c166f4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -74,6 +74,10 @@ export type Resources = { [arn: string]: T } +export type Tags = Record + +export type ResourceTags = Record + export type Credentials = AwsCredentialIdentity | undefined export interface RateLimiter { @@ -106,6 +110,7 @@ export type ScannerError = { export type ScannerResult = { resources: Resources + tags?: ResourceTags errors: ScannerError[] } @@ -174,6 +179,7 @@ export interface ProcessedData { [arn: string]: { name: string type: string + tags: {[key: string]: string | undefined} } } connections: { @@ -189,6 +195,7 @@ export interface ProcessedData { securityGroups: {[arn: string]: SecurityGroupContainer} subnets: {[arn: string]: SubnetContainer} } + tags: {[key: string]: string[]} } export interface StandardOutputSchema { @@ -196,6 +203,7 @@ export interface StandardOutputSchema { docVersion: string resources: Resources processed?: ProcessedData + tags: ResourceTags errors: ScannerError[] metadata: { account: string diff --git a/tests/aws-app/main.test.ts b/tests/aws-app/main.test.ts index 6bb520e..f4ceb78 100644 --- a/tests/aws-app/main.test.ts +++ b/tests/aws-app/main.test.ts @@ -37,10 +37,12 @@ describe('main function', () => { 'dummy:arn:1': { name: '1', type: 'dummy:instance', + tags: {}, }, 'dummy:arn:2': { name: '2', type: 'dummy:table', + tags: {}, }, }, connections: [], @@ -77,6 +79,7 @@ describe('main function', () => { securityGroups: {}, subnets: {}, }, + tags: {}, } beforeEach(() => { @@ -180,6 +183,7 @@ describe('main function', () => { startedAt: expectedStartedAt, finishedAt: expectedFinishedAt, }, + tags: {}, } expect(saveAsJson).toHaveBeenCalledWith( diff --git a/tests/scanners/common/createGlobalScanner.test.ts b/tests/scanners/common/createGlobalScanner.test.ts index 1ef4d9b..2bfc7c9 100644 --- a/tests/scanners/common/createGlobalScanner.test.ts +++ b/tests/scanners/common/createGlobalScanner.test.ts @@ -3,10 +3,14 @@ import {Resources, ResourceDescription, Credentials, ScannerLifecycleHook} from import {RateLimiterMockImpl} from 'tests/mocks/RateLimiterMock' import {createMockedHook} from 'tests/mocks/hookMock' +import {fetchTags} from '@/scanners/common/fetchTags' + +jest.mock('@/scanners/common/fetchTags') describe('createGlobalScanner', () => { let mockRateLimiter: RateLimiterMockImpl let mockGetRateLimiter: jest.Mock + let mockTagsRateLimiter: RateLimiterMockImpl let mockHooks: ScannerLifecycleHook[] let mockCredentials: Credentials let mockScanFunction: jest.Mock @@ -14,9 +18,11 @@ describe('createGlobalScanner', () => { beforeEach(() => { mockRateLimiter = new RateLimiterMockImpl() mockGetRateLimiter = jest.fn().mockReturnValue(mockRateLimiter) + mockTagsRateLimiter = new RateLimiterMockImpl() mockHooks = [createMockedHook(), createMockedHook()] mockCredentials = undefined mockScanFunction = jest.fn().mockResolvedValue({} as Resources) + ;(fetchTags as jest.Mock).mockResolvedValue({}) jest.clearAllMocks() }) @@ -25,6 +31,7 @@ describe('createGlobalScanner', () => { const scanner = createGlobalScanner('mockService', mockScanFunction, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -35,6 +42,7 @@ describe('createGlobalScanner', () => { const scanner = createGlobalScanner('mockService', mockScanFunction, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -52,13 +60,14 @@ describe('createGlobalScanner', () => { const scanner = createGlobalScanner('mockService', mockScanFunction, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) const result = await scanner() expect(mockScanFunction).toHaveBeenCalledWith(mockCredentials, mockRateLimiter) - expect(result).toEqual({resources: mockResources, errors: []}) + expect(result).toEqual({resources: mockResources, tags: {}, errors: []}) }) it('should return errors if scan fails', async () => { @@ -68,6 +77,7 @@ describe('createGlobalScanner', () => { const scanner = createGlobalScanner('mockService', mockScanFunction, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -77,6 +87,7 @@ describe('createGlobalScanner', () => { expect(mockScanFunction).toHaveBeenCalledWith(mockCredentials, mockRateLimiter) expect(result).toEqual({ resources: {} as Resources, + tags: {}, errors: [{service: 'mockService', message: mockError.message}], }) }) @@ -91,6 +102,7 @@ describe('createGlobalScanner', () => { const scanner = createGlobalScanner('mockService', mockScanFunction, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -113,6 +125,7 @@ describe('createGlobalScanner', () => { const scanner = createGlobalScanner('mockService', mockScanFunction, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) diff --git a/tests/scanners/common/createRegionalScanner.test.ts b/tests/scanners/common/createRegionalScanner.test.ts index 5864a56..af19beb 100644 --- a/tests/scanners/common/createRegionalScanner.test.ts +++ b/tests/scanners/common/createRegionalScanner.test.ts @@ -3,10 +3,14 @@ import {Resources, ResourceDescription, Credentials, ScannerLifecycleHook} from import {RateLimiterMockImpl} from 'tests/mocks/RateLimiterMock' import {createMockedHook} from 'tests/mocks/hookMock' +import {fetchTags} from '@/scanners/common/fetchTags' + +jest.mock('@/scanners/common/fetchTags') describe('createRegionalScanner', () => { let mockRateLimiter: RateLimiterMockImpl let mockGetRateLimiter: jest.Mock + let mockTagsRateLimiter: RateLimiterMockImpl let mockHooks: ScannerLifecycleHook[] let mockCredentials: Credentials let mockScanFunction: jest.Mock @@ -15,9 +19,11 @@ describe('createRegionalScanner', () => { beforeEach(() => { mockRateLimiter = new RateLimiterMockImpl() mockGetRateLimiter = jest.fn().mockReturnValue(mockRateLimiter) + mockTagsRateLimiter = new RateLimiterMockImpl() mockHooks = [createMockedHook(), createMockedHook()] mockCredentials = undefined mockScanFunction = jest.fn().mockResolvedValue({} as Resources) + ;(fetchTags as jest.Mock).mockResolvedValue({}) regions = ['eu-west-1', 'eu-west-2', 'us-east-1'] jest.clearAllMocks() @@ -27,6 +33,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -37,6 +44,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -56,6 +64,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -77,6 +86,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -94,6 +104,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -123,6 +134,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) @@ -142,6 +154,7 @@ describe('createRegionalScanner', () => { const scanner = createRegionalScanner('mockService', mockScanFunction, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockTagsRateLimiter, hooks: mockHooks, }) diff --git a/tests/scanners/getAwsScanners.test.ts b/tests/scanners/getAwsScanners.test.ts index 9e282ab..4dce7ad 100644 --- a/tests/scanners/getAwsScanners.test.ts +++ b/tests/scanners/getAwsScanners.test.ts @@ -85,11 +85,13 @@ describe('getAwsScanners', () => { expect(createRegionalScannerSpy).toHaveBeenCalledWith('autoscaling/groups', getAutoScalingResources, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockGetRateLimiter('resource-groups-tagging'), hooks: mockHooks, }) expect(createRegionalScannerSpy).toHaveBeenCalledWith('ec2/instances', getEC2Instances, regions, { credentials: mockCredentials, getRateLimiter: mockGetRateLimiter, + tagsRateLimiter: mockGetRateLimiter('resource-groups-tagging'), hooks: mockHooks, }) })