holmesgpt 0.12.6__py3-none-any.whl → 0.13.1__py3-none-any.whl

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.

Potentially problematic release.


This version of holmesgpt might be problematic. Click here for more details.

Files changed (125) hide show
  1. holmes/__init__.py +1 -1
  2. holmes/clients/robusta_client.py +19 -1
  3. holmes/common/env_vars.py +17 -0
  4. holmes/config.py +69 -9
  5. holmes/core/conversations.py +11 -0
  6. holmes/core/investigation.py +16 -3
  7. holmes/core/investigation_structured_output.py +12 -0
  8. holmes/core/llm.py +13 -1
  9. holmes/core/models.py +9 -1
  10. holmes/core/openai_formatting.py +72 -12
  11. holmes/core/prompt.py +13 -0
  12. holmes/core/supabase_dal.py +3 -0
  13. holmes/core/todo_manager.py +88 -0
  14. holmes/core/tool_calling_llm.py +230 -157
  15. holmes/core/tools.py +10 -1
  16. holmes/core/tools_utils/tool_executor.py +7 -2
  17. holmes/core/tools_utils/toolset_utils.py +7 -2
  18. holmes/core/toolset_manager.py +1 -5
  19. holmes/core/tracing.py +4 -3
  20. holmes/interactive.py +1 -0
  21. holmes/main.py +9 -2
  22. holmes/plugins/prompts/__init__.py +7 -1
  23. holmes/plugins/prompts/_current_date_time.jinja2 +1 -0
  24. holmes/plugins/prompts/_default_log_prompt.jinja2 +4 -2
  25. holmes/plugins/prompts/_fetch_logs.jinja2 +10 -1
  26. holmes/plugins/prompts/_general_instructions.jinja2 +14 -0
  27. holmes/plugins/prompts/_permission_errors.jinja2 +1 -1
  28. holmes/plugins/prompts/_toolsets_instructions.jinja2 +4 -4
  29. holmes/plugins/prompts/generic_ask.jinja2 +4 -3
  30. holmes/plugins/prompts/investigation_procedure.jinja2 +210 -0
  31. holmes/plugins/prompts/kubernetes_workload_ask.jinja2 +2 -0
  32. holmes/plugins/runbooks/CLAUDE.md +85 -0
  33. holmes/plugins/runbooks/README.md +24 -0
  34. holmes/plugins/toolsets/__init__.py +19 -6
  35. holmes/plugins/toolsets/atlas_mongodb/mongodb_atlas.py +27 -0
  36. holmes/plugins/toolsets/azure_sql/tools/analyze_connection_failures.py +2 -2
  37. holmes/plugins/toolsets/azure_sql/tools/analyze_database_connections.py +2 -1
  38. holmes/plugins/toolsets/azure_sql/tools/analyze_database_health_status.py +3 -1
  39. holmes/plugins/toolsets/azure_sql/tools/analyze_database_performance.py +2 -1
  40. holmes/plugins/toolsets/azure_sql/tools/analyze_database_storage.py +2 -1
  41. holmes/plugins/toolsets/azure_sql/tools/get_active_alerts.py +3 -1
  42. holmes/plugins/toolsets/azure_sql/tools/get_slow_queries.py +2 -1
  43. holmes/plugins/toolsets/azure_sql/tools/get_top_cpu_queries.py +2 -1
  44. holmes/plugins/toolsets/azure_sql/tools/get_top_data_io_queries.py +2 -1
  45. holmes/plugins/toolsets/azure_sql/tools/get_top_log_io_queries.py +2 -1
  46. holmes/plugins/toolsets/bash/argocd/__init__.py +65 -0
  47. holmes/plugins/toolsets/bash/argocd/constants.py +120 -0
  48. holmes/plugins/toolsets/bash/aws/__init__.py +66 -0
  49. holmes/plugins/toolsets/bash/aws/constants.py +529 -0
  50. holmes/plugins/toolsets/bash/azure/__init__.py +56 -0
  51. holmes/plugins/toolsets/bash/azure/constants.py +339 -0
  52. holmes/plugins/toolsets/bash/bash_instructions.jinja2 +6 -7
  53. holmes/plugins/toolsets/bash/bash_toolset.py +47 -13
  54. holmes/plugins/toolsets/bash/common/bash_command.py +131 -0
  55. holmes/plugins/toolsets/bash/common/stringify.py +14 -1
  56. holmes/plugins/toolsets/bash/common/validators.py +91 -0
  57. holmes/plugins/toolsets/bash/docker/__init__.py +59 -0
  58. holmes/plugins/toolsets/bash/docker/constants.py +255 -0
  59. holmes/plugins/toolsets/bash/helm/__init__.py +61 -0
  60. holmes/plugins/toolsets/bash/helm/constants.py +92 -0
  61. holmes/plugins/toolsets/bash/kubectl/__init__.py +80 -79
  62. holmes/plugins/toolsets/bash/kubectl/constants.py +0 -14
  63. holmes/plugins/toolsets/bash/kubectl/kubectl_describe.py +38 -56
  64. holmes/plugins/toolsets/bash/kubectl/kubectl_events.py +28 -76
  65. holmes/plugins/toolsets/bash/kubectl/kubectl_get.py +39 -99
  66. holmes/plugins/toolsets/bash/kubectl/kubectl_logs.py +34 -15
  67. holmes/plugins/toolsets/bash/kubectl/kubectl_run.py +1 -1
  68. holmes/plugins/toolsets/bash/kubectl/kubectl_top.py +38 -77
  69. holmes/plugins/toolsets/bash/parse_command.py +106 -32
  70. holmes/plugins/toolsets/bash/utilities/__init__.py +0 -0
  71. holmes/plugins/toolsets/bash/utilities/base64_util.py +12 -0
  72. holmes/plugins/toolsets/bash/utilities/cut.py +12 -0
  73. holmes/plugins/toolsets/bash/utilities/grep/__init__.py +10 -0
  74. holmes/plugins/toolsets/bash/utilities/head.py +12 -0
  75. holmes/plugins/toolsets/bash/utilities/jq.py +79 -0
  76. holmes/plugins/toolsets/bash/utilities/sed.py +164 -0
  77. holmes/plugins/toolsets/bash/utilities/sort.py +15 -0
  78. holmes/plugins/toolsets/bash/utilities/tail.py +12 -0
  79. holmes/plugins/toolsets/bash/utilities/tr.py +57 -0
  80. holmes/plugins/toolsets/bash/utilities/uniq.py +12 -0
  81. holmes/plugins/toolsets/bash/utilities/wc.py +12 -0
  82. holmes/plugins/toolsets/coralogix/api.py +6 -6
  83. holmes/plugins/toolsets/coralogix/toolset_coralogix_logs.py +7 -1
  84. holmes/plugins/toolsets/datadog/datadog_api.py +20 -8
  85. holmes/plugins/toolsets/datadog/datadog_metrics_instructions.jinja2 +8 -1
  86. holmes/plugins/toolsets/datadog/datadog_rds_instructions.jinja2 +82 -0
  87. holmes/plugins/toolsets/datadog/toolset_datadog_logs.py +12 -5
  88. holmes/plugins/toolsets/datadog/toolset_datadog_metrics.py +20 -11
  89. holmes/plugins/toolsets/datadog/toolset_datadog_rds.py +735 -0
  90. holmes/plugins/toolsets/datadog/toolset_datadog_traces.py +18 -11
  91. holmes/plugins/toolsets/git.py +15 -15
  92. holmes/plugins/toolsets/grafana/grafana_api.py +12 -1
  93. holmes/plugins/toolsets/grafana/toolset_grafana.py +5 -1
  94. holmes/plugins/toolsets/grafana/toolset_grafana_loki.py +9 -4
  95. holmes/plugins/toolsets/grafana/toolset_grafana_tempo.py +12 -5
  96. holmes/plugins/toolsets/internet/internet.py +2 -1
  97. holmes/plugins/toolsets/internet/notion.py +2 -1
  98. holmes/plugins/toolsets/investigator/__init__.py +0 -0
  99. holmes/plugins/toolsets/investigator/core_investigation.py +157 -0
  100. holmes/plugins/toolsets/investigator/investigator_instructions.jinja2 +253 -0
  101. holmes/plugins/toolsets/investigator/model.py +15 -0
  102. holmes/plugins/toolsets/kafka.py +14 -7
  103. holmes/plugins/toolsets/kubernetes_logs.py +454 -25
  104. holmes/plugins/toolsets/logging_utils/logging_api.py +115 -55
  105. holmes/plugins/toolsets/mcp/toolset_mcp.py +1 -1
  106. holmes/plugins/toolsets/newrelic.py +8 -3
  107. holmes/plugins/toolsets/opensearch/opensearch.py +8 -4
  108. holmes/plugins/toolsets/opensearch/opensearch_logs.py +9 -2
  109. holmes/plugins/toolsets/opensearch/opensearch_traces.py +6 -2
  110. holmes/plugins/toolsets/prometheus/prometheus.py +179 -44
  111. holmes/plugins/toolsets/rabbitmq/toolset_rabbitmq.py +8 -2
  112. holmes/plugins/toolsets/robusta/robusta.py +4 -4
  113. holmes/plugins/toolsets/runbook/runbook_fetcher.py +6 -5
  114. holmes/plugins/toolsets/servicenow/servicenow.py +18 -3
  115. holmes/plugins/toolsets/utils.py +8 -1
  116. holmes/utils/console/logging.py +6 -1
  117. holmes/utils/llms.py +20 -0
  118. holmes/utils/stream.py +90 -0
  119. {holmesgpt-0.12.6.dist-info → holmesgpt-0.13.1.dist-info}/METADATA +47 -34
  120. {holmesgpt-0.12.6.dist-info → holmesgpt-0.13.1.dist-info}/RECORD +123 -91
  121. holmes/plugins/toolsets/bash/grep/__init__.py +0 -52
  122. holmes/utils/robusta.py +0 -9
  123. {holmesgpt-0.12.6.dist-info → holmesgpt-0.13.1.dist-info}/LICENSE.txt +0 -0
  124. {holmesgpt-0.12.6.dist-info → holmesgpt-0.13.1.dist-info}/WHEEL +0 -0
  125. {holmesgpt-0.12.6.dist-info → holmesgpt-0.13.1.dist-info}/entry_points.txt +0 -0
