diagram-to-iac 1.9.0__tar.gz → 1.12.0__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.
Files changed (90) hide show
  1. diagram_to_iac-1.12.0/MANIFEST.in +0 -0
  2. {diagram_to_iac-1.9.0/src/diagram_to_iac.egg-info → diagram_to_iac-1.12.0}/PKG-INFO +1 -1
  3. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/pyproject.toml +2 -6
  4. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/enhanced_memory.py +3 -3
  5. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/issue_tracker.py +2 -13
  6. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/memory.py +6 -9
  7. diagram_to_iac-1.12.0/src/diagram_to_iac/core/test_config.py +0 -0
  8. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/services/observability.py +1 -12
  9. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/api_utils.py +2 -12
  10. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/git/git.py +19 -78
  11. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/sec_utils.py +38 -95
  12. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0/src/diagram_to_iac.egg-info}/PKG-INFO +1 -1
  13. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac.egg-info/SOURCES.txt +0 -11
  14. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/tests/test_devops_in_a_box.py +48 -95
  15. diagram_to_iac-1.9.0/MANIFEST.in +0 -7
  16. diagram_to_iac-1.9.0/src/diagram_to_iac/agents/demonstrator_langgraph/config.yaml +0 -56
  17. diagram_to_iac-1.9.0/src/diagram_to_iac/agents/git_langgraph/config.yaml +0 -91
  18. diagram_to_iac-1.9.0/src/diagram_to_iac/agents/hello_langgraph/config.yaml +0 -6
  19. diagram_to_iac-1.9.0/src/diagram_to_iac/agents/policy_agent/config.yaml +0 -43
  20. diagram_to_iac-1.9.0/src/diagram_to_iac/agents/supervisor_langgraph/config.yaml +0 -55
  21. diagram_to_iac-1.9.0/src/diagram_to_iac/agents/terraform_langgraph/config.yaml +0 -25
  22. diagram_to_iac-1.9.0/src/diagram_to_iac/config.yaml +0 -260
  23. diagram_to_iac-1.9.0/src/diagram_to_iac/core/test_config.py +0 -123
  24. diagram_to_iac-1.9.0/src/diagram_to_iac/templates/issue_frontmatter.yml +0 -240
  25. diagram_to_iac-1.9.0/src/diagram_to_iac/tools/git/git_config.yaml +0 -102
  26. diagram_to_iac-1.9.0/src/diagram_to_iac/tools/shell/shell_config.yaml +0 -41
  27. diagram_to_iac-1.9.0/src/diagram_to_iac/tools/tf/terraform_config.yaml +0 -21
  28. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/README.md +0 -0
  29. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/setup.cfg +0 -0
  30. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/__init__.py +0 -0
  31. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/actions/__init__.py +0 -0
  32. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/actions/git_entry.py +0 -0
  33. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/actions/supervisor_entry.py +0 -0
  34. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/actions/terraform_agent_entry.py +0 -0
  35. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/__init__.py +0 -0
  36. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/demonstrator_langgraph/__init__.py +0 -0
  37. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/demonstrator_langgraph/agent.py +0 -0
  38. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/git_langgraph/__init__.py +0 -0
  39. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/git_langgraph/agent.py +0 -0
  40. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/git_langgraph/pr.py +0 -0
  41. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/hello_langgraph/__init__.py +0 -0
  42. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/hello_langgraph/agent.py +0 -0
  43. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/policy_agent/__init__.py +0 -0
  44. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/policy_agent/agent.py +0 -0
  45. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/policy_agent/integration_example.py +0 -0
  46. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/policy_agent/tools/__init__.py +0 -0
  47. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/policy_agent/tools/tfsec_tool.py +0 -0
  48. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/shell_langgraph/__init__.py +0 -0
  49. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/shell_langgraph/agent.py +0 -0
  50. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/shell_langgraph/detector.py +0 -0
  51. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/__init__.py +0 -0
  52. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/agent.py +0 -0
  53. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/demonstrator.py +0 -0
  54. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/github_listener.py +0 -0
  55. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/guards.py +0 -0
  56. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/pat_loop.py +0 -0
  57. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/supervisor_langgraph/router.py +0 -0
  58. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/terraform_langgraph/__init__.py +0 -0
  59. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/terraform_langgraph/agent.py +0 -0
  60. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/agents/terraform_langgraph/parser.py +0 -0
  61. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/cli.py +0 -0
  62. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/__init__.py +0 -0
  63. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/agent_base.py +0 -0
  64. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/config_loader.py +0 -0
  65. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/errors.py +0 -0
  66. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/core/registry.py +0 -0
  67. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/r2d.py +0 -0
  68. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/services/__init__.py +0 -0
  69. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/services/commenter.py +0 -0
  70. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/services/step_summary.py +0 -0
  71. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/__init__.py +0 -0
  72. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/git/__init__.py +0 -0
  73. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/hello/__init__.py +0 -0
  74. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/hello/cal_utils.py +0 -0
  75. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/hello/text_utils.py +0 -0
  76. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/__init__.py +0 -0
  77. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/anthropic_driver.py +0 -0
  78. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/base_driver.py +0 -0
  79. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/gemini_driver.py +0 -0
  80. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/grok_driver.py +0 -0
  81. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/openai_driver.py +0 -0
  82. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/llm_utils/router.py +0 -0
  83. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/shell/__init__.py +0 -0
  84. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/shell/shell.py +0 -0
  85. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/text_utils.py +0 -0
  86. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac/tools/tf/terraform.py +0 -0
  87. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac.egg-info/dependency_links.txt +0 -0
  88. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac.egg-info/entry_points.txt +0 -0
  89. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac.egg-info/requires.txt +0 -0
  90. {diagram_to_iac-1.9.0 → diagram_to_iac-1.12.0}/src/diagram_to_iac.egg-info/top_level.txt +0 -0
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diagram-to-iac
3
- Version: 1.9.0
3
+ Version: 1.12.0
4
4
  Summary: Convert architecture diagrams into IaC modules
