@meyicloud/meyi-insight-server 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/controllers/tenant.controller.js +1 -1
  2. package/dist/controllers/tenant.controller.js.map +1 -1
  3. package/dist/features/ai-usage/ai-usage.controller.d.ts +7 -0
  4. package/dist/features/ai-usage/ai-usage.controller.d.ts.map +1 -0
  5. package/dist/features/ai-usage/ai-usage.controller.js +32 -0
  6. package/dist/features/ai-usage/ai-usage.controller.js.map +1 -0
  7. package/dist/features/ai-usage/ai-usage.model.d.ts +24 -0
  8. package/dist/features/ai-usage/ai-usage.model.d.ts.map +1 -0
  9. package/dist/features/ai-usage/ai-usage.model.js +105 -0
  10. package/dist/features/ai-usage/ai-usage.model.js.map +1 -0
  11. package/dist/features/ai-usage/ai-usage.query.d.ts +13 -0
  12. package/dist/features/ai-usage/ai-usage.query.d.ts.map +1 -0
  13. package/dist/features/ai-usage/ai-usage.query.js +119 -0
  14. package/dist/features/ai-usage/ai-usage.query.js.map +1 -0
  15. package/dist/features/ai-usage/ai-usage.routes.d.ts +8 -0
  16. package/dist/features/ai-usage/ai-usage.routes.d.ts.map +1 -0
  17. package/dist/features/ai-usage/ai-usage.routes.js +14 -0
  18. package/dist/features/ai-usage/ai-usage.routes.js.map +1 -0
  19. package/dist/features/ai-usage/ai-usage.service.d.ts +9 -0
  20. package/dist/features/ai-usage/ai-usage.service.d.ts.map +1 -0
  21. package/dist/features/ai-usage/ai-usage.service.js +52 -0
  22. package/dist/features/ai-usage/ai-usage.service.js.map +1 -0
  23. package/dist/features/ai-usage/ai-usage.types.d.ts +107 -0
  24. package/dist/features/ai-usage/ai-usage.types.d.ts.map +1 -0
  25. package/dist/features/ai-usage/ai-usage.types.js +14 -0
  26. package/dist/features/ai-usage/ai-usage.types.js.map +1 -0
  27. package/dist/features/ai-usage/index.d.ts +5 -0
  28. package/dist/features/ai-usage/index.d.ts.map +1 -0
  29. package/dist/features/ai-usage/index.js +5 -0
  30. package/dist/features/ai-usage/index.js.map +1 -0
  31. package/dist/features/sources/cloudtrail/stackTemplates.d.ts +1 -1
  32. package/dist/features/sources/cloudtrail/stackTemplates.d.ts.map +1 -1
  33. package/dist/features/sources/cloudtrail/stackTemplates.js +17 -18
  34. package/dist/features/sources/cloudtrail/stackTemplates.js.map +1 -1
  35. package/dist/features/sources/cloudtrail/template.d.ts.map +1 -1
  36. package/dist/features/sources/cloudtrail/template.js +146 -21
  37. package/dist/features/sources/cloudtrail/template.js.map +1 -1
  38. package/dist/migrations/run.d.ts.map +1 -1
  39. package/dist/migrations/run.js +30 -15
  40. package/dist/migrations/run.js.map +1 -1
  41. package/dist/pipeline/defaults/pipelineDefaults.js +1 -1
  42. package/dist/routes/index.d.ts +2 -0
  43. package/dist/routes/index.d.ts.map +1 -1
  44. package/dist/routes/index.js +6 -1
  45. package/dist/routes/index.js.map +1 -1
  46. package/dist/server.d.ts.map +1 -1
  47. package/dist/server.js +1 -0
  48. package/dist/server.js.map +1 -1
  49. package/dist/service.d.ts +2 -0
  50. package/dist/service.d.ts.map +1 -1
  51. package/dist/service.js +4 -0
  52. package/dist/service.js.map +1 -1
  53. package/dist/services/tenant.service.js +2 -2
  54. package/dist/services/tenant.service.js.map +1 -1
  55. package/dist/tenancy.d.ts +1 -0
  56. package/dist/tenancy.d.ts.map +1 -1
  57. package/dist/tenancy.js +9 -3
  58. package/dist/tenancy.js.map +1 -1
  59. package/package.json +75 -75