@@ -20,7 +20,12 @@ from holmes.plugins.toolsets.datadog.toolset_datadog_logs import DatadogLogsTool
20
20
  from holmes.plugins.toolsets.datadog.toolset_datadog_metrics import (
21
21
  DatadogMetricsToolset,
22
22
  )
23
- from holmes.plugins.toolsets.datadog.toolset_datadog_traces import DatadogTracesToolset
23
+ from holmes.plugins.toolsets.datadog.toolset_datadog_traces import (
24
+ DatadogTracesToolset,
25
+ )
26
+ from holmes.plugins.toolsets.datadog.toolset_datadog_rds import (
27
+ DatadogRDSToolset,
28
+ )
24
29
  from holmes.plugins.toolsets.git import GitToolset
25
30
  from holmes.plugins.toolsets.grafana.toolset_grafana import GrafanaToolset
26
31
  from holmes.plugins.toolsets.grafana.toolset_grafana_loki import GrafanaLokiToolset
@@ -39,6 +44,9 @@ from holmes.plugins.toolsets.rabbitmq.toolset_rabbitmq import RabbitMQToolset
39
44
  from holmes.plugins.toolsets.robusta.robusta import RobustaToolset
40
45
  from holmes.plugins.toolsets.runbook.runbook_fetcher import RunbookToolset
