├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── deployment ├── CFN-templates │ ├── aws-cloud-migration-factory-solution-automation.template │ ├── aws-cloud-migration-factory-solution-credentialmanager.template │ ├── aws-cloud-migration-factory-solution-mgh.template │ ├── aws-cloud-migration-factory-solution-mgn.template │ ├── aws-cloud-migration-factory-solution-replatform.template │ ├── aws-cloud-migration-factory-solution-target-account.template │ ├── aws-cloud-migration-factory-solution-tracker.template │ ├── aws-cloud-migration-factory-solution-waf-be.template │ ├── aws-cloud-migration-factory-solution-waf-fe.template │ └── aws-cloud-migration-factory-solution.template ├── build-s3-dist.sh ├── run-unit-tests.sh ├── run_integration_unit_tests.sh └── run_lambda_unit_test.sh ├── solution-manifest.yaml └── source ├── backend ├── lambda_functions │ ├── helper │ │ └── helper.py │ ├── lambda_auth │ │ └── lambda_auth.py │ ├── lambda_build │ │ └── lambda_build.py │ ├── lambda_cognito_group_update │ │ └── lambda_cognito_group_update.py │ ├── lambda_cognito_user_update │ │ └── lambda_cognito_user_update.py │ ├── lambda_cognitogroups │ │ └── lambda_cognitogroups.py │ ├── lambda_defaultschema │ │ ├── default_pipeline_templates_import.json │ │ ├── default_policies.json │ │ ├── default_roles.json │ │ ├── default_schema.json │ │ ├── default_tasks.json │ │ └── lambda_defaultschema.py │ ├── lambda_gfbuild │ │ ├── lambda_gfbuild.py │ │ ├── poetry.lock │ │ └── pyproject.toml │ ├── lambda_gfdeploy │ │ └── lambda_gfdeploy.py │ ├── lambda_gfvalidation │ │ └── lambda_gfvalidation.py │ ├── lambda_import_export_pipeline_templates │ │ ├── lambda_import_export_pipeline_templates.py │ │ └── models.py │ ├── lambda_item │ │ └── lambda_item.py │ ├── lambda_items │ │ └── lambda_items.py │ ├── lambda_login │ │ └── lambda_login.py │ ├── lambda_migrationtracker_glue_execute │ │ └── lambda_migrationtracker_glue_execute.py │ ├── lambda_migrationtracker_glue_scriptcopy │ │ └── lambda_migrationtracker_glue_scriptcopy.py │ ├── lambda_notifications │ │ └── lambda_notifications.py │ ├── lambda_pipeline_stream │ │ └── lambda_pipeline_stream.py │ ├── lambda_pipeline_task_execution_output │ │ └── lambda_pipeline_task_execution_output.py │ ├── lambda_policy │ │ └── lambda_policy.py │ ├── lambda_policy_attr │ │ └── lambda_policy_attr.py │ ├── lambda_replatformec2schema │ │ ├── __init__.py │ │ ├── factory.py │ │ └── lambda_replatformec2schema.py │ ├── lambda_reset │ │ └── lambda_reset.py │ ├── lambda_role │ │ └── lambda_role.py │ ├── lambda_role_item │ │ └── lambda_role_item.py │ ├── lambda_run_athena_savedquery │ │ └── lambda_run_athena_savedquery.py │ ├── lambda_schema │ │ └── lambda_schema.py │ ├── lambda_server_stream │ │ └── lambda_server_stream.py │ ├── lambda_service_account │ │ └── lambda_service_account.py │ ├── lambda_ssm │ │ └── lambda_ssm.py │ ├── lambda_ssm_jobs │ │ └── lambda_ssm_jobs.py │ ├── lambda_ssm_load_scripts │ │ ├── lambda_ssm_load_scripts.py │ │ ├── poetry.lock │ │ └── pyproject.toml │ ├── lambda_ssm_output │ │ └── lambda_ssm_output.py │ ├── lambda_ssm_scripts │ │ ├── lambda_ssm_scripts.py │ │ ├── poetry.lock │ │ └── pyproject.toml │ ├── lambda_ssm_socket │ │ ├── lambda_ssm_socket.py │ │ ├── poetry.lock │ │ └── pyproject.toml │ ├── lambda_task_orchestrator │ │ └── lambda_task_orchestrator.py │ ├── lambda_user_admin │ │ └── lambda_user_admin.py │ └── lambda_wave_stream │ │ └── lambda_wave_stream.py ├── lambda_layers │ ├── lambda_layer_items │ │ └── python │ │ │ ├── item_validation.py │ │ │ ├── query_comparator_operations.py │ │ │ └── query_conditions.py │ ├── lambda_layer_policy │ │ └── python │ │ │ ├── poetry.lock │ │ │ ├── policy.py │ │ │ └── pyproject.toml │ ├── lambda_layer_py_pkgs │ │ └── python │ │ │ ├── poetry.lock │ │ │ └── pyproject.toml │ └── lambda_layer_utils │ │ └── python │ │ ├── cmf_boto.py │ │ ├── cmf_logger.py │ │ ├── cmf_pipeline.py │ │ └── cmf_utils.py └── lambda_unit_test │ ├── poetry.lock │ ├── pyproject.toml │ ├── sample_data │ ├── CFN_Template_1_Wordpress.yaml │ ├── CFN_Template_2_OFBiz.yaml │ ├── Migration_Tracker_All_Extract_Script.py │ ├── apps.json │ ├── connection_ids.json │ ├── jwtRS256.key │ ├── jwtRS256.key.pub │ ├── pipeline_template_tasks.json │ ├── pipeline_templates.json │ ├── pipeline_templates_import.json │ ├── pipelines.json │ ├── policies.json │ ├── roles.json │ ├── schema_server_replatform_create_ec2.json │ ├── schema_server_replatform_create_server.json │ ├── schema_server_replatform_create_server_attrs.json │ ├── schema_server_replatform_delete_server.json │ ├── schema_server_replatform_delete_server_attrs.json │ ├── schema_server_replatform_update_server.json │ ├── schemas.json │ ├── schemas_modified_TS.json │ ├── schemas_no_app.json │ ├── schemas_no_server.json │ ├── schemas_no_wave.json │ ├── schemas_server_replatform_with_attrs.json │ ├── servers.json │ ├── ssm_jobs.json │ ├── ssm_load_scripts │ │ ├── README.md │ │ ├── invalid_zip_file.zip │ │ ├── package_incorrect_yaml_contents │ │ │ ├── Package-Structure.yml │ │ │ └── hello_world.py │ │ ├── package_invalid_attributes │ │ │ ├── Package-Structure.yml │ │ │ └── hello_world.py │ │ ├── package_invalid_yaml │ │ │ ├── Package-Structure.yml │ │ │ └── hello_world.py │ │ ├── package_missing_dependencies │ │ │ ├── Package-Structure.yml │ │ │ └── hello_world.py │ │ ├── package_no_master_file │ │ │ └── Package-Structure.yml │ │ ├── package_no_yaml │ │ │ └── hello_world.py │ │ ├── package_schema_extensions │ │ │ ├── Package-Structure.yml │ │ │ └── hello_world.py │ │ ├── package_valid │ │ │ ├── Package-Structure.yml │ │ │ └── hello_world.py │ │ ├── package_valid_with_dependencies │ │ │ ├── Package-Structure.yml │ │ │ ├── hello_world.py │ │ │ └── lib1.py │ │ ├── sample_ssm_script_1.json │ │ ├── sample_ssm_script_2.json │ │ └── sample_ssm_scripts.zip │ ├── ssm_scripts.json │ ├── ssm_socket_cognito_jwks.json │ ├── ssm_socket_cognito_jwks_error.json │ ├── tasks.json │ └── waves.json │ ├── test_cmf_pipeline.py │ ├── test_common_utils.py │ ├── test_helper.py │ ├── test_item_validation.py │ ├── test_lambda_auth.py │ ├── test_lambda_build.py │ ├── test_lambda_cognito_base.py │ ├── test_lambda_cognito_group_update.py │ ├── test_lambda_cognito_user_update.py │ ├── test_lambda_cognitogroups.py │ ├── test_lambda_defaultschema.py │ ├── test_lambda_export_pipeline_templates.py │ ├── test_lambda_gfbuild.py │ ├── test_lambda_gfcommon.py │ ├── test_lambda_gfdeploy.py │ ├── test_lambda_gfvalidation.py │ ├── test_lambda_import_pipeline_templates.py │ ├── test_lambda_item.py │ ├── test_lambda_item_common.py │ ├── test_lambda_items.py │ ├── test_lambda_login.py │ ├── test_lambda_login_common.py │ ├── test_lambda_migrationtracker_glue_base.py │ ├── test_lambda_migrationtracker_glue_execute.py │ ├── test_lambda_migrationtracker_glue_scriptcopy.py │ ├── test_lambda_notifications.py │ ├── test_lambda_pipeline_stream.py │ ├── test_lambda_pipeline_task_execution_output.py │ ├── test_lambda_policy.py │ ├── test_lambda_policy_attr.py │ ├── test_lambda_replatformec2schema.py │ ├── test_lambda_reset.py │ ├── test_lambda_role.py │ ├── test_lambda_role_item.py │ ├── test_lambda_run_athena_savedquery.py │ ├── test_lambda_schema.py │ ├── test_lambda_server_stream.py │ ├── test_lambda_service_account.py │ ├── test_lambda_ssm.py │ ├── test_lambda_ssm_base.py │ ├── test_lambda_ssm_jobs.py │ ├── test_lambda_ssm_load_scripts.py │ ├── test_lambda_ssm_output.py │ ├── test_lambda_ssm_scripts.py │ ├── test_lambda_ssm_socket.py │ ├── test_lambda_task_orchestrator.py │ ├── test_lambda_user_admin.py │ ├── test_lambda_wave_stream.py │ ├── test_policy.py │ └── tox.ini ├── frontend ├── .babelrc ├── .gitignore ├── .prettierignore ├── .prettierrc ├── README.md ├── index.html ├── index.prod.html ├── layout │ └── main.css ├── package.json ├── public │ ├── .well-known │ │ └── security.txt │ ├── env.js │ ├── favicon.ico │ └── manifest.json ├── src │ ├── App.test.tsx │ ├── App.tsx │ ├── AuthenticatedRoutes.tsx │ ├── PreAuthRoutes.tsx │ ├── __tests__ │ │ ├── TestUtils.ts │ │ ├── amplify_test_config.ts │ │ └── mocks │ │ │ ├── admin_api.ts │ │ │ ├── app_api.ts │ │ │ ├── credentialmanager_api.ts │ │ │ ├── login_api.ts │ │ │ ├── ssm_api.ts │ │ │ ├── tools_api.ts │ │ │ ├── user_api.ts │ │ │ └── wave_api.ts │ ├── actions │ │ ├── AdminPermissionsHook.ts │ │ ├── ApplicationsHook.ts │ │ ├── AutomationJobsHook.ts │ │ ├── AutomationScriptsHook.ts │ │ ├── CredentialManagerHook.ts │ │ ├── DatabasesHook.ts │ │ ├── PipelineTemplateTasksHook.ts │ │ ├── PipelineTemplatesHook.ts │ │ ├── PipelinesHook.ts │ │ ├── SchemaHook.ts │ │ ├── ServersHook.ts │ │ ├── TaskExecutionsHook.ts │ │ ├── ValueListsHook.ts │ │ └── WavesHook.ts │ ├── api_clients │ │ ├── adminApiClient.ts │ │ ├── loginApiClient.ts │ │ ├── toolsApiClient.ts │ │ └── userApiClient.ts │ ├── components │ │ ├── AmendItemModal.tsx │ │ ├── ApplicationView.tsx │ │ ├── AutomationJobView.tsx │ │ ├── AutomationScriptImport.tsx │ │ ├── AutomationScriptView.tsx │ │ ├── AutomationScriptsTable.tsx │ │ ├── AutomationTools.tsx │ │ ├── CMFTopNavigation.tsx │ │ ├── CredentialManagerModal.tsx │ │ ├── CredentialManagerTable.tsx │ │ ├── DatabaseView.tsx │ │ ├── IntakeFormTable.test.tsx │ │ ├── IntakeFormTable.tsx │ │ ├── ItemAmend.test.tsx │ │ ├── ItemAmend.tsx │ │ ├── ItemAmendModal.tsx │ │ ├── ItemTable.tsx │ │ ├── Modal.tsx │ │ ├── PermissionsView.tsx │ │ ├── PipelineTemplateJsonFileImport.tsx │ │ ├── PipelineTemplateView.tsx │ │ ├── PipelineView.tsx │ │ ├── SchemaAttributeAmendModal.tsx │ │ ├── SchemaAttributeConditionsEdit.tsx │ │ ├── SchemaAttributesTable.tsx │ │ ├── ServerView.tsx │ │ ├── TableHeader.tsx │ │ ├── TaskExecutionView.tsx │ │ ├── ToolHelp.tsx │ │ ├── ToolHelpEdit.tsx │ │ ├── UserGroupsModal.tsx │ │ ├── UserPipelineTemplateVisualEditor.test.tsx │ │ ├── UserPipelineTemplateVisualEditor.tsx │ │ ├── UserPipelineVisualManager.tsx │ │ ├── ViewTaskExecution.test.tsx │ │ ├── WaveView.tsx │ │ ├── dashboard │ │ │ ├── ChartOSTypes.tsx │ │ │ ├── ChartServerEnvTypes.tsx │ │ │ ├── MFOverview.tsx │ │ │ ├── ServerRepStatus.tsx │ │ │ ├── ServersByMonth.tsx │ │ │ └── WaveStatus.tsx │ │ ├── import │ │ │ ├── ImportCompletion.tsx │ │ │ ├── ImportIntakeWizard.tsx │ │ │ └── ImportOverview.tsx │ │ ├── servicenavigation.tsx │ │ └── ui_attributes │ │ │ ├── AllAttributes.tsx │ │ │ ├── AllViewerAttributes.tsx │ │ │ ├── Audit.tsx │ │ │ ├── CheckboxAttribute.tsx │ │ │ ├── DateAttribute.tsx │ │ │ ├── EmbeddedEntityAttribute.tsx │ │ │ ├── GroupsAttribute.tsx │ │ │ ├── JsonAttribute.tsx │ │ │ ├── ListAttribute.tsx │ │ │ ├── MultiValueStringAttribute.tsx │ │ │ ├── PoliciesAttribute.tsx │ │ │ ├── RelatedRecordPopover.tsx │ │ │ ├── RelationshipAttribute.tsx │ │ │ ├── TagAttribute.tsx │ │ │ ├── TextAttribute.tsx │ │ │ └── ValueWithLabel.tsx │ ├── containers │ │ ├── AdminPermissions.Groups.test.tsx │ │ ├── AdminPermissions.Policies.test.tsx │ │ ├── AdminPermissions.Roles.test.tsx │ │ ├── AdminPermissions.Users.test.tsx │ │ ├── AdminPermissions.test.tsx │ │ ├── AdminPermissions.tsx │ │ ├── AdminSchemaManagement.test.tsx │ │ ├── AdminSchemaMgmt.tsx │ │ ├── ChangePassword.test.tsx │ │ ├── ChangePassword.tsx │ │ ├── CredentialManager.test.tsx │ │ ├── CredentialManager.tsx │ │ ├── ForgotPassword.test.tsx │ │ ├── ForgotPassword.tsx │ │ ├── Login.test.tsx │ │ ├── Login.tsx │ │ ├── PipelineTemplatesImport.test.tsx │ │ ├── PipelineTemplatesImport.tsx │ │ ├── UserAutomationJobs.test.tsx │ │ ├── UserAutomationJobs.tsx │ │ ├── UserAutomationScripts.test.tsx │ │ ├── UserAutomationScripts.tsx │ │ ├── UserDashboard.test.tsx │ │ ├── UserDashboard.tsx │ │ ├── UserExport.test.tsx │ │ ├── UserExport.tsx │ │ ├── UserImport.test.tsx │ │ ├── UserImport.tsx │ │ ├── UserTableApps.test.tsx │ │ ├── UserTableApps.tsx │ │ ├── UserTableDatabases.test.tsx │ │ ├── UserTableDatabases.tsx │ │ ├── UserTablePipelineTemplates.test.tsx │ │ ├── UserTablePipelineTemplates.tsx │ │ ├── UserTablePipelines.test.tsx │ │ ├── UserTablePipelines.tsx │ │ ├── UserTableServers.test.tsx │ │ ├── UserTableServers.tsx │ │ ├── UserTableWaves.test.tsx │ │ └── UserTableWaves.tsx │ ├── contexts │ │ ├── NotificationContext.tsx │ │ ├── SessionContext.test.tsx │ │ ├── SessionContext.tsx │ │ ├── SplitPanelContext.tsx │ │ └── ToolsContext.tsx │ ├── index.tsx │ ├── models │ │ ├── AppChildProps.ts │ │ ├── Application.ts │ │ ├── CompletionNotification.ts │ │ ├── Database.ts │ │ ├── EntitySchema.ts │ │ ├── Events.ts │ │ ├── HelpContent.ts │ │ ├── Pipeline.ts │ │ ├── PipelineTemplate.ts │ │ ├── PipelineTemplateTask.ts │ │ ├── Server.ts │ │ ├── UserAccess.ts │ │ └── Wave.ts │ ├── resources │ │ ├── ItemTableConfig.tsx │ │ ├── auto-script-table-config.tsx │ │ ├── credential-table-config.ts │ │ ├── intakeform-table-config.tsx │ │ ├── main.test.ts │ │ ├── main.ts │ │ ├── permissionsReducer.ts │ │ ├── recordFunctions.ts │ │ ├── reducer.ts │ │ ├── schemaReducer.ts │ │ └── schemaattr-table-config.tsx │ ├── setupTests.ts │ └── utils │ │ ├── OptionDefinition.ts │ │ ├── entity-access-from-permissions.ts │ │ ├── entity-access-from-premissions.test.ts │ │ ├── import-utils.test.ts │ │ ├── import-utils.ts │ │ ├── table-utils.ts │ │ ├── xlsx-export.test.ts │ │ └── xlsx-export.ts ├── test_data │ ├── __mocks__ │ │ ├── fileMock.js │ │ └── styleMock.js │ ├── default_access_policy.json │ ├── default_groups.json │ ├── default_policies.json │ ├── default_roles.json │ ├── default_schema.ts │ ├── default_users.json │ ├── test_invalid.csv │ ├── test_invalid.xlsx │ ├── test_pipeline_template_import.json │ ├── test_valid.csv │ └── test_valid.xlsx ├── tsconfig.json ├── tsconfig.node.json ├── vendor │ └── xlsx-0.20.2.tgz └── vite.config.ts └── integrations ├── automation_packages └── ADS │ ├── 0-ADS-AgentInstall │ ├── 0-ADS-AgentInstall.py │ ├── 1-ADS-Install-Linux.py │ ├── 1-Install-Windows.ps1 │ └── Package-Structure.yml │ └── 1-ADS-AgentUninstall │ ├── 1-ADS-AgentUninstall.py │ ├── 1-ADS-Uninstall-Linux.py │ ├── 1-Uninstall-Windows.ps1 │ └── Package-Structure.yml ├── common └── mfcommon.py ├── credential_manager └── lambdas │ ├── CreateKeyValueSecret.py │ ├── CreateOsSecret.py │ ├── CreatePlainTextSecret.py │ ├── CredentialManager.py │ ├── DeleteSecret.py │ ├── GetSecret.py │ ├── ListSecret.py │ └── UpdateSecret.py ├── integration_unit_tests ├── FactoryEndpoints.json ├── __init__.py ├── automation_packages │ ├── __init__.py │ └── ads │ │ ├── __init__.py │ │ ├── test_ADS_AgentInstall.py │ │ ├── test_ADS_AgentUninstall.py │ │ ├── test_ADS_InstallLinux.py │ │ └── test_ads_common.py ├── common │ ├── __init__.py │ ├── test_cmf_get_credentials.py │ ├── test_cmf_get_servers.py │ ├── test_cmf_user_login.py │ ├── test_get_factory_databases.py │ ├── test_mfcommon.py │ └── test_mfcommon_util.py ├── credential_manager │ ├── __init__.py │ ├── test_credential_manager.py │ ├── test_credential_manager_base.py │ ├── test_credential_manager_exceptions.py │ └── test_credential_manager_lambda_handler.py ├── mgh │ ├── __init__.py │ ├── test_lambda_mgh.py │ └── test_lambda_mgh_common_util.py ├── mgn │ ├── __init__.py │ ├── test_0_prerequisites_checks.py │ ├── test_1_FileCopy.py │ ├── test_2_AddUser.py │ ├── test_2_RemoveUser.py │ ├── test_2_Verify_replication.py │ ├── test_3_Shutdown_all_servers.py │ ├── test_3_Verify_instance_status.py │ ├── test_4_Get_instance_IP.py │ ├── test_4_Verify_server_connection.py │ ├── test_5_post_cutover_validations.py │ ├── test_AgentInstall.py │ ├── test_InstallLinux.py │ ├── test_lambda_mgn.py │ ├── test_lambda_mgn_common_util.py │ ├── test_lambda_mgn_template.py │ ├── test_lambda_mgn_utils.py │ └── test_mgn_common.py ├── poetry.lock ├── pyproject.toml ├── test_util.py └── tox.ini ├── mgh └── lambdas │ ├── lambda_mgh.py │ ├── poetry.lock │ ├── pyproject.toml │ └── recommendation-preferences.json ├── mgn ├── MGN-automation-scripts │ ├── 0-Prerequisites-checks │ │ ├── 0-Prerequisites-Windows.ps1 │ │ ├── 0-Prerequisites-checks.py │ │ └── Package-Structure.yml │ ├── 1-AgentInstall │ │ ├── 1-AgentInstall.py │ │ ├── 1-Install-Linux.py │ │ ├── 1-Install-Windows.ps1 │ │ └── Package-Structure.yml │ ├── 1-FileCopy │ │ ├── 1-FileCopy.py │ │ └── Package-Structure.yml │ ├── 2-AddUser │ │ ├── 2-AddUser.py │ │ └── Package-Structure.yml │ ├── 2-RemoveUser │ │ ├── 2-RemoveUser.py │ │ └── Package-Structure.yml │ ├── 2-Verify-replication │ │ ├── 2-Verify-replication.py │ │ └── Package-Structure.yml │ ├── 3-Shutdown-all-servers │ │ ├── 3-Shutdown-all-servers.py │ │ └── Package-Structure.yml │ ├── 3-Verify-instance-status │ │ ├── 3-Verify-instance-status.py │ │ └── Package-Structure.yml │ ├── 4-Get-instance-IP │ │ ├── 4-Get-instance-IP.py │ │ └── Package-Structure.yml │ ├── 4-Verify-server-connection │ │ ├── 4-Verify-server-connection.py │ │ └── Package-Structure.yml │ ├── 5-Post-Cutover-Validations │ │ ├── 5-post_cutover_validations.py │ │ ├── Package-Structure.yml │ │ └── Software-Validation-Windows.ps1 │ ├── FactoryEndpoints.json │ └── server-list.csv └── lambdas │ ├── lambda_mgn.py │ ├── lambda_mgn_launch.py │ ├── lambda_mgn_template.py │ └── lambda_mgn_utils.py └── migration-tracker └── GlueScript ├── Migration_Tracker_App_Extract_Script.py ├── Migration_Tracker_Database_Extract_Script.py ├── Migration_Tracker_Server_Extract_Script.py └── Migration_Tracker_Wave_Extract_Script.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Please complete the following information about the solution:** 20 | - [ ] Version: [e.g. v1.1.0] 21 | 22 | To get the version of the solution, you can look at the description of the created CloudFormation stack. For example, "_(SO0097) - AWS CloudEndure Migration Factory Solution. Version **v1.1.0**_". 23 | 24 | - [ ] Region: [e.g. us-east-1] 25 | - [ ] Was the solution modified from the version published on this repository? 26 | - [ ] If the answer to the previous question was yes, are the changes available on GitHub? 27 | - [ ] Have you checked your [service quotas](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html) for the sevices this solution uses? 28 | - [ ] Were there any errors in the CloudWatch Logs? 29 | 30 | **Screenshots** 31 | If applicable, add screenshots to help explain your problem (please **DO NOT include sensitive information**). 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this solution 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the feature you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node - Logs 2 | *.log 3 | npm-debug.log* 4 | 5 | # Node - Dependencies 6 | node_modules 7 | 8 | # Temporary folder 9 | /tmp 10 | 11 | # OS - OSX 12 | .DS_Store 13 | 14 | # OS - Windows 15 | Thumbs.db 16 | ehthumbs.db 17 | 18 | # OS - Linux (KDE directory preferences) 19 | .directory 20 | # Webstorm IDE files 21 | /.idea/* 22 | /source/frontend/test-report.xml 23 | /source/frontend/dist 24 | 25 | # Frontend configuration file for local development 26 | /source/frontend/public/env_dev.js 27 | 28 | # Local build output 29 | /deployment/global-s3-assets/* 30 | /deployment/regional-s3-assets/* 31 | /source/backend/lambda_layers/lambda_layer_py_pkgs/.build 32 | 33 | #SonarQube 34 | /.scannerwork/* 35 | 36 | # Testing environment 37 | testing-venv 38 | 39 | **/**/.coverage 40 | **/**/coverage/ 41 | 42 | # Python 43 | __pycache__ 44 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /deployment/run_integration_unit_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | 7 | # This script must be executed from the package root directory 8 | 9 | set -e 10 | 11 | if [ ! -d "testing-venv" ]; then 12 | echo "Creating testing-venv..." 13 | python3 -m venv testing-venv 14 | fi 15 | 16 | 17 | echo " ---- Rebuilding package locally before testing..." 18 | source testing-venv/bin/activate 19 | echo " ---- Using python: `type python3`" 20 | echo " ---- Python version: `python3 --version`" 21 | echo " ---- Installing pip" 22 | pip3 install --quiet -U pip 23 | echo " ---- Installing dependency" 24 | source_code="$PWD" 25 | echo " ---- Changing working directory to the test directory" 26 | cd source/integrations/integration_unit_tests/ 27 | "$POETRY_HOME"/bin/poetry install 28 | echo "Updating source path $source_code" 29 | replace="s#%%SOURCE_PATH%%#$source_code#g" 30 | tox_path="$PWD/tox.ini" 31 | echo "tox.ini path: $tox_path" 32 | if [[ "$OSTYPE" == "darwin"* ]]; then 33 | sed -i '' -e $replace $tox_path 34 | else 35 | sed -i -e $replace $tox_path 36 | fi 37 | 38 | echo " ---- Running tests..." 39 | if [ -z "$1" ]; then 40 | echo " ---- Running all tests..." 41 | test_scope="test_*.py" 42 | else 43 | echo " ---- Running tests based on the pattern $1..." 44 | test_scope="$1" 45 | fi 46 | coverage run -m unittest discover -p "$test_scope" 47 | echo " ---- Please make sure all the test cases above pass" 48 | echo 49 | echo 50 | echo " ---- Waiting for 1 minutes for coverage journaling to complete." 51 | sleep 60 52 | echo 53 | echo " ---- Combining coverage file for multiprocessing..." 54 | coverage combine 55 | echo " ---- Unit test Coverage report" 56 | coverage report 57 | coverage xml -o./coverage/coverage.xml 58 | deactivate 59 | echo "Removing source path $source_code" 60 | replace="s#$source_code#%%SOURCE_PATH%%#g" 61 | if [[ "$OSTYPE" == "darwin"* ]]; then 62 | sed -i '' -e $replace $tox_path 63 | else 64 | sed -i -e $replace $tox_path 65 | fi 66 | echo "------------------------------------------------------------------------------" 67 | echo "[Unit Tests] Integrations Unit Tests Complete" 68 | echo "------------------------------------------------------------------------------" -------------------------------------------------------------------------------- /deployment/run_lambda_unit_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | 7 | # This script must be executed from the package root directory 8 | # 9 | # To run unittests against a subset of the tests for development testing, 10 | # the script accepts a single optional argument, this is string pattern 11 | # for the tests required to be run i.e. test_lambda_ssm* 12 | # If not provided all tests will be run. 13 | 14 | set -e 15 | 16 | if [ ! -d "testing-venv" ]; then 17 | echo "Creating testing-venv..." 18 | python3 -m venv testing-venv 19 | fi 20 | 21 | 22 | echo " ---- Rebuilding package locally before testing..." 23 | source testing-venv/bin/activate 24 | echo " ---- Using python: `type python3`" 25 | echo " ---- Python version: `python3 --version`" 26 | echo " ---- Installing pip" 27 | pip3 install --quiet -U pip 28 | echo " ---- Installing dependency" 29 | source_code="$PWD" 30 | echo " ---- Changing working directory to the test directory" 31 | cd source/backend/lambda_unit_test/ 32 | "$POETRY_HOME"/bin/poetry install 33 | echo "Updating source path $source_code" 34 | replace="s#%%SOURCE_PATH%%#$source_code#g" 35 | tox_path="$PWD/tox.ini" 36 | echo "tox.ini path: $tox_path" 37 | if [[ "$OSTYPE" == "darwin"* ]]; then 38 | sed -i '' -e $replace $tox_path 39 | else 40 | sed -i -e $replace $tox_path 41 | fi 42 | 43 | if [ -z "$1" ]; then 44 | echo " ---- Running all tests..." 45 | test_scope=discover 46 | else 47 | echo " ---- Running tests based on the pattern $1..." 48 | test_scope=$1 49 | fi 50 | coverage run --data-file=./coverage/.coverage -m unittest $test_scope 51 | echo " ---- Please make sure all the test cases above pass" 52 | echo 53 | echo 54 | echo " ---- Unit test Coverage report" 55 | coverage report --data-file=./coverage/.coverage 56 | coverage xml --data-file=./coverage/.coverage -o./coverage/coverage.xml 57 | deactivate 58 | echo "Removing source path $source_code" 59 | replace="s#$source_code#%%SOURCE_PATH%%#g" 60 | if [[ "$OSTYPE" == "darwin"* ]]; then 61 | sed -i '' -e $replace $tox_path 62 | else 63 | sed -i -e $replace $tox_path 64 | fi 65 | 66 | echo "------------------------------------------------------------------------------" 67 | echo "[Unit Tests] Backend Unit Tests Complete" 68 | echo "------------------------------------------------------------------------------" -------------------------------------------------------------------------------- /solution-manifest.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | id: SO0097 # Solution Id 3 | name: cloud-migration-factory-on-aws # trademarked name 4 | version: v4.0.3 # current version of the solution. Used to verify template headers 5 | cloudformation_templates: # This list should match with AWS CloudFormation templates section of IG 6 | - template: aws-cloud-migration-factory-solution.template 7 | main_template: true 8 | - template: aws-cloud-migration-factory-solution-target-account.template 9 | main_template: true 10 | build_environment: 11 | build_image: "aws/codebuild/standard:7.0" # Options include: 'aws/codebuild/standard:5.0','aws/codebuild/standard:6.0','aws/codebuild/standard:7.0','aws/codebuild/amazonlinux2-x86_64-standard:4.0','aws/codebuild/amazonlinux2-x86_64-standard:5.0' 12 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/helper/helper.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import json 6 | import uuid 7 | 8 | from urllib import request 9 | from cmf_logger import logger 10 | 11 | 12 | # Send response function 13 | def send_response(event, context, response_status, response_data): 14 | try: 15 | response_body = json.dumps({ 16 | "Status": response_status, 17 | "PhysicalResourceId": context.log_stream_name, 18 | "StackId": event['StackId'], 19 | "RequestId": event['RequestId'], 20 | "LogicalResourceId": event['LogicalResourceId'], 21 | "Data": response_data 22 | }) 23 | 24 | logger.info('Response URL: {}'.format(event['ResponseURL'])) 25 | logger.info('Response Body: {}'.format(response_body)) 26 | 27 | data = response_body.encode('utf-8') 28 | req = request.Request(event['ResponseURL'], data=data, method='PUT') 29 | req.add_header('Content-Type', '') 30 | req.add_header('Content-Length', len(response_body)) 31 | response = request.urlopen(req) # nosec B310 URL is provided by CloudFormation 32 | 33 | logger.info('Status code: {}'.format(response.getcode())) 34 | logger.info('Status message: {}'.format(response.msg)) 35 | except Exception as e: 36 | logger.error('Custom resource send_response error: {}'.format(e)) 37 | 38 | 39 | def lambda_handler(event, context): 40 | logger.info('Received event: {}'.format(json.dumps(event))) 41 | response_data = { 42 | "Message": "Return UUID" 43 | } 44 | 45 | try: 46 | if event['RequestType'] == 'Create': 47 | response_data = { 48 | "UUID": str(uuid.uuid4()) 49 | } 50 | 51 | send_response(event, context, 'SUCCESS', response_data) 52 | except Exception as e: 53 | logger.error('Error: {}'.format(e)) 54 | response_data = { 55 | 'Error': e 56 | } 57 | send_response(event, context, 'FAILED', response_data) 58 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_auth/lambda_auth.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from policy import MFAuth 5 | from cmf_logger import logger, log_event_received 6 | 7 | 8 | def lambda_handler(event, _): 9 | log_event_received(event) 10 | if 'methodArn' in event: 11 | logger.info('Authenticating API Gateway request' + event['methodArn']) 12 | else: 13 | logger.info('Authenticating non-API Gateway request') 14 | auth = MFAuth() 15 | auth_response = auth.get_admin_resource_policy(event) 16 | logger.info(auth_response) 17 | return auth_response 18 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_cognitogroups/lambda_cognitogroups.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import json 6 | import os 7 | 8 | import cmf_boto 9 | from cmf_logger import logger, log_event_received 10 | from cmf_utils import cors 11 | 12 | default_http_headers = { 13 | 'Access-Control-Allow-Origin': cors, 14 | 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload', 15 | 'Content-Security-Policy' : "base-uri 'self'; upgrade-insecure-requests; default-src 'none'; object-src 'none'; connect-src none; img-src 'self' data:; script-src blob: 'self'; style-src 'self'; font-src 'self' data:; form-action 'self';" 16 | } 17 | 18 | 19 | def lambda_handler(event, _): 20 | log_event_received(event) 21 | 22 | client = cmf_boto.client('cognito-idp') 23 | response = client.list_groups( 24 | UserPoolId=os.environ['userpool_id'] 25 | ) 26 | groups = [] 27 | for group in response['Groups']: 28 | groups.append(group['GroupName']) 29 | return {'headers': {**default_http_headers}, 30 | 'statusCode': 200, 31 | 'body': json.dumps(groups) 32 | } -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_defaultschema/default_roles.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "groups": { 4 | "L": [ 5 | { 6 | "M": { 7 | "group_name": { 8 | "S": "admin" 9 | } 10 | } 11 | } 12 | ] 13 | }, 14 | "role_id": { 15 | "S": "1" 16 | }, 17 | "role_name": { 18 | "S": "FactoryAdmin" 19 | }, 20 | "policies": { 21 | "L": [ 22 | { 23 | "M": { 24 | "policy_id": { 25 | "S": "1" 26 | } 27 | } 28 | } 29 | ] 30 | } 31 | }, 32 | { 33 | "groups": { 34 | "L": [ 35 | { 36 | "M": { 37 | "group_name": { 38 | "S": "readonly" 39 | } 40 | } 41 | } 42 | ] 43 | }, 44 | "role_id": { 45 | "S": "2" 46 | }, 47 | "role_name": { 48 | "S": "FactoryReadOnly" 49 | }, 50 | "policies": { 51 | "L": [ 52 | { 53 | "M": { 54 | "policy_id": { 55 | "S": "2" 56 | } 57 | } 58 | } 59 | ] 60 | } 61 | }, 62 | { 63 | "groups": { 64 | "L": [ 65 | { 66 | "M": { 67 | "group_name": { 68 | "S": "orchestrator" 69 | } 70 | } 71 | } 72 | ] 73 | }, 74 | "role_id": { 75 | "S": "3" 76 | }, 77 | "role_name": { 78 | "S": "FactoryAutomationTaskOrchestrator" 79 | }, 80 | "policies": { 81 | "L": [ 82 | { 83 | "M": { 84 | "policy_id": { 85 | "S": "3" 86 | } 87 | } 88 | } 89 | ] 90 | } 91 | } 92 | ] -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_gfbuild/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | troposphere = "==4.9.0" 8 | 9 | [build-system] 10 | requires = ["poetry-core"] 11 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_import_export_pipeline_templates/models.py: -------------------------------------------------------------------------------- 1 | from typing import TypedDict, Optional, List 2 | 3 | 4 | class PipelineTemplateTask(TypedDict): 5 | pipeline_template_task_id: str 6 | pipeline_template_task_name: str 7 | pipeline_template_id: str 8 | task_id: Optional[str] 9 | task_name: Optional[str] 10 | task_successors: List[str] 11 | _history: dict 12 | 13 | 14 | class PipelineTemplate(TypedDict): 15 | pipeline_template_id: str 16 | pipeline_template_description: str 17 | pipeline_template_name: str 18 | pipeline_template_tasks: Optional[List[PipelineTemplateTask]] 19 | _history: dict 20 | 21 | 22 | class ClientException(Exception): 23 | def __init__(self, error: str, message: str, status_code: int = 400): 24 | self.error = error 25 | self.message = message 26 | self.status_code = status_code 27 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_login/lambda_login.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import json 6 | import os 7 | 8 | import cmf_boto 9 | from cmf_logger import logger, log_event_received 10 | from cmf_utils import cors, default_http_headers 11 | 12 | 13 | def lambda_handler(event, _): 14 | response = {} 15 | log_event_received(event) 16 | 17 | try: 18 | body = json.loads(event['body']) 19 | client = cmf_boto.client('cognito-idp') 20 | 21 | if 'mfacode' in body: 22 | # This is a response to MFA request on previous login attempt. 23 | userid = body['username'] 24 | mfacode = body['mfacode'] 25 | session = body['session'] 26 | response = client.respond_to_auth_challenge( 27 | ClientId=os.environ['clientId'], 28 | ChallengeName='SMS_MFA', 29 | Session=session, 30 | ChallengeResponses={ 31 | 'SMS_MFA_CODE': mfacode, 32 | 'USERNAME': userid 33 | } 34 | ) 35 | else: 36 | userid = body['username'] 37 | password = body['password'] 38 | response = client.initiate_auth( 39 | ClientId=os.environ['clientId'], 40 | AuthFlow='USER_PASSWORD_AUTH', 41 | AuthParameters={ 42 | 'USERNAME': userid, 43 | 'PASSWORD': password 44 | } 45 | ) 46 | except Exception as e: 47 | if "NotAuthorizedException" in str(e) or "UserNotFoundException" in str(e): 48 | logger.error('Incorrect username or password: %s', userid) 49 | return {'headers': {**default_http_headers}, 50 | 'statusCode': 400, 51 | 'body': 'Incorrect username or password' 52 | } 53 | else: 54 | logger.error(e) 55 | 56 | if 'AuthenticationResult' in response: 57 | logger.info('User authenticated: %s', userid) 58 | return {'headers': {**default_http_headers}, 59 | 'statusCode': 200, 60 | 'body': json.dumps(response['AuthenticationResult']['IdToken']) 61 | } 62 | elif 'ChallengeName' in response: 63 | logger.info('User challenge requested: %s', userid) 64 | return {'headers': {**default_http_headers}, 65 | 'statusCode': 200, 66 | 'body': json.dumps(response) 67 | } 68 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_pipeline_task_execution_output/lambda_pipeline_task_execution_output.py: -------------------------------------------------------------------------------- 1 | import gzip 2 | import json 3 | import base64 4 | import re 5 | import os 6 | from datetime import datetime 7 | import time 8 | 9 | import cmf_boto 10 | from cmf_logger import logger 11 | import cmf_pipeline 12 | 13 | ddb_client = cmf_boto.resource("dynamodb") 14 | application = os.environ["application"] 15 | environment = os.environ["environment"] 16 | task_executions_table_name = '{}-{}-task_executions'.format(application, environment) 17 | task_executions_table = ddb_client.Table(task_executions_table_name) 18 | 19 | 20 | def update_log(task_execution_id, status, message): 21 | logger.info(f'Writing log for task execution ID: {task_execution_id}') 22 | resp = task_executions_table.get_item(Key={'task_execution_id': task_execution_id}) 23 | if "Item" not in resp: 24 | logger.warn("Task execution ID not found") 25 | return 26 | task_execution_data = resp["Item"] 27 | 28 | message = "[" + time.strftime("%H:%M:%S") + "] " + "\n" + message + "\n" 29 | output = task_execution_data.get("output", "") + message 30 | last_output_message = message.split(f'[{status}]',1)[1] 31 | 32 | cmf_pipeline.update_task_execution_output(task_execution_id, last_output_message, output) 33 | cmf_pipeline.update_task_execution_status(task_execution_id, cmf_pipeline.TaskExecutionStatus(status)) 34 | 35 | 36 | def lambda_handler(event, _): 37 | # parse Cloudwatch Log 38 | cw_data = event['awslogs']['data'] 39 | compressed_payload = base64.b64decode(cw_data) 40 | uncompressed_payload = gzip.decompress(compressed_payload) 41 | payload = json.loads(uncompressed_payload) 42 | for log_event in payload['logEvents']: 43 | message = log_event["message"] 44 | 45 | logger.info('Processing Cloudwatch event.') 46 | 47 | # Expected log format to be "[task_execution_id][status] message" 48 | message_metadata = re.findall(r"\[(.*?)\]", message) 49 | if (len(message_metadata) < 2): 50 | logger.debug(f"Can't process message format: {message}") 51 | continue 52 | 53 | update_log(message_metadata[0], message_metadata[1], message) -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_replatformec2schema/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from . import factory -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_reset/lambda_reset.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import json 6 | import os 7 | 8 | import cmf_boto 9 | from cmf_utils import cors, default_http_headers 10 | from cmf_logger import logger, log_event_received 11 | 12 | 13 | def lambda_handler(event, _): 14 | log_event_received(event) 15 | 16 | body = json.loads(event['body']) 17 | userid = body['username'] 18 | oldpassword = body['oldpassword'] 19 | newpassword = body['newpassword'] 20 | client = cmf_boto.client('cognito-idp') 21 | try: 22 | response = client.initiate_auth( 23 | ClientId=os.environ['clientId'], 24 | AuthFlow='USER_PASSWORD_AUTH', 25 | AuthParameters={ 26 | 'USERNAME': userid, 27 | 'PASSWORD': oldpassword 28 | } 29 | ) 30 | except Exception as e: 31 | if "NotAuthorizedException" in str(e) or "UserNotFoundException" in str(e): 32 | return {'headers': {**default_http_headers}, 33 | 'statusCode': 400, 34 | 'body': 'Incorrect old username or password' 35 | } 36 | 37 | challenge_name = response['ChallengeName'] 38 | if challenge_name == "NEW_PASSWORD_REQUIRED": 39 | response = client.respond_to_auth_challenge( 40 | ClientId=os.environ['clientId'], 41 | ChallengeName='NEW_PASSWORD_REQUIRED', 42 | Session=response['Session'], 43 | ChallengeResponses={ 44 | 'NEW_PASSWORD': newpassword, 45 | 'USERNAME' : userid 46 | 47 | } 48 | ) 49 | 50 | return { 51 | 'headers': {**default_http_headers}, 52 | 'statusCode': 200, 53 | 'body': json.dumps(response) 54 | } 55 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_ssm_load_scripts/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | PyYAML = "^6.0.2" 8 | 9 | [build-system] 10 | requires = ["poetry-core"] 11 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_ssm_scripts/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | PyYAML = "^6.0.2" 8 | 9 | [build-system] 10 | requires = ["poetry-core"] 11 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_ssm_socket/poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "pyjwt" 5 | version = "2.10.1" 6 | description = "JSON Web Token implementation in Python" 7 | optional = false 8 | python-versions = ">=3.9" 9 | groups = ["main"] 10 | files = [ 11 | {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, 12 | {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, 13 | ] 14 | 15 | [package.extras] 16 | crypto = ["cryptography (>=3.4.0)"] 17 | dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] 18 | docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] 19 | tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] 20 | 21 | [metadata] 22 | lock-version = "2.1" 23 | python-versions = "^3.11" 24 | content-hash = "0b979cc021881b0dd9dbc97614dcc0a16d1ffc8698f60e1e926fa2ed9f859f8c" 25 | -------------------------------------------------------------------------------- /source/backend/lambda_functions/lambda_ssm_socket/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | PyJWT= "2.10.1" 8 | 9 | [build-system] 10 | requires = ["poetry-core"] 11 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_items/python/query_comparator_operations.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import query_conditions 5 | 6 | # list of operation names as constants 7 | EQUAL_COMPARATOR = "=" 8 | NOT_EQUAL_COMPARATOR = "!=" 9 | EMPTY_COMPARATOR = "empty" 10 | NOT_EMPTY_COMPARATOR = "!empty" 11 | 12 | query_comparator_operations_dictionary = { 13 | EQUAL_COMPARATOR: query_conditions.equal_query_condition, 14 | NOT_EQUAL_COMPARATOR: query_conditions.not_equal_query_condition, 15 | EMPTY_COMPARATOR: query_conditions.empty_query_condition, 16 | NOT_EMPTY_COMPARATOR: query_conditions.not_empty_query_condition 17 | } -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_items/python/query_conditions.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | def equal_query_condition(item, query, query_result): 6 | if query['attribute'] in item and query['value']: 7 | if item[query['attribute']] == query['value']: 8 | query_result = True if query_result != False else query_result 9 | return query_result 10 | 11 | return False 12 | 13 | 14 | def not_equal_query_condition(item, query, query_result): 15 | if query['attribute'] in item and query['value']: 16 | if item[query['attribute']] != query['value']: 17 | query_result = True if query_result != False else query_result 18 | return query_result 19 | 20 | return False 21 | 22 | 23 | def empty_query_condition(item, query, query_result): 24 | if query['attribute'] in item: 25 | query_result = non_list_type_attribute_for_empty_comparator(item, query, query_result) 26 | elif query['attribute'] not in item and 'comparator' in query: 27 | query_result = True if query_result != False else query_result 28 | 29 | return query_result 30 | 31 | 32 | def not_empty_query_condition(item, query, query_result): 33 | if query['attribute'] in item: 34 | query_result = non_list_type_attribute_for_not_empty_comparator(item, query, query_result) 35 | 36 | return query_result 37 | 38 | 39 | def non_list_type_attribute_for_empty_comparator(item, query, query_result): 40 | if item[query['attribute']] == '': 41 | query_result = True if query_result != False else query_result 42 | return query_result 43 | 44 | return False 45 | 46 | 47 | def non_list_type_attribute_for_not_empty_comparator(item, query, query_result): 48 | if item[query['attribute']] != '': 49 | query_result = True if query_result != False else query_result 50 | return query_result 51 | 52 | return False 53 | 54 | 55 | def parse_outcomes(outcomes): 56 | return_required = False 57 | return_hidden = False 58 | 59 | for outcome in outcomes: 60 | if outcome == 'required': 61 | return_required = True 62 | elif outcome == 'not_required': 63 | return_required = False 64 | elif outcome == 'hidden': 65 | return_hidden = True 66 | elif outcome == 'not_hidden': 67 | return_hidden = False 68 | 69 | return return_required, return_hidden -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_policy/python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | urllib3 = ">=2.3.0" 8 | requests = "==2.32.3" 9 | PyJWT = {extras = ["crypto"], version = "2.10.1"} 10 | simplejson = "==3.20.1" 11 | 12 | [build-system] 13 | requires = ["poetry-core"] 14 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_py_pkgs/python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | urllib3 = ">=2.3.0" 8 | requests = "==2.32.3" 9 | simplejson = "==3.20.1" 10 | boto3 = "^1.37.6" 11 | botocore = "^1.37.6" 12 | aws-lambda-powertools = ">=3.7.0" 13 | mypy-boto3-dynamodb = ">=1.37.0" 14 | 15 | [build-system] 16 | requires = ["poetry-core"] 17 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_utils/python/cmf_boto.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from botocore.config import Config 5 | import boto3 6 | import os 7 | 8 | 9 | def client(*args, **kwargs): 10 | """ 11 | returns a boto client instrumented with a user agent 12 | """ 13 | _add_user_agent(kwargs) 14 | return boto3.client(*args, **kwargs) 15 | 16 | 17 | def resource(*args, **kwargs): 18 | """ 19 | returns a boto resource instrumented with a user agent 20 | """ 21 | _add_user_agent(kwargs) 22 | return boto3.resource(*args, **kwargs) 23 | 24 | 25 | def session_client(session, *args, **kwargs): 26 | """ 27 | returns a boto session_client instrumented with a user agent 28 | """ 29 | _add_user_agent(kwargs) 30 | return session.client(*args, **kwargs) 31 | 32 | 33 | def _add_user_agent(kwargs): 34 | """ 35 | adds a user agent to the kwargs if there isn't none 36 | """ 37 | solution_id = os.getenv('SOLUTION_ID', 'SO0097') 38 | solution_version = os.getenv('SOLUTION_VERSION', 'unknown') 39 | user_agent = f'AwsSolution/{solution_id}/{solution_version}' 40 | if 'config' not in kwargs: 41 | boto_config = Config(user_agent_extra=user_agent) 42 | kwargs['config'] = boto_config 43 | else: 44 | kwargs['config'] = kwargs['config'].merge(Config(user_agent_extra=user_agent)) 45 | -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_utils/python/cmf_logger.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from importlib import reload 5 | import logging 6 | import os 7 | 8 | LOGGER_LEVELS = { 9 | 'DEBUG': logging.DEBUG, 10 | 'INFO': logging.INFO, 11 | 'WARNING': logging.WARNING, 12 | 'ERROR': logging.ERROR, 13 | } 14 | 15 | LOGLEVEL = os.getenv('LOGLEVEL', 'INFO').upper() 16 | # This will not take effect if a basicConfig has already been set for the process 17 | logging.basicConfig(format='%(asctime)s | %(levelname)s | %(message)s', level=LOGLEVEL) # //NOSONAR Basic configuration doesn't pose security risk 18 | logger = logging.getLogger() 19 | logger.setLevel(LOGGER_LEVELS[LOGLEVEL]) 20 | 21 | 22 | def get_logger(name=None): 23 | return logging.getLogger(name) 24 | 25 | 26 | def init_task_execution_logger(filter): 27 | reload(logging) 28 | task_execution_logger = logging.getLogger() 29 | logging.basicConfig(format='[%(task_execution_id)s][%(status)s] %(message)s', level=logging.INFO) 30 | task_execution_logger.setLevel(logging.INFO) 31 | task_execution_logger.addFilter(filter) 32 | return task_execution_logger 33 | 34 | def log_event_received(event): 35 | logger.info(f'RequestId: {event.get("requestContext", {}).get("requestId", "{not provided}")}, ' 36 | f'ExtendedRequestId: {event.get("requestContext", {}).get("extendedRequestId", "{not provided}")}') -------------------------------------------------------------------------------- /source/backend/lambda_layers/lambda_layer_utils/python/cmf_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | from datetime import datetime, timezone 4 | import os 5 | import requests 6 | import json 7 | 8 | # System-wide data format for logging and notifications. 9 | CONST_DT_FORMAT = '%Y-%m-%dT%H:%M:%S.%f%z' 10 | CONST_DT_FORMAT_V3 = '%Y-%m-%dT%H:%M:%S.%f' 11 | 12 | REQUESTS_DEFAULT_TIMEOUT = 60 13 | 14 | if 'cors' in os.environ: 15 | cors = os.environ['cors'] 16 | else: 17 | cors = '*' 18 | 19 | default_http_headers = { 20 | 'Access-Control-Allow-Origin': cors, 21 | 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload', 22 | 'Content-Security-Policy': "base-uri 'self'; upgrade-insecure-requests; default-src 'none'; object-src 'none'; connect-src none; img-src 'self' data:; script-src blob: 'self'; style-src 'self'; font-src 'self' data:; form-action 'self';" 23 | } 24 | 25 | # anonymous_usage_data settings. 26 | anonymous_usage_data = os.environ.get('AnonymousUsageData', 'Yes') 27 | s_uuid = os.environ.get('solutionUUID', '') 28 | region = os.environ.get('region','unknown') 29 | if region == 'unknown': 30 | region = os.environ.get('REGION', 'unknown') 31 | anonymous_usage_data_url = 'https://metrics.awssolutionsbuilder.com/generic' 32 | solution_id = os.getenv('SOLUTION_ID', 'SO0097') 33 | 34 | 35 | def send_anonymous_usage_data(status): 36 | if anonymous_usage_data == "Yes": 37 | usage_data = {"Solution": solution_id, 38 | "UUID": s_uuid, 39 | "Status": status, 40 | "TimeStamp": str(datetime.now()), 41 | "Region": region 42 | } 43 | requests.post(anonymous_usage_data_url, 44 | data=json.dumps(usage_data), 45 | headers={'content-type': 'application/json'}, 46 | timeout=REQUESTS_DEFAULT_TIMEOUT) 47 | 48 | 49 | def get_date_from_string(str_date): 50 | try: 51 | created_timestamp = datetime.strptime(str_date, CONST_DT_FORMAT) 52 | except Exception as _: 53 | # try old pre v4 format for backward compatibility. 54 | created_timestamp = datetime.strptime(str_date, CONST_DT_FORMAT_V3) 55 | 56 | created_timestamp = created_timestamp.replace(tzinfo=timezone.utc) 57 | 58 | return created_timestamp 59 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "cloud-migration-factory-on-aws" 3 | package-mode = false 4 | 5 | [tool.poetry.dependencies] 6 | python = "^3.11" 7 | urllib3 = ">=2.3.0" 8 | requests = "==2.32.3" 9 | simplejson = "==3.20.1" 10 | boto3 = "^1.37.6" 11 | botocore = "^1.37.6" 12 | moto = "==5.1.1" 13 | coverage = "==7.6.12" 14 | troposphere = "==4.9.0" 15 | PyYAML = "==6.0.2" 16 | pyparsing = "==3.2.1" 17 | docker = "==7.1.0" 18 | aws-lambda-powertools = {extras = ["aws-sdk"], version = ">=3.7.0"} 19 | PyJWT = {extras = ["crypto"], version = "2.10.1"} 20 | joserfc = "~=1.0.4" 21 | mypy-boto3-dynamodb = ">=1.37.0" 22 | 23 | [tool.poetry.group.dev.dependencies] 24 | 25 | [build-system] 26 | requires = ["poetry-core"] 27 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/Migration_Tracker_All_Extract_Script.py: -------------------------------------------------------------------------------- 1 | # sample file for testing 2 | # used by test_lambda_migrationtracker_glue_base.py, the lambda lambda_migrationtracker_glue_base.py copies the file 3 | # to a specified S3 bucket. So the tests verify that the file is copied regardless of the content 4 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/apps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "app_id": { 4 | "S": "1" 5 | }, 6 | "app_name": { 7 | "S": "Wordpress" 8 | }, 9 | "aws_accountid": { 10 | "S": "111111111111" 11 | }, 12 | "aws_region": { 13 | "S": "us-east-1" 14 | }, 15 | "wave_id": { 16 | "S": "1" 17 | }, 18 | "tags": { 19 | "L": [ 20 | { 21 | "S": "tag1" 22 | }, 23 | { 24 | "S": "tag2" 25 | } 26 | ] 27 | }, 28 | "description":{ 29 | "S": "The amazing wordpress" 30 | } 31 | }, 32 | { 33 | "app_id": { 34 | "S": "2" 35 | }, 36 | "app_name": { 37 | "S": "OFBiz" 38 | }, 39 | "aws_accountid": { 40 | "S": "111111111111" 41 | }, 42 | "aws_region": { 43 | "S": "us-east-1" 44 | }, 45 | "wave_id": { 46 | "S": "1" 47 | } 48 | } 49 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/connection_ids.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "connectionId": { 4 | "S": "1" 5 | } 6 | }, 7 | { 8 | "connectionId": { 9 | "S": "2" 10 | } 11 | } 12 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/jwtRS256.key.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx363yFGiUUD0M3zy4G7Y 3 | 6cjTm+k9BYaTbaXYJe7l/coCJg0KK+xkRtWFGqftDiRM1qAbHrLrLolfF2HwWaMp 4 | 9sya6cYNnj+z64cJ1YwPXO8ATX5pD2vNQHFgwWYp20McpNADxrJ908kCrGav9Qws 5 | yZb5AICPJ6zY6mPBSkJkSbY+Gxp/Lkf+EGVTifCIr1Ob7SfVrS7NMXcwqhh3iAF7 6 | n83DCU9QHrIYY1A/2E96NIx1y+CcaWLd7XB20atC7vNnrh06rL/fg12OrfDAfIb/ 7 | Ln6EeYDmDMOgHX9i0UhInIGd2LSF2+sIIO+W94Wrcz7EtotruBvDCL4O2cuW3qPY 8 | B4OX3ARI0/octMCBb373gTRzjVFE5X4DeHAXWo9ljq3FeA9GlcNfekTNvZ//HbuL 9 | oJM3w5kA4zptkHEAWcEFIe87VgdVBXnHASyN9XFcaWhenPBxtr33+Yxsw6o9SNCU 10 | iGrHu7O5ZLcLE9BuONoawOv3oHpuUupNJlUBKe5uocXV2neAyysD0dmIZQ8lVVfc 11 | eaM14GI8ozImlEpLkyZ3uocXqS4RoQ7kmneSXxa0Mc3jVSyJ/lNEdTGNK+e80hC7 12 | ZD4FyyIvB8zNtFROwUj8cSOWEy2E/Hd5dMQsSBDAEr2MEfGOf6D7G/ziPG8wU1XO 13 | kFMvemw6dqq4ju3+FE1Yvz8CAwEAAQ== 14 | -----END PUBLIC KEY----- 15 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/pipeline_templates.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pipeline_template_id": { 4 | "S": "1" 5 | }, 6 | "pipeline_template_description": { 7 | "S": "Imports Application Discovery Service (ADS) inventory data and EC2 recommendations" 8 | }, 9 | "pipeline_template_name": { 10 | "S": "Migration Hub Import" 11 | }, 12 | "_history": { 13 | "M": { 14 | "createdBy": { 15 | "M": { 16 | "email": { 17 | "S": "someone@example.com" 18 | }, 19 | "userRef": { 20 | "S": "0468d488-50a1-706b-dfb1-4a977a1e105b" 21 | } 22 | } 23 | }, 24 | "createdTimestamp": { 25 | "S": "2024-09-17T11:00:37.943349+00:00" 26 | } 27 | } 28 | } 29 | }, 30 | { 31 | "pipeline_template_id": { 32 | "S": "2" 33 | }, 34 | "pipeline_template_description": { 35 | "S": "Facilitates server replications via Application Migration Service (MGN) for the selected wave" 36 | }, 37 | "pipeline_template_name": { 38 | "S": "Rehost with Application Migration Service (MGN)" 39 | }, 40 | "_history": { 41 | "M": { 42 | "createdBy": { 43 | "M": { 44 | "email": { 45 | "S": "someone@example.com" 46 | }, 47 | "userRef": { 48 | "S": "0468d488-50a1-706b-dfb1-4a977a1e105b" 49 | } 50 | } 51 | }, 52 | "createdTimestamp": { 53 | "S": "2024-09-17T11:00:43.603504+00:00" 54 | } 55 | } 56 | } 57 | } 58 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/pipelines.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pipeline_id": { 4 | "S": "1" 5 | }, 6 | "pipeline_name": { 7 | "S": "Pipeline1" 8 | }, 9 | "pipeline_status": { 10 | "S": "Not Started" 11 | }, 12 | "_history": { 13 | "M": { 14 | "lastModifiedTimestamp": { 15 | "S": "test" 16 | }, 17 | "lastModifiedBy": { 18 | "S": "test" 19 | } 20 | }, 21 | "M": { 22 | "createdByTimestamp": { 23 | "S": "test" 24 | }, 25 | "createdBy": { 26 | "M": { 27 | "email": { 28 | "S": "test" 29 | }, 30 | "userRef": { 31 | "S": "test" 32 | } 33 | } 34 | } 35 | } 36 | } 37 | }, 38 | { 39 | "pipeline_id": { 40 | "S": "2" 41 | }, 42 | "pipeline_name": { 43 | "S": "Pipeline2" 44 | }, 45 | "pipeline_status": { 46 | "S": "In Progress" 47 | }, 48 | "_history": { 49 | "M": { 50 | "lastModifiedTimestamp": { 51 | "S": "test" 52 | }, 53 | "lastModifiedBy": { 54 | "S": "test" 55 | } 56 | }, 57 | "M": { 58 | "createdByTimestamp": { 59 | "S": "test" 60 | }, 61 | "createdBy": { 62 | "M": { 63 | "email": { 64 | "S": "test" 65 | }, 66 | "userRef": { 67 | "S": "test" 68 | } 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | { 75 | "pipeline_id": { 76 | "S": "2" 77 | }, 78 | "pipeline_name": { 79 | "S": "Pipeline2" 80 | }, 81 | "pipeline_status": { 82 | "S": "In Progress" 83 | }, 84 | "_history": { 85 | "M": { 86 | "lastModifiedTimestamp": { 87 | "S": "test" 88 | }, 89 | "lastModifiedBy": { 90 | "S": "test" 91 | } 92 | }, 93 | "M": { 94 | "createdByTimestamp": { 95 | "S": "test" 96 | }, 97 | "createdBy": { 98 | "M": { 99 | "email": { 100 | "S": "test" 101 | }, 102 | "userRef": { 103 | "S": "test" 104 | } 105 | } 106 | } 107 | } 108 | } 109 | } 110 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/policies.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "policy_id": { 4 | "S": "1" 5 | }, 6 | "policy_name": { 7 | "S": "Administrator" 8 | } 9 | }, 10 | { 11 | "policy_id": { 12 | "S": "2" 13 | }, 14 | "policy_name": { 15 | "S": "ReadOnly" 16 | } 17 | }, 18 | { 19 | "policy_id": { 20 | "S": "3" 21 | }, 22 | "policy_name": { 23 | "S": "CustomPolicy" 24 | } 25 | } 26 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/roles.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role_id": { 4 | "S": "1" 5 | }, 6 | "groups": { 7 | "L": [ 8 | { 9 | "M": { 10 | "group_name": { 11 | "S": "admin" 12 | } 13 | } 14 | } 15 | ] 16 | }, 17 | "policies": { 18 | "L": [ 19 | { 20 | "M": { 21 | "policy_id": { 22 | "S": "1" 23 | } 24 | } 25 | } 26 | ] 27 | }, 28 | "role_name": { 29 | "S": "FactoryAdmin" 30 | } 31 | }, 32 | { 33 | "role_id": { 34 | "S": "2" 35 | }, 36 | "groups": { 37 | "L": [ 38 | { 39 | "M": { 40 | "group_name": { 41 | "S": "readonly" 42 | } 43 | } 44 | } 45 | ] 46 | }, 47 | "policies": { 48 | "L": [ 49 | { 50 | "M": { 51 | "policy_id": { 52 | "S": "2" 53 | } 54 | } 55 | } 56 | ] 57 | }, 58 | "role_name": { 59 | "S": "FactoryReadOnly" 60 | } 61 | }, 62 | { 63 | "role_id": { 64 | "S": "3" 65 | }, 66 | "groups": { 67 | "L": [ 68 | { 69 | "M": { 70 | "group_name": { 71 | "S": "orchestrator" 72 | } 73 | } 74 | } 75 | ] 76 | }, 77 | "policies": { 78 | "L": [ 79 | { 80 | "M": { 81 | "policy_id": { 82 | "S": "3" 83 | } 84 | } 85 | } 86 | ] 87 | }, 88 | "role_name": { 89 | "S": "FactoryAutomationTaskOrchestrator" 90 | } 91 | } 92 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schema_server_replatform_create_ec2.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "EC2", 3 | "schema_type": "automation", 4 | "friendly_name": "EC2", 5 | "attributes": [ 6 | { 7 | "rel_display_attribute": "aws_accountid", 8 | "system": true, 9 | "validation_regex": "^(?!\\s*$).+", 10 | "rel_key": "aws_accountid", 11 | "name": "accountid", 12 | "description": "AWS account ID", 13 | "rel_entity": "application", 14 | "validation_regex_msg": "AWS account ID must be provided.", 15 | "type": "relationship" 16 | }, 17 | { 18 | "rel_display_attribute": "wave_name", 19 | "system": true, 20 | "validation_regex": "^(?!\\s*$).+", 21 | "rel_key": "wave_id", 22 | "name": "waveid", 23 | "description": "Wave", 24 | "rel_entity": "wave", 25 | "validation_regex_msg": "Wave must be provided.", 26 | "type": "relationship" 27 | } 28 | ], 29 | "group": "RePlatform", 30 | "description": "New EC2 Build", 31 | "actions": [ 32 | { 33 | "name": "EC2 Input Validation", 34 | "apiMethod": "post", 35 | "id": "EC2 Input Validation", 36 | "awsuistyle": "primary", 37 | "apiPath": "/gfvalidate" 38 | }, 39 | { 40 | "name": "EC2 Generate CF Template", 41 | "apiMethod": "post", 42 | "id": "EC2 Generate CF Template", 43 | "awsuistyle": "primary", 44 | "apiPath": "/gfbuild" 45 | }, 46 | { 47 | "name": "EC2 Deployment", 48 | "apiMethod": "post", 49 | "id": "EC2 Deployment", 50 | "awsuistyle": "primary", 51 | "apiPath": "/gfdeploy" 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schema_server_replatform_delete_server.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "server", 3 | "schema_type": "user", 4 | "attributes": [ 5 | { 6 | "description": "Server Id", 7 | "hidden": true, 8 | "name": "server_id", 9 | "required": true, 10 | "system": true, 11 | "type": "string" 12 | }, 13 | { 14 | "description": "Application", 15 | "group_order": "-998", 16 | "name": "app_id", 17 | "rel_display_attribute": "app_name", 18 | "rel_entity": "application", 19 | "rel_key": "app_id", 20 | "required": true, 21 | "system": true, 22 | "type": "relationship" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schema_server_replatform_delete_server_attrs.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "server", 3 | "schema_type": "user", 4 | "attributes": [ 5 | { 6 | "description": "Server Id", 7 | "hidden": true, 8 | "name": "server_id", 9 | "required": true, 10 | "system": true, 11 | "type": "string" 12 | }, 13 | { 14 | "description": "Application", 15 | "group_order": "-998", 16 | "name": "app_id", 17 | "rel_display_attribute": "app_name", 18 | "rel_entity": "application", 19 | "rel_key": "app_id", 20 | "required": true, 21 | "system": true, 22 | "type": "relationship" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schema_server_replatform_update_server.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "server", 3 | "schema_type": "user", 4 | "attributes": [ 5 | { 6 | "description": "Server Id", 7 | "hidden": true, 8 | "name": "server_id", 9 | "required": true, 10 | "system": true, 11 | "type": "string" 12 | }, 13 | { 14 | "description": "Application", 15 | "group_order": "-998", 16 | "name": "app_id", 17 | "rel_display_attribute": "app_name", 18 | "rel_entity": "application", 19 | "rel_key": "app_id", 20 | "required": true, 21 | "system": true, 22 | "type": "relationship" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schemas.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "schema_name": { 4 | "S": "server" 5 | }, 6 | "schema_type": { 7 | "S": "user" 8 | }, 9 | "attributes": { 10 | "L": [ 11 | { 12 | "M": { 13 | "description": { 14 | "S": "Server Id" 15 | }, 16 | "hidden": { 17 | "BOOL": true 18 | }, 19 | "name": { 20 | "S": "server_id" 21 | }, 22 | "required": { 23 | "BOOL": true 24 | }, 25 | "system": { 26 | "BOOL": true 27 | }, 28 | "type": { 29 | "S": "string" 30 | } 31 | } 32 | }, 33 | { 34 | "M": { 35 | "description": { 36 | "S": "Application" 37 | }, 38 | "group_order": { 39 | "S": "-998" 40 | }, 41 | "name": { 42 | "S": "app_id" 43 | }, 44 | "rel_display_attribute": { 45 | "S": "app_name" 46 | }, 47 | "rel_entity": { 48 | "S": "application" 49 | }, 50 | "rel_key": { 51 | "S": "app_id" 52 | }, 53 | "required": { 54 | "BOOL": true 55 | }, 56 | "system": { 57 | "BOOL": true 58 | }, 59 | "type": { 60 | "S": "relationship" 61 | } 62 | } 63 | } 64 | ] 65 | } 66 | }, 67 | { 68 | "schema_name": { 69 | "S": "wave" 70 | }, 71 | "schema_type": { 72 | "S": "user" 73 | } 74 | }, 75 | { 76 | "schema_name": { 77 | "S": "app" 78 | }, 79 | "schema_type": { 80 | "S": "user" 81 | }, 82 | "attributes": { 83 | "L": [ 84 | { 85 | "M": { 86 | "name": { 87 | "S": "app_id" 88 | }, 89 | "type": { 90 | "S": "string" 91 | } 92 | } 93 | }, 94 | { 95 | "M": { 96 | "name": { 97 | "S": "app_name" 98 | }, 99 | "type": { 100 | "S": "string" 101 | } 102 | } 103 | } 104 | ] 105 | } 106 | }, 107 | { 108 | "schema_name": { 109 | "S": "automation" 110 | }, 111 | "schema_type": { 112 | "S": "automation" 113 | } 114 | } 115 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schemas_modified_TS.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "schema_name": { 4 | "S": "server" 5 | }, 6 | "lastModifiedTimestamp": { 7 | "S": "2023-04-28T15:27:12.991773+00:00" 8 | }, 9 | "schema_type": { 10 | "S": "user" 11 | } 12 | }, 13 | { 14 | "schema_name": { 15 | "S": "wave" 16 | }, 17 | "lastModifiedTimestamp": { 18 | "S": "2023-04-28T15:27:12.991773+00:00" 19 | }, 20 | "schema_type": { 21 | "S": "user" 22 | } 23 | }, 24 | { 25 | "schema_name": { 26 | "S": "app" 27 | }, 28 | "lastModifiedTimestamp": { 29 | "S": "2023-04-25T18:53:25.915746+00:00" 30 | }, 31 | "schema_type": { 32 | "S": "user" 33 | } 34 | } 35 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schemas_no_app.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "schema_name": { 4 | "S": "server" 5 | }, 6 | "schema_type": { 7 | "S": "user" 8 | } 9 | }, 10 | { 11 | "schema_name": { 12 | "S": "wave" 13 | }, 14 | "schema_type": { 15 | "S": "user" 16 | } 17 | } 18 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schemas_no_server.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "schema_name": { 4 | "S": "wave" 5 | }, 6 | "schema_type": { 7 | "S": "user" 8 | } 9 | }, 10 | { 11 | "schema_name": { 12 | "S": "app" 13 | }, 14 | "schema_type": { 15 | "S": "user" 16 | } 17 | } 18 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/schemas_no_wave.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "schema_name": { 4 | "S": "server" 5 | }, 6 | "schema_type": { 7 | "S": "user" 8 | } 9 | }, 10 | { 11 | "schema_name": { 12 | "S": "app" 13 | }, 14 | "schema_type": { 15 | "S": "user" 16 | } 17 | } 18 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/README.md: -------------------------------------------------------------------------------- 1 | This folder contains test data for the lambdas 2 | - lambda_ssm_load_scripts 3 | - lambda_ssm_scripts 4 | 5 | ### lambda_ssm_load_scripts 6 | The tests expect a zip file with scripts. 7 | - sample_ssm_scripts.zip, the zip file containing sample_ssm_script_1.json and sample_ssm_script_2.json 8 | - sample_ssm_script_1.json and sample_ssm_script_2.json are the sample json files included for the convenience of checking the contents without unzipping 9 | 10 | ### lambda_ssm_scripts 11 | - invalid_zip_file.zip - a single python source file renamed with .zip extension to be used as invalid zip in the tests 12 | 13 | 14 | - package_valid consists of 15 | - hello_world.py 16 | - mfcommon.py 17 | - Package-Structure.yml 18 | 19 | The test then creates a zip file containing the above files on the fly 20 | 21 | Similarly, the following packages are used in the tests 22 | - package_invalid_yaml 23 | - package_no_yaml 24 | - package_incorrect_yaml_contents 25 | - package_no_master_file 26 | - package_valid_with_dependencies 27 | - package_missing_dependencies 28 | - package_schema_extensions 29 | - package_invalid_attributes 30 | 31 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_incorrect_yaml_contents/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name1: "Hello World" 2 | Description1: "This script will output the text provided in the argument." 3 | MasterFileName1: "hello_world.py" 4 | Arguments1: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_incorrect_yaml_contents/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_invalid_attributes/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "" 7 | long_desc1: "Message to output." 8 | description1: "Message that will be output from python and powershell," 9 | type1: "sting" 10 | - name: "MyMessage 2" 11 | long_desc: "Message to output 2." 12 | description: "Message that will be output from python and powershell 2," 13 | type: "list" -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_invalid_attributes/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_invalid_yaml/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" 10 | INVALID LINE -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_invalid_yaml/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_missing_dependencies/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" 10 | Dependencies: 11 | - lib1.py -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_missing_dependencies/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_no_master_file/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_no_yaml/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_schema_extensions/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" 10 | SchemaExtensions: 11 | - 12 | name: "extension_script_1" 13 | schema: "extension_schema_1" -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_schema_extensions/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_valid/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_valid/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_valid_with_dependencies/Package-Structure.yml: -------------------------------------------------------------------------------- 1 | Name: "Hello World" 2 | Description: "This script will output the text provided in the argument." 3 | MasterFileName: "hello_world.py" 4 | Arguments: 5 | - 6 | name: "MyMessage" 7 | long_desc: "Message to output." 8 | description: "Message that will be output from python and powershell," 9 | type: "sting" 10 | Dependencies: 11 | - lib1.py -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_valid_with_dependencies/hello_world.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/package_valid_with_dependencies/lib1.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # no content, test only expects the presence of the file 5 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/sample_ssm_script_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample ssm script 1 for testing lambda_ssm_scripts.py", 3 | "comment": "sample_ssm_script_1.json and sample_ssm_script_2.json are zipped in sample_ssm_scripts.zip. The test expects only sample_ssm_scripts.zip. The json files included for for the convenience of checking the contents without unzipping" 4 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/sample_ssm_script_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample ssm script 1 for testing lambda_ssm_scripts.py", 3 | "comment": "sample_ssm_script_1.json and sample_ssm_script_2.json are zipped in sample_ssm_scripts.zip. The test expects only sample_ssm_scripts.zip. The json files included for for the convenience of checking the contents without unzipping" 4 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_load_scripts/sample_ssm_scripts.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-solutions/cloud-migration-factory-on-aws/f151fc4eb1195021be7170e7075c8e924073c3c5/source/backend/lambda_unit_test/sample_data/ssm_load_scripts/sample_ssm_scripts.zip -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_socket_cognito_jwks.json: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "alg": "RS256", 5 | "e": "AQAB", 6 | "kid": "UPSZ26EORotKU88HFmnKO6Z1NgTVteSRMVwvIfqmpKA=", 7 | "kty": "RSA", 8 | "n": "x363yFGiUUD0M3zy4G7Y6cjTm-k9BYaTbaXYJe7l_coCJg0KK-xkRtWFGqftDiRM1qAbHrLrLolfF2HwWaMp9sya6cYNnj-z64cJ1YwPXO8ATX5pD2vNQHFgwWYp20McpNADxrJ908kCrGav9QwsyZb5AICPJ6zY6mPBSkJkSbY-Gxp_Lkf-EGVTifCIr1Ob7SfVrS7NMXcwqhh3iAF7n83DCU9QHrIYY1A_2E96NIx1y-CcaWLd7XB20atC7vNnrh06rL_fg12OrfDAfIb_Ln6EeYDmDMOgHX9i0UhInIGd2LSF2-sIIO-W94Wrcz7EtotruBvDCL4O2cuW3qPYB4OX3ARI0_octMCBb373gTRzjVFE5X4DeHAXWo9ljq3FeA9GlcNfekTNvZ__HbuLoJM3w5kA4zptkHEAWcEFIe87VgdVBXnHASyN9XFcaWhenPBxtr33-Yxsw6o9SNCUiGrHu7O5ZLcLE9BuONoawOv3oHpuUupNJlUBKe5uocXV2neAyysD0dmIZQ8lVVfceaM14GI8ozImlEpLkyZ3uocXqS4RoQ7kmneSXxa0Mc3jVSyJ_lNEdTGNK-e80hC7ZD4FyyIvB8zNtFROwUj8cSOWEy2E_Hd5dMQsSBDAEr2MEfGOf6D7G_ziPG8wU1XOkFMvemw6dqq4ju3-FE1Yvz8", 9 | "use": "sig" 10 | }, 11 | { 12 | "alg": "RS256", 13 | "e": "AQAB", 14 | "kid": "as27v9YhmOD4TTdky8xvFHCjZ+ZqKKEjhi7eAeBGBhE=", 15 | "kty": "RSA", 16 | "n": "zQGdp6Mp4opT5WGS8vzdrTJjxipxNLrUDMX4TLZ76JxzgMdyK5btlmyCVdg7k13fo_n3tKtjEuZ1c7ukxMpLf_Pfo5k9Bdz9YoGuawv1VNzpKGQKPbK9W1JTynbhYsWKYc6XdQ0LsB4rNa1KkKfJCLVloReqPbLBFC5WylZrTrIpXRTR5FdXk6UD3dbEifuxEj6EUC6Z9IqJ8p79yoDR20Cwv3cYBPrZZbjESFcokqQSlpsScMnA8L5Xxli8hUHXPJdQkKlW_19D6xwHk54OoUk8EZTWVZ3KheTwr-8qHh8-i1D2yj8iGbF68yn5PiSQS2Ku12kTpUmTw9iQIGZdaw", 17 | "use": "sig" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/ssm_socket_cognito_jwks_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "keys": [ 3 | { 4 | "alg": "RS256", 5 | "e": "AQAB", 6 | "kid": "UPSZ26EORotKU88HFmnKO6Z1NgTVteSRMVwvIfqmpKA=", 7 | "kty": "RSA", 8 | "n": "errorx363yFGiUUD0M3zy4G7Y6cjTm-k9BYaTbaXYJe7l_coCJg0KK-xkRtWFGqftDiRM1qAbHrLrLolfF2HwWaMp9sya6cYNnj-z64cJ1YwPXO8ATX5pD2vNQHFgwWYp20McpNADxrJ908kCrGav9QwsyZb5AICPJ6zY6mPBSkJkSbY-Gxp_Lkf-EGVTifCIr1Ob7SfVrS7NMXcwqhh3iAF7n83DCU9QHrIYY1A_2E96NIx1y-CcaWLd7XB20atC7vNnrh06rL_fg12OrfDAfIb_Ln6EeYDmDMOgHX9i0UhInIGd2LSF2-sIIO-W94Wrcz7EtotruBvDCL4O2cuW3qPYB4OX3ARI0_octMCBb373gTRzjVFE5X4DeHAXWo9ljq3FeA9GlcNfekTNvZ__HbuLoJM3w5kA4zptkHEAWcEFIe87VgdVBXnHASyN9XFcaWhenPBxtr33-Yxsw6o9SNCUiGrHu7O5ZLcLE9BuONoawOv3oHpuUupNJlUBKe5uocXV2neAyysD0dmIZQ8lVVfceaM14GI8ozImlEpLkyZ3uocXqS4RoQ7kmneSXxa0Mc3jVSyJ_lNEdTGNK-e80hC7ZD4FyyIvB8zNtFROwUj8cSOWEy2E_Hd5dMQsSBDAEr2MEfGOf6D7G_ziPG8wU1XOkFMvemw6dqq4ju3-FE1Yvz8", 9 | "use": "sig" 10 | }, 11 | { 12 | "alg": "RS256", 13 | "e": "AQAB", 14 | "kid": "as27v9YhmOD4TTdky8xvFHCjZ+ZqKKEjhi7eAeBGBhE=", 15 | "kty": "RSA", 16 | "n": "zQGdp6Mp4opT5WGS8vzdrTJjxipxNLrUDMX4TLZ76JxzgMdyK5btlmyCVdg7k13fo_n3tKtjEuZ1c7ukxMpLf_Pfo5k9Bdz9YoGuawv1VNzpKGQKPbK9W1JTynbhYsWKYc6XdQ0LsB4rNa1KkKfJCLVloReqPbLBFC5WylZrTrIpXRTR5FdXk6UD3dbEifuxEj6EUC6Z9IqJ8p79yoDR20Cwv3cYBPrZZbjESFcokqQSlpsScMnA8L5Xxli8hUHXPJdQkKlW_19D6xwHk54OoUk8EZTWVZ3KheTwr-8qHh8-i1D2yj8iGbF68yn5PiSQS2Ku12kTpUmTw9iQIGZdaw", 17 | "use": "sig" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/sample_data/waves.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "wave_id": { 4 | "S": "1" 5 | }, 6 | "wave_name": { 7 | "S": "Wave 1" 8 | } 9 | }, 10 | { 11 | "wave_id": { 12 | "S": "2" 13 | }, 14 | "wave_name": { 15 | "S": "Wave 2" 16 | } 17 | } 18 | ] -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/test_lambda_cognitogroups.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import json 6 | import os 7 | import unittest 8 | from unittest import mock 9 | 10 | from moto import mock_aws 11 | import boto3 12 | 13 | import test_common_utils 14 | 15 | @mock.patch.dict('os.environ', test_common_utils.default_mock_os_environ) 16 | class LambdaCognitoGroupsTest(unittest.TestCase): 17 | 18 | @mock_aws 19 | def assert_lambda_handler(self): 20 | import lambda_cognitogroups 21 | test_client = boto3.client('cognito-idp') 22 | user_pool_id = test_client.create_user_pool(PoolName='testPool')['UserPool']['Id'] 23 | test_group_name = 'testUserGroup' 24 | test_client.create_group( 25 | GroupName=test_group_name, 26 | UserPoolId=user_pool_id, 27 | ) 28 | os.environ['userpool_id'] = user_pool_id 29 | response = lambda_cognitogroups.lambda_handler({}, {}) 30 | self.assertEqual(200, response['statusCode']) 31 | self.assertEqual(json.dumps([test_group_name]), response['body']) 32 | 33 | def test_lambda_handler(self): 34 | self.assert_lambda_handler() 35 | 36 | def test_lambda_handler_with_cors_set(self): 37 | import os 38 | os.environ['cors'] = '*' 39 | self.assert_lambda_handler() 40 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/test_lambda_item_common.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import os 6 | import unittest 7 | from unittest import mock 8 | 9 | import boto3 10 | from moto import mock_aws 11 | from mypy_boto3_dynamodb.service_resource import Table 12 | 13 | import test_common_utils 14 | from test_common_utils import logger, default_mock_os_environ as mock_os_environ 15 | 16 | 17 | def mock_item_check_valid_item_create_valid(item, schema, related_items=None): 18 | logger.debug(f'mock_item_check_valid_item_create({item}, {schema}, {related_items})') 19 | return None 20 | 21 | 22 | def mock_item_check_valid_item_create_in_valid(item, schema, related_items=None): 23 | logger.debug(f'mock_item_check_valid_item_create({item}, {schema}, {related_items})') 24 | return ['Simulated error, attribute x is required'] 25 | 26 | @mock.patch.dict('os.environ', mock_os_environ) 27 | @mock_aws 28 | class LambdaItemCommonTest(unittest.TestCase): 29 | 30 | def setUp(self) -> None: 31 | os.environ['AWS_DEFAULT_REGION'] = 'us-east-1' 32 | self.ddb_client = boto3.client('dynamodb') 33 | self.schema_table_name = f'{os.environ["application"]}-{os.environ["environment"]}-schema' 34 | self.apps_table_name = f'{os.environ["application"]}-{os.environ["environment"]}-apps' 35 | self.pipeline_templates_table_name = \ 36 | f'{os.environ["application"]}-{os.environ["environment"]}-pipeline_templates' 37 | self.pipeline_template_tasks_table_name = \ 38 | f'{os.environ["application"]}-{os.environ["environment"]}-pipeline_template_tasks' 39 | test_common_utils.create_and_populate_schemas(self.ddb_client, self.schema_table_name) 40 | test_common_utils.create_and_populate_apps(self.ddb_client, self.apps_table_name) 41 | self.apps_table = boto3.resource('dynamodb').Table(self.apps_table_name) 42 | self.pipeline_templates_table: Table = boto3.resource('dynamodb').Table(self.pipeline_templates_table_name) 43 | self.pipeline_templates_tasks_table: Table = boto3.resource('dynamodb').Table( 44 | self.pipeline_template_tasks_table_name) 45 | 46 | self.event_schema_no_exist = { 47 | 'httpMethod': 'GET', 48 | 'pathParameters': { 49 | 'schema': 'NO_EXIST' 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/test_lambda_login_common.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | from test_common_utils import logger 6 | import botocore 7 | 8 | model = botocore.session.get_session().get_service_model('cognito-idp') 9 | factory = botocore.errorfactory.ClientExceptionsFactory() 10 | exceptions = factory.create_client_exceptions(model) 11 | 12 | 13 | def mock_boto_api_call_success(client, operation_name, kwarg): 14 | logger.info(f'client = {client}, operation_name = {operation_name}, kwarg = {kwarg}') 15 | if operation_name == 'InitiateAuth': 16 | return { 17 | 'ChallengeName': 'NEW_PASSWORD_REQUIRED', 18 | 'Session': 'TEST_SESSION' 19 | } 20 | if operation_name == 'RespondToAuthChallenge': 21 | return { 22 | 'AuthenticationResult': { 23 | 'IdToken': 'TOKEN_123' 24 | } 25 | } 26 | 27 | 28 | def mock_boto_api_call_incorrect_chanllenge(client, operation_name, kwarg): 29 | logger.info(f'client = {client}, operation_name = {operation_name}, kwarg = {kwarg}') 30 | if operation_name == 'InitiateAuth': 31 | return { 32 | 'ChallengeName': 'NEW_PASSWORD_REQUIRED_INCORRECT', 33 | 'Session': 'TEST_SESSION' 34 | } 35 | 36 | 37 | def mock_boto_api_call_exception(client, operation_name, kwarg): 38 | logger.info(f'client = {client}, operation_name = {operation_name}, kwarg = {kwarg}') 39 | if operation_name == 'InitiateAuth': 40 | raise exceptions.ClientError({'Error': {'Code': 'NotAuthorizedException'}}, 41 | 'test-op') 42 | 43 | 44 | def mock_boto_api_call_exception_unexpected(client, operation_name, kwarg): 45 | logger.info(f'client = {client}, operation_name = {operation_name}, kwarg = {kwarg}') 46 | if operation_name == 'InitiateAuth': 47 | raise exceptions.ClientError({'Error': {'Code': 'UnExpectedException'}}, 48 | 'test-op') 49 | 50 | 51 | def mock_boto_api_call_next_challenge(client, operation_name, kwarg): 52 | logger.info(f'client = {client}, operation_name = {operation_name}, kwarg = {kwarg}') 53 | if operation_name == 'InitiateAuth': 54 | return { 55 | 'ChallengeName': 'NEW_PASSWORD_REQUIRED', 56 | 'Session': 'TEST_SESSION' 57 | } 58 | if operation_name == 'RespondToAuthChallenge': 59 | return { 60 | 'AuthenticationResult': { 61 | 'IdToken': 'TOKEN_123' 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/test_lambda_run_athena_savedquery.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import os 6 | import unittest 7 | from unittest import mock 8 | import time 9 | 10 | import boto3 11 | from moto import mock_aws 12 | from test_common_utils import LambdaContextFnArn, test_account_id 13 | from test_common_utils import logger, default_mock_os_environ 14 | 15 | 16 | mock_os_environ = { 17 | **default_mock_os_environ, 18 | 'database': 'cmf_db', 19 | 'workgroup': 'cmf_workgroup' 20 | } 21 | 22 | 23 | @mock.patch.dict('os.environ', mock_os_environ) 24 | @mock_aws 25 | class LambdaRunAthenaSavedQueryTest(unittest.TestCase): 26 | 27 | @mock.patch.dict('os.environ', mock_os_environ) 28 | def setUp(self) -> None: 29 | self.athena_client = boto3.client('athena') 30 | self.athena_client.create_work_group(Name=os.getenv('workgroup'), Configuration={}) 31 | # add sleep to make sure that the resource is created 32 | time.sleep(5) 33 | logger.info(f'{os.getenv("workgroup")} athena work group created') 34 | 35 | def test_lambda_handler(self): 36 | import lambda_run_athena_savedquery 37 | context = LambdaContextFnArn( 38 | 'arn:aws:lambda:us-east-1:' + test_account_id + ':function:migration-factory-lab-test') 39 | workgroup = self.athena_client.get_work_group(WorkGroup=os.getenv('workgroup')) 40 | logger.info(f'In test_lambda_handler, retrieved workgroup - {workgroup}') 41 | response = lambda_run_athena_savedquery.lambda_handler(None, context) 42 | # the function doesn't return anything, so no validation with moto 43 | # can add test with patch that validate arguments called with 44 | self.assertIsNone(response) 45 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/test_lambda_ssm_base.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import unittest 6 | import uuid 7 | from datetime import datetime 8 | from datetime import timedelta 9 | from unittest import mock 10 | 11 | from moto import mock_aws 12 | 13 | from test_common_utils import default_mock_os_environ 14 | 15 | 16 | @mock.patch.dict('os.environ', default_mock_os_environ) 17 | @mock_aws 18 | class LambdaSSMBaseTest(unittest.TestCase): 19 | def put_recent_job(self, table_obj, job_id, num_hours): 20 | current_time = datetime.utcnow() 21 | current_time = current_time + timedelta(hours=-num_hours) 22 | current_time_str = current_time.isoformat(sep='T') 23 | ssm_uuid = str(uuid.uuid4()) 24 | instance_id = 'i-00000000000000000' 25 | ssm_id = instance_id + '+' + ssm_uuid + '+' + current_time_str 26 | item = { 27 | 'SSMId': ssm_id, 28 | 'uuid': ssm_uuid, 29 | 'jobname': 'Test job ' + str(job_id), 30 | 'status': 'RUNNING', 31 | 'SSMData': { 32 | 'status': 'RUNNING', 33 | }, 34 | 'output': 'job output 123', 35 | '_history': { 36 | 'createdTimestamp': current_time_str 37 | } 38 | } 39 | table_obj.put_item(Item=item) 40 | return ssm_id 41 | -------------------------------------------------------------------------------- /source/backend/lambda_unit_test/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py39 3 | skipsdist = True 4 | 5 | [coverage:run] 6 | relative_files = True 7 | branch = True 8 | source = %%SOURCE_PATH%% 9 | -------------------------------------------------------------------------------- /source/frontend/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-typescript", 5 | [ 6 | "@babel/preset-react", 7 | { 8 | "runtime": "automatic" 9 | } 10 | ] 11 | ] 12 | } -------------------------------------------------------------------------------- /source/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | /vite.config.d.ts 23 | /vite.config.js 24 | -------------------------------------------------------------------------------- /source/frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | build 2 | coverage 3 | *.svg 4 | Config -------------------------------------------------------------------------------- /source/frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": false, 7 | "trailingComma": "es5", 8 | "bracketSpacing": true, 9 | "bracketSameLine": false, 10 | "arrowParens": "always" 11 | } 12 | -------------------------------------------------------------------------------- /source/frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | To install the project, you can run: 6 | 7 | ### `npm install` 8 | 9 | To run the project, you can run: 10 | 11 | ### `npm start` 12 | 13 | Runs the app in the development mode.
14 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 15 | 16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console. 18 | 19 | ### `npm test` 20 | 21 | Launches the test runner in the interactive watch mode.
22 | See the section about [running tests](#running-tests) for more information. 23 | 24 | ### `npm run build` 25 | 26 | Builds the app for production to the `build` folder.
27 | It correctly bundles React in production mode and optimizes the build for the best performance. 28 | -------------------------------------------------------------------------------- /source/frontend/index.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | AWS Migration Factory 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/frontend/public/.well-known/security.txt: -------------------------------------------------------------------------------- 1 | # For security issues related to Amazon Web Services (AWS), please see our security policy 2 | Policy: https://aws.amazon.com/security/vulnerability-reporting/ 3 | 4 | # To contact AWS regarding a vulnerability 5 | Contact: mailto:aws-security@amazon.com 6 | Preferred-Languages: en 7 | 8 | # We support PGP encryption 9 | Encryption: https://aws.amazon.com/security/aws-pgp-public-key/ 10 | 11 | # This file expires every 365 days 12 | Expires: %%SECURITY_EXPIRY_DATE%% 13 | 14 | # We're hiring - join Amazon Security! 15 | Hiring: https://www.amazon.jobs/en/business_categories/amazon-security 16 | -------------------------------------------------------------------------------- /source/frontend/public/env.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | window.env = { 7 | API_REGION: "{{region}}", 8 | API_USER: "{{user-api}}", 9 | API_ADMIN: "{{admin-api}}", 10 | API_LOGIN: "{{login-api}}", 11 | API_TOOLS: "{{tools-api}}", 12 | API_SSMSocket: "{{ssm-ws-api}}", 13 | API_VPCE_ID: "{{vpce-id}}", 14 | COGNITO_REGION: "{{region}}", 15 | COGNITO_USER_POOL_ID: "{{user-pool-id}}", 16 | COGNITO_APP_CLIENT_ID: "{{app-client-id}}", 17 | COGNITO_HOSTED_UI_URL: "{{cognito-hosted_ui_url}}", 18 | VERSION_UI: "{{version}}", 19 | AUTO_LOGOUT_MINUTES: 30, 20 | }; 21 | -------------------------------------------------------------------------------- /source/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-solutions/cloud-migration-factory-on-aws/f151fc4eb1195021be7170e7075c8e924073c3c5/source/frontend/public/favicon.ico -------------------------------------------------------------------------------- /source/frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Migration Factory", 3 | "name": "AWS Migration Factory", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /source/frontend/src/PreAuthRoutes.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | import React from "react"; 7 | import { Route, Routes } from "react-router-dom"; 8 | import Login from "./containers/Login"; 9 | import ForgotPassword from "./containers/ForgotPassword"; 10 | import ChangePassword from "./containers/ChangePassword"; 11 | import { CMFTopNavigation } from "./components/CMFTopNavigation"; 12 | 13 | export const PreAuthApp = () => { 14 | return ( 15 | <> 16 | 38 | 39 | } /> 40 | } /> 41 | } /> 42 | {/* Finally, catch all unmatched routes */} 43 | } /> 44 | 45 |