@@ -1,3 +1,3 @@
1
- export declare const STACK_YAML = "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n Meyi Connect Security Monitoring - Regional Events Stack.\n Deploys regional security alerting rules and SNS webhook delivery.\n\nParameters:\n Environment:\n Type: String\n Default: \"MeyiConnect\"\n Description: Environment name (used as a prefix for resource names)\n\n WebhookUrl:\n Type: String\n Description: MeyiConnect webhook URL for security alerts.\n\n CreateCloudTrail:\n Type: String\n Default: 'false'\n Description: Kept for backwards compatibility.\n\n PrimaryRegion:\n Type: String\n Default: 'us-east-1'\n Description: Kept for backwards compatibility.\n\n DeploymentMode:\n Type: String\n Default: 'Organizations'\n Description: Kept for backwards compatibility.\n\nResources:\n\n # ============================================================\n # SNS TOPIC & SUBSCRIPTION FOR ALERTS\n # ============================================================\n\n SecurityAlertsTopic:\n Type: AWS::SNS::Topic\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n\n SecurityAlertsTopicPolicy:\n Type: AWS::SNS::TopicPolicy\n Properties:\n Topics:\n - !Ref SecurityAlertsTopic\n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Principal:\n Service: events.amazonaws.com\n Action: sns:Publish\n Resource: !Ref SecurityAlertsTopic\n\n WebhookSubscription:\n Type: AWS::SNS::Subscription\n Properties:\n TopicArn: !Ref SecurityAlertsTopic\n Endpoint: !Ref WebhookUrl\n Protocol: https\n\n # ============================================================\n # EVENTBRIDGE RULES ON DEFAULT BUS\n # Regional events fire directly in this region - no forwarding needed\n # ============================================================\n\n DataAndInfrastructureSecurityRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: EC2, VPC, network, S3, and RDS configuration changes in the deployment region\n EventPattern:\n source:\n - aws.ec2\n - aws.s3\n - aws.rds\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventSource:\n - ec2.amazonaws.com\n - s3.amazonaws.com\n - rds.amazonaws.com\n eventName:\n # EC2 & Network Events\n - StopInstances\n - RunInstances\n - RebootInstances\n - StartInstances\n - TerminateInstances\n - CreateCustomerGateway\n - DeleteCustomerGateway\n - AttachInternetGateway\n - CreateInternetGateway\n - DeleteInternetGateway\n - DetachInternetGateway\n - CreateNetworkAcl\n - DeleteNetworkAcl\n - CreateNetworkAclEntry\n - DeleteNetworkAclEntry\n - ReplaceNetworkAclEntry\n - ReplaceNetworkAclAssociation\n - AuthorizeSecurityGroupIngress\n - AuthorizeSecurityGroupEgress\n - RevokeSecurityGroupIngress\n - RevokeSecurityGroupEgress\n - ModifySecurityGroupRules\n - UpdateSecurityGroupRuleDescriptionsIngress\n - UpdateSecurityGroupRuleDescriptionsEgress\n - CreateSecurityGroup\n - DeleteSecurityGroup\n - CreateVpc\n - DeleteVpc\n - ModifyVpcAttribute\n - AcceptVpcPeeringConnection\n - CreateVpcPeeringConnection\n - DeleteVpcPeeringConnection\n - RejectVpcPeeringConnection\n - AttachClassicLinkVpc\n - DetachClassicLinkVpc\n - DisableVpcClassicLink\n - EnableVpcClassicLink\n - ModifyImageAttribute\n - ModifySnapshotAttribute\n - ModifyInstanceAttribute\n - ImportKeyPair\n - CreateKeyPair\n - DisableEbsEncryptionByDefault\n - DeleteFlowLogs\n # S3 Events\n - PutBucketPublicAccessBlock\n - DeletePublicAccessBlock\n - PutBucketPolicy\n - DeleteBucketPolicy\n - PutBucketAcl\n - PutBucketEncryption\n - DeleteBucketEncryption\n - DeleteBucket\n # RDS Events\n - ModifyDBInstance\n - ModifyDBSnapshotAttribute\n - DeleteDBInstance\n - DeleteDBClusterSnapshot\n - RestoreDBInstanceFromDBSnapshot\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n OperationsAndSecretsSecurityRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: Lambda, SSM, Secrets Manager, and KMS configuration/management events\n EventPattern:\n source:\n - aws.lambda\n - aws.ssm\n - aws.secretsmanager\n - aws.kms\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventSource:\n - lambda.amazonaws.com\n - ssm.amazonaws.com\n - secretsmanager.amazonaws.com\n - kms.amazonaws.com\n eventName:\n # Lambda, SSM, Secrets Manager\n - AddPermission\n - CreateFunction\n - UpdateFunctionCode\n - CreateEventSourceMapping\n - SendCommand\n - StartSession\n - PutParameter\n - DeleteParameter\n - DeleteSecret\n - PutResourcePolicy\n # KMS\n - ScheduleKeyDeletion\n - DisableKey\n - DisableKeyRotation\n - PutKeyPolicy\n - DeleteAlias\n - CancelKeyDeletion\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n AuditAndTamperingSecurityRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: CloudTrail, GuardDuty, Security Hub, and Config auditing or tampering events\n EventPattern:\n source:\n - aws.cloudtrail\n - aws.securityhub\n - aws.guardduty\n - aws.config\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventSource:\n - cloudtrail.amazonaws.com\n - securityhub.amazonaws.com\n - guardduty.amazonaws.com\n - config.amazonaws.com\n eventName:\n # CloudTrail\n - CreateTrail\n - UpdateTrail\n - DeleteTrail\n - StartLogging\n - StopLogging\n - PutEventSelectors\n - DeleteEventDataStore\n # Security Services Tampering\n - BatchDisableStandards\n - DeleteMembers\n - DisassociateMembers\n - DeleteDetector\n - UpdateDetector\n - CreateFilter\n - StopMonitoringMembers\n - DisableSecurityHub\n - StopConfigurationRecorder\n - DeleteConfigurationRecorder\n - DeleteDeliveryChannel\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n ControlTowerManagedRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: Security Hub findings imported by AWS Control Tower\n EventPattern:\n source:\n - aws.securityhub\n detail-type:\n - Security Hub Findings - Imported\n detail:\n findings:\n Compliance:\n AssociatedStandards:\n StandardsId:\n - prefix: standards/service-managed-aws-control-tower\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n# ============================================================\n# OUTPUTS\n# ============================================================\n\nOutputs:\n SecurityAlertsTopicArn:\n Description: ARN of the regional security alerts SNS topic\n Value: !Ref SecurityAlertsTopic";
1
+ export declare const STACK_YAML = "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n Meyi Connect Security Monitoring - Regional Events Stack.\n Deploys regional security alerting rules and SNS webhook delivery.\n\nParameters:\n Environment:\n Type: String\n Default: \"MeyiConnect\"\n Description: Environment name (used as a prefix for resource names)\n\n WebhookUrl:\n Type: String\n Description: MeyiConnect webhook URL for security alerts.\n\n CreateCloudTrail:\n Type: String\n Default: 'false'\n Description: Kept for backwards compatibility.\n\n PrimaryRegion:\n Type: String\n Default: 'us-east-1'\n Description: Kept for backwards compatibility.\n\n DeploymentMode:\n Type: String\n Default: 'Organizations'\n Description: Kept for backwards compatibility.\n\nResources:\n\n # ============================================================\n # SNS TOPIC & SUBSCRIPTION FOR ALERTS\n # ============================================================\n\n SecurityAlertsTopic:\n Type: AWS::SNS::Topic\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n\n SecurityAlertsTopicPolicy:\n Type: AWS::SNS::TopicPolicy\n Properties:\n Topics:\n - !Ref SecurityAlertsTopic\n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Principal:\n Service: events.amazonaws.com\n Action: sns:Publish\n Resource: !Ref SecurityAlertsTopic\n\n WebhookSubscription:\n Type: AWS::SNS::Subscription\n Properties:\n TopicArn: !Ref SecurityAlertsTopic\n Endpoint: !Ref WebhookUrl\n Protocol: https\n\n # ============================================================\n # EVENTBRIDGE RULES ON DEFAULT BUS\n # Regional events fire directly in this region - no forwarding needed\n # ============================================================\n\n DataAndInfrastructureSecurityRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: EC2, VPC, network, S3, and RDS configuration changes in the deployment region\n EventPattern:\n source:\n - aws.ec2\n - aws.s3\n - aws.rds\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventSource:\n - ec2.amazonaws.com\n - s3.amazonaws.com\n - rds.amazonaws.com\n eventName:\n # EC2 & Network Events\n - StopInstances\n - RunInstances\n - RebootInstances\n - StartInstances\n - TerminateInstances\n - CreateCustomerGateway\n - DeleteCustomerGateway\n - AttachInternetGateway\n - CreateInternetGateway\n - DeleteInternetGateway\n - DetachInternetGateway\n - CreateNetworkAcl\n - DeleteNetworkAcl\n - CreateNetworkAclEntry\n - DeleteNetworkAclEntry\n - ReplaceNetworkAclEntry\n - ReplaceNetworkAclAssociation\n - AuthorizeSecurityGroupIngress\n - AuthorizeSecurityGroupEgress\n - RevokeSecurityGroupIngress\n - RevokeSecurityGroupEgress\n - ModifySecurityGroupRules\n - UpdateSecurityGroupRuleDescriptionsIngress\n - UpdateSecurityGroupRuleDescriptionsEgress\n - CreateSecurityGroup\n - DeleteSecurityGroup\n - CreateVpc\n - DeleteVpc\n - ModifyVpcAttribute\n - AcceptVpcPeeringConnection\n - CreateVpcPeeringConnection\n - DeleteVpcPeeringConnection\n - RejectVpcPeeringConnection\n - AttachClassicLinkVpc\n - DetachClassicLinkVpc\n - DisableVpcClassicLink\n - EnableVpcClassicLink\n - ModifyImageAttribute\n - ModifySnapshotAttribute\n - ModifyInstanceAttribute\n - ImportKeyPair\n - CreateKeyPair\n - DisableEbsEncryptionByDefault\n - DeleteFlowLogs\n # S3 Events\n - PutBucketPublicAccessBlock\n - DeletePublicAccessBlock\n - PutBucketPolicy\n - DeleteBucketPolicy\n - PutBucketAcl\n - PutBucketEncryption\n - DeleteBucketEncryption\n - DeleteBucket\n # RDS Events\n - ModifyDBInstance\n - ModifyDBSnapshotAttribute\n - DeleteDBInstance\n - DeleteDBClusterSnapshot\n - RestoreDBInstanceFromDBSnapshot\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n OperationsAndSecretsSecurityRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: Lambda, SSM, Secrets Manager, and KMS configuration/management events\n EventPattern:\n source:\n - aws.lambda\n - aws.ssm\n - aws.secretsmanager\n - aws.kms\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventSource:\n - lambda.amazonaws.com\n - ssm.amazonaws.com\n - secretsmanager.amazonaws.com\n - kms.amazonaws.com\n eventName:\n # Lambda, SSM, Secrets Manager\n - AddPermission\n - CreateFunction\n - UpdateFunctionCode\n - CreateEventSourceMapping\n - StartSession\n - PutParameter\n - DeleteParameter\n - DeleteSecret\n - PutResourcePolicy\n # KMS\n - ScheduleKeyDeletion\n - DisableKey\n - DisableKeyRotation\n - PutKeyPolicy\n - DeleteAlias\n - CancelKeyDeletion\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n AuditAndTamperingSecurityRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: CloudTrail, GuardDuty, Security Hub, and Config auditing or tampering events\n EventPattern:\n source:\n - aws.cloudtrail\n - aws.securityhub\n - aws.guardduty\n - aws.config\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventSource:\n - cloudtrail.amazonaws.com\n - securityhub.amazonaws.com\n - guardduty.amazonaws.com\n - config.amazonaws.com\n eventName:\n # CloudTrail\n - CreateTrail\n - UpdateTrail\n - DeleteTrail\n - StartLogging\n - StopLogging\n - PutEventSelectors\n - DeleteEventDataStore\n # Security Services Tampering\n - BatchDisableStandards\n - DeleteMembers\n - DisassociateMembers\n - DeleteDetector\n - UpdateDetector\n - CreateFilter\n - StopMonitoringMembers\n - DisableSecurityHub\n - StopConfigurationRecorder\n - DeleteConfigurationRecorder\n - DeleteDeliveryChannel\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n ControlTowerManagedRule:\n Type: AWS::Events::Rule\n DependsOn: SecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: Security Hub findings imported by AWS Control Tower\n EventPattern:\n source:\n - aws.securityhub\n detail-type:\n - Security Hub Findings - Imported\n detail:\n findings:\n Compliance:\n AssociatedStandards:\n StandardsId:\n - prefix: standards/service-managed-aws-control-tower\n State: ENABLED\n Targets:\n - Arn: !Ref SecurityAlertsTopic\n Id: SNSTarget\n\n# ============================================================\n# OUTPUTS\n# ============================================================\n\nOutputs:\n SecurityAlertsTopicArn:\n Description: ARN of the regional security alerts SNS topic\n Value: !Ref SecurityAlertsTopic";
2
2
  export declare const GLOBAL_STACK_YAML = "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n Meyi Connect Security Monitoring - Global Events Stack (us-east-1). Fully independent of\n the regional Central Stack. Captures IAM, Root Login, Console Login Failure, and AWS Health\n events (all global services that only fire in us-east-1) and delivers them directly to the\n Meyi Connect webhook via Amazon SNS. No cross-region forwarding,\n no shared resources with any other stack.\n\nParameters:\n Environment:\n Type: String\n Default: \"MeyiConnect\"\n Description: Environment name (used as a prefix for resource names)\n\n WebhookUrl:\n Type: String\n Description: MeyiConnect webhook URL for global security alerts.\n\n CreateCloudTrail:\n Type: String\n Default: 'false'\n Description: Dummy parameter for compatibility with meyi-security-monitoring.yaml.\n\n PrimaryRegion:\n Type: String\n Default: 'us-east-1'\n Description: Dummy parameter for compatibility with meyi-security-monitoring.yaml.\n\n DeploymentMode:\n Type: String\n Default: 'Organizations'\n AllowedValues:\n - 'Organizations'\n - 'Standalone'\n Description: Whether this is deployed via AWS Organizations or as a standalone account.\n\nResources:\n\n # ============================================================\n # SNS TOPIC & SUBSCRIPTION FOR GLOBAL ALERTS\n # ============================================================\n\n GlobalSecurityAlertsTopic:\n Type: AWS::SNS::Topic\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n\n GlobalSecurityAlertsTopicPolicy:\n Type: AWS::SNS::TopicPolicy\n Properties:\n Topics:\n - !Ref GlobalSecurityAlertsTopic\n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Principal:\n Service: events.amazonaws.com\n Action: sns:Publish\n Resource: !Ref GlobalSecurityAlertsTopic\n\n WebhookSubscription:\n Type: AWS::SNS::Subscription\n Properties:\n TopicArn: !Ref GlobalSecurityAlertsTopic\n Endpoint: !Ref WebhookUrl\n Protocol: https\n\n # ============================================================\n # EVENTBRIDGE RULES - GLOBAL EVENTS\n # IAM, Root Login, Console Login, Health, and Organizations all fire only in us-east-1\n # ============================================================\n\n IAMAndOrganizationsSecurityEventsRule:\n Type: AWS::Events::Rule\n DependsOn: GlobalSecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: IAM and Organizations security configuration changes\n EventPattern:\n source:\n - aws.iam\n - aws.organizations\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n eventName:\n # IAM events\n - CreateUser\n - DeleteUser\n - CreateAccessKey\n - UpdateAccessKey\n - DeleteAccessKey\n - AttachRolePolicy\n - DetachRolePolicy\n - PutUserPolicy\n - PutRolePolicy\n - UpdateAssumeRolePolicy\n - DeactivateMFADevice\n - CreateLoginProfile\n - UpdateLoginProfile\n - DeleteLoginProfile\n - CreateAccountAlias\n - DeleteAccountAlias\n - UpdateAccountPasswordPolicy\n - DeleteAccountPasswordPolicy\n - DeleteGroupPolicy\n - PutGroupPolicy\n - CreatePolicy\n - DeletePolicy\n - CreatePolicyVersion\n - DeletePolicyVersion\n - AttachUserPolicy\n - DetachUserPolicy\n - AttachGroupPolicy\n - DetachGroupPolicy\n - CreateRole\n - DeleteRole\n - CreateSAMLProvider\n - UpdateSAMLProvider\n - CreateOpenIDConnectProvider\n - UpdateOpenIDConnectProvider\n - CreateServiceSpecificCredential\n # Organizations events\n - LeaveOrganization\n - RemoveAccountFromOrganization\n - DeletePolicy\n - DetachPolicy\n - DisablePolicyType\n - UpdatePolicy\n - CreateAccount\n - InviteAccountToOrganization\n State: ENABLED\n Targets:\n - Arn: !Ref GlobalSecurityAlertsTopic\n Id: SNSTarget\n\n ConsoleLoginRule:\n Type: AWS::Events::Rule\n DependsOn: GlobalSecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: Root login, failed console logins, and MFA-not-used console login attempts\n EventPattern:\n detail-type:\n - AWS Console Sign In via CloudTrail\n detail:\n eventName:\n - ConsoleLogin\n $or:\n - userIdentity:\n type:\n - Root\n responseElements:\n ConsoleLogin:\n - Success\n - responseElements:\n ConsoleLogin:\n - Failure\n - responseElements:\n ConsoleLogin:\n - Success\n additionalEventData:\n MFAUsed:\n - \"No\"\n State: ENABLED\n Targets:\n - Arn: !Ref GlobalSecurityAlertsTopic\n Id: SNSTarget\n\n HealthEventsRule:\n Type: AWS::Events::Rule\n DependsOn: GlobalSecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: AWS Health notifications\n EventPattern:\n source:\n - aws.health\n detail-type:\n - AWS Health Event\n State: ENABLED\n Targets:\n - Arn: !Ref GlobalSecurityAlertsTopic\n Id: SNSTarget\n\n RootAPICallsRule:\n Type: AWS::Events::Rule\n DependsOn: GlobalSecurityAlertsTopicPolicy\n Properties:\n Tags:\n - Key: Project\n Value: MeyiConnect\n - Key: Created_for\n Value: L1 Security\n - Key: aws-apn-id\n Value: pc:eyl8vo7kcwv8k9qctzbathhiq\n Description: Capture any API call made by the Root user account in us-east-1\n EventPattern:\n detail-type:\n - AWS API Call via CloudTrail\n detail:\n userIdentity:\n type:\n - Root\n State: ENABLED\n Targets:\n - Arn: !Ref GlobalSecurityAlertsTopic\n Id: SNSTarget\n\n# ============================================================\n# OUTPUTS\n# ============================================================\n\nOutputs:\n TopicArn:\n Description: Global security alerts SNS Topic ARN\n Value: !Ref GlobalSecurityAlertsTopic\n\n RulesDeployed:\n Description: Rules deployed in this stack\n Value: IAMAndOrganizationsSecurityEvents, ConsoleLogin, HealthEvents, RootAPICalls";
