thothctl 0.24.0__tar.gz → 0.24.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {thothctl-0.24.0 → thothctl-0.24.2}/PKG-INFO +1 -1
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/workflow/commands/devsecops.py +90 -11
- thothctl-0.24.2/src/thothctl/services/workflow/phases/build.py +84 -0
- thothctl-0.24.2/src/thothctl/services/workflow/phases/deploy.py +68 -0
- thothctl-0.24.2/src/thothctl/services/workflow/phases/monitor.py +85 -0
- thothctl-0.24.2/src/thothctl/services/workflow/phases/plan.py +150 -0
- thothctl-0.24.2/src/thothctl/services/workflow/phases/test.py +110 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/workflow_service.py +11 -1
- thothctl-0.24.2/src/thothctl/version.py +2 -0
- thothctl-0.24.0/src/thothctl/version.py +0 -2
- {thothctl-0.24.0 → thothctl-0.24.2}/.devcontainer/Dockerfile +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.devcontainer/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.devcontainer/devcontainer.json +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.github/workflows/docs.yml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.github/workflows/python-publish.yml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.gitignore +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.pre-commit-config.yaml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/.readthedocs.yaml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/Dockerfile +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/LICENSE +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/catalog/catalog-info.yaml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/dashboard/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/ai-review/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/ai-review/agent_specifications.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/ai-review/agentcore.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/blast-radius.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/check_environment.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/check_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/check_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/check_project_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/check_space.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/cost-analysis-quick-reference.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/cost-analysis.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/customizing_rules.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/deps-advanced.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/deps.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/drift-detection.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/check/plan.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/customizing_docs.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/document_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/document_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/mermaid_examples.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/mermaid_quickref.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/document/use_cases.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/generate/generate_components.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/generate/generate_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/generate/generate_stacks.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/init/init.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/init/init_space.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/inventory/CHANGELOG.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/inventory/frameworks/terraform.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/inventory/frameworks/terragrunt.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/inventory/iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/inventory/inventory_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/inventory/inventory_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/list/list_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/list/list_projects.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/list/list_spaces.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/mcp/mcp.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/project/iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/project/project_cleanup.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/project/project_convert.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/project/project_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/project/project_upgrade.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/project/use_cases.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/remove/remove_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/remove/remove_project.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/remove/remove_space.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/scan/iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/scan/scan_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/scan/scan_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/scan/use_cases.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/commands/upgrade/upgrade_overview.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/concepts.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/cross_platform_support.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/framework_architecture.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/infrasctructure_composition.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/policy_as_code.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/roadmap_fdi.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/software_architecture.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/space_configuration.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/specs/phase1_intent_to_iac.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/ai_dlc.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/check_command.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/devsecops_quickstart.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/devsecops_sdlc.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/inventory_command.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/platform_engineering_templates.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/space_management.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/tasks/create_template.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/framework/use_cases/tasks/workflow_implementation_plan.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/iac_devsecops_use_case.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/automate_tasks_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/commnad_init.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/create_component.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/create_inventory.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/doc_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/document_project_code.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/framework/thothforge-framework.svg +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/framework/thothfr.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/iacpeerbot_summary.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/icon-light.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/icon.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/init_project.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/inventory_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/notification_img.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/report_dependencies.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/report_dependencies_summary.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/restore_inventory_version.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/reuse_project_pattern.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/scan_code.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/scan_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/stable/scan_report_example.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/sync_wk_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/transform_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/update_inventory_version.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/validate_command.png +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/validate_environment.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/img/validate_project.gif +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/includes/abbreviations.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/index.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/installation/devcontainer_setup.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/installation/linux_installation.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/installation/windows_installation.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/javascripts/tablesort.js +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/mcp.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/navigation.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/quick_start.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/requirements.txt +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/stylesheets/extra-enhanced.css +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/stylesheets/extra.css +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/telemetry.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/template_engine/cli_commands_audit.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/template_engine/for_developers.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/template_engine/for_platform_engineers.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/template_engine/github_templates.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/template_engine/template_engine.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/troubleshooting/linux_troubleshooting.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/troubleshooting/macos_troubleshooting.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/troubleshooting/troubleshooting.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/docs/troubleshooting/windows_troubleshooting.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/mkdocs.yaml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/pyproject.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/scripts/run_mcp_server.sh +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/application/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/autocomplete.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/analyze.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/apply_fix.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/configure.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/configure_decisions.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/decide.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/history.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/improve.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/orchestrate.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/override.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/report.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/ai_review/commands/serve.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/environment.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/iac.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/project/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/project/iac.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/project.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/check/commands/space.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/dashboard/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/dashboard/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/dashboard/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/dashboard/commands/launch.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/document/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/document/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/document/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/document/commands/iac.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/generate/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/generate/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/generate/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/generate/commands/component.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/generate/commands/stacks.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/commands/env.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/commands/project.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/commands/space.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/init/commands/template.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/inventory/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/inventory/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/inventory/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/inventory/commands/check.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/inventory/commands/iac.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/list/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/list/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/list/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/list/commands/projects.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/list/commands/spaces.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/list/commands/templates.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/commands/register.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/commands/server.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/commands/status.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/mcp/commands/stop.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/commands/bootstrap.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/commands/cleanup.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/commands/convert.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/project/commands/upgrade.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/remove/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/remove/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/remove/project.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/remove/space.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/scan/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/scan/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/scan/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/scan/commands/iac.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/space/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/space/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/space/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/space/commands/activate.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/space/commands/show.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/space/commands/update.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/upgrade/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/workflow/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/workflow/cli.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/commands/workflow/commands/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/.thothcf.setup.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/.thothcf_home.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/.thothcf_module.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/.thothcf_project.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/.thothcf_template_parameters.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/common.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/common/terragrunt/.thothcf_project.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/constants.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/default_values.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/defaults.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/settings.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/template_config.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/template_configs.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/templates.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/config/validation.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/cli_ui.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/commands.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/config.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/azure_devops/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/azure_devops/get_azure_devops.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/azure_devops/pull_request_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/github/get_github.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/github/pull_request_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/integrate_messages_services/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/integrate_messages_services/microsoft_teams.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/integrate_messages_services/sent_message_teams.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/pattern_names.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/pr_comments/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/integrations/pr_comments/pr_comment_publisher.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/logger.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/telemetry.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/core/version_tools.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/domain/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/domain/interfaces/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/domain/models/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/mcp/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/mcp/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/mcp/server.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/agentcore/agentcore.json +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/ai_agent.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/analyzers/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/analyzers/code_reviewer.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/analyzers/context_builder.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/analyzers/report_analyzer.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/analyzers/risk_assessor.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/bedrock_agent_api.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/config/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/config/ai_settings.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/config/decision_rules.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/decision_engine.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/main.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/memory.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/orchestrator.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/pr_decision_publisher.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/providers/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/providers/azure_provider.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/providers/bedrock_agent_provider.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/providers/bedrock_provider.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/providers/ollama_provider.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/providers/openai_provider.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/safety/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/safety/safety_guard.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/strands_agent.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/tracing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/utils/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/utils/cost_tracker.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/utils/fix_patterns.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/utils/fix_prompts.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/utils/formatters.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/ai_review/utils/prompts.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/environment/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/environment/check_environment.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/org_policy_loader.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/blast_radius_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cfn_blast_radius_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/check_origin_version.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/check_project_structure.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/cost_analyzer.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/models/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/models/cloudformation_mapper.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/models/cost_models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/aws_pricing_client.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/base_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/apigateway_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/bedrock_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/cloudwatch_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/dynamodb_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/ebs_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/ec2_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/ecs_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/eip_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/eks_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/elb_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/free_resources_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/kms_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/lambda_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/msk_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/rds_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/s3_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/secrets_manager_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/pricing/providers/vpc_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/cost/unified_cost_report.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/cfn_drift_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/drift_ai.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/drift_history.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/drift_policy.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/drift_report.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/drift_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/drift/models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/risk_assessment.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/project/validate_project_structure.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/rule_merger.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/check/stack_optimizer/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/dashboard/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/dashboard/dashboard_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/dashboard/data_loader.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/architecture_renderer.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/create_documentation.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/files_content.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/files_scan.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/iac_documentation.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/iac_grunt_graph.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/iac_grunt_info.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/document/topology_generator.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_stacks/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_stacks/config_generator.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_stacks/remote_config_generation.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_stacks/stack_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_stacks/templates/terragrunt.hcl.j2 +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/config.yaml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/create_code.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/create_component.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/create_component_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/create_stacks.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/create_template.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/files_content.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/github_template_loader.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/generate/create_template/project_templates.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/environment/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/environment/install_tools.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/project/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/project/project.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/space/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/space/example_space.toml +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/space/local_registry.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/init/space/space.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/changelog_parser.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/inventory_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/module_compatibility_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/report_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/schema_compatibility_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/terragrunt_parser.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/update_versions.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/inventory/version_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/mcp/README.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/mcp/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/mcp/simple_http_server.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/mcp/stdio_server.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/bootstrap/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/bootstrap/bootstrap_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/cleanup/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/cleanup/clean_project.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/cleanup/clean_space.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/conversion_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/get_project_data.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/post_init.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/project_converter.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/project_defaults.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/convert/set_project_parameters.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/create_terramate/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/create_terramate/create_terramate_stacks.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/create_terramate/detect_changes_stacks.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/create_terramate/manage_terramate_stacks.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/upgrade/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/project/upgrade/upgrade_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/compliance_review.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/import_reports.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/report_parser.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/sarif_output.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scan_history.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scan_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/checkov.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/kics.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/opa.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/scan_reports.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/scanners.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/terraform_compliance.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/tfsec.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/scan/scanners/trivy.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/phases/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/phases/base.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/phases/develop.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/services/workflow/phases/secure.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/templates/ai_reports/pr_comment.md +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/templates/reports/inventory_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/templates/reports/inventory_report.js +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/templates/unified_report_styles.css +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/banner.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/create_compliance_html_reports.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/create_html_reports.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/delete_directory.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/fix_report_styling.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/render_scan_report.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/report_html_utils.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/dashboard.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/index_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/individual_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/simple_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/unified_report_styles.css +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/unified_scan_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/unified_simple_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/common/templates/xunit_report.html +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/crypto.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/manage_backend_resources/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/manage_backend_resources/manage_backend_resources.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/modules_ops/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/modules_ops/terraform_module_details.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/modules_ops/terraform_modules_fetcher.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/platform_utils.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/process_hcl/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/process_hcl/analyze_terraform_plan.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/process_hcl/graph_manager.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/process_hcl/graph_terragrunt_dependencies.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/process_hcl/process_terraform_file.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/process_hcl/risk_analyzing_terraform_plan.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/sync_workspaces/__init__.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/sync_workspaces/sync_terraform_workspaces.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/sync_workspaces/sync_terragrunt_workspaces.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/template_loader.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/utils/thoth_colors.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/src/thothctl/wellcome_banner.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/conftest.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_agentcore_entrypoint.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_apply_fix.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_decision_engine.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_fix_patterns.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_memory.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_orchestrator.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_pr_decision.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ai_safety_guard.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_aws_pricing_client.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_azure_devops_pr_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_bedrock_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cdk_language_selection.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cfn_blast_radius.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cfn_drift_detection.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_context_steering.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cost_analyzer.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cost_models.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cost_policy_enforcement.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_cost_pr_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_dashboard_loading_fix.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_dashboard_service.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_drift.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_drift_detection.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_ec2_pricing.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_github_pr_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_iac_cost_integration.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_init_ai_tools.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_init_template_params.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_inventory_pr_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_kics_scanner.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_mermaid_edge_labels.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_new_cost_providers.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_opa_data_files.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_parallel_scan.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_platform_utils.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_pr_comment_publisher.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_provider_source_url_fix.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_provider_versions.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_scan_cfn_support.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_scan_pr_comments.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_space_command.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_space_management.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_stack_optimizer.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_template_url_fix.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_terragrunt_parser.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tests/test_topology_generator.py +0 -0
- {thothctl-0.24.0 → thothctl-0.24.2}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: thothctl
|
|
3
|
-
Version: 0.24.
|
|
3
|
+
Version: 0.24.2
|
|
4
4
|
Summary: A CLI for Developer Control Plane. Accelerate your cloud IaC deployments.
|
|
5
5
|
Project-URL: SourceCode, https://github.com/thothforge/thothctl
|
|
6
6
|
Project-URL: HomePage, https://github.com/thothforge/thothctl
|
|
@@ -5,16 +5,30 @@ import time
|
|
|
5
5
|
import click
|
|
6
6
|
import rich.box
|
|
7
7
|
from rich.console import Console
|
|
8
|
+
from rich.live import Live
|
|
8
9
|
from rich.panel import Panel
|
|
10
|
+
from rich.spinner import Spinner
|
|
9
11
|
from rich.table import Table
|
|
12
|
+
from rich.text import Text
|
|
10
13
|
|
|
11
14
|
from ....core.commands import ClickCommand
|
|
12
|
-
from ....services.workflow.models import Phase, StepStatus
|
|
13
|
-
from ....services.workflow.workflow_service import WorkflowService
|
|
15
|
+
from ....services.workflow.models import Phase, PhaseResult, StepStatus
|
|
16
|
+
from ....services.workflow.workflow_service import WorkflowService, COMPOSITE_PHASES, PHASE_ORDER
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
logger = logging.getLogger(__name__)
|
|
17
20
|
|
|
21
|
+
# Phase icons for display
|
|
22
|
+
PHASE_ICONS = {
|
|
23
|
+
Phase.PLAN: "📋",
|
|
24
|
+
Phase.DEVELOP: "💻",
|
|
25
|
+
Phase.BUILD: "🔨",
|
|
26
|
+
Phase.TEST: "✅",
|
|
27
|
+
Phase.SECURE: "🔒",
|
|
28
|
+
Phase.DEPLOY: "🚀",
|
|
29
|
+
Phase.MONITOR: "📊",
|
|
30
|
+
}
|
|
31
|
+
|
|
18
32
|
|
|
19
33
|
class DevSecOpsWorkflowCommand(ClickCommand):
|
|
20
34
|
"""Execute DevSecOps SDLC phases."""
|
|
@@ -24,7 +38,7 @@ class DevSecOpsWorkflowCommand(ClickCommand):
|
|
|
24
38
|
service = WorkflowService()
|
|
25
39
|
|
|
26
40
|
# Resolve phase
|
|
27
|
-
|
|
41
|
+
selected_phase = Phase(phase)
|
|
28
42
|
|
|
29
43
|
ctx = click.get_current_context()
|
|
30
44
|
directory = ctx.obj.get("CODE_DIRECTORY", ".")
|
|
@@ -46,18 +60,17 @@ class DevSecOpsWorkflowCommand(ClickCommand):
|
|
|
46
60
|
border_style="blue",
|
|
47
61
|
))
|
|
48
62
|
|
|
49
|
-
#
|
|
63
|
+
# Resolve which phases will run
|
|
64
|
+
phases_to_run = self._resolve_phases(selected_phase, service)
|
|
65
|
+
|
|
66
|
+
# Execute with live progress
|
|
50
67
|
start = time.perf_counter()
|
|
51
|
-
result =
|
|
52
|
-
|
|
53
|
-
directory=directory,
|
|
54
|
-
reports_dir=reports_dir,
|
|
55
|
-
options=options,
|
|
56
|
-
enforcement=enforcement,
|
|
68
|
+
result = self._execute_with_progress(
|
|
69
|
+
console, service, [selected_phase], directory, reports_dir, options, enforcement, phases_to_run
|
|
57
70
|
)
|
|
58
71
|
total_time = time.perf_counter() - start
|
|
59
72
|
|
|
60
|
-
# Display results
|
|
73
|
+
# Display final results
|
|
61
74
|
self._display_results(console, result, total_time)
|
|
62
75
|
|
|
63
76
|
if result.stopped_at:
|
|
@@ -70,6 +83,72 @@ class DevSecOpsWorkflowCommand(ClickCommand):
|
|
|
70
83
|
))
|
|
71
84
|
raise SystemExit(1)
|
|
72
85
|
|
|
86
|
+
def _resolve_phases(self, phase: Phase, service: WorkflowService) -> list:
|
|
87
|
+
"""Resolve composite phases into ordered list."""
|
|
88
|
+
if phase in COMPOSITE_PHASES:
|
|
89
|
+
resolved = COMPOSITE_PHASES[phase]
|
|
90
|
+
else:
|
|
91
|
+
resolved = [phase]
|
|
92
|
+
|
|
93
|
+
# Filter to only phases that have executors
|
|
94
|
+
return [p for p in resolved if p in service._executors]
|
|
95
|
+
|
|
96
|
+
def _execute_with_progress(
|
|
97
|
+
self, console, service, phases, directory, reports_dir, options, enforcement, phases_to_run
|
|
98
|
+
):
|
|
99
|
+
"""Execute workflow with live spinner showing current phase."""
|
|
100
|
+
from ....services.workflow.models import WorkflowResult
|
|
101
|
+
|
|
102
|
+
options = options or {}
|
|
103
|
+
options["enforcement"] = enforcement
|
|
104
|
+
result = WorkflowResult(enforcement=enforcement)
|
|
105
|
+
|
|
106
|
+
total_phases = len(phases_to_run)
|
|
107
|
+
|
|
108
|
+
for idx, phase in enumerate(phases_to_run, 1):
|
|
109
|
+
executor = service._executors.get(phase)
|
|
110
|
+
if not executor:
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
icon = PHASE_ICONS.get(phase, "⚙️")
|
|
114
|
+
phase_name = phase.value.capitalize()
|
|
115
|
+
|
|
116
|
+
# Show spinner while phase runs
|
|
117
|
+
with console.status(
|
|
118
|
+
f"[bold blue]{icon} Running phase {idx}/{total_phases}: {phase_name}[/bold blue] "
|
|
119
|
+
f"[dim]({executor.description})[/dim]",
|
|
120
|
+
spinner="dots",
|
|
121
|
+
spinner_style="cyan",
|
|
122
|
+
):
|
|
123
|
+
phase_result = executor.execute(directory, reports_dir, options)
|
|
124
|
+
|
|
125
|
+
# Show immediate result after phase completes
|
|
126
|
+
if phase_result.total_findings > 0:
|
|
127
|
+
console.print(
|
|
128
|
+
f" {icon} [bold]{phase_name}[/bold] — "
|
|
129
|
+
f"[red]{phase_result.total_findings} finding(s)[/red]"
|
|
130
|
+
)
|
|
131
|
+
elif any(s.status == StepStatus.SKIPPED for s in phase_result.steps):
|
|
132
|
+
console.print(
|
|
133
|
+
f" {icon} [bold]{phase_name}[/bold] — "
|
|
134
|
+
f"[dim]skipped (prerequisites missing)[/dim]"
|
|
135
|
+
)
|
|
136
|
+
else:
|
|
137
|
+
console.print(
|
|
138
|
+
f" {icon} [bold]{phase_name}[/bold] — "
|
|
139
|
+
f"[green]passed[/green]"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
result.phases.append(phase_result)
|
|
143
|
+
|
|
144
|
+
# Stop on hard enforcement failure
|
|
145
|
+
if enforcement == "hard" and phase_result.gate_blocked:
|
|
146
|
+
result.stopped_at = phase
|
|
147
|
+
break
|
|
148
|
+
|
|
149
|
+
console.print() # Blank line before results table
|
|
150
|
+
return result
|
|
151
|
+
|
|
73
152
|
def _display_results(self, console: Console, result, total_time: float):
|
|
74
153
|
"""Render workflow results."""
|
|
75
154
|
table = Table(
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Build phase: inventory creation, dependency tracking, version management."""
|
|
2
|
+
import logging
|
|
3
|
+
import subprocess
|
|
4
|
+
import time
|
|
5
|
+
from typing import Dict, Optional
|
|
6
|
+
|
|
7
|
+
from ..models import Phase, PhaseResult, StepResult, StepStatus
|
|
8
|
+
from .base import PhaseExecutor
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BuildPhaseExecutor(PhaseExecutor):
|
|
14
|
+
"""Phase 3: Infrastructure inventory, SBOM, version tracking."""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def phase(self) -> Phase:
|
|
18
|
+
return Phase.BUILD
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def description(self) -> str:
|
|
22
|
+
return "\U0001f528 Build — Inventory creation, dependency tracking, version management"
|
|
23
|
+
|
|
24
|
+
def execute(
|
|
25
|
+
self,
|
|
26
|
+
directory: str,
|
|
27
|
+
reports_dir: str,
|
|
28
|
+
options: Optional[Dict] = None,
|
|
29
|
+
) -> PhaseResult:
|
|
30
|
+
options = options or {}
|
|
31
|
+
result = PhaseResult(phase=self.phase)
|
|
32
|
+
|
|
33
|
+
# Step 1: Inventory with version checks
|
|
34
|
+
result.steps.append(self._run_inventory(directory, options))
|
|
35
|
+
|
|
36
|
+
# Phase passes if no steps failed
|
|
37
|
+
result.passed = not any(
|
|
38
|
+
s.status == StepStatus.FAILED for s in result.steps
|
|
39
|
+
)
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
def _run_inventory(self, directory: str, options: Dict) -> StepResult:
|
|
43
|
+
"""Run thothctl inventory iac --check-versions --check-provider-versions."""
|
|
44
|
+
start = time.perf_counter()
|
|
45
|
+
try:
|
|
46
|
+
cmd = [
|
|
47
|
+
"thothctl", "inventory", "iac",
|
|
48
|
+
"--check-versions",
|
|
49
|
+
"--check-provider-versions",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
proc = subprocess.run(
|
|
53
|
+
cmd,
|
|
54
|
+
capture_output=True,
|
|
55
|
+
text=True,
|
|
56
|
+
timeout=180,
|
|
57
|
+
cwd=directory,
|
|
58
|
+
)
|
|
59
|
+
duration = time.perf_counter() - start
|
|
60
|
+
status = StepStatus.PASSED if proc.returncode == 0 else StepStatus.WARNING
|
|
61
|
+
return StepResult(
|
|
62
|
+
name="inventory",
|
|
63
|
+
status=status,
|
|
64
|
+
command="thothctl inventory iac --check-versions --check-provider-versions",
|
|
65
|
+
duration_seconds=duration,
|
|
66
|
+
summary="Inventory created with version analysis" if status == StepStatus.PASSED else "Inventory completed with warnings",
|
|
67
|
+
)
|
|
68
|
+
except subprocess.TimeoutExpired:
|
|
69
|
+
return StepResult(
|
|
70
|
+
name="inventory",
|
|
71
|
+
status=StepStatus.SKIPPED,
|
|
72
|
+
command="thothctl inventory iac --check-versions",
|
|
73
|
+
duration_seconds=time.perf_counter() - start,
|
|
74
|
+
summary="Timed out after 180s",
|
|
75
|
+
)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
return StepResult(
|
|
78
|
+
name="inventory",
|
|
79
|
+
status=StepStatus.FAILED,
|
|
80
|
+
command="thothctl inventory iac --check-versions",
|
|
81
|
+
duration_seconds=time.perf_counter() - start,
|
|
82
|
+
summary=str(e),
|
|
83
|
+
findings_count=1,
|
|
84
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Deploy phase: pre-deployment validation and enforcement gates."""
|
|
2
|
+
import logging
|
|
3
|
+
import time
|
|
4
|
+
from typing import Dict, Optional
|
|
5
|
+
|
|
6
|
+
from ..models import Phase, PhaseResult, StepResult, StepStatus
|
|
7
|
+
from .base import PhaseExecutor
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DeployPhaseExecutor(PhaseExecutor):
|
|
13
|
+
"""Phase 6: Pre-deployment checks and approval gates."""
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def phase(self) -> Phase:
|
|
17
|
+
return Phase.DEPLOY
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def description(self) -> str:
|
|
21
|
+
return "\U0001f680 Deploy — Pre-deployment validation, enforcement gates"
|
|
22
|
+
|
|
23
|
+
def execute(
|
|
24
|
+
self,
|
|
25
|
+
directory: str,
|
|
26
|
+
reports_dir: str,
|
|
27
|
+
options: Optional[Dict] = None,
|
|
28
|
+
) -> PhaseResult:
|
|
29
|
+
options = options or {}
|
|
30
|
+
result = PhaseResult(phase=self.phase)
|
|
31
|
+
enforcement = options.get("enforcement", "soft")
|
|
32
|
+
|
|
33
|
+
# Step 1: Run security scan with hard enforcement
|
|
34
|
+
# This reuses the secure phase but forces hard enforcement
|
|
35
|
+
from .secure import SecurePhaseExecutor
|
|
36
|
+
|
|
37
|
+
secure_executor = SecurePhaseExecutor()
|
|
38
|
+
deploy_options = dict(options)
|
|
39
|
+
deploy_options["enforcement"] = "hard"
|
|
40
|
+
|
|
41
|
+
start = time.perf_counter()
|
|
42
|
+
secure_result = secure_executor.execute(directory, reports_dir, deploy_options)
|
|
43
|
+
duration = time.perf_counter() - start
|
|
44
|
+
|
|
45
|
+
# Translate secure results into deploy gate
|
|
46
|
+
total_failures = secure_result.total_findings
|
|
47
|
+
if total_failures == 0:
|
|
48
|
+
result.steps.append(StepResult(
|
|
49
|
+
name="deploy-gate",
|
|
50
|
+
status=StepStatus.PASSED,
|
|
51
|
+
command="thothctl scan iac --enforcement hard",
|
|
52
|
+
duration_seconds=duration,
|
|
53
|
+
summary="All security gates passed — safe to deploy",
|
|
54
|
+
))
|
|
55
|
+
else:
|
|
56
|
+
result.steps.append(StepResult(
|
|
57
|
+
name="deploy-gate",
|
|
58
|
+
status=StepStatus.FAILED,
|
|
59
|
+
command="thothctl scan iac --enforcement hard",
|
|
60
|
+
duration_seconds=duration,
|
|
61
|
+
summary=f"Deployment blocked: {total_failures} violation(s) must be resolved",
|
|
62
|
+
findings_count=total_failures,
|
|
63
|
+
))
|
|
64
|
+
result.passed = False
|
|
65
|
+
if enforcement == "hard":
|
|
66
|
+
result.gate_blocked = True
|
|
67
|
+
|
|
68
|
+
return result
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Monitor phase: drift detection, continuous monitoring."""
|
|
2
|
+
import logging
|
|
3
|
+
import subprocess
|
|
4
|
+
import time
|
|
5
|
+
from typing import Dict, Optional
|
|
6
|
+
|
|
7
|
+
from ..models import Phase, PhaseResult, StepResult, StepStatus
|
|
8
|
+
from .base import PhaseExecutor
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MonitorPhaseExecutor(PhaseExecutor):
|
|
14
|
+
"""Phase 7: Drift detection and continuous monitoring."""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def phase(self) -> Phase:
|
|
18
|
+
return Phase.MONITOR
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def description(self) -> str:
|
|
22
|
+
return "\U0001f4ca Monitor — Drift detection, continuous monitoring"
|
|
23
|
+
|
|
24
|
+
def execute(
|
|
25
|
+
self,
|
|
26
|
+
directory: str,
|
|
27
|
+
reports_dir: str,
|
|
28
|
+
options: Optional[Dict] = None,
|
|
29
|
+
) -> PhaseResult:
|
|
30
|
+
options = options or {}
|
|
31
|
+
result = PhaseResult(phase=self.phase)
|
|
32
|
+
|
|
33
|
+
# Step 1: Drift detection
|
|
34
|
+
result.steps.append(self._run_drift_detection(directory, options))
|
|
35
|
+
|
|
36
|
+
# Phase passes if no steps failed
|
|
37
|
+
result.passed = not any(
|
|
38
|
+
s.status == StepStatus.FAILED for s in result.steps
|
|
39
|
+
)
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
def _run_drift_detection(self, directory: str, options: Dict) -> StepResult:
|
|
43
|
+
"""Run thothctl check iac -type drift."""
|
|
44
|
+
start = time.perf_counter()
|
|
45
|
+
tftool = options.get("tftool", "tofu")
|
|
46
|
+
try:
|
|
47
|
+
cmd = [
|
|
48
|
+
"thothctl", "check", "iac",
|
|
49
|
+
"-type", "drift",
|
|
50
|
+
"--tftool", tftool,
|
|
51
|
+
"--recursive",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
proc = subprocess.run(
|
|
55
|
+
cmd,
|
|
56
|
+
capture_output=True,
|
|
57
|
+
text=True,
|
|
58
|
+
timeout=300,
|
|
59
|
+
cwd=directory,
|
|
60
|
+
)
|
|
61
|
+
duration = time.perf_counter() - start
|
|
62
|
+
status = StepStatus.PASSED if proc.returncode == 0 else StepStatus.WARNING
|
|
63
|
+
return StepResult(
|
|
64
|
+
name="drift-detection",
|
|
65
|
+
status=status,
|
|
66
|
+
command=f"thothctl check iac -type drift --tftool {tftool} --recursive",
|
|
67
|
+
duration_seconds=duration,
|
|
68
|
+
summary="No drift detected" if status == StepStatus.PASSED else "Drift detected — review changes",
|
|
69
|
+
)
|
|
70
|
+
except subprocess.TimeoutExpired:
|
|
71
|
+
return StepResult(
|
|
72
|
+
name="drift-detection",
|
|
73
|
+
status=StepStatus.SKIPPED,
|
|
74
|
+
command="thothctl check iac -type drift",
|
|
75
|
+
duration_seconds=time.perf_counter() - start,
|
|
76
|
+
summary="Timed out after 300s (requires cloud credentials)",
|
|
77
|
+
)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
return StepResult(
|
|
80
|
+
name="drift-detection",
|
|
81
|
+
status=StepStatus.SKIPPED,
|
|
82
|
+
command="thothctl check iac -type drift",
|
|
83
|
+
duration_seconds=time.perf_counter() - start,
|
|
84
|
+
summary=f"Skipped: {e}",
|
|
85
|
+
)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Plan phase: cost estimation, blast radius, risk assessment."""
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
from ..models import Phase, PhaseResult, StepResult, StepStatus
|
|
10
|
+
from .base import PhaseExecutor
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PlanPhaseExecutor(PhaseExecutor):
|
|
16
|
+
"""Phase 1: Cost estimation and risk assessment from tfplan."""
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def phase(self) -> Phase:
|
|
20
|
+
return Phase.PLAN
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def description(self) -> str:
|
|
24
|
+
return "\U0001f4cb Plan — Cost estimation, blast radius, risk assessment"
|
|
25
|
+
|
|
26
|
+
def execute(
|
|
27
|
+
self,
|
|
28
|
+
directory: str,
|
|
29
|
+
reports_dir: str,
|
|
30
|
+
options: Optional[Dict] = None,
|
|
31
|
+
) -> PhaseResult:
|
|
32
|
+
options = options or {}
|
|
33
|
+
result = PhaseResult(phase=self.phase)
|
|
34
|
+
|
|
35
|
+
# Find tfplan files
|
|
36
|
+
plan_files = self._find_plan_files(directory)
|
|
37
|
+
|
|
38
|
+
if not plan_files:
|
|
39
|
+
result.steps.append(StepResult(
|
|
40
|
+
name="plan-check",
|
|
41
|
+
status=StepStatus.SKIPPED,
|
|
42
|
+
command="(requires tfplan.json)",
|
|
43
|
+
summary=(
|
|
44
|
+
"No tfplan.json found. Generate plans first:\n"
|
|
45
|
+
" Terragrunt: terragrunt run-all plan --out-dir tfplan --json-out-dir tfplan\n"
|
|
46
|
+
" Terraform: terraform plan -out=tfplan.binary && "
|
|
47
|
+
"terraform show -json tfplan.binary > tfplan.json"
|
|
48
|
+
),
|
|
49
|
+
))
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
# Step 1: Cost analysis
|
|
53
|
+
result.steps.append(self._run_cost_analysis(directory))
|
|
54
|
+
|
|
55
|
+
# Step 2: Blast radius
|
|
56
|
+
result.steps.append(self._run_blast_radius(directory))
|
|
57
|
+
|
|
58
|
+
# Phase passes if no steps failed
|
|
59
|
+
result.passed = not any(
|
|
60
|
+
s.status == StepStatus.FAILED for s in result.steps
|
|
61
|
+
)
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
def _find_plan_files(self, directory: str) -> List[str]:
|
|
65
|
+
"""Find tfplan.json files in the project."""
|
|
66
|
+
plans = []
|
|
67
|
+
for root, _, files in os.walk(directory):
|
|
68
|
+
# Skip hidden dirs and Reports
|
|
69
|
+
if any(part.startswith(".") for part in Path(root).parts):
|
|
70
|
+
continue
|
|
71
|
+
if "Reports" in root:
|
|
72
|
+
continue
|
|
73
|
+
for f in files:
|
|
74
|
+
if f == "tfplan.json":
|
|
75
|
+
plans.append(os.path.join(root, f))
|
|
76
|
+
return plans
|
|
77
|
+
|
|
78
|
+
def _run_cost_analysis(self, directory: str) -> StepResult:
|
|
79
|
+
"""Run thothctl check iac -type cost-analysis."""
|
|
80
|
+
start = time.perf_counter()
|
|
81
|
+
try:
|
|
82
|
+
proc = subprocess.run(
|
|
83
|
+
["thothctl", "check", "iac", "-type", "cost-analysis", "--recursive"],
|
|
84
|
+
capture_output=True,
|
|
85
|
+
text=True,
|
|
86
|
+
timeout=120,
|
|
87
|
+
cwd=directory,
|
|
88
|
+
)
|
|
89
|
+
duration = time.perf_counter() - start
|
|
90
|
+
status = StepStatus.PASSED if proc.returncode == 0 else StepStatus.WARNING
|
|
91
|
+
return StepResult(
|
|
92
|
+
name="cost-analysis",
|
|
93
|
+
status=status,
|
|
94
|
+
command="thothctl check iac -type cost-analysis --recursive",
|
|
95
|
+
duration_seconds=duration,
|
|
96
|
+
summary="Cost estimation completed" if status == StepStatus.PASSED else "Cost analysis had warnings",
|
|
97
|
+
)
|
|
98
|
+
except subprocess.TimeoutExpired:
|
|
99
|
+
return StepResult(
|
|
100
|
+
name="cost-analysis",
|
|
101
|
+
status=StepStatus.SKIPPED,
|
|
102
|
+
command="thothctl check iac -type cost-analysis",
|
|
103
|
+
duration_seconds=time.perf_counter() - start,
|
|
104
|
+
summary="Timed out after 120s",
|
|
105
|
+
)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
return StepResult(
|
|
108
|
+
name="cost-analysis",
|
|
109
|
+
status=StepStatus.SKIPPED,
|
|
110
|
+
command="thothctl check iac -type cost-analysis",
|
|
111
|
+
duration_seconds=time.perf_counter() - start,
|
|
112
|
+
summary=f"Skipped: {e}",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def _run_blast_radius(self, directory: str) -> StepResult:
|
|
116
|
+
"""Run thothctl check iac -type blast-radius."""
|
|
117
|
+
start = time.perf_counter()
|
|
118
|
+
try:
|
|
119
|
+
proc = subprocess.run(
|
|
120
|
+
["thothctl", "check", "iac", "-type", "blast-radius", "--recursive"],
|
|
121
|
+
capture_output=True,
|
|
122
|
+
text=True,
|
|
123
|
+
timeout=120,
|
|
124
|
+
cwd=directory,
|
|
125
|
+
)
|
|
126
|
+
duration = time.perf_counter() - start
|
|
127
|
+
status = StepStatus.PASSED if proc.returncode == 0 else StepStatus.WARNING
|
|
128
|
+
return StepResult(
|
|
129
|
+
name="blast-radius",
|
|
130
|
+
status=status,
|
|
131
|
+
command="thothctl check iac -type blast-radius --recursive",
|
|
132
|
+
duration_seconds=duration,
|
|
133
|
+
summary="Blast radius assessed" if status == StepStatus.PASSED else "Blast radius warnings",
|
|
134
|
+
)
|
|
135
|
+
except subprocess.TimeoutExpired:
|
|
136
|
+
return StepResult(
|
|
137
|
+
name="blast-radius",
|
|
138
|
+
status=StepStatus.SKIPPED,
|
|
139
|
+
command="thothctl check iac -type blast-radius",
|
|
140
|
+
duration_seconds=time.perf_counter() - start,
|
|
141
|
+
summary="Timed out after 120s",
|
|
142
|
+
)
|
|
143
|
+
except Exception as e:
|
|
144
|
+
return StepResult(
|
|
145
|
+
name="blast-radius",
|
|
146
|
+
status=StepStatus.SKIPPED,
|
|
147
|
+
command="thothctl check iac -type blast-radius",
|
|
148
|
+
duration_seconds=time.perf_counter() - start,
|
|
149
|
+
summary=f"Skipped: {e}",
|
|
150
|
+
)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Test phase: plan validation, change impact analysis."""
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
from ..models import Phase, PhaseResult, StepResult, StepStatus
|
|
10
|
+
from .base import PhaseExecutor
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestPhaseExecutor(PhaseExecutor):
|
|
16
|
+
"""Phase 4: Terraform plan validation and impact analysis."""
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def phase(self) -> Phase:
|
|
20
|
+
return Phase.TEST
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def description(self) -> str:
|
|
24
|
+
return "\u2705 Test — Plan validation, change impact analysis"
|
|
25
|
+
|
|
26
|
+
def execute(
|
|
27
|
+
self,
|
|
28
|
+
directory: str,
|
|
29
|
+
reports_dir: str,
|
|
30
|
+
options: Optional[Dict] = None,
|
|
31
|
+
) -> PhaseResult:
|
|
32
|
+
options = options or {}
|
|
33
|
+
result = PhaseResult(phase=self.phase)
|
|
34
|
+
|
|
35
|
+
# Check if tfplan exists
|
|
36
|
+
plan_files = self._find_plan_files(directory)
|
|
37
|
+
|
|
38
|
+
if not plan_files:
|
|
39
|
+
result.steps.append(StepResult(
|
|
40
|
+
name="tfplan-check",
|
|
41
|
+
status=StepStatus.SKIPPED,
|
|
42
|
+
command="(requires tfplan.json)",
|
|
43
|
+
summary=(
|
|
44
|
+
"No tfplan.json found. Generate plans first:\n"
|
|
45
|
+
" Terragrunt: terragrunt run-all plan --out-dir tfplan --json-out-dir tfplan\n"
|
|
46
|
+
" Terraform: terraform plan -out=tfplan.binary && "
|
|
47
|
+
"terraform show -json tfplan.binary > tfplan.json"
|
|
48
|
+
),
|
|
49
|
+
))
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
# Step 1: Validate tfplan
|
|
53
|
+
result.steps.append(self._validate_tfplan(directory))
|
|
54
|
+
|
|
55
|
+
# Phase passes if no steps failed
|
|
56
|
+
result.passed = not any(
|
|
57
|
+
s.status == StepStatus.FAILED for s in result.steps
|
|
58
|
+
)
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
def _find_plan_files(self, directory: str) -> List[str]:
|
|
62
|
+
"""Find tfplan.json files in the project."""
|
|
63
|
+
plans = []
|
|
64
|
+
for root, _, files in os.walk(directory):
|
|
65
|
+
if any(part.startswith(".") for part in Path(root).parts):
|
|
66
|
+
continue
|
|
67
|
+
if "Reports" in root:
|
|
68
|
+
continue
|
|
69
|
+
for f in files:
|
|
70
|
+
if f == "tfplan.json":
|
|
71
|
+
plans.append(os.path.join(root, f))
|
|
72
|
+
return plans
|
|
73
|
+
|
|
74
|
+
def _validate_tfplan(self, directory: str) -> StepResult:
|
|
75
|
+
"""Run thothctl check iac -type tfplan."""
|
|
76
|
+
start = time.perf_counter()
|
|
77
|
+
try:
|
|
78
|
+
proc = subprocess.run(
|
|
79
|
+
["thothctl", "check", "iac", "-type", "tfplan", "--recursive"],
|
|
80
|
+
capture_output=True,
|
|
81
|
+
text=True,
|
|
82
|
+
timeout=120,
|
|
83
|
+
cwd=directory,
|
|
84
|
+
)
|
|
85
|
+
duration = time.perf_counter() - start
|
|
86
|
+
status = StepStatus.PASSED if proc.returncode == 0 else StepStatus.WARNING
|
|
87
|
+
return StepResult(
|
|
88
|
+
name="tfplan-validation",
|
|
89
|
+
status=status,
|
|
90
|
+
command="thothctl check iac -type tfplan --recursive",
|
|
91
|
+
duration_seconds=duration,
|
|
92
|
+
summary="Plan validation passed" if status == StepStatus.PASSED else "Plan has changes to review",
|
|
93
|
+
)
|
|
94
|
+
except subprocess.TimeoutExpired:
|
|
95
|
+
return StepResult(
|
|
96
|
+
name="tfplan-validation",
|
|
97
|
+
status=StepStatus.SKIPPED,
|
|
98
|
+
command="thothctl check iac -type tfplan",
|
|
99
|
+
duration_seconds=time.perf_counter() - start,
|
|
100
|
+
summary="Timed out after 120s",
|
|
101
|
+
)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
return StepResult(
|
|
104
|
+
name="tfplan-validation",
|
|
105
|
+
status=StepStatus.FAILED,
|
|
106
|
+
command="thothctl check iac -type tfplan",
|
|
107
|
+
duration_seconds=time.perf_counter() - start,
|
|
108
|
+
summary=str(e),
|
|
109
|
+
findings_count=1,
|
|
110
|
+
)
|
|
@@ -4,15 +4,20 @@ from typing import Dict, List, Optional
|
|
|
4
4
|
|
|
5
5
|
from .models import Phase, WorkflowResult
|
|
6
6
|
from .phases.base import PhaseExecutor
|
|
7
|
+
from .phases.plan import PlanPhaseExecutor
|
|
7
8
|
from .phases.develop import DevelopPhaseExecutor
|
|
9
|
+
from .phases.build import BuildPhaseExecutor
|
|
10
|
+
from .phases.test import TestPhaseExecutor
|
|
8
11
|
from .phases.secure import SecurePhaseExecutor
|
|
12
|
+
from .phases.deploy import DeployPhaseExecutor
|
|
13
|
+
from .phases.monitor import MonitorPhaseExecutor
|
|
9
14
|
|
|
10
15
|
logger = logging.getLogger(__name__)
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
# Phase execution order
|
|
14
19
|
PHASE_ORDER = [
|
|
15
|
-
Phase.DEVELOP, Phase.BUILD, Phase.TEST,
|
|
20
|
+
Phase.PLAN, Phase.DEVELOP, Phase.BUILD, Phase.TEST,
|
|
16
21
|
Phase.SECURE, Phase.DEPLOY, Phase.MONITOR,
|
|
17
22
|
]
|
|
18
23
|
|
|
@@ -28,8 +33,13 @@ class WorkflowService:
|
|
|
28
33
|
|
|
29
34
|
def __init__(self):
|
|
30
35
|
self._executors: Dict[Phase, PhaseExecutor] = {
|
|
36
|
+
Phase.PLAN: PlanPhaseExecutor(),
|
|
31
37
|
Phase.DEVELOP: DevelopPhaseExecutor(),
|
|
38
|
+
Phase.BUILD: BuildPhaseExecutor(),
|
|
39
|
+
Phase.TEST: TestPhaseExecutor(),
|
|
32
40
|
Phase.SECURE: SecurePhaseExecutor(),
|
|
41
|
+
Phase.DEPLOY: DeployPhaseExecutor(),
|
|
42
|
+
Phase.MONITOR: MonitorPhaseExecutor(),
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
def execute(
|