41
46
  from holmes.plugins.toolsets.servicenow.servicenow import ServiceNowToolset
47
+ from holmes.plugins.toolsets.investigator.core_investigation import (
48
+ CoreInvestigationToolset,
49
+ )
42
50
 
43
51
  THIS_DIR = os.path.abspath(os.path.dirname(__file__))
44
52
 
@@ -63,6 +71,7 @@ def load_toolsets_from_file(
63
71
  def load_python_toolsets(dal: Optional[SupabaseDal]) -> List[Toolset]:
64
72
  logging.debug("loading python toolsets")
65
73
  toolsets: list[Toolset] = [
74
+ CoreInvestigationToolset(), # Load first for higher priority
66
75
  InternetToolset(),
67
76
  RobustaToolset(dal),
68
77
  OpenSearchToolset(),
@@ -75,6 +84,7 @@ def load_python_toolsets(dal: Optional[SupabaseDal]) -> List[Toolset]:
75
84
  DatadogLogsToolset(),
76
85
  DatadogMetricsToolset(),
77
86
  DatadogTracesToolset(),
87
+ DatadogRDSToolset(),
78
88
  PrometheusToolset(),
79
89
  OpenSearchLogsToolset(),
80
90
  OpenSearchTracesToolset(),
@@ -152,8 +162,15 @@ def load_toolsets_from_config(
152
162
  for name, config in toolsets.items():
153
163
  try:
154
164
  toolset_type = config.get("type", ToolsetType.BUILTIN.value)
155
- # MCP server is not a built-in toolset, so we need to set the type explicitly
165
+
166
+ # Resolve env var placeholders before creating the Toolset.
167
+ # If done after, .override_with() will overwrite resolved values with placeholders
168
+ # because model_dump() returns the original, unprocessed config from YAML.
169
+ if config:
170
+ config = env_utils.replace_env_vars_values(config)
171
+
156
172
  validated_toolset: Optional[Toolset] = None
173
+ # MCP server is not a built-in toolset, so we need to set the type explicitly
157
174
  if toolset_type == ToolsetType.MCP.value:
158
175
  validated_toolset = RemoteMCPToolset(**config, name=name)
159
176
  elif strict_check:
@@ -163,10 +180,6 @@ def load_toolsets_from_config(
163
180
  **config, name=name
164
181
  )
165
182
 
166
- if validated_toolset.config:
167
- validated_toolset.config = env_utils.replace_env_vars_values(
168
- validated_toolset.config
169
- )
170
183
  loaded_toolsets.append(validated_toolset)
171
184
  except ValidationError as e:
172
185
  logging.warning(f"Toolset '{name}' is invalid: {e}")
@@ -18,6 +18,8 @@ from datetime import datetime, timedelta, timezone
18
18
  import os
19
19
  from collections import Counter
20
20
 
21
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
22
+
21
23
 
22
24
  class MongoDBConfig(BaseModel):
23
25
  public_key: str
@@ -103,6 +105,7 @@ class MongoDBAtlasBaseTool(Tool):
103
105
  )
104
106
 
105
107
  def get_parameterized_one_liner(self, params) -> str:
108
+ # Default implementation - will be overridden by subclasses
106
109
  return f"MongoDB {self.name} project {self.toolset.config.get('project_id')} {params}"
107
110
 
108
111
 
@@ -111,6 +114,10 @@ class ReturnProjectAlerts(MongoDBAtlasBaseTool):
111
114
  name: str = "atlas_return_project_alerts"
112
115
  description: str = "Returns all project alerts. These alerts apply to all components in one project. You receive an alert when a monitored component meets or exceeds a value you set."
113
116
 
117
+ def get_parameterized_one_liner(self, params) -> str:
118
+ project_id = self.toolset.config.get("project_id", "")
119
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Project Alerts ({project_id})"
120
+
114
121
  def _invoke(self, params: Any) -> StructuredToolResult:
115
122
  try:
116
123
  url = "https://cloud.mongodb.com/api/atlas/v2/groups/{project_id}/alerts".format(
@@ -132,6 +139,10 @@ class ReturnProjectProcesses(MongoDBAtlasBaseTool):
132
139
  name: str = "atlas_return_project_processes"
133
140
  description: str = "Returns details of all processes for the specified project. Useful for getting logs and data for specific project"
134
141
 
142
+ def get_parameterized_one_liner(self, params) -> str:
143
+ project_id = self.toolset.config.get("project_id", "")
144
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Project Processes ({project_id})"
145
+
135
146
  def _invoke(self, params: Any) -> StructuredToolResult:
136
147
  try:
137
148
  url = "https://cloud.mongodb.com/api/atlas/v2/groups/{project_id}/processes".format(
@@ -161,6 +172,10 @@ class ReturnProjectSlowQueries(MongoDBAtlasBaseTool):
161
172
  ),
162
173
  }
163
174
 
175
+ def get_parameterized_one_liner(self, params) -> str:
176
+ process_id = params.get("process_id", "")
177
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Slow Queries ({process_id})"
178
+
164
179
  def _invoke(self, params: Any) -> StructuredToolResult:
165
180
  try:
166
181
  url = self.url.format(
@@ -184,6 +199,10 @@ class ReturnEventsFromProject(MongoDBAtlasBaseTool):
184
199
  description: str = "Returns all events occurrences for the specified project. Events identify significant database, security activities or status changes. can only query the last 4 hours."
185
200
  url: str = "https://cloud.mongodb.com/api/atlas/v2/groups/{projectId}/events"
186
201
 
202
+ def get_parameterized_one_liner(self, params) -> str:
203
+ project_id = self.toolset.config.get("project_id", "")
204
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Project Events ({project_id})"
205
+
187
206
  def _invoke(self, params: Any) -> StructuredToolResult:
188
207
  params.update({"itemsPerPage": 500})
189
208
  try:
@@ -237,6 +256,10 @@ class ReturnLogsForProcessInProject(MongoDBAtlasBaseTool):
237
256
  ),
238
257
  }
239
258
 
259
+ def get_parameterized_one_liner(self, params) -> str:
260
+ hostname = params.get("hostName", "")
261
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Host Logs ({hostname})"
262
+
240
263
  def _invoke(self, params: Any) -> StructuredToolResult:
241
264
  one_hour_ago = datetime.now(timezone.utc) - timedelta(hours=1)
242
265
  try:
@@ -285,6 +308,10 @@ class ReturnEventTypeFromProject(MongoDBAtlasBaseTool):
285
308
  ),