3
3
  //# sourceMappingURL=stackTemplates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stackTemplates.d.ts","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/stackTemplates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,+kSA4Sa,CAAC;AAErC,eAAO,MAAM,iBAAiB,u6OAqPyD,CAAC"}
1
+ {"version":3,"file":"stackTemplates.d.ts","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/stackTemplates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,wnSA2Sa,CAAC;AAErC,eAAO,MAAM,iBAAiB,u6OAqPyD,CAAC"}
@@ -188,24 +188,23 @@ Resources:
188
188
  - secretsmanager.amazonaws.com
189
189
  - kms.amazonaws.com
190
190
  eventName:
191
- # Lambda, SSM, Secrets Manager
192
- - AddPermission
193
- - CreateFunction
194
- - UpdateFunctionCode
195
- - CreateEventSourceMapping
196
- - SendCommand
197
- - StartSession
198
- - PutParameter
199
- - DeleteParameter
200
- - DeleteSecret
201
- - PutResourcePolicy
202
- # KMS
203
- - ScheduleKeyDeletion
204
- - DisableKey
205
- - DisableKeyRotation
206
- - PutKeyPolicy
207
- - DeleteAlias
208
- - CancelKeyDeletion
191
+ # Lambda, SSM, Secrets Manager
192
+ - AddPermission
193
+ - CreateFunction
194
+ - UpdateFunctionCode
195
+ - CreateEventSourceMapping
196
+ - StartSession
197
+ - PutParameter
198
+ - DeleteParameter
199
+ - DeleteSecret
200
+ - PutResourcePolicy
201
+ # KMS
202
+ - ScheduleKeyDeletion
203
+ - DisableKey
204
+ - DisableKeyRotation
205
+ - PutKeyPolicy
206
+ - DeleteAlias
207
+ - CancelKeyDeletion
209
208
  State: ENABLED