5
5
  Author-email: vindpro <admin@vindpro.com>
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "diagram-to-iac"
7
- version = "1.9.0"
7
+ version = "1.12.0"
8
8
  description = "Convert architecture diagrams into IaC modules"
9
9
  readme = "README.md"
10
10
  authors = [{ name="vindpro", email="admin@vindpro.com" }]
@@ -22,12 +22,8 @@ git-agent = "diagram_to_iac.actions.git_entry:main"
22
22
  terraform-agent = "diagram_to_iac.actions.terraform_agent_entry:main"
23
23
  supervisor-agent = "diagram_to_iac.actions.supervisor_entry:main"
24
24
 
25
- [tool.setuptools]
26
- include-package-data = true
25
+ [tool.setuptools] # (intentionally left empty)
27
26
 
28
27
  [tool.setuptools.packages.find] # find‑options live here
29
28
  where = ["src"]
30
29
  exclude = ["tests*", "scripts*"]
31
-
32
- [tool.setuptools.package-data]
33
- "diagram_to_iac" = ["config.yaml", "*.yaml"]
@@ -101,12 +101,12 @@ class PersistentFileMemory(MemoryInterface):
101
101
 
102
102
  def __init__(self, file_path: Optional[str] = None):
103
103
  if file_path is None:
104
- # Get workspace base from config with fallback
105
- workspace_base = get_config_value("system.workspace_base", "/workspace")
104
+ # Get workspace base from environment variable first, then config with fallback
105
+ workspace_base = os.environ.get("WORKSPACE_BASE") or get_config_value("system.workspace_base", "/workspace")
106
106
 
107
107
  # Default to workspace or /tmp directory for container safety
108
108
  try:
109
- # Try workspace first (from config)
109
+ # Try workspace first (from environment or config)
110
110
  base_dir = Path(workspace_base) if Path(workspace_base).exists() else Path.cwd()
