Skip to content

Commit 48fa296

Browse files
authored
Merge branch 'main' into sqs-kms-policy-condition
2 parents a43996f + 0aad6c9 commit 48fa296

3 files changed

Lines changed: 47 additions & 17 deletions

File tree

packages/@aws-cdk/aws-iam/lib/policy-statement.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { IConstruct } from 'constructs';
33
import { Group } from './group';
44
import {
55
AccountPrincipal, AccountRootPrincipal, AnyPrincipal, ArnPrincipal, CanonicalUserPrincipal,
6-
FederatedPrincipal, IPrincipal, PrincipalBase, PrincipalPolicyFragment, ServicePrincipal, ServicePrincipalOpts,
6+
FederatedPrincipal, IPrincipal, PrincipalBase, PrincipalPolicyFragment, ServicePrincipal, ServicePrincipalOpts, validateConditionObject,
77
} from './principals';
88
import { normalizeStatement } from './private/postprocess-policy-document';
99
import { LITERAL_STRING_KEY, mergePrincipal, sum } from './util';
@@ -380,6 +380,8 @@ export class PolicyStatement {
380380
*/
381381
public addCondition(key: string, value: Condition) {
382382
this.assertNotFrozen('addCondition');
383+
validateConditionObject(value);
384+
383385
const existingValue = this._condition[key];
384386
this._condition[key] = existingValue ? { ...existingValue, ...value } : value;
385387
}
@@ -670,19 +672,15 @@ export enum Effect {
670672
* Condition for when an IAM policy is in effect. Maps from the keys in a request's context to
671673
* a string value or array of string values. See the Conditions interface for more details.
672674
*/
673-
export type Condition = any;
675+
export type Condition = unknown;
674676

675-
// NOTE! We'd ideally like to type this as `Record<string, any>`, because the
676-
// API expects a map which can take either strings or lists of strings.
677-
//
678-
// However, if we were to change this right now, the Java bindings for CDK would
679-
// emit a type of `Map<String, Object>`, but the most common types people would
680-
// instantiate would be an `ImmutableMap<String, String>` which would not be
681-
// assignable to `Map<String, Object>`. The types don't have a built-in notion
682-
// of co-contravariance, you have to indicate that on the type. So jsii would first
683-
// need to emit the type as `Map<String, ? extends Object>`.
677+
// NOTE! We would have liked to have typed this as `Record<string, unknown>`, but in some places
678+
// of the code we are assuming we can pass a `CfnJson` object into where a `Condition` is expected,
679+
// and that wouldn't typecheck anymore.
684680
//
685-
// Feature request in https://github.com/aws/jsii/issues/1517
681+
// Needs to be `unknown` instead of `any` so that the type of `Conditions` is
682+
// `Record<string, unknown>`; if it had been `Record<string, any>`, TypeScript would have allowed
683+
// passing an array into `conditions` arguments (where it needs to be a map).
686684

687685
/**
688686
* Conditions for when an IAM Policy is in effect, specified in the following structure:
@@ -877,4 +875,4 @@ class OrderedSet<A> {
877875
public direct(): readonly A[] {
878876
return this.array;
879877
}
880-
}
878+
}

packages/@aws-cdk/aws-iam/lib/principals.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,15 @@ export class PrincipalWithConditions extends PrincipalAdapter {
267267
* Add a condition to the principal
268268
*/
269269
public addCondition(key: string, value: Condition) {
270+
validateConditionObject(value);
271+
270272
const existingValue = this.additionalConditions[key];
271-
this.additionalConditions[key] = existingValue ? { ...existingValue, ...value } : value;
273+
if (!existingValue) {
274+
this.additionalConditions[key] = value;
275+
}
276+
validateConditionObject(existingValue);
277+
278+
this.additionalConditions[key] = { ...existingValue, ...value };
272279
}
273280

274281
/**
@@ -335,6 +342,9 @@ export class PrincipalWithConditions extends PrincipalAdapter {
335342
throw new Error(`multiple "${operator}" conditions cannot be merged if one of them contains an unresolved token`);
336343
}
337344

345+
validateConditionObject(existing);
346+
validateConditionObject(condition);
347+
338348
mergedConditions[operator] = { ...existing, ...condition };
339349
});
340350
return mergedConditions;
@@ -913,3 +923,17 @@ class ServicePrincipalToken implements cdk.IResolvable {
913923
return `<${this.service}>`;
914924
}
915925
}
926+
927+
/**
928+
* Validate that the given value is a valid Condition object
929+
*
930+
* The type of `Condition` should have been different, but it's too late for that.
931+
*
932+
* Also, the IAM library relies on being able to pass in a `CfnJson` instance for
933+
* a `Condition`.
934+
*/
935+
export function validateConditionObject(x: unknown): asserts x is Record<string, unknown> {
936+
if (!x || typeof x !== 'object' || Array.isArray(x)) {
937+
throw new Error('A Condition should be represented as a map of operator to value');
938+
}
939+
}

packages/@aws-cdk/aws-lambda/lib/function-base.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -618,9 +618,9 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC
618618

619619
if (!conditions) { return undefined; }
620620

621-
const sourceArn = conditions.ArnLike ? conditions.ArnLike['aws:SourceArn'] : undefined;
622-
const sourceAccount = conditions.StringEquals ? conditions.StringEquals['aws:SourceAccount'] : undefined;
623-
const principalOrgID = conditions.StringEquals ? conditions.StringEquals['aws:PrincipalOrgID'] : undefined;
621+
const sourceArn = requireString(requireObject(conditions.ArnLike)?.['aws:SourceArn']);
622+
const sourceAccount = requireString(requireObject(conditions.StringEquals)?.['aws:SourceAccount']);
623+
const principalOrgID = requireString(requireObject(conditions.StringEquals)?.['aws:PrincipalOrgID']);
624624

625625
// PrincipalOrgID cannot be combined with any other conditions
626626
if (principalOrgID && (sourceArn || sourceAccount)) {
@@ -768,3 +768,11 @@ class LatestVersion extends FunctionBase implements IVersion {
768768
return addAlias(this, this, aliasName, options);
769769
}
770770
}
771+
772+
function requireObject(x: unknown): Record<string, unknown> | undefined {
773+
return x && typeof x === 'object' && !Array.isArray(x) ? x as any : undefined;
774+
}
775+
776+
function requireString(x: unknown): string | undefined {
777+
return x && typeof x === 'string' ? x : undefined;
778+
}

0 commit comments

Comments
 (0)