210
209
  Targets:
211
210
  - Arn: !Ref SecurityAlertsTopic
@@ -1 +1 @@
1
- {"version":3,"file":"stackTemplates.js","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/stackTemplates.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCA4SU,CAAC;AAErC,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uFAqPsD,CAAC"}
1
+ {"version":3,"file":"stackTemplates.js","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/stackTemplates.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCA2SU,CAAC;AAErC,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uFAqPsD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,sBAAsB,QAUxB,CAAC;AA+rCZ,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,eAAe,GAAG,YAAY,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAoBT"}
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,sBAAsB,QAUxB,CAAC;AA4zCZ,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,eAAe,GAAG,YAAY,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAqBT"}
@@ -34,6 +34,7 @@ Metadata:
34
34
  Parameters:
35
35
  - DeploymentMode
36
36
  - CreateIAMRoles
37
+ - DeployToManagementAccount
37
38
  - TargetOUs
38
39
  - TargetAccounts
39
40
  - TargetRegions
@@ -59,6 +60,8 @@ Metadata:
59
60
  default: "Deployment Mode"
60
61
  CreateIAMRoles:
61
62
  default: "Create StackSet IAM Roles?"
63
+ DeployToManagementAccount:
64
+ default: "Also deploy to this (management) account?"
62
65
  TargetOUs:
63
66
  default: "Target Organizational Unit IDs (comma separated)"
64
67
  TargetAccounts:
@@ -95,7 +98,15 @@ Parameters:
95
98
  AllowedValues:
96
99
  - 'true'
97
100
  - 'false'
98
- Description: "Create standard AWSCloudFormationStackSetAdministrationRole and AWSCloudFormationStackSetExecutionRole? Only used in Standalone mode."
101
+ Description: "Create standard AWSCloudFormationStackSetAdministrationRole and AWSCloudFormationStackSetExecutionRole? Used in Standalone mode, and in Organizations mode when DeployToManagementAccount is true. Set to false if these roles already exist in this account."
102
+
103
+ DeployToManagementAccount:
104
+ Type: String
105
+ Default: 'true'
106
+ AllowedValues:
107
+ - 'true'
108
+ - 'false'
109
+ Description: "Organizations mode only. Service-managed StackSets never deploy to the management account, so when true this stack also deploys the same monitoring to THIS account through two additional self-managed StackSets."
99
110
 
100
111
  TargetOUs:
101
112
  Type: CommaDelimitedList
@@ -141,7 +152,8 @@ Conditions:
141
152
  HasTargetAccounts: !Not [ !Equals [ !Join [ "", !Ref TargetAccounts ], "" ] ]
142
153
  IsServiceManaged: !Equals [ !Ref DeploymentMode, 'Organizations' ]
143
154
  IsSelfManaged: !Equals [ !Ref DeploymentMode, 'Standalone' ]
144
- ShouldCreateRoles: !And [ !Equals [ !Ref DeploymentMode, 'Standalone' ], !Equals [ !Ref CreateIAMRoles, 'true' ] ]
155
+ DeployManagement: !And [ !Condition IsServiceManaged, !Equals [ !Ref DeployToManagementAccount, 'true' ] ]
156
+ ShouldCreateRoles: !And [ !Or [ !Condition IsSelfManaged, !Condition DeployManagement ], !Equals [ !Ref CreateIAMRoles, 'true' ] ]
145
157
  ShouldCreateStackInstances: !Or [ !Condition IsSelfManaged, !Condition HasTargetOUs ]
146
158
 
147
159
  Resources:
@@ -229,6 +241,8 @@ Resources:
229
241
  - cloudtrail:GetTrailStatus
230
242
  - cloudtrail:StartLogging
231
243
  - cloudtrail:StopLogging
244
+ - cloudtrail:PutEventSelectors
245
+ - cloudtrail:GetEventSelectors
232
246
  - cloudtrail:ListTags
233
247
  - cloudtrail:AddTags
234
248
  - cloudtrail:RemoveTags
@@ -260,6 +274,45 @@ Resources:
260
274
  - events:UntagResource
261
275
  - events:ListTagsForResource
262
276
  Resource: !Sub "arn:aws:events:*:\${AWS::AccountId}:rule/\${AWS::StackName}-*"
277
+ - Sid: EventBridgeApiDestinationOperations
278
+ Effect: Allow
279
+ Action:
280
+ - events:CreateConnection
281
+ - events:UpdateConnection
282
+ - events:DeleteConnection
283
+ - events:DescribeConnection
284
+ - events:CreateApiDestination
285
+ - events:UpdateApiDestination
286
+ - events:DeleteApiDestination
287
+ - events:DescribeApiDestination
288
+ Resource:
289
+ - !Sub "arn:aws:events:*:\${AWS::AccountId}:connection/\${AWS::StackName}-*"
290
+ - !Sub "arn:aws:events:*:\${AWS::AccountId}:api-destination/\${AWS::StackName}-*"
291
+ - Sid: EventBridgeConnectionSecret
292
+ Effect: Allow
293
+ Action:
294
+ - secretsmanager:CreateSecret
295
+ - secretsmanager:UpdateSecret
296
+ - secretsmanager:DeleteSecret
297
+ - secretsmanager:DescribeSecret
298
+ - secretsmanager:GetSecretValue
299
+ - secretsmanager:PutSecretValue
300
+ Resource: !Sub "arn:aws:secretsmanager:*:\${AWS::AccountId}:secret:events!connection/*"
301
+ - Sid: ApiDestinationInvokeRole
302
+ Effect: Allow
303
+ Action:
304
+ - iam:CreateRole
305
+ - iam:DeleteRole
306
+ - iam:GetRole
307
+ - iam:PutRolePolicy
308
+ - iam:DeleteRolePolicy
309
+ - iam:GetRolePolicy
310
+ - iam:TagRole
311
+ - iam:UntagRole
312
+ - iam:PassRole
313
+ Resource:
314
+ - !Sub "arn:aws:iam::\${AWS::AccountId}:role/\${AWS::StackName}-EbRole-*"
315
+ - !Sub "arn:aws:iam::\${AWS::AccountId}:role/\${AWS::StackName}-GlEbRole-*"
263
316
 
264
317
  # ============================================================
265
318
  # STACKSET
