txt2detection 1.0.2__py3-none-any.whl → 1.0.3__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 txt2detection might be problematic. Click here for more details.

txt2detection/__main__.py CHANGED
@@ -13,6 +13,7 @@ import uuid
13
13
  from stix2 import Identity
14
14
  import yaml
15
15
 
16
+ from txt2detection import credential_checker
16
17
  from txt2detection.ai_extractor.base import BaseAIExtractor
17
18
  from txt2detection.models import TAG_PATTERN, DetectionContainer, Level, SigmaRuleDetection
18
19
  from txt2detection.utils import validate_token_count
@@ -91,6 +92,7 @@ def parse_args():
91
92
  file = mode.add_parser('file', help="process a file input using ai")
92
93
  text = mode.add_parser('text', help="process a text argument using ai")
93
94
  sigma = mode.add_parser('sigma', help="process a sigma file without ai")
95
+ check_credentials = mode.add_parser('check-credentials', help="show status of external services with respect to credentials")
94
96
 
95
97
  for mode_parser in [file, text, sigma]:
96
98
  mode_parser.add_argument('--report_id', type=uuid.UUID, help='report_id to use for generated report')
@@ -115,7 +117,10 @@ def parse_args():
115
117
  sigma.add_argument('--level', help="If passed, will overwrite any existing `level` recorded in the rule", choices=Level._member_names_)
116
118
 
117
119
  args: Args = parser.parse_args()
118
- print(args)
120
+ if args.mode == "check-credentials":
121
+ statuses = credential_checker.check_statuses(test_llms=True)
122
+ credential_checker.format_statuses(statuses)
123
+ sys.exit(0)
119
124
 
120
125
  if args.mode != 'sigma':
121
126
  assert args.ai_provider, "--ai_provider is required in file or txt mode"
@@ -129,6 +134,8 @@ def parse_args():
129
134
  return args
130
135
 
131
136
 
137
+
138
+
132
139
  def run_txt2detection(name, identity, tlp_level, input_text: str, labels: list[str], report_id: str|uuid.UUID, ai_provider: BaseAIExtractor, **kwargs) -> Bundler:
133
140
  if sigma := kwargs.get('sigma_file'):
134
141
  detection = get_sigma_detections(sigma)
@@ -54,4 +54,14 @@ class BaseAIExtractor():
54
54
 
55
55
  @property
56
56
  def extractor_name(self):
57
- return f"{self.provider}:{self.llm.model}"
57
+ return f"{self.provider}:{self.llm.model}"
58
+
59
+ def check_credential(self):
60
+ try:
61
+ return "authorized" if self._check_credential() else "unauthorized"
62
+ except:
63
+ return "unknown"
64
+
65
+ def _check_credential(self):
66
+ self.llm.complete("say 'hi'")
67
+ return True
txt2detection/bundler.py CHANGED
@@ -244,7 +244,7 @@ class Bundler:
244
244
 
245
245
  headers = {}
246
246
  if api_key := os.environ.get('CTIBUTLER_API_KEY'):
247
- headers['Authorization'] = "Bearer " + api_key
247
+ headers['API-KEY'] = api_key
248
248
 
249
249
  return self._get_objects(endpoint, headers)
250
250
 
@@ -255,7 +255,7 @@ class Bundler:
255
255
  endpoint = urljoin(os.environ['VULMATCH_BASE_URL'] + '/', f"v1/cve/objects/?cve_id="+','.join(cve_ids))
256
256
  headers = {}
257
257
  if api_key := os.environ.get('VULMATCH_API_KEY'):
258
- headers['Authorization'] = "Bearer " + api_key
258
+ headers['API-KEY'] = api_key
259
259
 
260
260
  return self._get_objects(endpoint, headers)
261
261
 
