Skip to content

Commit 10756c1

Browse files
authored
feat(kms): throw ValidationErrors instead of untyped errors (#34431)
### Issue Relates to #32569 ### Reason for this change untyped Errors are not recommended ### Description of changes `ValidationError`s everywhere ### Describe any new or updated permissions being added None ### Description of how you validated changes Existing tests. Exemptions granted as this is a refactor of existing code. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 2e7c55b commit 10756c1

File tree

3 files changed

+21
-21
lines changed

3 files changed

+21
-21
lines changed

packages/aws-cdk-lib/.eslintrc.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ const noThrowDefaultErrorNotYetSupported = [
2424
'aws-globalaccelerator',
2525
'aws-globalaccelerator-endpoints',
2626
'aws-iam',
27-
'aws-kms',
2827
'aws-lambda-destinations',
2928
'aws-lambda-event-sources',
3029
'aws-lambda-nodejs',

packages/aws-cdk-lib/aws-kms/lib/alias.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Construct } from 'constructs';
22
import { IKey } from './key';
33
import { CfnAlias } from './kms.generated';
44
import * as iam from '../../aws-iam';
5-
import { FeatureFlags, RemovalPolicy, Resource, Stack, Token, Tokenization } from '../../core';
5+
import { FeatureFlags, RemovalPolicy, Resource, Stack, Token, Tokenization, ValidationError } from '../../core';
66
import { addConstructMetadata } from '../../core/lib/metadata-resource';
77
import { KMS_ALIAS_NAME_REF } from '../../cx-api';
88

@@ -192,8 +192,8 @@ export class Alias extends AliasBase {
192192
public readonly keyArn = Stack.of(this).formatArn({ service: 'kms', resource: aliasName });
193193
public readonly keyId = aliasName;
194194
public readonly aliasName = aliasName;
195-
public get aliasTargetKey(): IKey { throw new Error('Cannot access aliasTargetKey on an Alias imported by Alias.fromAliasName().'); }
196-
public addAlias(_alias: string): Alias { throw new Error('Cannot call addAlias on an Alias imported by Alias.fromAliasName().'); }
195+
public get aliasTargetKey(): IKey { throw new ValidationError('Cannot access aliasTargetKey on an Alias imported by Alias.fromAliasName().', this); }
196+
public addAlias(_alias: string): Alias { throw new ValidationError('Cannot call addAlias on an Alias imported by Alias.fromAliasName().', this); }
197197
public addToResourcePolicy(_statement: iam.PolicyStatement, _allowNoOp?: boolean): iam.AddToResourcePolicyResult {
198198
return { statementAdded: false };
199199
}
@@ -223,15 +223,15 @@ export class Alias extends AliasBase {
223223
}
224224

225225
if (aliasName === REQUIRED_ALIAS_PREFIX) {
226-
throw new Error(`Alias must include a value after "${REQUIRED_ALIAS_PREFIX}": ${aliasName}`);
226+
throw new ValidationError(`Alias must include a value after "${REQUIRED_ALIAS_PREFIX}": ${aliasName}`, scope);
227227
}
228228

229229
if (aliasName.toLocaleLowerCase().startsWith(DISALLOWED_PREFIX)) {
230-
throw new Error(`Alias cannot start with ${DISALLOWED_PREFIX}: ${aliasName}`);
230+
throw new ValidationError(`Alias cannot start with ${DISALLOWED_PREFIX}: ${aliasName}`, scope);
231231
}
232232

233233
if (!aliasName.match(/^[a-zA-Z0-9:/_-]{1,256}$/)) {
234-
throw new Error('Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-');
234+
throw new ValidationError('Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-', scope);
235235
}
236236
} else if (Tokenization.reverseString(aliasName).firstValue && Tokenization.reverseString(aliasName).firstToken === undefined) {
237237
const valueInToken = Tokenization.reverseString(aliasName).firstValue;
@@ -241,11 +241,11 @@ export class Alias extends AliasBase {
241241
}
242242

243243
if (valueInToken.toLocaleLowerCase().startsWith(DISALLOWED_PREFIX)) {
244-
throw new Error(`Alias cannot start with ${DISALLOWED_PREFIX}: ${aliasName}`);
244+
throw new ValidationError(`Alias cannot start with ${DISALLOWED_PREFIX}: ${aliasName}`, scope);
245245
}
246246

247247
if (!valueInToken.match(/^[a-zA-Z0-9:/_-]{1,256}$/)) {
248-
throw new Error('Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-');
248+
throw new ValidationError('Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-', scope);
249249
}
250250
}
251251

packages/aws-cdk-lib/aws-kms/lib/key.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ResourceProps,
1919
Stack,
2020
Token,
21+
ValidationError,
2122
} from '../../core';
2223
import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource';
2324
import * as cxapi from '../../cx-api';
@@ -163,7 +164,7 @@ abstract class KeyBase extends Resource implements IKey {
163164

164165
if (!this.policy) {
165166
if (allowNoOp) { return { statementAdded: false }; }
166-
throw new Error(`Unable to add statement to IAM resource policy for KMS key: ${JSON.stringify(stack.resolve(this.keyArn))}`);
167+
throw new ValidationError(`Unable to add statement to IAM resource policy for KMS key: ${JSON.stringify(stack.resolve(this.keyArn))}`, this);
167168
}
168169

169170
this.policy.addStatements(statement);
@@ -630,7 +631,7 @@ export class Key extends KeyBase {
630631

631632
const keyResourceName = Stack.of(scope).splitArn(keyArn, ArnFormat.SLASH_RESOURCE_NAME).resourceName;
632633
if (!keyResourceName) {
633-
throw new Error(`KMS key ARN must be in the format 'arn:<partition>:kms:<region>:<account>:key/<keyId>', got: '${keyArn}'`);
634+
throw new ValidationError(`KMS key ARN must be in the format 'arn:<partition>:kms:<region>:<account>:key/<keyId>', got: '${keyArn}'`, scope);
634635
}
635636

636637
return new Import(keyResourceName, {
@@ -671,9 +672,9 @@ export class Key extends KeyBase {
671672
// throw an exception suggesting to use the other importing methods instead.
672673
// We might make this parsing logic smarter later,
673674
// but let's start by erroring out.
674-
throw new Error('Could not parse the PolicyDocument of the passed AWS::KMS::Key resource because it contains CloudFormation functions. ' +
675+
throw new ValidationError('Could not parse the PolicyDocument of the passed AWS::KMS::Key resource because it contains CloudFormation functions. ' +
675676
'This makes it impossible to create a mutable IKey from that Policy. ' +
676-
'You have to use fromKeyArn instead, passing it the ARN attribute property of the low-level CfnKey');
677+
'You have to use fromKeyArn instead, passing it the ARN attribute property of the low-level CfnKey', cfnKey);
677678
}
678679

679680
// change the key policy of the L1, so that all changes done in the L2 are reflected in the resulting template
@@ -730,7 +731,7 @@ export class Key extends KeyBase {
730731
}
731732
}
732733
if (Token.isUnresolved(options.aliasName)) {
733-
throw new Error('All arguments to Key.fromLookup() must be concrete (no Tokens)');
734+
throw new ValidationError('All arguments to Key.fromLookup() must be concrete (no Tokens)', scope);
734735
}
735736

736737
const attributes: cxapi.KeyContextResponse = ContextProvider.getValue(scope, {
@@ -814,25 +815,25 @@ export class Key extends KeyBase {
814815
const keySpec = props.keySpec ?? KeySpec.SYMMETRIC_DEFAULT;
815816
const keyUsage = props.keyUsage ?? KeyUsage.ENCRYPT_DECRYPT;
816817
if (denyLists[keyUsage].includes(keySpec)) {
817-
throw new Error(`key spec '${keySpec}' is not valid with usage '${keyUsage}'`);
818+
throw new ValidationError(`key spec '${keySpec}' is not valid with usage '${keyUsage}'`, this);
818819
}
819820

820821
if (keySpec.startsWith('HMAC') && props.enableKeyRotation) {
821-
throw new Error('key rotation cannot be enabled on HMAC keys');
822+
throw new ValidationError('key rotation cannot be enabled on HMAC keys', this);
822823
}
823824

824825
if (keySpec !== KeySpec.SYMMETRIC_DEFAULT && props.enableKeyRotation) {
825-
throw new Error('key rotation cannot be enabled on asymmetric keys');
826+
throw new ValidationError('key rotation cannot be enabled on asymmetric keys', this);
826827
}
827828

828829
this.enableKeyRotation = props.enableKeyRotation;
829830

830831
if (props.rotationPeriod) {
831832
if (props.enableKeyRotation === false) {
832-
throw new Error('\'rotationPeriod\' cannot be specified when \'enableKeyRotation\' is disabled');
833+
throw new ValidationError('\'rotationPeriod\' cannot be specified when \'enableKeyRotation\' is disabled', this);
833834
}
834835
if (props.rotationPeriod.toDays() < 90 || props.rotationPeriod.toDays() > 2560) {
835-
throw new Error(`'rotationPeriod' value must between 90 and 2650 days. Received: ${props.rotationPeriod.toDays()}`);
836+
throw new ValidationError(`'rotationPeriod' value must between 90 and 2650 days. Received: ${props.rotationPeriod.toDays()}`, this);
836837
}
837838
// If rotationPeriod is specified, enableKeyRotation is set to true by default
838839
if (props.enableKeyRotation === undefined) {
@@ -845,7 +846,7 @@ export class Key extends KeyBase {
845846
this.policy = props.policy ?? new iam.PolicyDocument();
846847
if (defaultKeyPoliciesFeatureEnabled) {
847848
if (props.trustAccountIdentities === false) {
848-
throw new Error('`trustAccountIdentities` cannot be false if the @aws-cdk/aws-kms:defaultKeyPolicies feature flag is set');
849+
throw new ValidationError('`trustAccountIdentities` cannot be false if the @aws-cdk/aws-kms:defaultKeyPolicies feature flag is set', this);
849850
}
850851

851852
this.trustAccountIdentities = true;
@@ -866,7 +867,7 @@ export class Key extends KeyBase {
866867
if (props.pendingWindow) {
867868
pendingWindowInDays = props.pendingWindow.toDays();
868869
if (pendingWindowInDays < 7 || pendingWindowInDays > 30) {
869-
throw new Error(`'pendingWindow' value must between 7 and 30 days. Received: ${pendingWindowInDays}`);
870+
throw new ValidationError(`'pendingWindow' value must between 7 and 30 days. Received: ${pendingWindowInDays}`, this);
870871
}
871872
}
872873

0 commit comments

Comments
 (0)