@@ -599,24 +652,23 @@ Resources:
599
652
  - secretsmanager.amazonaws.com
600
653
  - kms.amazonaws.com
601
654
  eventName:
602
- # Lambda, SSM, Secrets Manager
603
- - AddPermission
604
- - CreateFunction
605
- - UpdateFunctionCode
606
- - CreateEventSourceMapping
607
- - SendCommand
608
- - StartSession
609
- - PutParameter
610
- - DeleteParameter
611
- - DeleteSecret
612
- - PutResourcePolicy
613
- # KMS
614
- - ScheduleKeyDeletion
615
- - DisableKey
616
- - DisableKeyRotation
617
- - PutKeyPolicy
618
- - DeleteAlias
619
- - CancelKeyDeletion
655
+ # Lambda, SSM, Secrets Manager
656
+ - AddPermission
657
+ - CreateFunction
658
+ - UpdateFunctionCode
659
+ - CreateEventSourceMapping
660
+ - StartSession
661
+ - PutParameter
662
+ - DeleteParameter
663
+ - DeleteSecret
664
+ - PutResourcePolicy
665
+ # KMS
666
+ - ScheduleKeyDeletion
667
+ - DisableKey
668
+ - DisableKeyRotation
669
+ - PutKeyPolicy
670
+ - DeleteAlias
671
+ - CancelKeyDeletion
620
672
  State: ENABLED
621
673
  Targets:
622
674
  - Id: ApiDestinationTarget
@@ -1089,6 +1141,7 @@ Resources:
1089
1141
  - Key: aws-apn-id
1090
1142
  Value: pc:eyl8vo7kcwv8k9qctzbathhiq
1091
1143
 
1144
+ __MEYI_MANAGEMENT_STACKSETS__
1092
1145
  # ============================================================
1093
1146
  # EVENTBRIDGE API DESTINATION & CONNECTION (PARENT STACKSET STATUS)
1094
1147
  # ============================================================
@@ -1230,15 +1283,87 @@ Outputs:
1230
1283
  Backend: \${BackendUrl}
1231
1284
 
1232
1285
  `;
1286
+ /**
1287
+ * Service-managed StackSets never deploy to the Organizations management account.
1288
+ * To cover it from the same stack, clone the two StackSets above as self-managed
1289
+ * StackSets that target only this account, reusing their inline TemplateBody.
1290
+ */
1291
+ function buildManagementStackSets(yaml) {
1292
+ const bodyOf = (resource) => {
1293
+ const start = yaml.indexOf(` ${resource}:\n`);
1294
+ if (start < 0)
1295
+ throw new Error(`Template resource not found: ${resource}`);
1296
+ const from = yaml.indexOf(' TemplateBody: |\n', start);
1297
+ const to = yaml.indexOf(' PermissionModel:', from);
1298
+ if (from < 0 || to < 0)
1299
+ throw new Error(`TemplateBody not found: ${resource}`);
1300
+ return yaml.slice(from, to);
1301
+ };
1302
+ const build = (id, suffix, description, body, regions) => ` ${id}:
1303
+ Type: AWS::CloudFormation::StackSet
1304
+ Condition: DeployManagement
1305
+ DependsOn:
1306
+ - StackSetApiDestination
1307
+ - StackSetOperationRule
1308
+ Properties:
1309
+ StackSetName: !Sub "\${AWS::StackName}-SecurityMonitoring${suffix}-Mgmt"
1310
+ Description: !Sub "\${AWS::StackName} ${description} (management account)"
1311
+ ${body} PermissionModel: SELF_MANAGED
1312
+ AdministrationRoleARN: !If
1313
+ - ShouldCreateRoles
1314
+ - !GetAtt StackSetAdministrationRole.Arn
1315
+ - !Sub "arn:aws:iam::\${AWS::AccountId}:role/AWSCloudFormationStackSetAdministrationRole"
1316
+ ExecutionRoleName: AWSCloudFormationStackSetExecutionRole
1317
+ Parameters:
1318
+ - ParameterKey: ParentStackName
1319
+ ParameterValue: !Ref "AWS::StackName"
1320
+ - ParameterKey: WebhookUrl
1321
+ ParameterValue: !Ref WebhookUrl
1322
+ - ParameterKey: WebhookAuthToken
1323
+ ParameterValue: !Ref WebhookAuthToken
1324
+ - ParameterKey: CreateCloudTrail
1325
+ ParameterValue: !Ref CreateCloudTrail
1326
+ - ParameterKey: PrimaryRegion
1327
+ ParameterValue: !Ref PrimaryRegion
1328
+ StackInstancesGroup:
1329
+ - DeploymentTargets:
1330
+ Accounts:
1331
+ - !Ref AWS::AccountId
1332
+ Regions: ${regions}
1333
+ OperationPreferences:
1334
+ MaxConcurrentPercentage: 50
1335
+ FailureToleranceCount: 1
1336
+ RegionConcurrencyType: PARALLEL
1337
+ Capabilities:
1338
+ - CAPABILITY_NAMED_IAM
1339
+ Tags:
1340
+ - Key: Project
1341
+ Value: MeyiConnectSecurityMonitoring
1342
+ - Key: Created_for
1343
+ Value: L1 Security
1344
+ - Key: aws-apn-id
1345
+ Value: pc:eyl8vo7kcwv8k9qctzbathhiq
1346
+
1347
+ `;
1348
+ return [
1349
+ ' # ============================================================',
1350
+ ' # MANAGEMENT ACCOUNT STACKSETS (self-managed, Organizations mode only)',
1351
+ ' # ============================================================',
1352
+ '',
1353
+ build('ManagementSecurityMonitoringStackSet', '', 'Security Monitoring (regional logs)', bodyOf('SecurityMonitoringStackSet'), '!Ref TargetRegions'),
1354
+ build('ManagementGlobalSecurityMonitoringStackSet', '-Global', 'Global Security Monitoring (us-east-1 only)', bodyOf('GlobalSecurityMonitoringStackSet'), '[ us-east-1 ]'),
1355
+ ].join('\n');
1356
+ }
1233
1357
  export function buildCloudTrailCentralStackTemplate(input) {
1234
1358
  const mode = input.deploymentMode ?? 'Standalone';
1235
- const createIAMRoles = mode === 'Standalone' ? 'true' : 'false';
1359
+ const createIAMRoles = 'true';
1236
1360
  const targetOUs = input.targetOUs ?? '';
1237
1361
  const targetAccounts = input.targetAccounts ?? '';
1238
1362
  const resolvedRegions = (input.targetRegions ?? '').trim() || ALL_AWS_ACTIVE_REGIONS;
1239
1363
  const primaryRegion = resolvedRegions.split(',')[0].trim() || 'us-east-1';
1240
1364
  const createCloudTrailDefault = input.createCloudTrail ? "true" : "false";
1241
1365
  return CENTRAL_STACK_YAML
1366
+ .replace(/__MEYI_MANAGEMENT_STACKSETS__/g, buildManagementStackSets(CENTRAL_STACK_YAML))
1242
1367
  .replace(/__MEYI_WEBHOOK_URL__/g, input.webhookUrl)
1243
1368
  .replace(/__MEYI_WEBHOOK_AUTH_TOKEN__/g, input.webhookAuthToken || '')
1244
1369
  .replace(/__MEYI_DEPLOYMENT_STATUS_URL__/g, input.deploymentStatusUrl)
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/template.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../../src/features/sources/cloudtrail/template.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/migrations/run.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAohD1D"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/migrations/run.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAiiD1D"}
@@ -1,12 +1,22 @@
1
1
  import { sql } from "drizzle-orm";
2
2
  import yaml from "js-yaml";
3
+ import { isMultiTenantEnabled } from "../tenancy.js";
3
4
  /**
4
5
  * Run all DDL migrations for the Insight plugin.
5
6
  * Safe to run on every start - all statements use IF NOT EXISTS / IF EXISTS guards.
6
7
  */
7
8
  export async function runMigrations(db) {
8
- const defaultTenantId = (process.env.INSIGHT_DEFAULT_TENANT_ID || "default").trim() || "default";
9
+ // Standalone single-tenant mode keeps one tenant that owns everything. A
10
+ // multi-tenant host (Meyi Connect) has no default tenant: nothing is created
11
+ // for one and no row is assigned to one.
12
+ const defaultTenantId = isMultiTenantEnabled()
13
+ ? ""
14
+ : (process.env.INSIGHT_DEFAULT_TENANT_ID || "default").trim() || "default";
9
15
  const defaultTenantSql = defaultTenantId.replace(/'/g, "''");
16
+ const backfill = async (statement) => {
17
+ if (defaultTenantId)
18
+ await db.execute(sql.raw(statement));
19
+ };
10
20
  const defaultTokenTtlDaysRaw = Number.parseInt(process.env.INSIGHT_WEBHOOK_TOKEN_DEFAULT_DAYS || "30", 10);
11
21
  const defaultTokenTtlDays = Number.isFinite(defaultTokenTtlDaysRaw) && defaultTokenTtlDaysRaw > 0
12
22
  ? defaultTokenTtlDaysRaw
@@ -111,13 +121,13 @@ export async function runMigrations(db) {
111
121
  "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
112
122
  "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()
113
123
  );
114
- INSERT INTO "meyiconnect"."insight_tenants" ("id", "name", "is_default")
124
+ ${defaultTenantId ? `INSERT INTO "meyiconnect"."insight_tenants" ("id", "name", "is_default")
115
125
  VALUES ('${defaultTenantSql}', 'Default tenant', true)