111
111
  data_dir = base_dir / "data" / "db"
112
112
  data_dir.mkdir(parents=True, exist_ok=True)
@@ -1,5 +1,4 @@
1
1
  import json
2
- import os
3
2
  from pathlib import Path
4
3
  from typing import Dict, Optional
5
4
 
@@ -8,18 +7,8 @@ class IssueTracker:
8
7
 
9
8
  def __init__(self, file_path: Optional[str] = None):
10
9
  if file_path is None:
11
- # Check environment variable first
12
- if os.environ.get('ISSUE_TRACKER_FILE'):
13
- file_path = os.environ['ISSUE_TRACKER_FILE']
14
- else:
15
- # Check for workspace-based path first (for containers)
16
- workspace_base = os.environ.get('WORKSPACE_BASE', '/workspace')
17
- if os.path.exists(workspace_base):
18
- base_dir = Path(workspace_base)
19
- else:
20
- # Fallback to package-relative path
21
- base_dir = Path(__file__).resolve().parents[3]
22
- file_path = base_dir / "data" / "db" / "issue_tracker.json"
10
+ base_dir = Path(__file__).resolve().parents[3]
11
+ file_path = base_dir / "data" / "db" / "issue_tracker.json"
23
12
  self.file_path = Path(file_path)
24
13
  self._table: Dict[str, Dict[str, int]] = {}
25
14
  self._load()
@@ -87,15 +87,12 @@ class EnhancedMemory(Memory):
87
87
 
88
88
  # Default path for the persistent agent state JSON file. Allows override via
89
89
  # `AGENT_STATE_FILE` environment variable for testing.
90
- def _get_default_agent_state_path():
91
- """Get the default agent state path, checking workspace first."""
92
- workspace_base = os.environ.get('WORKSPACE_BASE', '/workspace')
93
- if os.path.exists(workspace_base):
94
- return Path(workspace_base) / "data" / "state" / "agent_state.json"
95
- else:
96
- return Path(__file__).resolve().parents[3] / "state" / ".agent_state" / "agent_state.json"
97
-
98
- _DEFAULT_AGENT_STATE_PATH = _get_default_agent_state_path()
90
+ _DEFAULT_AGENT_STATE_PATH = (
91
+ Path(__file__).resolve().parents[3]
92
+ / "state"
93
+ / ".agent_state"
94
+ / "agent_state.json"
95
+ )
99
96
  AGENT_STATE_PATH = Path(os.environ.get("AGENT_STATE_FILE", _DEFAULT_AGENT_STATE_PATH))
100
97
 
101
98
 
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
- import os
5
4
  from datetime import datetime, timezone
6
5
  from pathlib import Path
7
6
  import threading
@@ -12,17 +11,7 @@ class LogBus:
12
11
  """Simple JSONL logging service."""
13
12
 
14
13
  def __init__(self, log_dir: str | Path | None = None) -> None:
15
- if log_dir:
16
- self.log_dir = Path(log_dir)
17
- else:
18
- # Check for workspace-based path first (for containers)
19
- workspace_base = os.environ.get('WORKSPACE_BASE', '/workspace')
20
- if os.path.exists(workspace_base):
21
- self.log_dir = Path(workspace_base) / "logs"
22
- else:
23
- # Fallback to package-relative path
24
- self.log_dir = Path(__file__).resolve().parents[3] / "logs"
25
-
14
+ self.log_dir = Path(log_dir) if log_dir else Path(__file__).resolve().parents[3] / "logs"
26
15
  self.log_dir.mkdir(parents=True, exist_ok=True)
27
16
  timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
28
17
  self.log_path = self.log_dir / f"run-{timestamp}.jsonl"
@@ -3,14 +3,8 @@ import os
3
3
  from openai import OpenAI
4
4
  from anthropic import Anthropic
5
5
  import requests
