From 797f920c8cf0c3ca23c9e5ad03ba9c016de94d8d Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:07:12 +0000 Subject: [PATCH 01/11] feat(cli-plugin-contract): introduce a public contract between CLI and plugins --- .../@aws-cdk/cli-plugin-contract/.eslintrc.js | 8 + .../@aws-cdk/cli-plugin-contract/.gitignore | 29 +++ .../@aws-cdk/cli-plugin-contract/.npmignore | 23 ++ packages/@aws-cdk/cli-plugin-contract/LICENSE | 201 ++++++++++++++++++ packages/@aws-cdk/cli-plugin-contract/NOTICE | 16 ++ .../@aws-cdk/cli-plugin-contract/README.md | 52 +++++ .../cli-plugin-contract/jest.config.js | 10 + .../@aws-cdk/cli-plugin-contract/lib/index.ts | 101 +++++++++ .../@aws-cdk/cli-plugin-contract/package.json | 56 +++++ .../lib/api/aws-auth/credential-plugins.ts | 9 +- .../aws-cdk/lib/api/aws-auth/sdk-provider.ts | 2 +- .../api/bootstrap/bootstrap-environment.ts | 2 +- .../lib/api/bootstrap/deploy-bootstrap.ts | 2 +- .../aws-cdk/lib/api/environment-access.ts | 2 +- .../garbage-collection/garbage-collector.ts | 2 +- .../aws-cdk/lib/api/hotswap-deployments.ts | 2 +- .../lib/api/logs/find-cloudwatch-logs.ts | 2 +- .../api/plugin/credential-provider-source.ts | 30 --- packages/aws-cdk/lib/api/plugin/index.ts | 3 +- packages/aws-cdk/lib/api/plugin/plugin.ts | 35 +-- packages/aws-cdk/lib/api/util/placeholders.ts | 2 +- packages/aws-cdk/lib/commands/migrate.ts | 2 +- packages/aws-cdk/lib/util/asset-publishing.ts | 2 +- packages/aws-cdk/package.json | 4 + .../test/api/plugin/plugin-host.test.ts | 5 +- .../aws-cdk/test/api/sdk-provider.test.ts | 3 +- packages/aws-cdk/test/cdk-toolkit.test.ts | 2 +- tools/@aws-cdk/pkglint/lib/rules.ts | 1 + 28 files changed, 524 insertions(+), 84 deletions(-) create mode 100644 packages/@aws-cdk/cli-plugin-contract/.eslintrc.js create mode 100644 packages/@aws-cdk/cli-plugin-contract/.gitignore create mode 100644 packages/@aws-cdk/cli-plugin-contract/.npmignore create mode 100644 packages/@aws-cdk/cli-plugin-contract/LICENSE create mode 100644 packages/@aws-cdk/cli-plugin-contract/NOTICE create mode 100644 packages/@aws-cdk/cli-plugin-contract/README.md create mode 100644 packages/@aws-cdk/cli-plugin-contract/jest.config.js create mode 100644 packages/@aws-cdk/cli-plugin-contract/lib/index.ts create mode 100644 packages/@aws-cdk/cli-plugin-contract/package.json delete mode 100644 packages/aws-cdk/lib/api/plugin/credential-provider-source.ts diff --git a/packages/@aws-cdk/cli-plugin-contract/.eslintrc.js b/packages/@aws-cdk/cli-plugin-contract/.eslintrc.js new file mode 100644 index 0000000000000..b284f20df26e9 --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/.eslintrc.js @@ -0,0 +1,8 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; + +baseConfig.rules['import/no-extraneous-dependencies'] = ['error', { devDependencies: true, peerDependencies: true } ]; +baseConfig.rules['import/order'] = 'off'; +baseConfig.rules['@aws-cdk/invalid-cfn-imports'] = 'off'; + +module.exports = baseConfig; diff --git a/packages/@aws-cdk/cli-plugin-contract/.gitignore b/packages/@aws-cdk/cli-plugin-contract/.gitignore new file mode 100644 index 0000000000000..573a12d965554 --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/.gitignore @@ -0,0 +1,29 @@ +*.js +*.js.map +*.d.ts +*.gz +!lib/init-templates/**/javascript/**/* +node_modules +dist +.jsii +tsconfig.json + +# Generated by generate.sh +build-info.json + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk + +assets.json +npm-shrinkwrap.json +!.eslintrc.js +!jest.config.js + +junit.xml + +lib/**/*.wasm +lib/**/*.yaml diff --git a/packages/@aws-cdk/cli-plugin-contract/.npmignore b/packages/@aws-cdk/cli-plugin-contract/.npmignore new file mode 100644 index 0000000000000..5890f9a58f970 --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/.npmignore @@ -0,0 +1,23 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +**/*.snapshot diff --git a/packages/@aws-cdk/cli-plugin-contract/LICENSE b/packages/@aws-cdk/cli-plugin-contract/LICENSE new file mode 100644 index 0000000000000..dcf28b52a83af --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/cli-plugin-contract/NOTICE b/packages/@aws-cdk/cli-plugin-contract/NOTICE new file mode 100644 index 0000000000000..9d28b2500bc86 --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/NOTICE @@ -0,0 +1,16 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Third party attributions of this package can be found in the THIRD_PARTY_LICENSES file diff --git a/packages/@aws-cdk/cli-plugin-contract/README.md b/packages/@aws-cdk/cli-plugin-contract/README.md new file mode 100644 index 0000000000000..915908ffd07be --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/README.md @@ -0,0 +1,52 @@ +# AWS CDK CLI Library + + + +--- + +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) + +--- + + + +## Overview + +As any piece of software that interacts with an AWS account, the CDK CLI, needs +AWS credentials for authentication and authorization. When it comes to choose +which sources to get credentials from, it has the same behavior as the AWS CLI. +But this basic behavior may result in some failure scenarios: + +- The initial set of credentials to work with cannot be obtained. +- The account to which the initial credentials belong to cannot be obtained. +- The account associated to the credentials is different from the account on + which the CLI is trying to operate on. + +Since these failures may happen for valid use case reasons, the CDK CLI offers +an alternative mechanism for users to provide AWS credentials: credential +plugins. This package defines the types and the contract between the CLI and the +plugins, which plugin authors are expected to adhere to. + +[//]: # (TODO explain how the CLI gets hold of a plugin in the first place) + +Once the CLI gets an instance of a plugin, it first initializes plugin by +calling the `Plugin.init()` method, if one is defined. The CLI uses this method +to pass an instance of `CredentialProviderSourceRepository` to the plugin. The +plugin, in turn, can use the repository to register one or more instances of +`CredentialProviderSource`, which is where the actual logic for providing +credentials is located. + +If, in the authentication process, the CLI decides to use plugins, it will try +each credential provider source in the order in which they were registered. For +each source, the first thing the CLI will check is whether the source is ready +to interact at all, by calling the `isAvailable()` +method. If it is available, the next check is whether it can provide credentials +for the specific account the CLI is targeting at that moment. This is the +`canProvideCredentials()` method. + +If both checks pass, the CLI asks the source for credentials by calling +`getProvider()`. In addition to the account ID, this method also receives the +`Mode` of operation, which can be `ForReading` or `ForWriting`. This information +may be useful to tailor the credentials for the use case. For example, if the +CLI needs the credentials only for reading, the plugin may return credentials +with more restricted permissions. \ No newline at end of file diff --git a/packages/@aws-cdk/cli-plugin-contract/jest.config.js b/packages/@aws-cdk/cli-plugin-contract/jest.config.js new file mode 100644 index 0000000000000..d052cbb29f05d --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 60, + }, + }, +}; diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts new file mode 100644 index 0000000000000..35cedbc262130 --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -0,0 +1,101 @@ +/** + * The basic contract for plug-ins to adhere to:: + * + * import { CustomCredentialProviderSource, CredentialProviderSourceRepository, Plugin } from '@aws-cdk/cli-plugin-contract'; + * + * export default class FooCDKPlugIn implements Plugin { + * public readonly version = '1'; + * + * public init(host: CredentialProviderSourceRepository) { + * host.registerCredentialProviderSource(new CustomCredentialProviderSource()); + * } + * } + * + */ +export interface Plugin { + /** + * The version of the plug-in interface used by the plug-in. This will be used by + * the plug-in host to handle version changes. + */ + version: '1'; + + /** + * When defined, this function is invoked right after the plug-in has been loaded, + * so that the plug-in is able to initialize itself. It may call methods of the + * `CredentialProviderSourceRepository` instance it receives to register new + * `CredentialProviderSource` instances. + */ + init?: (host: CredentialProviderSourceRepository) => void; +} + +export interface AwsCredentials { + /** + * AWS access key ID + */ + readonly accessKeyId: string; + /** + * AWS secret access key + */ + readonly secretAccessKey: string; + /** + * A security or session token to use with these credentials. Usually + * present for temporary credentials. + */ + readonly sessionToken?: string; + /** + * AWS credential scope for this set of credentials. + */ + readonly credentialScope?: string; + /** + * AWS accountId. + */ + readonly accountId?: string; + + /** + * Refreshes the current credentials. + */ + getPromise?: () => Promise; +} + +export enum Mode { + ForReading, + ForWriting, +} + +/** + */ +export interface CredentialProviderSource { + name: string; + + /** + * Whether the credential provider is even online + * + * Guaranteed to be called before any of the other functions are called. + */ + isAvailable(): Promise; + + /** + * Whether the credential provider can provide credentials for the given account. + */ + canProvideCredentials(accountId: string): Promise; + + /** + * Construct a credential provider for the given account and the given access mode + * + * Guaranteed to be called only if canProvideCredentails() returned true at some point. + */ + getProvider(accountId: string, mode: Mode): Promise; +} + +/** + * A list of credential provider sources + */ +export interface CredentialProviderSourceRepository { + + /** + * Registers a credential provider source. If, in the authentication process, + * the CLI decides to try credentials from the plugins, it will go through the + * sources registered in this way, in the same order as they were registered. + */ + registerCredentialProviderSource(source: CredentialProviderSource): void; +} diff --git a/packages/@aws-cdk/cli-plugin-contract/package.json b/packages/@aws-cdk/cli-plugin-contract/package.json new file mode 100644 index 0000000000000..d4046d8f4f432 --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/package.json @@ -0,0 +1,56 @@ +{ + "name": "@aws-cdk/cli-plugin-contract", + "description": "Contract between the CLI and authentication plugins, for the exchange of AWS credentials", + "version": "0.0.0", + "types": "lib/index.d.ts", + "main": "lib/index.js", + "scripts": { + "build": "cdk-build", + "lint": "cdk-lint", + "pkglint": "pkglint -f", + "watch": "cdk-watch", + "build+test": "yarn build", + "build+extract": "yarn build", + "build+test+package": "yarn build+test && yarn package", + "build+test+extract": "yarn build+test", + "package": "cdk-package" + }, + "ubergen": { + "exclude": true + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "ts-node": "^10.9.2" + }, + "repository": { + "url": "https://github.com/aws/aws-cdk.git", + "type": "git", + "directory": "packages/@aws-cdk/cli-plugin-contract" + }, + "keywords": [ + "aws", + "cdk" + ], + "homepage": "https://github.com/aws/aws-cdk", + "separate-module": true, + "engines": { + "node": ">= 14.15.0" + }, + "stability": "stable", + "maturity": "stable", + "publishConfig": { + "tag": "latest" + }, + "awscdkio": { + "announce": false + }, + "dependencies": {}, + "peerDependencies": {} +} diff --git a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts index 06900ef3807cb..8be804bdfe180 100644 --- a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts +++ b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts @@ -1,6 +1,7 @@ +import { AwsCredentials, CredentialProviderSource, Mode } from '@aws-cdk/cli-plugin-contract'; import type { AwsCredentialIdentity } from '@smithy/types'; import { debug, warning } from '../../logging'; -import { CredentialProviderSource, Mode, PluginHost } from '../plugin'; +import { PluginHost } from '../plugin'; /** * Cache for credential providers. @@ -65,13 +66,13 @@ export class CredentialPlugins { // Otherwise it must have returned credentials. const credentials = (providerOrCreds as any).resolvePromise ? await (providerOrCreds as any).resolvePromise() - : providerOrCreds; + : providerOrCreds as AwsCredentials; // Another layer of backwards compatibility: in SDK v2, the credentials object // is both a container and a provider. So we need to force the refresh using getPromise. // In SDK v3, these two responsibilities are separate, and the getPromise doesn't exist. - if ((credentials as any).getPromise) { - await (credentials as any).getPromise(); + if (credentials.getPromise) { + await credentials.getPromise(); } return { credentials, pluginName: source.name }; diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts index 0aded40cfce1f..32008ee20b93a 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts @@ -1,4 +1,5 @@ import * as os from 'os'; +import { Mode } from '@aws-cdk/cli-plugin-contract'; import { ContextLookupRoleOptions } from '@aws-cdk/cloud-assembly-schema'; import { Environment, EnvironmentUtils, UNKNOWN_ACCOUNT, UNKNOWN_REGION } from '@aws-cdk/cx-api'; import { AssumeRoleCommandInput } from '@aws-sdk/client-sts'; @@ -11,7 +12,6 @@ import { CredentialPlugins } from './credential-plugins'; import { SDK } from './sdk'; import { debug, warning } from '../../logging'; import { traceMethods } from '../../util/tracing'; -import { Mode } from '../plugin'; export type AssumeRoleAdditionalOptions = Partial>; diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts index 779a056e3e666..59a7e83a62da0 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts @@ -1,5 +1,6 @@ import { info } from 'console'; import * as path from 'path'; +import { Mode } from '@aws-cdk/cli-plugin-contract'; import * as cxapi from '@aws-cdk/cx-api'; import type { BootstrapEnvironmentOptions, BootstrappingParameters } from './bootstrap-props'; import { BootstrapStack, bootstrapVersionFromTemplate } from './deploy-bootstrap'; @@ -9,7 +10,6 @@ import { loadStructuredFile, serializeStructure } from '../../serialize'; import { rootDir } from '../../util/directories'; import type { SDK, SdkProvider } from '../aws-auth'; import type { SuccessfulDeployStackResult } from '../deploy-stack'; -import { Mode } from '../plugin'; export type BootstrapSource = { source: 'legacy' } | { source: 'default' } | { source: 'custom'; templateFile: string }; diff --git a/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts b/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts index 00ef3be686798..680748aabc9c5 100644 --- a/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts +++ b/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts @@ -1,5 +1,6 @@ import * as os from 'os'; import * as path from 'path'; +import { Mode } from '@aws-cdk/cli-plugin-contract'; import { ArtifactType } from '@aws-cdk/cloud-assembly-schema'; import { CloudAssemblyBuilder, Environment, EnvironmentUtils } from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; @@ -14,7 +15,6 @@ import * as logging from '../../logging'; import type { SDK, SdkProvider } from '../aws-auth'; import { assertIsSuccessfulDeployStackResult, deployStack, SuccessfulDeployStackResult } from '../deploy-stack'; import { NoBootstrapStackEnvironmentResources } from '../environment-resources'; -import { Mode } from '../plugin'; import { DEFAULT_TOOLKIT_STACK_NAME, ToolkitInfo } from '../toolkit-info'; /** diff --git a/packages/aws-cdk/lib/api/environment-access.ts b/packages/aws-cdk/lib/api/environment-access.ts index 1985801c2151e..5074216d2e729 100644 --- a/packages/aws-cdk/lib/api/environment-access.ts +++ b/packages/aws-cdk/lib/api/environment-access.ts @@ -1,9 +1,9 @@ +import { Mode } from '@aws-cdk/cli-plugin-contract'; import * as cxapi from '@aws-cdk/cx-api'; import { SDK } from './aws-auth'; import { warning } from '../logging'; import { CredentialsOptions, SdkForEnvironment, SdkProvider } from './aws-auth/sdk-provider'; import { EnvironmentResources, EnvironmentResourcesRegistry } from './environment-resources'; -import { Mode } from './plugin'; import { replaceEnvPlaceholders, StringWithoutPlaceholders } from './util/placeholders'; /** diff --git a/packages/aws-cdk/lib/api/garbage-collection/garbage-collector.ts b/packages/aws-cdk/lib/api/garbage-collection/garbage-collector.ts index 3bab51095d7f7..7416c417197a9 100644 --- a/packages/aws-cdk/lib/api/garbage-collection/garbage-collector.ts +++ b/packages/aws-cdk/lib/api/garbage-collection/garbage-collector.ts @@ -1,3 +1,4 @@ +import { Mode } from '@aws-cdk/cli-plugin-contract'; import * as cxapi from '@aws-cdk/cx-api'; import { ImageIdentifier } from '@aws-sdk/client-ecr'; import { Tag } from '@aws-sdk/client-s3'; @@ -8,7 +9,6 @@ import { IECRClient, IS3Client, SDK, SdkProvider } from '../aws-auth'; import { DEFAULT_TOOLKIT_STACK_NAME, ToolkitInfo } from '../toolkit-info'; import { ProgressPrinter } from './progress-printer'; import { ActiveAssetCache, BackgroundStackRefresh, refreshStacks } from './stack-refresh'; -import { Mode } from '../plugin'; // Must use a require() otherwise esbuild complains // eslint-disable-next-line @typescript-eslint/no-require-imports diff --git a/packages/aws-cdk/lib/api/hotswap-deployments.ts b/packages/aws-cdk/lib/api/hotswap-deployments.ts index 3bfb3cd04c07c..6d058e3c718e1 100644 --- a/packages/aws-cdk/lib/api/hotswap-deployments.ts +++ b/packages/aws-cdk/lib/api/hotswap-deployments.ts @@ -1,3 +1,4 @@ +import { Mode } from '@aws-cdk/cli-plugin-contract'; import * as cfn_diff from '@aws-cdk/cloudformation-diff'; import * as cxapi from '@aws-cdk/cx-api'; import { WaiterResult } from '@smithy/util-waiter'; @@ -27,7 +28,6 @@ import { } from './hotswap/s3-bucket-deployments'; import { isHotswappableStateMachineChange } from './hotswap/stepfunctions-state-machines'; import { NestedStackTemplates, loadCurrentTemplateWithNestedStacks } from './nested-stack-helpers'; -import { Mode } from './plugin'; import { CloudFormationStack } from './util/cloudformation'; // Must use a require() otherwise esbuild complains about calling a namespace diff --git a/packages/aws-cdk/lib/api/logs/find-cloudwatch-logs.ts b/packages/aws-cdk/lib/api/logs/find-cloudwatch-logs.ts index 760f63ad0f4c1..e1d5ca1f9c9f4 100644 --- a/packages/aws-cdk/lib/api/logs/find-cloudwatch-logs.ts +++ b/packages/aws-cdk/lib/api/logs/find-cloudwatch-logs.ts @@ -1,10 +1,10 @@ +import { Mode } from '@aws-cdk/cli-plugin-contract'; import type { CloudFormationStackArtifact, Environment } from '@aws-cdk/cx-api'; import type { StackResourceSummary } from '@aws-sdk/client-cloudformation'; import { debug } from '../../logging'; import type { SDK, SdkProvider } from '../aws-auth'; import { EnvironmentAccess } from '../environment-access'; import { EvaluateCloudFormationTemplate, LazyListStackResources } from '../evaluate-cloudformation-template'; -import { Mode } from '../plugin'; import { DEFAULT_TOOLKIT_STACK_NAME } from '../toolkit-info'; // resource types that have associated CloudWatch Log Groups that should _not_ be monitored diff --git a/packages/aws-cdk/lib/api/plugin/credential-provider-source.ts b/packages/aws-cdk/lib/api/plugin/credential-provider-source.ts deleted file mode 100644 index 78e781ae6e259..0000000000000 --- a/packages/aws-cdk/lib/api/plugin/credential-provider-source.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { AwsCredentialIdentity } from '@smithy/types'; -export enum Mode { - ForReading, - ForWriting, -} - -/** - */ -export interface CredentialProviderSource { - name: string; - - /** - * Whether the credential provider is even online - * - * Guaranteed to be called before any of the other functions are called. - */ - isAvailable(): Promise; - - /** - * Whether the credential provider can provide credentials for the given account. - */ - canProvideCredentials(accountId: string): Promise; - - /** - * Construct a credential provider for the given account and the given access mode - * - * Guaranteed to be called only if canProvideCredentails() returned true at some point. - */ - getProvider(accountId: string, mode: Mode): Promise; -} diff --git a/packages/aws-cdk/lib/api/plugin/index.ts b/packages/aws-cdk/lib/api/plugin/index.ts index 8bf5be8809f41..223d3a34cae6d 100644 --- a/packages/aws-cdk/lib/api/plugin/index.ts +++ b/packages/aws-cdk/lib/api/plugin/index.ts @@ -1,3 +1,2 @@ export * from './plugin'; -export * from './context-provider-plugin'; -export * from './credential-provider-source'; \ No newline at end of file +export * from './context-provider-plugin'; \ No newline at end of file diff --git a/packages/aws-cdk/lib/api/plugin/plugin.ts b/packages/aws-cdk/lib/api/plugin/plugin.ts index 16df596e4cccb..437337125c8f0 100644 --- a/packages/aws-cdk/lib/api/plugin/plugin.ts +++ b/packages/aws-cdk/lib/api/plugin/plugin.ts @@ -1,8 +1,8 @@ import { inspect } from 'util'; +import { CredentialProviderSource, CredentialProviderSourceRepository, Plugin } from '@aws-cdk/cli-plugin-contract'; import * as chalk from 'chalk'; import { type ContextProviderPlugin, isContextProviderPlugin } from './context-provider-plugin'; -import type { CredentialProviderSource } from './credential-provider-source'; import { error } from '../../logging'; export let TESTING = false; @@ -11,42 +11,11 @@ export function markTesting() { TESTING = true; } -/** - * The basic contract for plug-ins to adhere to:: - * - * import { Plugin, PluginHost } from 'aws-cdk'; - * import { CustomCredentialProviderSource } from './custom-credential-provider-source'; - * - * export default class FooCDKPlugIn implements PluginHost { - * public readonly version = '1'; - * - * public init(host: PluginHost) { - * host.registerCredentialProviderSource(new CustomCredentialProviderSource()); - * } - * } - * - */ -export interface Plugin { - /** - * The version of the plug-in interface used by the plug-in. This will be used by - * the plug-in host to handle version changes. - */ - version: '1'; - - /** - * When defined, this function is invoked right after the plug-in has been loaded, - * so that the plug-in is able to initialize itself. It may call methods of the - * ``PluginHost`` instance it receives to register new ``CredentialProviderSource`` - * instances. - */ - init?: (host: PluginHost) => void; -} - /** * A utility to manage plug-ins. * */ -export class PluginHost { +export class PluginHost implements CredentialProviderSourceRepository { public static instance = new PluginHost(); /** diff --git a/packages/aws-cdk/lib/api/util/placeholders.ts b/packages/aws-cdk/lib/api/util/placeholders.ts index 2d38d05db531d..76d9d7c9ed6bc 100644 --- a/packages/aws-cdk/lib/api/util/placeholders.ts +++ b/packages/aws-cdk/lib/api/util/placeholders.ts @@ -1,7 +1,7 @@ +import { Mode } from '@aws-cdk/cli-plugin-contract'; import { type Environment, EnvironmentPlaceholders } from '@aws-cdk/cx-api'; import { Branded } from '../../util/type-brands'; import type { SdkProvider } from '../aws-auth/sdk-provider'; -import { Mode } from '../plugin/credential-provider-source'; /** * Replace the {ACCOUNT} and {REGION} placeholders in all strings found in a complex object. diff --git a/packages/aws-cdk/lib/commands/migrate.ts b/packages/aws-cdk/lib/commands/migrate.ts index 15a9115efbdc0..0c135df06c4d6 100644 --- a/packages/aws-cdk/lib/commands/migrate.ts +++ b/packages/aws-cdk/lib/commands/migrate.ts @@ -2,6 +2,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import * as fs from 'fs'; import * as path from 'path'; +import { Mode } from '@aws-cdk/cli-plugin-contract'; import { Environment, UNKNOWN_ACCOUNT, UNKNOWN_REGION } from '@aws-cdk/cx-api'; import type { DescribeGeneratedTemplateCommandOutput, @@ -20,7 +21,6 @@ import * as chalk from 'chalk'; import { cliInit } from '../../lib/init'; import { print } from '../../lib/logging'; import type { ICloudFormationClient, SdkProvider } from '../api/aws-auth'; -import { Mode } from '../api/plugin'; import { CloudFormationStack } from '../api/util/cloudformation'; import { zipDirectory } from '../util/archive'; const camelCase = require('camelcase'); diff --git a/packages/aws-cdk/lib/util/asset-publishing.ts b/packages/aws-cdk/lib/util/asset-publishing.ts index fdc432d9d26c6..2022b5c44dc6f 100644 --- a/packages/aws-cdk/lib/util/asset-publishing.ts +++ b/packages/aws-cdk/lib/util/asset-publishing.ts @@ -1,3 +1,4 @@ +import { Mode } from '@aws-cdk/cli-plugin-contract'; import { type Environment, UNKNOWN_ACCOUNT, UNKNOWN_REGION } from '@aws-cdk/cx-api'; import { type Account, @@ -14,7 +15,6 @@ import { } from 'cdk-assets'; import type { SDK } from '../api'; import type { SdkProvider } from '../api/aws-auth/sdk-provider'; -import { Mode } from '../api/plugin'; import { debug, error, print } from '../logging'; export interface PublishAssetsOptions { diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 4cad33d3794d2..d85e4a011723e 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -102,6 +102,7 @@ "xml-js": "^1.6.11" }, "dependencies": { + "@aws-cdk/cli-plugin-contract": "0.0.0", "@aws-cdk/cloud-assembly-schema": "^38.0.0", "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", @@ -187,5 +188,8 @@ "maturity": "stable", "publishConfig": { "tag": "latest" + }, + "peerDependencies": { + "@aws-cdk/cli-plugin-contract": "0.0.0" } } diff --git a/packages/aws-cdk/test/api/plugin/plugin-host.test.ts b/packages/aws-cdk/test/api/plugin/plugin-host.test.ts index c2f96b6afa459..c05db9c001301 100644 --- a/packages/aws-cdk/test/api/plugin/plugin-host.test.ts +++ b/packages/aws-cdk/test/api/plugin/plugin-host.test.ts @@ -1,6 +1,5 @@ -import { ContextProviderPlugin } from '../../../lib/api/plugin/context-provider-plugin'; -import { CredentialProviderSource } from '../../../lib/api/plugin/credential-provider-source'; -import { PluginHost, markTesting } from '../../../lib/api/plugin/plugin'; +import { CredentialProviderSource } from '@aws-cdk/cli-plugin-contract'; +import { ContextProviderPlugin, PluginHost, markTesting } from '../../../lib/api/plugin'; markTesting(); diff --git a/packages/aws-cdk/test/api/sdk-provider.test.ts b/packages/aws-cdk/test/api/sdk-provider.test.ts index f5b276c17431d..5bc66aff072f0 100644 --- a/packages/aws-cdk/test/api/sdk-provider.test.ts +++ b/packages/aws-cdk/test/api/sdk-provider.test.ts @@ -1,5 +1,6 @@ import * as os from 'os'; import { bockfs } from '@aws-cdk/cdk-build-tools'; +import { Mode } from '@aws-cdk/cli-plugin-contract'; import * as cxapi from '@aws-cdk/cx-api'; import { AssumeRoleCommand, GetCallerIdentityCommand } from '@aws-sdk/client-sts'; import * as promptly from 'promptly'; @@ -8,7 +9,7 @@ import { FakeSts, RegisterRoleOptions, RegisterUserOptions } from './fake-sts'; import { ConfigurationOptions, SDK, SdkProvider } from '../../lib/api/aws-auth'; import { AwsCliCompatible } from '../../lib/api/aws-auth/awscli-compatible'; import { defaultCliUserAgent } from '../../lib/api/aws-auth/user-agent'; -import { Mode, PluginHost } from '../../lib/api/plugin'; +import { PluginHost } from '../../lib/api/plugin'; import * as logging from '../../lib/logging'; import { withMocked } from '../util'; import { mockSTSClient, restoreSdkMocksToDefault } from '../util/mock-sdk'; diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index cfc9aca1bc398..2e9728a2b9220 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -60,6 +60,7 @@ jest.setTimeout(30_000); import 'aws-sdk-client-mock'; import * as os from 'os'; import * as path from 'path'; +import { Mode } from '@aws-cdk/cli-plugin-contract'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { Manifest } from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; @@ -86,7 +87,6 @@ import { RollbackStackResult, } from '../lib/api/deployments'; import { HotswapMode } from '../lib/api/hotswap/common'; -import { Mode } from '../lib/api/plugin'; import { Template } from '../lib/api/util/cloudformation'; import { CdkToolkit, markTesting, Tag } from '../lib/cdk-toolkit'; import { RequireApproval } from '../lib/diff'; diff --git a/tools/@aws-cdk/pkglint/lib/rules.ts b/tools/@aws-cdk/pkglint/lib/rules.ts index b6a105ad7089e..f28774c4b8353 100644 --- a/tools/@aws-cdk/pkglint/lib/rules.ts +++ b/tools/@aws-cdk/pkglint/lib/rules.ts @@ -1663,6 +1663,7 @@ export class UbergenPackageVisibility extends ValidationRule { // The ONLY (non-alpha) packages that should be published for v2. // These include dependencies of the CDK CLI (aws-cdk). private readonly v2PublicPackages = [ + '@aws-cdk/cli-plugin-contract', '@aws-cdk/cloudformation-diff', '@aws-cdk/cx-api', '@aws-cdk/region-info', From af8d279b62e7c749bafdb9ed7d11cc3e437b3803 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:52:31 +0000 Subject: [PATCH 02/11] README update --- .../@aws-cdk/cli-plugin-contract/README.md | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/cli-plugin-contract/README.md b/packages/@aws-cdk/cli-plugin-contract/README.md index 915908ffd07be..c9c017d92e701 100644 --- a/packages/@aws-cdk/cli-plugin-contract/README.md +++ b/packages/@aws-cdk/cli-plugin-contract/README.md @@ -12,10 +12,11 @@ ## Overview -As any piece of software that interacts with an AWS account, the CDK CLI, needs +As any piece of software that interacts with an AWS account, the CDK CLI needs AWS credentials for authentication and authorization. When it comes to choose -which sources to get credentials from, it has the same behavior as the AWS CLI. -But this basic behavior may result in some failure scenarios: +which sources to get credentials from, it has +the [same behavior as the AWS CLI][cli-auth]. But this basic behavior may result +in some failure scenarios: - The initial set of credentials to work with cannot be obtained. - The account to which the initial credentials belong to cannot be obtained. @@ -24,10 +25,14 @@ But this basic behavior may result in some failure scenarios: Since these failures may happen for valid use case reasons, the CDK CLI offers an alternative mechanism for users to provide AWS credentials: credential -plugins. This package defines the types and the contract between the CLI and the -plugins, which plugin authors are expected to adhere to. +provider plugins. -[//]: # (TODO explain how the CLI gets hold of a plugin in the first place) +This package defines the types and the contract between the CLI and the plugins, +which plugin authors are expected to adhere to. + +The entrypoint is communicated to the CLI via the `--plugin` command line +argument. The value of this argument should be a JavaScript file that, when +`require`'d, will return an instance of the `Plugin` interface. Once the CLI gets an instance of a plugin, it first initializes plugin by calling the `Plugin.init()` method, if one is defined. The CLI uses this method @@ -49,4 +54,6 @@ If both checks pass, the CLI asks the source for credentials by calling `Mode` of operation, which can be `ForReading` or `ForWriting`. This information may be useful to tailor the credentials for the use case. For example, if the CLI needs the credentials only for reading, the plugin may return credentials -with more restricted permissions. \ No newline at end of file +with more restricted permissions. + +[cli-auth]: (https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-authentication.html) \ No newline at end of file From 819ca45352e1d6b11f5610cfedf7c59cbf37526e Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:19:34 +0000 Subject: [PATCH 03/11] Fixes --- .../@aws-cdk/cli-plugin-contract/README.md | 2 +- .../@aws-cdk/cli-plugin-contract/package.json | 3 ++- .../cli-plugin-contract/tsconfig.json | 24 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 packages/@aws-cdk/cli-plugin-contract/tsconfig.json diff --git a/packages/@aws-cdk/cli-plugin-contract/README.md b/packages/@aws-cdk/cli-plugin-contract/README.md index c9c017d92e701..743925b99fac0 100644 --- a/packages/@aws-cdk/cli-plugin-contract/README.md +++ b/packages/@aws-cdk/cli-plugin-contract/README.md @@ -56,4 +56,4 @@ may be useful to tailor the credentials for the use case. For example, if the CLI needs the credentials only for reading, the plugin may return credentials with more restricted permissions. -[cli-auth]: (https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-authentication.html) \ No newline at end of file +[cli-auth]: (https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-authentication.html) diff --git a/packages/@aws-cdk/cli-plugin-contract/package.json b/packages/@aws-cdk/cli-plugin-contract/package.json index d4046d8f4f432..9d4118e556537 100644 --- a/packages/@aws-cdk/cli-plugin-contract/package.json +++ b/packages/@aws-cdk/cli-plugin-contract/package.json @@ -13,7 +13,8 @@ "build+extract": "yarn build", "build+test+package": "yarn build+test && yarn package", "build+test+extract": "yarn build+test", - "package": "cdk-package" + "package": "cdk-package", + "test": "cdk-test" }, "ubergen": { "exclude": true diff --git a/packages/@aws-cdk/cli-plugin-contract/tsconfig.json b/packages/@aws-cdk/cli-plugin-contract/tsconfig.json new file mode 100644 index 0000000000000..4ff0e9d59a3ad --- /dev/null +++ b/packages/@aws-cdk/cli-plugin-contract/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target":"ES2020", + "module": "commonjs", + "lib": ["es2020", "dom"], + "declaration": true, + "composite": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "strictPropertyInitialization":false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true + }, + "include": ["**/*.ts" ], + "exclude": ["node_modules"] +} From 54dac392c64c3eb08d1d634ba0ca82a8e282d69a Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:31:44 +0000 Subject: [PATCH 04/11] yarn build && yarn test --- packages/@aws-cdk/cli-plugin-contract/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cli-plugin-contract/package.json b/packages/@aws-cdk/cli-plugin-contract/package.json index 9d4118e556537..860ea3a2597a8 100644 --- a/packages/@aws-cdk/cli-plugin-contract/package.json +++ b/packages/@aws-cdk/cli-plugin-contract/package.json @@ -9,7 +9,7 @@ "lint": "cdk-lint", "pkglint": "pkglint -f", "watch": "cdk-watch", - "build+test": "yarn build", + "build+test": "yarn build && yarn test", "build+extract": "yarn build", "build+test+package": "yarn build+test && yarn package", "build+test+extract": "yarn build+test", From d7b671a5f113568d742d62fb8150203c9139ede7 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:39:05 +0000 Subject: [PATCH 05/11] New test --- .../test/api/credential-plugins.test.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 packages/aws-cdk/test/api/credential-plugins.test.ts diff --git a/packages/aws-cdk/test/api/credential-plugins.test.ts b/packages/aws-cdk/test/api/credential-plugins.test.ts new file mode 100644 index 0000000000000..e59c542aa3ec3 --- /dev/null +++ b/packages/aws-cdk/test/api/credential-plugins.test.ts @@ -0,0 +1,40 @@ +import { AwsCredentials, Mode } from '@aws-cdk/cli-plugin-contract'; +import { CredentialPlugins } from '../../lib/api/aws-auth/credential-plugins'; +import { PluginHost } from '../../lib/api/plugin'; + +test('returns credential from plugin', async () => { + // GIVEN + const creds = { + accessKeyId: 'aaa', + secretAccessKey: 'bbb', + getPromise: () => Promise.resolve(), + }; + const host = PluginHost.instance; + + host.registerCredentialProviderSource({ + name: 'Fake', + + canProvideCredentials(_accountId: string): Promise { + return Promise.resolve(true); + }, + + isAvailable(): Promise { + return Promise.resolve(true); + }, + + getProvider(_accountId: string, _mode: Mode): Promise { + return Promise.resolve(creds); + }, + }); + + const plugins = new CredentialPlugins(); + + // WHEN + const pluginCredentials = await plugins.fetchCredentialsFor('aaa', Mode.ForReading); + + // THEN + expect(pluginCredentials).toEqual({ + credentials: creds, + pluginName: 'Fake', + }); +}); \ No newline at end of file From 16d3d4de9bbff655b0a67a25aabb175c73164a9a Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:51:58 +0000 Subject: [PATCH 06/11] const enum --- packages/@aws-cdk/cli-plugin-contract/lib/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts index 35cedbc262130..4d4c75311990d 100644 --- a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -57,7 +57,7 @@ export interface AwsCredentials { getPromise?: () => Promise; } -export enum Mode { +export const enum Mode { ForReading, ForWriting, } From 3aa719bffda4a8918bc1427e6de18e41669eff13 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:37:33 +0000 Subject: [PATCH 07/11] Revert "const enum" This reverts commit 16d3d4de9bbff655b0a67a25aabb175c73164a9a. --- packages/@aws-cdk/cli-plugin-contract/lib/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts index 4d4c75311990d..35cedbc262130 100644 --- a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -57,7 +57,7 @@ export interface AwsCredentials { getPromise?: () => Promise; } -export const enum Mode { +export enum Mode { ForReading, ForWriting, } From 2dad46017c2ae7b089fa040edb07b18e4272897a Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:43:15 +0000 Subject: [PATCH 08/11] More details on `getPromise()` --- packages/@aws-cdk/cli-plugin-contract/lib/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts index 35cedbc262130..32c9fbdb3647e 100644 --- a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -52,7 +52,9 @@ export interface AwsCredentials { readonly accountId?: string; /** - * Refreshes the current credentials. + * Refreshes the current credentials. This function only exists for + * legacy reasons, to be compatible with the `AWS.Credentials` class. + * Plugins that use the AWS SDK v3 don't need this. */ getPromise?: () => Promise; } From ddd6733a6edfbfdee01d87c3c429258e65d0f7f3 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:17:08 +0000 Subject: [PATCH 09/11] Add `expiration` field. --- packages/@aws-cdk/cli-plugin-contract/lib/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts index 32c9fbdb3647e..73f31edf4db52 100644 --- a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -51,6 +51,11 @@ export interface AwsCredentials { */ readonly accountId?: string; + /** + * A Date when the identity or credential will no longer be accepted. + */ + readonly expiration?: Date; + /** * Refreshes the current credentials. This function only exists for * legacy reasons, to be compatible with the `AWS.Credentials` class. From 390e99f0e391146c3e3a237a5454d49f8e9d2807 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:20:01 +0000 Subject: [PATCH 10/11] Formatting --- packages/@aws-cdk/cli-plugin-contract/lib/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts index 73f31edf4db52..362b450519972 100644 --- a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -33,19 +33,23 @@ export interface AwsCredentials { * AWS access key ID */ readonly accessKeyId: string; + /** * AWS secret access key */ readonly secretAccessKey: string; + /** * A security or session token to use with these credentials. Usually * present for temporary credentials. */ readonly sessionToken?: string; + /** * AWS credential scope for this set of credentials. */ readonly credentialScope?: string; + /** * AWS accountId. */ From 236dd39edc72bb09360c09a811ae7e551dde0af4 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:36:25 +0000 Subject: [PATCH 11/11] Remove `as any` --- packages/@aws-cdk/cli-plugin-contract/lib/index.ts | 9 ++++++--- packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts | 4 ++-- packages/aws-cdk/package.json | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts index 362b450519972..c13924b117f12 100644 --- a/packages/@aws-cdk/cli-plugin-contract/lib/index.ts +++ b/packages/@aws-cdk/cli-plugin-contract/lib/index.ts @@ -61,11 +61,14 @@ export interface AwsCredentials { readonly expiration?: Date; /** - * Refreshes the current credentials. This function only exists for - * legacy reasons, to be compatible with the `AWS.Credentials` class. - * Plugins that use the AWS SDK v3 don't need this. + * Refreshes the current credentials. */ getPromise?: () => Promise; + + /** + * Returns a Promise of AwsCredentials. + */ + resolvePromise?: () => Promise; } export enum Mode { diff --git a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts index 8be804bdfe180..824055d1703cb 100644 --- a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts +++ b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts @@ -64,8 +64,8 @@ export class CredentialPlugins { // Backwards compatibility: if the plugin returns a ProviderChain, resolve that chain. // Otherwise it must have returned credentials. - const credentials = (providerOrCreds as any).resolvePromise - ? await (providerOrCreds as any).resolvePromise() + const credentials = providerOrCreds.resolvePromise + ? await providerOrCreds.resolvePromise() : providerOrCreds as AwsCredentials; // Another layer of backwards compatibility: in SDK v2, the credentials object diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 4699d49e8a176..82b9d27c02e3a 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -69,6 +69,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cli-plugin-contract": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/yargs-gen": "0.0.0", "@octokit/rest": "^18.12.0", @@ -102,7 +103,6 @@ "xml-js": "^1.6.11" }, "dependencies": { - "@aws-cdk/cli-plugin-contract": "0.0.0", "@aws-cdk/cloud-assembly-schema": "^38.0.0", "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0",