116
- ON CONFLICT ("id") DO UPDATE SET "is_default" = true, "updated_at" = NOW();
126
+ ON CONFLICT ("id") DO UPDATE SET "is_default" = true, "updated_at" = NOW();` : "NULL;"}
117
127
  ELSIF v_relkind = 'r' THEN
118
- INSERT INTO "meyiconnect"."insight_tenants" ("id", "name", "is_default")
128
+ ${defaultTenantId ? `INSERT INTO "meyiconnect"."insight_tenants" ("id", "name", "is_default")
119
129
  VALUES ('${defaultTenantSql}', 'Default tenant', true)
120
- ON CONFLICT ("id") DO UPDATE SET "is_default" = true, "updated_at" = NOW();
130
+ ON CONFLICT ("id") DO UPDATE SET "is_default" = true, "updated_at" = NOW();` : "NULL;"}
121
131
  END IF;
122
132
  END $$;
123
133
  `));
@@ -153,7 +163,7 @@ export async function runMigrations(db) {
153
163
  END IF;
154
164
  END $$;
155
165
  `));
156
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_sources" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`));
166
+ await backfill(`UPDATE "meyiconnect"."insight_sources" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`);
157
167
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_sources_tenant_id_idx ON "meyiconnect"."insight_sources" ("tenant_id")`));
158
168
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_sources" ADD COLUMN IF NOT EXISTS "webhook_token_never_expires" BOOLEAN NOT NULL DEFAULT false`));
159
169
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_sources" ADD COLUMN IF NOT EXISTS "webhook_token_expires_at" TIMESTAMPTZ`));
@@ -430,7 +440,7 @@ export async function runMigrations(db) {
430
440
  ADD COLUMN IF NOT EXISTS "aws_secret_access_key" TEXT,
431
441
  ADD COLUMN IF NOT EXISTS "aws_region" TEXT
432
442
  `));
433
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_projects" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`));
443
+ await backfill(`UPDATE "meyiconnect"."insight_projects" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`);
434
444
  await db.execute(sql.raw(`DROP INDEX IF EXISTS "meyiconnect"."insight_projects_tag_unique"`)).catch(() => { });
435
445
  await db.execute(sql.raw(`DROP INDEX IF EXISTS insight_projects_tag_unique`)).catch(() => { });
436
446
  await db.execute(sql.raw(`CREATE UNIQUE INDEX IF NOT EXISTS insight_projects_tenant_tag_unique ON "meyiconnect"."insight_projects" ("tenant_id", "tag")`));