6
- try:
7
- import google.generativeai as genai
8
- except ImportError:
9
- genai = None
10
- try:
11
- import googleapiclient.discovery
12
- except ImportError:
13
- googleapiclient = None
6
+ import google.generativeai as genai
7
+ import googleapiclient.discovery
14
8
  from concurrent.futures import ThreadPoolExecutor, TimeoutError
15
9
 
16
10
  # Import centralized configuration
@@ -51,10 +45,6 @@ def test_openai_api():
51
45
 
52
46
  def test_gemini_api():
53
47
  try:
54
- if genai is None:
55
- print("❌ Gemini API error: google-generativeai package not installed.")
56
- return False
57
-
58
48
  google_api_key = os.environ.get("GOOGLE_API_KEY")
59
49
  if not google_api_key:
60
50
  print("❌ Gemini API error: GOOGLE_API_KEY environment variable not set.")
@@ -767,86 +767,27 @@ class GitExecutor:
767
767
  labels_str = ",".join(gh_input.labels)
768
768
  gh_command += f" --label \"{labels_str}\""
769
769
 
770
- # Load GitHub assignee configuration from config
771
- github_config = self.config.get('github', {})
772
- issue_assignment_config = github_config.get('issue_assignment', {})
773
- copilot_assignee = github_config.get('copilot_assignee', 'Copilot')
774
- prefer_copilot = issue_assignment_config.get('prefer_copilot', True)
775
- auto_assign_when_empty = issue_assignment_config.get('auto_assign_when_empty', True)
776
- smart_prioritization = issue_assignment_config.get('smart_prioritization', True)
777
- fallback_strategy = github_config.get('fallback_assignee_strategy', 'owner')
778
-
779
- # Smart assignee prioritization logic
770
+ # Handle assignees - auto-assign to repository owner or github-copilot if none provided
780
771
  assignees_to_use = gh_input.assignees or []
781
-
782
- if assignees_to_use:
783
- # If assignees are provided, apply smart prioritization (if enabled)
784
- if smart_prioritization:
785
- if copilot_assignee in assignees_to_use:
786
- # Multiple assignees with Copilot -> assign to Copilot only
787
- assignees_to_use = [copilot_assignee]
788
- self.logger.info(f"Multiple assignees detected with @{copilot_assignee} - assigning to @{copilot_assignee} only")
789
- elif len(assignees_to_use) == 1 and assignees_to_use[0] == owner:
790
- # Only owner as assignee -> keep as owner
791
- self.logger.info(f"Single assignee is repository owner - assigning to @{owner}")
792
- elif len(assignees_to_use) > 1 and copilot_assignee not in assignees_to_use:
793
- # Multiple assignees without Copilot -> assign to owner only
794
- assignees_to_use = [owner]
795
- self.logger.info(f"Multiple assignees without @{copilot_assignee} - assigning to repository owner @{owner} only")
796
- # Single non-owner assignee -> keep as provided
797
- else:
798
- self.logger.info("Smart prioritization disabled - using assignees as provided")
799
- else:
800
- # No assignees provided - auto-assign based on configuration
801
- if auto_assign_when_empty and prefer_copilot:
802
- try:
803
- # Check if configured Copilot user exists
804
- check_copilot_cmd = f"gh api /users/{copilot_assignee}"
805
- check_shell_input = ShellExecInput(command=check_copilot_cmd, timeout=10)
806
- check_result = self.shell_executor.shell_exec(check_shell_input)
807
-
808
- if check_result.exit_code == 0:
809
- assignees_to_use = [copilot_assignee]
810
- self.logger.info(f"No assignees provided - auto-assigning to @{copilot_assignee}")
811
- else:
812
- # Fallback based on strategy
813
- if fallback_strategy == "owner":
814
- assignees_to_use = [owner]
815
- self.logger.info(f"No assignees provided, @{copilot_assignee} not available - auto-assigning to repository owner @{owner}")
816
- elif fallback_strategy == "default_assignees":
817
- default_assignees = github_config.get('default_assignees', [])
818
- assignees_to_use = default_assignees if default_assignees else [owner]
819
- self.logger.info(f"No assignees provided, @{copilot_assignee} not available - using default assignees: {assignees_to_use}")
820
- else: # fallback_strategy == "none"
821
- assignees_to_use = []
822
- self.logger.info(f"No assignees provided, @{copilot_assignee} not available - no assignee set")
823
- except Exception as e:
824
- # Fallback to configured strategy if check fails
825
- if fallback_strategy == "owner":
826
- assignees_to_use = [owner]
827
- self.logger.info(f"Failed to check @{copilot_assignee}, assigning to repository owner @{owner}. Error: {e}")
828
- elif fallback_strategy == "default_assignees":
829
- default_assignees = github_config.get('default_assignees', [])
830
- assignees_to_use = default_assignees if default_assignees else [owner]
831
- self.logger.info(f"Failed to check @{copilot_assignee}, using default assignees: {assignees_to_use}. Error: {e}")
832
- else: # fallback_strategy == "none"
833
- assignees_to_use = []
834
- self.logger.info(f"Failed to check @{copilot_assignee}, no assignee set. Error: {e}")
835
- elif auto_assign_when_empty:
836
- # Auto-assign but don't prefer Copilot
837
- if fallback_strategy == "owner":
772
+ if not assignees_to_use:
773
+ # Try to assign to @github-copilot first, fallback to repository owner
774
+ try:
775
+ # Check if github-copilot exists as a user
776
+ check_copilot_cmd = "gh api /users/github-copilot"
777
+ check_shell_input = ShellExecInput(command=check_copilot_cmd, timeout=10)
778
+ check_result = self.shell_executor.shell_exec(check_shell_input)
779
+
780
+ if check_result.exit_code == 0:
781
+ assignees_to_use = ["github-copilot"]
782
+ self.logger.info("Auto-assigning issue to @github-copilot")
783
+ else:
784
+ # Fallback to repository owner
838
785
  assignees_to_use = [owner]