@@ -0,0 +1,80 @@
1
+ import argparse
2
+ import os
3
+ import random
4
+ from urllib.parse import urljoin
5
+ import requests
6
+
7
+
8
+
9
+ def check_llms():
10
+ from txt2detection.__main__ import parse_model
11
+
12
+ auth_info = dict()
13
+ for model_name in ["openai", "deepseek", "gemini", "openrouter", "anthropic"]:
14
+ try:
15
+ model = parse_model(model_name)
16
+ auth_info[model_name] = model.check_credential()
17
+ except argparse.ArgumentTypeError:
18
+ auth_info[model_name] = "unsupported"
19
+ except:
20
+ auth_info[model_name] = "unauthorized"
21
+ return auth_info
22
+
23
+
24
+ def check_ctibutler_vulmatch(service):
25
+ session = requests.Session()
26
+ if service == 'vulmatch':
27
+ base_url = os.getenv('VULMATCH_BASE_URL')
28
+ url = urljoin(base_url, 'v1/cve/objects/vulnerability--f552f6f4-39da-48dc-8717-323772c99588/')
29
+ session.headers['API-KEY'] = os.environ.get('VULMATCH_API_KEY')
30
+ elif service == 'ctibutler':
31
+ base_url = os.getenv('CTIBUTLER_BASE_URL')
32
+ url = urljoin(base_url, 'v1/location/versions/available/')
33
+ session.headers['API-KEY'] = os.environ.get('CTIBUTLER_API_KEY')
34
+
35
+ try:
36
+ resp = session.get(url)
37
+ match resp.status_code:
38
+ case 401 | 403:
39
+ return "unauthorized"
40
+ case 200:
41
+ return "authorized"
42
+ case _:
43
+ return "unknown"
44
+ except:
45
+ return "offline"
46
+
47
+
48
+ def check_statuses(test_llms=False):
49
+ statuses = dict(
50
+ ctibutler=check_ctibutler_vulmatch("ctibutler"),
51
+ vulmatch=check_ctibutler_vulmatch("vulmatch"),
52
+ )
53
+ if test_llms:
54
+ statuses.update(llms=check_llms())
55
+ return statuses
56
+
57
+
58
+ def format_statuses(status_dict):
59
+ def get_marker(status):
60
+ """Return a checkmark, cross, or dash based on status."""
61
+ match status.lower():
62
+ case "authorized":
63
+ return "✔"
64
+ case "unauthorized":
65
+ return "✖"
66
+ case "unknown" | "offline" | "unsupported":
67
+ return "–"
68
+ case _:
69
+ return "?"
70
+
71
+ print("============= Service Statuses ===============")
72
+ for key, value in status_dict.items():
73
+ if key == "llms" and isinstance(value, dict):
74
+ print(f"\n {key.upper()}:")
75
+ for llm_name, llm_status in value.items():
76
+ marker = get_marker(llm_status)
77
+ print(f" {llm_name:<12}: {llm_status:<15} {marker}")
78
+ else:
79
+ marker = get_marker(value)
80
+ print(f" {key:<12}: {value:<15} {marker}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: txt2detection
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: A command line tool that takes a txt file containing threat intelligence and turns it into a detection rule.
5
5
  Project-URL: Homepage, https://github.com/muchdogesec/txt2detection
6
6
  Project-URL: Issues, https://github.com/muchdogesec/txt2detection/issues
@@ -100,6 +100,30 @@ cp .env.example .env
100
100
 
101
101
  To see more information about how to set the variables, and what they do, read the `.env.markdown` file.
102
102
 
103
+ Then test your configoration
104
+
105
+ ```shell
106
+ python3 txt2detection.py \
107
+ check-credentials
108
+ ```
109
+
110
+ It will return a response to show what API keys are working
111
+
112
+ ```txt
113
+ ============= Service Statuses ===============
114
+ ctibutler : authorized ✔
115
+ vulmatch : authorized ✔
116
+
117
+ LLMS:
118
+ openai : authorized ✔
119
+ deepseek : unsupported –
120
+ gemini : unsupported –
121
+ openrouter : unsupported –
122
+ anthropic : unsupported –
123
+ ```
124
+
125
+ Not all services need to be configured, if you have no intention of using them.
126
+
103
127
  ### Run
104
128
 
105
129
  ```shell
@@ -1,12 +1,13 @@
1
1
  txt2detection/__init__.py,sha256=Fc460P0q_eb2u3Xc89z-fwl-4ai3jrPqPNVwJQYNkNQ,89
2
- txt2detection/__main__.py,sha256=Zvz1hZRSsdPONUnMPCpbImM3bXB2Qeq3d95dgztxLSA,8993
3
- txt2detection/bundler.py,sha256=l3MerTfDkcbiJg_GiovytlvGyY9ZunABuus-PngJB4g,10858
2
+ txt2detection/__main__.py,sha256=R9TgWWGzA8rxF39rZr2MNOrQubhItdRAgP2nd8Tfb78,9337
3
+ txt2detection/bundler.py,sha256=rIvVTlLEHu9SMPqy8AyLbiJ3Cg0WNq7uWvGIXGoaPsg,10822
4
+ txt2detection/credential_checker.py,sha256=YoOe1ABjNfAJIcNE6PRAZtvznTybUKHNBB57DPQhZsU,2564
4
5
  txt2detection/models.py,sha256=wDRL-Thme8XXuX1b850v_egTjL3mNYpdVmDvYwfzKI8,12000
5
6
  txt2detection/observables.py,sha256=NNnwF_gOsPmAbfgk5fj1rcluMsShZOHssAGy2VJgvmo,6763
6
7
  txt2detection/utils.py,sha256=wCol8_DBlvzJOV8VvjqvVR6FWWDQjmz8ItbxG8qbvnw,2755
7
8
  txt2detection/ai_extractor/__init__.py,sha256=itcwTF0-S80mx-SuSvfrKazvcwsojR-QsBN-UvnSDwE,418
8
9
  txt2detection/ai_extractor/anthropic.py,sha256=YOi2rHUeeoRMS4CFG6mX7xUU4q4rw9qNl72R74UN6ZM,420
9
- txt2detection/ai_extractor/base.py,sha256=2wskkhKaiGe2Lc1nJK1k3WMyGIIiP5DlFAkcui07h9s,2061
10
+ txt2detection/ai_extractor/base.py,sha256=urZe_kpYu3BwXyKJsQ0GQIEtTasUQYp4dFzuz34Hai8,2336
10
11
  txt2detection/ai_extractor/deepseek.py,sha256=2XehIYbWXG6Odq68nQX4CNtl5GdmBlAmjLP_lG2eEFo,660
11
12
  txt2detection/ai_extractor/gemini.py,sha256=hlcKkiHGzQJ0dQECfIhjx2LfdhZoquAF9POwz61RAhw,557
12
13
  txt2detection/ai_extractor/openai.py,sha256=e5Of3i-T2CvUSx1T_v7wHOuewHK2IoImxZXfXeZc3Ds,625
@@ -14,8 +15,8 @@ txt2detection/ai_extractor/openrouter.py,sha256=-KcdcyKPpaeiGfvqJB4L7vMmcXTDhml3
14
15
  txt2detection/ai_extractor/prompts.py,sha256=ACYFWUafdHXHBXz7fq_RSooA4PJ-mBdaBzqsOOSFpVg,5918
15
16
  txt2detection/ai_extractor/utils.py,sha256=SUxyPhkGp5yDbX_H_E018i93R8IbyLsQ00PIBDecfuc,540
16
17
  txt2detection/config/detection_languages.yaml,sha256=dgQUJPxhDRJ_IiFEFOiH0yhEer3SkFSIhY4pS3BsX2c,287
17
- txt2detection-1.0.2.dist-info/METADATA,sha256=0kzRkCRhivgHhCyNcNDD8bgiwqGYIlfDLkOJswYpeqk,13650
18
- txt2detection-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
- txt2detection-1.0.2.dist-info/entry_points.txt,sha256=ep_rLlS2r1-kKE7S3iKf3SVwbCU9-FZhU9zUebitw7A,62
20
- txt2detection-1.0.2.dist-info/licenses/LICENSE,sha256=BK8Ppqlc4pdgnNzIxnxde0taoQ1BgicdyqmBvMiNYgY,11364
21
- txt2detection-1.0.2.dist-info/RECORD,,
18
+ txt2detection-1.0.3.dist-info/METADATA,sha256=uObp1AT1iejmjazeIxZdB-EmY3tk087qnHxv-x1kj88,14213
19
+ txt2detection-1.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
+ txt2detection-1.0.3.dist-info/entry_points.txt,sha256=ep_rLlS2r1-kKE7S3iKf3SVwbCU9-FZhU9zUebitw7A,62
21
+ txt2detection-1.0.3.dist-info/licenses/LICENSE,sha256=BK8Ppqlc4pdgnNzIxnxde0taoQ1BgicdyqmBvMiNYgY,11364
22
+ txt2detection-1.0.3.dist-info/RECORD,,