All files / src persona.ts

98.3% Statements 116/118
96.15% Branches 25/26
100% Functions 5/5
98.3% Lines 116/118

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 1191x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 17x 17x 17x 1x 1x 16x 16x 16x 16x 17x 1x 1x 15x 15x 15x 15x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6x     6x 6x 6x 6x 18x 18x 6x 6x 6x 6x 6x 6x 6x 6x 18x 18x 6x 6x 6x 1x 1x 15x 9x 9x 15x 15x 2x 2x 15x 1x 1x 15x 15x 8x 8x 15x 1x 1x 12x 7x 7x 5x 12x 1x 1x 12x 1x 1x 12x 12x 8x 8x 12x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as kms from 'aws-cdk-lib/aws-kms';
import { Construct } from 'constructs';
 
import {
  Activity,
  VPCOptions,
  KMSOptions,
} from './activity';
 
export interface PersonaProps extends VPCOptions, KMSOptions {
  readonly activities: Activity[];
}
 
export class Persona extends Construct {
 
  public readonly activities: Activity[];
 
  public constructor(scope: Construct, id: string, props: PersonaProps) {
    super(scope, id);
 
    if (props.activities.length === 0) {
      throw TypeError('The array activities must be of type Activity[] with at least one element.');
    }
 
    this.activities = props.activities;
 
    const activityNames = this.activities.map((activity) => {return activity.activityName;});
    if (activityNames.length !== new Set(activityNames).size) {
      throw TypeError('The array activities must be of type Activity[] and must not contain duplicate activities.');
    }
 
    this.customizeVPC(props.subnets, props.securityGroups);
    this.customizeKMS(props.dataKeys, props.volumeKeys);
  }
 
  /**
     * Creates role with permissions of persona
     * @param scope the Construct scope.
     * @param id the resource id.
     * @param roleNameSuffix the name suffix of the role that will be created, if empty the role will have the name of the activity.
     * @param roleDescription the description of the role that will be created.
     * @returns - The role that is created with the permissions of the persona
     */
  public createRole(scope: Construct, id: string, roleNameSuffix: string, roleDescription: string = ''): iam.IRole {
    if (!roleNameSuffix || !roleNameSuffix.length) {
      throw TypeError('The role name should be a non empty string');
    }
 
    const policies: iam.Policy[] = [];
 
    for (const activity of this.activities) {
      policies.push(activity.createPolicy(scope));
    }
 
    const role = new iam.Role(scope, id, {
      roleName: `SageMaker-${roleNameSuffix}`,
      description: roleDescription,
      assumedBy: this.activities[0].createPrincipal(),
    });
 
    for (const policy of policies) {
      role.attachInlinePolicy(policy);
    }
 
    return role;
  }
 
  public customizeVPC(subnets?: ec2.ISubnet[], securityGroups?: ec2.ISecurityGroup[]) {
    if (!subnets && !securityGroups) {
      return;
    }
 
    if (!subnets || !subnets.length) {
      throw TypeError('The array subnets must be of type ec2.ISubnet[] with at least one element.');
    }
    if (!securityGroups || !securityGroups.length) {
      throw TypeError('The array securityGroups must be of type ec2.ISecurityGroup[] with at least one element.');
    }
 
    for (const activity of this.activities) {
      activity.customizeVPC(subnets, securityGroups);
    }
  }
 
  public customizeKMS(dataKeys?: kms.IKey[], volumeKeys?: kms.IKey[]) {
    if (!dataKeys && !volumeKeys) {
      return;
    }
 
    if (!dataKeys || !dataKeys.length) {
      throw TypeError('The array dataKeys must be of type kms.IKey[] with at least one element.');
    }
    if (!volumeKeys || !volumeKeys.length) {
      throw TypeError('The array volumeKeys must be of type kms.IKey[] with at least one element.');
    }
 
    for (const activity of this.activities) {
      activity.customizeKMS(dataKeys, volumeKeys);
    }
  }
 
  /**
     * Grant permissions of activity to identity
     * @param identity identity to be granted permissions
     * @returns - The grant with the permissions granted to the identity
     */
  public grantPermissionsTo(identity: iam.IGrantable): iam.Grant {
    let grant = this.activities[0].grantPermissionsTo(identity);
    for (let i = 1; i < this.activities.length; i++) {
      grant = grant.combine(this.activities[i].grantPermissionsTo(identity));
    }
 
    return grant;
  }
 
}