839
- self.logger.info(f"No assignees provided - auto-assigning to repository owner @{owner}")
840
- elif fallback_strategy == "default_assignees":
841
- default_assignees = github_config.get('default_assignees', [])
842
- assignees_to_use = default_assignees if default_assignees else [owner]
843
- self.logger.info(f"No assignees provided - using default assignees: {assignees_to_use}")
844
- else: # fallback_strategy == "none"
845
- assignees_to_use = []
846
- self.logger.info("No assignees provided - no auto-assignment configured")
847
- else:
848
- assignees_to_use = []
849
- self.logger.info("No assignees provided - auto-assignment disabled")
786
+ self.logger.info(f"Auto-assigning issue to repository owner: @{owner}")
787
+ except Exception as e:
788
+ # Fallback to repository owner if check fails
789
+ assignees_to_use = [owner]
790
+ self.logger.info(f"Failed to check @github-copilot, assigning to repository owner: @{owner}. Error: {e}")
850
791
 
851
792
  if assignees_to_use:
852
793
  assignees_str = ",".join(assignees_to_use)
@@ -37,77 +37,44 @@ except ImportError:
37
37
  # Path inside container where the encoded YAML is mounted (dev only)
38
38
  _YAML_PATH = pathlib.Path("/run/secrets.yaml")
39
39
 