286
309
  }
287
310
 
311
+ def get_parameterized_one_liner(self, params) -> str:
312
+ event_type = params.get("eventType", "")
313
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Event Details ({event_type})"
314
+
288
315
  def _invoke(self, params: Any) -> StructuredToolResult:
289
316
  try:
290
317
  url = self.url.format(projectId=self.toolset.config.get("project_id"))
@@ -12,6 +12,7 @@ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClie
12
12
  from holmes.plugins.toolsets.azure_sql.apis.connection_failure_api import (
13
13
  ConnectionFailureAPI,
14
14
  )
15
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
15
16
 
16
17
 
17
18
  class AnalyzeConnectionFailures(BaseAzureSQLTool):
@@ -267,8 +268,7 @@ class AnalyzeConnectionFailures(BaseAzureSQLTool):
267
268
 
268
269
  def get_parameterized_one_liner(self, params: Dict) -> str:
269
270
  db_config = self.toolset.database_config()
270
- hours_back = params.get("hours_back", 24)
271
- return f"Analyze connection failures for {db_config.server_name}/{db_config.database_name} over {hours_back} hours"
271
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Analyze Connection Failures ({db_config.server_name}/{db_config.database_name})"
272
272
 
273
273
  @staticmethod
274
274
  def validate_config(
@@ -12,6 +12,7 @@ from holmes.plugins.toolsets.azure_sql.apis.connection_monitoring_api import (
12
12
  ConnectionMonitoringAPI,
13
13
  )
14
14
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
15
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
15
16
 
16
17
 
17
18
  class AnalyzeDatabaseConnections(BaseAzureSQLTool):
@@ -212,7 +213,7 @@ class AnalyzeDatabaseConnections(BaseAzureSQLTool):
212
213
 
213
214
  def get_parameterized_one_liner(self, params: Dict) -> str:
214
215
  db_config = self.toolset.database_config()
215
- return f"Analyze database connections for {db_config.server_name}/{db_config.database_name}"
216
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Analyze Database Connections ({db_config.server_name}/{db_config.database_name})"
216
217
 
217
218
  @staticmethod
218
219
  def validate_config(
@@ -11,6 +11,8 @@ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
11
11
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
12
12
  from typing import Tuple
13
13
 
14
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
15
+
14
16
 
15
17
  class AnalyzeDatabaseHealthStatus(BaseAzureSQLTool):
16
18
  def __init__(self, toolset: "BaseAzureSQLToolset"):
@@ -156,7 +158,7 @@ class AnalyzeDatabaseHealthStatus(BaseAzureSQLTool):
156
158
 
157
159
  def get_parameterized_one_liner(self, params: Dict) -> str:
158
160
  db_config = self.toolset.database_config()
159
- return f"Analyze health status for database {db_config.server_name}/{db_config.database_name}"
161
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Analyze Health Status ({db_config.server_name}/{db_config.database_name})"
160
162
 
161
163
  @staticmethod
162
164
  def validate_config(
@@ -9,6 +9,7 @@ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
9
9
  AzureSQLDatabaseConfig,
10
10
  )
11
11
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
12
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
12
13
 
13
14
 
14
15
  class AnalyzeDatabasePerformance(BaseAzureSQLTool):
@@ -218,7 +219,7 @@ class AnalyzeDatabasePerformance(BaseAzureSQLTool):
218
219
 
219
220
  def get_parameterized_one_liner(self, params: Dict) -> str:
220
221
  db_config = self.toolset.database_config()
221
- return f"Analyze performance for database {db_config.server_name}/{db_config.database_name}"
222
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Analyze Database Performance ({db_config.server_name}/{db_config.database_name})"
222
223
 
223
224
  @staticmethod
224
225
  def validate_config(
@@ -12,6 +12,7 @@ from holmes.plugins.toolsets.azure_sql.apis.storage_analysis_api import (
12
12
  StorageAnalysisAPI,
13
13
  )
14
14
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
15
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
15
16
 
16
17
 
17
18
  class AnalyzeDatabaseStorage(BaseAzureSQLTool):
@@ -319,7 +320,7 @@ class AnalyzeDatabaseStorage(BaseAzureSQLTool):
319
320
 
320
321
  def get_parameterized_one_liner(self, params: Dict) -> str:
321
322
  db_config = self.toolset.database_config()
322
- return f"Analyzed database storage for database {db_config.server_name}/{db_config.database_name}"
323
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Analyze Database Storage ({db_config.server_name}/{db_config.database_name})"
323
324
 
324
325
  @staticmethod
325
326
  def validate_config(
@@ -14,6 +14,8 @@ from holmes.plugins.toolsets.azure_sql.apis.alert_monitoring_api import (
14
14
  )
15
15
  from typing import Tuple
16
16
 
17
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
18
+
17
19
 
18
20
  class GetActiveAlerts(BaseAzureSQLTool):
19
21
  def __init__(self, toolset: "BaseAzureSQLToolset"):
@@ -190,7 +192,7 @@ class GetActiveAlerts(BaseAzureSQLTool):
190
192
 
191
193
  def get_parameterized_one_liner(self, params: Dict) -> str:
192
194
  db_config = self.toolset.database_config()
193
- return f"Fetch active alerts for database {db_config.server_name}/{db_config.database_name}"
195
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Active Alerts ({db_config.server_name}/{db_config.database_name})"
194
196
 
195
197
  @staticmethod
196
198
  def validate_config(
@@ -9,6 +9,7 @@ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
9
9
  )
10
10
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
11
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
12
13
 
13
14
 
14
15
  class GetSlowQueries(BaseAzureSQLTool):
@@ -137,7 +138,7 @@ class GetSlowQueries(BaseAzureSQLTool):
137
138
 
138
139
  def get_parameterized_one_liner(self, params: Dict) -> str:
139
140
  db_config = self.toolset.database_config()
140
- return f"Fetch slowest queries for database {db_config.server_name}/{db_config.database_name}"
141
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Slow Queries ({db_config.server_name}/{db_config.database_name})"
141
142
 
142
143
  @staticmethod
143
144
  def validate_config(
@@ -9,6 +9,7 @@ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
9
9
  )
10
10
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
11
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
12
13
 
13
14
 
14
15
  class GetTopCPUQueries(BaseAzureSQLTool):
@@ -135,7 +136,7 @@ class GetTopCPUQueries(BaseAzureSQLTool):
135
136
 
136
137
  def get_parameterized_one_liner(self, params: Dict) -> str:
137
138
  db_config = self.toolset.database_config()
138
- return f"Fetch top CPU consuming queries for database {db_config.server_name}/{db_config.database_name}"
139
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Top CPU Queries ({db_config.server_name}/{db_config.database_name})"
139
140
 
140
141
  @staticmethod
141
142
  def validate_config(
@@ -9,6 +9,7 @@ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
9
9
  )
10
10
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
11
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
12
13
 
13
14
 
14
15
  class GetTopDataIOQueries(BaseAzureSQLTool):
@@ -153,7 +154,7 @@ class GetTopDataIOQueries(BaseAzureSQLTool):
153
154
 
154
155
  def get_parameterized_one_liner(self, params: Dict) -> str:
155
156
  db_config = self.toolset.database_config()
156
- return f"Fetch top data I/O consuming queries for database {db_config.server_name}/{db_config.database_name}"
157
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Top Data I/O Queries ({db_config.server_name}/{db_config.database_name})"
157
158
 
158
159
  @staticmethod
159
160
  def validate_config(
@@ -9,6 +9,7 @@ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
9
9
  )
10
10
  from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
11
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
+ from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
12
13
 
13
14
 
14
15
  class GetTopLogIOQueries(BaseAzureSQLTool):
@@ -145,7 +146,7 @@ class GetTopLogIOQueries(BaseAzureSQLTool):
145
146
 
146
147
  def get_parameterized_one_liner(self, params: Dict) -> str:
147
148
  db_config = self.toolset.database_config()
148
- return f"Fetch top log I/O consuming queries for database {db_config.server_name}/{db_config.database_name}"
149
+ return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Top Log I/O Queries ({db_config.server_name}/{db_config.database_name})"
149
150
 
150
151
  @staticmethod
151
152
  def validate_config(
@@ -0,0 +1,65 @@
1
+ import argparse
2
+ from typing import Any, Optional
3
+
4
+ from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
5
+ from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
6
+ from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
7
+ from holmes.plugins.toolsets.bash.argocd.constants import (
8
+ ALLOWED_ARGOCD_COMMANDS,
9
+ DENIED_ARGOCD_COMMANDS,
10
+ )
11
+ from holmes.plugins.toolsets.bash.common.validators import (
12
+ validate_command_and_operations,
13
+ )
14
+
15
+
16
+ class ArgocdCommand(BashCommand):
17
+ def __init__(self):
18
+ super().__init__("argocd")
19
+
20
+ def add_parser(self, parent_parser: Any):
21
+ """Create Argo CD CLI parser with safe command validation."""
22
+ argocd_parser = parent_parser.add_parser(
23
+ "argocd", help="Argo CD Command Line Interface", exit_on_error=False
24
+ )
25
+
26
+ # Add command subparser
27
+ argocd_parser.add_argument(
28
+ "command", help="Argo CD command (e.g., app, cluster, proj, repo)"
29
+ )
30
+
31
+ # Capture remaining arguments
32
+ argocd_parser.add_argument(
33
+ "options",
34
+ nargs=argparse.REMAINDER,
35
+ default=[],
36
+ help="Argo CD CLI subcommands, operations, and options",
37
+ )
38
+ return argocd_parser
39
+
40
+ def validate_command(
41
+ self, command: Any, original_command: str, config: Optional[BashExecutorConfig]
42
+ ) -> None:
43
+ if hasattr(command, "options"):
44
+ validate_command_and_operations(
45
+ command.command,
46
+ command.options,
47
+ ALLOWED_ARGOCD_COMMANDS,
48
+ DENIED_ARGOCD_COMMANDS,
49
+ )
50
+
51
+ def stringify_command(
52
+ self, command: Any, original_command: str, config: Optional[BashExecutorConfig]
53
+ ) -> str:
54
+ """Convert parsed Argo CD command back to safe command string."""
55
+ parts = ["argocd", command.command]
56
+
57
+ if hasattr(command, "options") and command.options:
58
+ parts.extend(command.options)
59
+
60
+ return " ".join(escape_shell_args(parts))
61
+
62
+
63
+ def create_argocd_parser(parent_parser: Any):
64
+ argocd_command = ArgocdCommand()
65
+ return argocd_command.add_parser(parent_parser)
@@ -0,0 +1,120 @@
1
+ ALLOWED_ARGOCD_COMMANDS: dict[str, dict] = {
2
+ # Application management (read-only)
3
+ "app": {
4
+ "list": {},
5
+ "get": {},
6
+ "resources": {},
7
+ "diff": {},
8
+ "history": {},
9
+ "manifests": {},
10
+ "logs": {},
11
+ "wait": {}, # Wait for app to reach desired state (read-only monitoring)
12
+ },
13
+ # Cluster management (read-only)
14
+ "cluster": {
15
+ "list": {},
16
+ "get": {},
17
+ },
18
+ # Project management (read-only)
19
+ "proj": {
20
+ "list": {},
21
+ "get": {},
22
+ },
23
+ # Repository management (read-only)
24
+ "repo": {
25
+ "list": {},
26
+ "get": {},
27
+ },
28
+ # Context management (read-only operations)
29
+ "context": {},
30
+ # Version information (completely safe)
31
+ "version": {},
32
+ # Account information (read-only)
33
+ "account": {
34
+ "list": {},
35
+ "get": {},
36
+ "get-user-info": {},
37
+ "can-i": {},
38
+ },
39
+ # Administrative commands (limited read-only)
40
+ "admin": {
41
+ "dashboard": {}, # Starts read-only web UI
42
+ "settings": {}, # Shows/validates settings (read-only)
43
+ },
44
+ }
45
+
46
+ DENIED_ARGOCD_COMMANDS: dict[str, dict] = {
47
+ # Authentication operations (sensitive)
48
+ "login": {},
49
+ "logout": {},
50
+ "relogin": {},
51
+ # Application lifecycle operations (state-modifying)
52
+ "app": {
53
+ "create": {},
54
+ "delete": {},
55
+ "sync": {},
56
+ "rollback": {},
57
+ "edit": {},
58
+ "set": {},
59
+ "unset": {},
60
+ "patch": {},
61
+ "delete-resource": {},
62
+ "terminate-op": {},
63
+ "actions": {}, # Custom resource actions
64
+ },
65
+ # Account management (sensitive)
66
+ "account": {
67
+ "generate-token": {},
68
+ "delete-token": {},
69
+ "update-password": {},
70
+ "bcrypt": {},
71
+ },
72
+ # Cluster management (state-modifying)
73
+ "cluster": {
74
+ "add": {},
75
+ "rm": {},
76
+ "set": {},
77
+ "rotate-auth": {},
78
+ },
79
+ # Project management (state-modifying)
80
+ "proj": {
81
+ "create": {},
82
+ "delete": {},
83
+ "edit": {},
84
+ "add-source": {},
85
+ "remove-source": {},
86
+ "add-destination": {},
87
+ "remove-destination": {},
88
+ "add-cluster-resource-whitelist": {},
89
+ "remove-cluster-resource-whitelist": {},
90
+ "add-namespace-resource-blacklist": {},
91
+ "remove-namespace-resource-blacklist": {},
92
+ "add-cluster-resource-blacklist": {},
93
+ "remove-cluster-resource-blacklist": {},
94
+ "add-namespace-resource-whitelist": {},
95
+ "remove-namespace-resource-whitelist": {},
96
+ "add-orphaned-ignore": {},
97
+ "remove-orphaned-ignore": {},
98
+ "add-signature-key": {},
99
+ "remove-signature-key": {},
100
+ "set-orphaned-ignore": {},
101
+ "add-role": {},
102
+ "remove-role": {},
103
+ "add-role-token": {},
104
+ "delete-role-token": {},
105
+ "set-role": {},
106
+ },
107
+ # Repository management (state-modifying)
108
+ "repo": {
109
+ "add": {},
110
+ "rm": {},
111
+ },
112
+ # Certificate management
113
+ "cert": {},
114
+ # GPG key management
115
+ "gpg": {},
116
+ # Application set operations
117
+ "appset": {},
118
+ # Notification operations
119
+ "notifications": {},
120
+ }
@@ -0,0 +1,66 @@
1
+ import argparse
2
+ from typing import Any, Optional
3
+
4
+ from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
5
+ from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
6
+ from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
7
+ from holmes.plugins.toolsets.bash.common.validators import (
8
+ validate_command_and_operations,
9
+ )
10
+ from holmes.plugins.toolsets.bash.aws.constants import (
11
+ ALLOWED_AWS_COMMANDS,
12
+ DENIED_AWS_COMMANDS,
13
+ )
14
+
15
+
16
+ class AWSCommand(BashCommand):
17
+ def __init__(self):
18
+ super().__init__("aws")
19
+
20
+ def add_parser(self, parent_parser: Any):
21
+ """Create AWS CLI parser with safe command validation."""
22
+ aws_parser = parent_parser.add_parser(
23
+ "aws",
24
+ help="Amazon Web Services Command Line Interface",
25
+ exit_on_error=False,
26
+ )
27
+
28
+ aws_parser.add_argument(
29
+ "service",
30
+ help="AWS service name (e.g., ec2, s3, lambda)",
31
+ )
32
+
33
+ aws_parser.add_argument("operation", help="AWS operation to perform")
34
+
35
+ aws_parser.add_argument(
36
+ "options",
37
+ nargs=argparse.REMAINDER,
38
+ default=[],
39
+ help="Additional AWS CLI options and parameters",
40
+ )
41
+ return aws_parser
42
+
43
+ def validate_command(
44
+ self, command: Any, original_command: str, config: Optional[BashExecutorConfig]
45
+ ) -> None:
46
+ # Build options list with operation and remaining arguments
47
+ options = [command.operation] + (
48
+ command.options if hasattr(command, "options") else []
49
+ )
50
+ validate_command_and_operations(
51
+ command=command.service,
52
+ options=options,
53
+ allowed_commands=ALLOWED_AWS_COMMANDS,
54
+ denied_commands=DENIED_AWS_COMMANDS,
55
+ )
56
+
57
+ def stringify_command(
58
+ self, command: Any, original_command: str, config: Optional[BashExecutorConfig]
59
+ ) -> str:
60
+ """Convert parsed AWS command back to safe command string."""
61
+ parts = ["aws", command.service, command.operation]
62
+
63
+ if hasattr(command, "options") and command.options:
64
+ parts.extend(command.options)
65
+
66
+ return " ".join(escape_shell_args(parts))