security-use 0.1.1__py3-none-any.whl → 0.2.9__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.
Files changed (45) hide show
  1. security_use/__init__.py +9 -1
  2. security_use/auth/__init__.py +16 -0
  3. security_use/auth/client.py +223 -0
  4. security_use/auth/config.py +177 -0
  5. security_use/auth/oauth.py +317 -0
  6. security_use/cli.py +699 -34
  7. security_use/compliance/__init__.py +10 -0
  8. security_use/compliance/mapper.py +275 -0
  9. security_use/compliance/models.py +50 -0
  10. security_use/dependency_scanner.py +76 -30
  11. security_use/fixers/iac_fixer.py +173 -95
  12. security_use/iac/rules/azure.py +246 -0
  13. security_use/iac/rules/gcp.py +255 -0
  14. security_use/iac/rules/kubernetes.py +429 -0
  15. security_use/iac/rules/registry.py +56 -0
  16. security_use/parsers/__init__.py +18 -0
  17. security_use/parsers/base.py +2 -0
  18. security_use/parsers/composer.py +101 -0
  19. security_use/parsers/conda.py +97 -0
  20. security_use/parsers/dotnet.py +89 -0
  21. security_use/parsers/gradle.py +90 -0
  22. security_use/parsers/maven.py +108 -0
  23. security_use/parsers/npm.py +196 -0
  24. security_use/parsers/yarn.py +108 -0
  25. security_use/reporter.py +29 -1
  26. security_use/sbom/__init__.py +10 -0
  27. security_use/sbom/generator.py +340 -0
  28. security_use/sbom/models.py +40 -0
  29. security_use/scanner.py +15 -2
  30. security_use/sensor/__init__.py +125 -0
  31. security_use/sensor/alert_queue.py +207 -0
  32. security_use/sensor/config.py +217 -0
  33. security_use/sensor/dashboard_alerter.py +246 -0
  34. security_use/sensor/detector.py +415 -0
  35. security_use/sensor/endpoint_analyzer.py +339 -0
  36. security_use/sensor/middleware.py +521 -0
  37. security_use/sensor/models.py +140 -0
  38. security_use/sensor/webhook.py +227 -0
  39. security_use-0.2.9.dist-info/METADATA +531 -0
  40. security_use-0.2.9.dist-info/RECORD +60 -0
  41. security_use-0.2.9.dist-info/licenses/LICENSE +21 -0
  42. security_use-0.1.1.dist-info/METADATA +0 -92
  43. security_use-0.1.1.dist-info/RECORD +0 -30
  44. {security_use-0.1.1.dist-info → security_use-0.2.9.dist-info}/WHEEL +0 -0
  45. {security_use-0.1.1.dist-info → security_use-0.2.9.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,227 @@
1
+ """Webhook alerter for sending security alerts."""
2
+
3
+ import asyncio
4
+ import logging
5
+ from datetime import datetime
6
+ from typing import Optional
7
+
8
+ import httpx
9
+
10
+ from .models import ActionTaken, AlertPayload, AlertResponse, SecurityEvent
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class WebhookAlerter:
16
+ """Sends security alerts to a webhook endpoint."""
17
+
18
+ def __init__(
19
+ self,
20
+ webhook_url: str,
21
+ retry_count: int = 3,
22
+ retry_delay: float = 1.0,
23
+ timeout: float = 10.0,
24
+ headers: Optional[dict[str, str]] = None,
25
+ ):
26
+ """Initialize the webhook alerter.
27
+
28
+ Args:
29
+ webhook_url: URL to send alerts to.
30
+ retry_count: Number of retry attempts on failure.
31
+ retry_delay: Delay in seconds between retries (doubles each attempt).
32
+ timeout: Request timeout in seconds.
33
+ headers: Additional headers to include in requests.
34
+ """
35
+ self.webhook_url = webhook_url
36
+ self.retry_count = retry_count
37
+ self.retry_delay = retry_delay
38
+ self.timeout = timeout
39
+ self.headers = headers or {}
40
+
41
+ async def send_alert(
42
+ self,
43
+ event: SecurityEvent,
44
+ action_taken: ActionTaken = ActionTaken.LOGGED,
45
+ ) -> AlertResponse:
46
+ """Send a security alert to the webhook.
47
+
48
+ Args:
49
+ event: The security event to report.
50
+ action_taken: What action was taken in response.
51
+
52
+ Returns:
53
+ AlertResponse with success status and details.
54
+ """
55
+ payload = AlertPayload(
56
+ timestamp=datetime.utcnow(),
57
+ alert=event,
58
+ action_taken=action_taken,
59
+ )
60
+
61
+ attempt = 0
62
+ last_error: Optional[str] = None
63
+ last_status = 0
64
+
65
+ async with httpx.AsyncClient(timeout=self.timeout) as client:
66
+ while attempt <= self.retry_count:
67
+ try:
68
+ response = await client.post(
69
+ self.webhook_url,
70
+ json=payload.to_dict(),
71
+ headers={
72
+ "Content-Type": "application/json",
73
+ "User-Agent": "security-use-sensor/1.0",
74
+ **self.headers,
75
+ },
76
+ )
77
+ last_status = response.status_code
78
+
79
+ if 200 <= response.status_code < 300:
80
+ logger.info(
81
+ "Alert sent successfully: %s (attempt %d)",
82
+ event.event_type.value,
83
+ attempt + 1,
84
+ )
85
+ return AlertResponse(
86
+ success=True,
87
+ webhook_status=response.status_code,
88
+ retry_count=attempt,
89
+ )
90
+
91
+ # Non-success status code
92
+ last_error = f"HTTP {response.status_code}: {response.text[:200]}"
93
+ logger.warning(
94
+ "Webhook returned %d (attempt %d/%d): %s",
95
+ response.status_code,
96
+ attempt + 1,
97
+ self.retry_count + 1,
98
+ response.text[:100],
99
+ )
100
+
101
+ except httpx.TimeoutException as e:
102
+ last_error = f"Timeout: {e}"
103
+ logger.warning(
104
+ "Webhook timeout (attempt %d/%d): %s",
105
+ attempt + 1,
106
+ self.retry_count + 1,
107
+ e,
108
+ )
109
+
110
+ except httpx.RequestError as e:
111
+ last_error = f"Request error: {e}"
112
+ logger.warning(
113
+ "Webhook request error (attempt %d/%d): %s",
114
+ attempt + 1,
115
+ self.retry_count + 1,
116
+ e,
117
+ )
118
+
119
+ attempt += 1
120
+ if attempt <= self.retry_count:
121
+ delay = self.retry_delay * (2 ** (attempt - 1))
122
+ await asyncio.sleep(delay)
123
+
124
+ logger.error(
125
+ "Failed to send alert after %d attempts: %s",
126
+ self.retry_count + 1,
127
+ last_error,
128
+ )
129
+ return AlertResponse(
130
+ success=False,
131
+ webhook_status=last_status,
132
+ retry_count=attempt - 1,
133
+ error_message=last_error,
134
+ )
135
+
136
+ def send_alert_sync(
137
+ self,
138
+ event: SecurityEvent,
139
+ action_taken: ActionTaken = ActionTaken.LOGGED,
140
+ ) -> AlertResponse:
141
+ """Synchronous version of send_alert for non-async contexts.
142
+
143
+ Args:
144
+ event: The security event to report.
145
+ action_taken: What action was taken in response.
146
+
147
+ Returns:
148
+ AlertResponse with success status and details.
149
+ """
150
+ payload = AlertPayload(
151
+ timestamp=datetime.utcnow(),
152
+ alert=event,
153
+ action_taken=action_taken,
154
+ )
155
+
156
+ attempt = 0
157
+ last_error: Optional[str] = None
158
+ last_status = 0
159
+
160
+ with httpx.Client(timeout=self.timeout) as client:
161
+ while attempt <= self.retry_count:
162
+ try:
163
+ response = client.post(
164
+ self.webhook_url,
165
+ json=payload.to_dict(),
166
+ headers={
167
+ "Content-Type": "application/json",
168
+ "User-Agent": "security-use-sensor/1.0",
169
+ **self.headers,
170
+ },
171
+ )
172
+ last_status = response.status_code
173
+
174
+ if 200 <= response.status_code < 300:
175
+ logger.info(
176
+ "Alert sent successfully: %s (attempt %d)",
177
+ event.event_type.value,
178
+ attempt + 1,
179
+ )
180
+ return AlertResponse(
181
+ success=True,
182
+ webhook_status=response.status_code,
183
+ retry_count=attempt,
184
+ )
185
+
186
+ last_error = f"HTTP {response.status_code}: {response.text[:200]}"
187
+ logger.warning(
188
+ "Webhook returned %d (attempt %d/%d)",
189
+ response.status_code,
190
+ attempt + 1,
191
+ self.retry_count + 1,
192
+ )
193
+
194
+ except httpx.TimeoutException as e:
195
+ last_error = f"Timeout: {e}"
196
+ logger.warning(
197
+ "Webhook timeout (attempt %d/%d)",
198
+ attempt + 1,
199
+ self.retry_count + 1,
200
+ )
201
+
202
+ except httpx.RequestError as e:
203
+ last_error = f"Request error: {e}"
204
+ logger.warning(
205
+ "Webhook request error (attempt %d/%d)",
206
+ attempt + 1,
207
+ self.retry_count + 1,
208
+ )
209
+
210
+ attempt += 1
211
+ if attempt <= self.retry_count:
212
+ import time
213
+
214
+ delay = self.retry_delay * (2 ** (attempt - 1))
215
+ time.sleep(delay)
216
+
217
+ logger.error(
218
+ "Failed to send alert after %d attempts: %s",
219
+ self.retry_count + 1,
220
+ last_error,
221
+ )
222
+ return AlertResponse(
223
+ success=False,
224
+ webhook_status=last_status,
225
+ retry_count=attempt - 1,
226
+ error_message=last_error,
227
+ )