40
- def _load_config_secrets():
41
- """Load secret configuration from config.yaml."""
42
- try:
43
- # Try to load from config.yaml
44
- config_path = pathlib.Path(__file__).parent.parent / "config.yaml"
45
- if config_path.exists() and yaml:
46
- config_data = yaml.safe_load(config_path.read_text())
47
- security_config = config_data.get("security", {})
48
-
49
- required_secrets = security_config.get("required_secrets", ["REPO_API_KEY"])
50
- optional_secrets = security_config.get("optional_secrets", [])
51
- secret_mappings = security_config.get("secret_mappings", {})
52
-
53
- # Combine required and optional secrets
54
- expected_secrets = required_secrets + optional_secrets
55
-
56
- # Create full mapping (defaults to same name if not mapped)
57
- full_mapping = {}
58
- for secret in expected_secrets:
59
- full_mapping[secret] = secret_mappings.get(secret, secret)
60
-
61
- # AI API secrets (hardcoded as they're specific to AI functionality)
62
- ai_secrets = [
63
- "OPENAI_API_KEY",
64
- "GOOGLE_API_KEY",
65
- "ANTHROPIC_API_KEY",
66
- "GROK_API_KEY"
67
- ]
68
-
69
- return expected_secrets, required_secrets, ai_secrets, full_mapping
70
- except Exception as e:
71
- print(f"⚠️ Warning: Could not load secret config from config.yaml: {e}")
72
-
73
- # Fallback to hardcoded values
74
- expected_secrets = [
75
- "DOCKERHUB_API_KEY",
76
- "DOCKERHUB_USERNAME",
77
- "TF_API_KEY",
78
- "PYPI_API_KEY",
79
- "OPENAI_API_KEY",
80
- "GOOGLE_API_KEY",
81
- "ANTHROPIC_API_KEY",
82
- "GROK_API_KEY",
83
- "REPO_API_KEY"
84
- ]
85
-
86
- required_secrets = ["REPO_API_KEY"]
87
-
88
- ai_secrets = [
89
- "OPENAI_API_KEY",
90
- "GOOGLE_API_KEY",
91
- "ANTHROPIC_API_KEY",
92
- "GROK_API_KEY"
93
- ]
94
-
95
- secret_mapping = {
96
- "REPO_API_KEY": "GITHUB_TOKEN",
97
- "TF_API_KEY": "TFE_TOKEN",
98
- "DOCKERHUB_API_KEY": "DOCKERHUB_API_KEY",
99
- "DOCKERHUB_USERNAME": "DOCKERHUB_USERNAME",
100
- "PYPI_API_KEY": "PYPI_API_KEY",
101
- "OPENAI_API_KEY": "OPENAI_API_KEY",
102
- "GOOGLE_API_KEY": "GOOGLE_API_KEY",
103
- "ANTHROPIC_API_KEY": "ANTHROPIC_API_KEY",
104
- "GROK_API_KEY": "GROK_API_KEY"
105
- }
106
-
107
- return expected_secrets, required_secrets, ai_secrets, secret_mapping
40
+ # Expected secrets based on secrets_example.yaml
41
+ EXPECTED_SECRETS = [
42
+ "DOCKERHUB_API_KEY",
43
+ "DOCKERHUB_USERNAME",
44
+ "TF_API_KEY",
45
+ "PYPI_API_KEY",
46
+ "OPENAI_API_KEY",
47
+ "GOOGLE_API_KEY",
48
+ "ANTHROPIC_API_KEY",
49
+ "GROK_API_KEY",
50
+ "REPO_API_KEY"
51
+ ]
52
+
53
+ # Required secrets that must be present (others are optional)
54
+ REQUIRED_SECRETS = [
55
+ "REPO_API_KEY" # GITHUB_TOKEN is required for repo operations
56
+ ]
57
+
58
+ # Optional AI API secrets (at least one should be present for AI functionality)
59
+ AI_API_SECRETS = [
60
+ "OPENAI_API_KEY",
61
+ "GOOGLE_API_KEY",
62
+ "ANTHROPIC_API_KEY",
63
+ "GROK_API_KEY"
64
+ ]
108
65
 