@@ -486,7 +496,7 @@ export async function runMigrations(db) {
486
496
  END IF;
487
497
  END $$;
488
498
  `));
489
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_incidents" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`));
499
+ await backfill(`UPDATE "meyiconnect"."insight_incidents" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`);
490
500
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_incidents_tenant_id_idx ON "meyiconnect"."insight_incidents" ("tenant_id")`));
491
501
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_incidents" ADD COLUMN IF NOT EXISTS "incident_down_time" TEXT NOT NULL DEFAULT ''`));
492
502
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_incidents" ADD COLUMN IF NOT EXISTS "name" TEXT`));
@@ -628,7 +638,7 @@ export async function runMigrations(db) {
628
638
  END IF;
629
639
  END $$;
630
640
  `));
631
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_alerts" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`));
641
+ await backfill(`UPDATE "meyiconnect"."insight_alerts" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`);
632
642
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_alerts_tenant_id_idx ON "meyiconnect"."insight_alerts" ("tenant_id")`));
633
643
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_alerts" ADD COLUMN IF NOT EXISTS "alias_id" TEXT`));
634
644
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_alerts" ADD COLUMN IF NOT EXISTS "additional_configuration" JSONB`));
@@ -744,7 +754,7 @@ export async function runMigrations(db) {
744
754
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_settings" ADD COLUMN IF NOT EXISTS "aws_bedrock_secret_access_key" TEXT`));
745
755
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_settings" ADD COLUMN IF NOT EXISTS "aws_bedrock_region" TEXT`));
746
756
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_settings" ADD COLUMN IF NOT EXISTS "tenant_id" TEXT`));
747
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_settings" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`));
757
+ await backfill(`UPDATE "meyiconnect"."insight_settings" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`);
748
758
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_settings_tenant_id_idx ON "meyiconnect"."insight_settings" ("tenant_id")`));
749
759
  // notification_providers
750
760
  await db.execute(sql.raw(`
@@ -762,7 +772,7 @@ export async function runMigrations(db) {
762
772
  )
763
773
  `));
764
774
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."notification_providers" ADD COLUMN IF NOT EXISTS "tenant_id" TEXT`)).catch(() => { });
765
- await db.execute(sql.raw(`UPDATE "meyiconnect"."notification_providers" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`)).catch(() => { });
775
+ await backfill(`UPDATE "meyiconnect"."notification_providers" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id"::text = ''`).catch(() => { });
766
776
  await db.execute(sql.raw(`DROP INDEX IF EXISTS "meyiconnect"."notification_providers_provider_name_unique"`)).catch(() => { });
767
777
  await db.execute(sql.raw(`DROP INDEX IF EXISTS notification_providers_provider_name_unique`)).catch(() => { });
768
778
  await db.execute(sql.raw(`CREATE UNIQUE INDEX IF NOT EXISTS notification_providers_tenant_name_unique ON "meyiconnect"."notification_providers" ("tenant_id", "provider_name")`)).catch(() => { });
@@ -869,7 +879,7 @@ export async function runMigrations(db) {
869
879
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_sops" ADD COLUMN IF NOT EXISTS "project" TEXT`));
870
880
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_sops" ADD COLUMN IF NOT EXISTS "ai_model_used" TEXT`));
871
881
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_sops" ADD COLUMN IF NOT EXISTS "tenant_id" TEXT`));
872
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_sops" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`));
882
+ await backfill(`UPDATE "meyiconnect"."insight_sops" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`);
873
883
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_sops_tenant_id_idx ON "meyiconnect"."insight_sops" ("tenant_id")`));
874
884
  await db.execute(sql.raw(`CREATE UNIQUE INDEX IF NOT EXISTS insight_sops_tenant_sop_id_unique ON "meyiconnect"."insight_sops" ("tenant_id", "sop_id")`));
875
885
  // incident_evidence
@@ -904,7 +914,7 @@ export async function runMigrations(db) {
904
914
  `));
905
915
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_workflows" ADD COLUMN IF NOT EXISTS "tenant_id" TEXT`));
906
916
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_workflows" ADD COLUMN IF NOT EXISTS "source_id" UUID REFERENCES "meyiconnect"."insight_sources"("id") ON DELETE CASCADE`));
907
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_workflows" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`));
917
+ await backfill(`UPDATE "meyiconnect"."insight_workflows" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`);
908
918
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_workflows_tenant_id_idx ON "meyiconnect"."insight_workflows" ("tenant_id")`));
909
919
  await db.execute(sql.raw(`
910
920
  ALTER TABLE "meyiconnect"."insight_workflows"
@@ -937,12 +947,12 @@ export async function runMigrations(db) {
937
947
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_workflow_executions" ADD COLUMN IF NOT EXISTS "tenant_id" TEXT`));
938
948
  await db.execute(sql.raw(`
939
949
  UPDATE "meyiconnect"."insight_workflow_executions" e
940
- SET "tenant_id" = COALESCE(w."tenant_id", '${defaultTenantSql}')
950
+ SET "tenant_id" = ${defaultTenantId ? `COALESCE(w."tenant_id", '${defaultTenantSql}')` : `w."tenant_id"`}
941
951
  FROM "meyiconnect"."insight_workflows" w
942
952
  WHERE e."workflow_id" = w."id"
943
953
  AND (e."tenant_id" IS NULL OR e."tenant_id" = '')
944
954
  `));
945
- await db.execute(sql.raw(`UPDATE "meyiconnect"."insight_workflow_executions" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`));
955
+ await backfill(`UPDATE "meyiconnect"."insight_workflow_executions" SET "tenant_id" = '${defaultTenantSql}' WHERE "tenant_id" IS NULL OR "tenant_id" = ''`);
946
956
  await db.execute(sql.raw(`CREATE INDEX IF NOT EXISTS insight_workflow_executions_tenant_id_idx ON "meyiconnect"."insight_workflow_executions" ("tenant_id")`));
947
957
  // ─── insight_alerts pipeline columns (Phase 1) ───────────────────────────────
948
958
  await db.execute(sql.raw(`ALTER TABLE "meyiconnect"."insight_alerts" ADD COLUMN IF NOT EXISTS "fingerprint" TEXT`));
@@ -1439,6 +1449,11 @@ export async function runMigrations(db) {
1439
1449
  // the same column, so either host can migrate first.
1440
1450
  await db.execute(sql.raw(`
1441
1451
  ALTER TABLE "meyiconnect"."ai_usage_log" ADD COLUMN IF NOT EXISTS "report_id" TEXT;
1452
+ `));
1453
+ // The AI usage API (src/features/ai-usage) reads a tenant's rows by time window.
1454
+ await db.execute(sql.raw(`
1455
+ CREATE INDEX IF NOT EXISTS ai_usage_log_tenant_created_idx
1456
+ ON "meyiconnect"."ai_usage_log" ("tenant_id", "created_at" DESC);
1442
1457
  `));
1443
1458
  // ─── insight_incidents.priority ───────────────────────────────────────────
1444
1459
  // P1..P4. The default is set before the backfill so rows inserted meanwhile (e.g. by a server that