109
- # Load configuration at module level
110
- EXPECTED_SECRETS, REQUIRED_SECRETS, AI_API_SECRETS, SECRET_ENV_MAPPING = _load_config_secrets()
66
+ # Map internal secret names to environment variable names
67
+ SECRET_ENV_MAPPING = {
68
+ "REPO_API_KEY": "GITHUB_TOKEN",
69
+ "TF_API_KEY": "TFE_TOKEN",
70
+ "DOCKERHUB_API_KEY": "DOCKERHUB_API_KEY",
71
+ "DOCKERHUB_USERNAME": "DOCKERHUB_USERNAME",
72
+ "PYPI_API_KEY": "PYPI_API_KEY",
73
+ "OPENAI_API_KEY": "OPENAI_API_KEY",
74
+ "GOOGLE_API_KEY": "GOOGLE_API_KEY",
75
+ "ANTHROPIC_API_KEY": "ANTHROPIC_API_KEY",
76
+ "GROK_API_KEY": "GROK_API_KEY"
77
+ }
111
78
 
112
79
 
113
80
  def _decode_b64(enc: str) -> str:
@@ -140,35 +107,12 @@ def _is_dev_environment() -> bool:
140
107
  )
141
108
 
142
109
 
143
- def _is_ci_environment() -> bool:
144
- """Check if running in CI environment."""
145
- return os.environ.get("CI") == "true" or os.environ.get("GITHUB_ACTIONS") == "true"
146
-
147
-
148
110
  def _get_env_secrets() -> Dict[str, Optional[str]]:
149
111
  """Get secrets from environment variables."""
150
112
  env_secrets = {}
151
- is_ci = _is_ci_environment()
152
-
153
113
  for secret_key in EXPECTED_SECRETS:
154
114
  env_name = SECRET_ENV_MAPPING.get(secret_key, secret_key)
155
- raw_value = None
156
-
157
- if is_ci:
158
- # In CI, check for _ENCODED variant first (since that's how they're provided)
159
- encoded_env_name = f"{secret_key}_ENCODED" # Use secret_key directly for CI
160
- raw_value = os.environ.get(encoded_env_name)
161
-
162
- # If not found with secret_key, try with env_name
163
- if raw_value is None:
164
- encoded_env_name = f"{env_name}_ENCODED"
165
- raw_value = os.environ.get(encoded_env_name)
166
-
167
- # If still not found, try the direct environment variable name
168
- if raw_value is None:
169
- raw_value = os.environ.get(env_name)
170
-
171
- # If we found a value, process it
115
+ raw_value = os.environ.get(env_name)
172
116
  if raw_value:
173
117
  # Check if value is already decoded, use as-is; otherwise decode it
174
118
  if (secret_key == "TF_API_KEY" and ".atlasv1." in raw_value) or \
@@ -182,7 +126,6 @@ def _get_env_secrets() -> Dict[str, Optional[str]]:
182
126
  env_secrets[secret_key] = _decode_b64(raw_value)
183
127
  else:
184
128
  env_secrets[secret_key] = None
185
-
186
129
  return env_secrets
187
130
 
188
131
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diagram-to-iac
3
- Version: 1.9.0
3
+ Version: 1.12.0
4
4
  Summary: Convert architecture diagrams into IaC modules
5
5
  Author-email: vindpro <admin@vindpro.com>
6
6
  Description-Content-Type: text/markdown
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  src/diagram_to_iac/__init__.py
5
5
  src/diagram_to_iac/cli.py
6
- src/diagram_to_iac/config.yaml
7
6
  src/diagram_to_iac/r2d.py
8
7
  src/diagram_to_iac.egg-info/PKG-INFO
9
8
  src/diagram_to_iac.egg-info/SOURCES.txt
@@ -18,17 +17,13 @@ src/diagram_to_iac/actions/terraform_agent_entry.py
18
17
  src/diagram_to_iac/agents/__init__.py
19
18
  src/diagram_to_iac/agents/demonstrator_langgraph/__init__.py
20
19
  src/diagram_to_iac/agents/demonstrator_langgraph/agent.py
21
- src/diagram_to_iac/agents/demonstrator_langgraph/config.yaml
22
20
  src/diagram_to_iac/agents/git_langgraph/__init__.py
23
21
  src/diagram_to_iac/agents/git_langgraph/agent.py
24
- src/diagram_to_iac/agents/git_langgraph/config.yaml
25
22
  src/diagram_to_iac/agents/git_langgraph/pr.py
26
23
  src/diagram_to_iac/agents/hello_langgraph/__init__.py
27
24
  src/diagram_to_iac/agents/hello_langgraph/agent.py
28
- src/diagram_to_iac/agents/hello_langgraph/config.yaml
29
25
  src/diagram_to_iac/agents/policy_agent/__init__.py
30
26
  src/diagram_to_iac/agents/policy_agent/agent.py
31
- src/diagram_to_iac/agents/policy_agent/config.yaml
32
27
  src/diagram_to_iac/agents/policy_agent/integration_example.py
33
28
  src/diagram_to_iac/agents/policy_agent/tools/__init__.py
34
29
  src/diagram_to_iac/agents/policy_agent/tools/tfsec_tool.py
@@ -37,7 +32,6 @@ src/diagram_to_iac/agents/shell_langgraph/agent.py
37
32
  src/diagram_to_iac/agents/shell_langgraph/detector.py
38
33
  src/diagram_to_iac/agents/supervisor_langgraph/__init__.py
39
34
  src/diagram_to_iac/agents/supervisor_langgraph/agent.py
40
- src/diagram_to_iac/agents/supervisor_langgraph/config.yaml
41
35
  src/diagram_to_iac/agents/supervisor_langgraph/demonstrator.py
42
36
  src/diagram_to_iac/agents/supervisor_langgraph/github_listener.py
43
37
  src/diagram_to_iac/agents/supervisor_langgraph/guards.py
@@ -45,7 +39,6 @@ src/diagram_to_iac/agents/supervisor_langgraph/pat_loop.py
45
39
  src/diagram_to_iac/agents/supervisor_langgraph/router.py
46
40
  src/diagram_to_iac/agents/terraform_langgraph/__init__.py
47
41
  src/diagram_to_iac/agents/terraform_langgraph/agent.py
48
- src/diagram_to_iac/agents/terraform_langgraph/config.yaml
49
42
  src/diagram_to_iac/agents/terraform_langgraph/parser.py
50
43
  src/diagram_to_iac/core/__init__.py
51
44
  src/diagram_to_iac/core/agent_base.py
@@ -60,14 +53,12 @@ src/diagram_to_iac/services/__init__.py
60
53
  src/diagram_to_iac/services/commenter.py
61
54
  src/diagram_to_iac/services/observability.py
62
55
  src/diagram_to_iac/services/step_summary.py
63
- src/diagram_to_iac/templates/issue_frontmatter.yml
64
56
  src/diagram_to_iac/tools/__init__.py
65
57
  src/diagram_to_iac/tools/api_utils.py
66
58
  src/diagram_to_iac/tools/sec_utils.py
67
59
  src/diagram_to_iac/tools/text_utils.py
68
60
  src/diagram_to_iac/tools/git/__init__.py
69
61
  src/diagram_to_iac/tools/git/git.py
70
- src/diagram_to_iac/tools/git/git_config.yaml
71
62
  src/diagram_to_iac/tools/hello/__init__.py
72
63
  src/diagram_to_iac/tools/hello/cal_utils.py
73
64
  src/diagram_to_iac/tools/hello/text_utils.py
@@ -80,7 +71,5 @@ src/diagram_to_iac/tools/llm_utils/openai_driver.py
80
71
  src/diagram_to_iac/tools/llm_utils/router.py
81
72
  src/diagram_to_iac/tools/shell/__init__.py
82
73
  src/diagram_to_iac/tools/shell/shell.py
83
- src/diagram_to_iac/tools/shell/shell_config.yaml
84
74
  src/diagram_to_iac/tools/tf/terraform.py
85
- src/diagram_to_iac/tools/tf/terraform_config.yaml
86
75
  tests/test_devops_in_a_box.py