t-bug-catcher 0.4.0__tar.gz → 0.4.1__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 (27) hide show
  1. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/PKG-INFO +1 -1
  2. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/setup.cfg +1 -1
  3. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/setup.py +3 -1
  4. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/__init__.py +1 -1
  5. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/config.py +1 -0
  6. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/jira.py +5 -5
  7. t_bug_catcher-0.4.1/t_bug_catcher/resources/whispers_config.yml +44 -0
  8. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/stack_saver.py +24 -29
  9. t_bug_catcher-0.4.1/t_bug_catcher/utils/common.py +41 -0
  10. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher.egg-info/PKG-INFO +1 -1
  11. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher.egg-info/SOURCES.txt +1 -0
  12. t_bug_catcher-0.4.0/t_bug_catcher/utils/common.py +0 -17
  13. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/MANIFEST.in +0 -0
  14. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/README.rst +0 -0
  15. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/pyproject.toml +0 -0
  16. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/requirements.txt +0 -0
  17. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/bug_catcher.py +0 -0
  18. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/bug_snag.py +0 -0
  19. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/exceptions.py +0 -0
  20. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/utils/__init__.py +0 -0
  21. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/utils/logger.py +0 -0
  22. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher/workitems.py +0 -0
  23. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
  24. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher.egg-info/not-zip-safe +0 -0
  25. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher.egg-info/requires.txt +0 -0
  26. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/t_bug_catcher.egg-info/top_level.txt +0 -0
  27. {t_bug_catcher-0.4.0 → t_bug_catcher-0.4.1}/tests/test_t_bug_catcher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.4.0
2
+ current_version = 0.4.1
3
3
  commit = True
4
4
  tag = False
5
5
 
@@ -26,7 +26,9 @@ setup(
26
26
  packages=find_packages(include=["t_bug_catcher", "t_bug_catcher.*"]),
27
27
  test_suite="tests",
28
28
  url="https://www.thoughtful.ai/",
29
- version="0.4.0",
29
+ version="0.4.1",
30
30
  zip_safe=False,
31
31
  install_requires=install_requirements,
32
+ include_package_data=True,
33
+ package_data={"": ["resources/*.yml"]},
32
34
  )
@@ -3,7 +3,7 @@
3
3
  __author__ = """Thoughtful"""
4
4
  __email__ = "support@thoughtful.ai"
5
5
  # fmt: off
6
- __version__ = '0.4.0'
6
+ __version__ = '0.4.1'
7
7
  # fmt: on
8
8
 
9
9
  from .bug_catcher import (
@@ -13,6 +13,7 @@ class Config:
13
13
  MAX_ISSUE_ATTACHMENTS: int = 100
14
14
  MAX_DESCRIPTION_LENGTH: int = 250
15
15
  SUMMARY_LENGTH: int = 120
16
+ STACK_SCOPE: int = 3
16
17
 
17
18
  SUPPORT_BOARD = "AB"
18
19
 
@@ -1,12 +1,12 @@
1
1
  """JiraPoster class for interacting with the Jira API."""
2
2
 
3
- import datetime
4
3
  import hashlib
5
4
  import json
6
5
  import os
7
6
  import re
8
7
  import sys
9
8
  import traceback
9
+ from datetime import datetime
10
10
  from importlib.metadata import version
11
11
  from pathlib import Path
12
12
  from types import TracebackType
@@ -19,7 +19,7 @@ from retry import retry
19
19
  from .config import CONFIG
20
20
  from .exceptions import BadRequestError
21
21
  from .utils import logger
22
- from .utils.common import get_frames
22
+ from .utils.common import Encoder, get_frames
23
23
  from .workitems import variables
24
24
 
25
25
 
@@ -389,7 +389,7 @@ class Jira:
389
389
  },
390
390
  {
391
391
  "type": "text",
392
- "text": str(datetime.datetime.now().strftime("%B %d, %Y %I:%M:%S %p")),
392
+ "text": str(datetime.now().strftime("%B %d, %Y %I:%M:%S %p")),
393
393
  },
394
394
  ],
395
395
  }
@@ -521,7 +521,7 @@ class Jira:
521
521
  "content": [
522
522
  {
523
523
  "type": "text",
524
- "text": json.dumps(metadata, indent=4),
524
+ "text": json.dumps(metadata, indent=4, cls=Encoder),
525
525
  }
526
526
  ],
527
527
  },
@@ -735,7 +735,7 @@ class Jira:
735
735
  date_markup = [
736
736
  {
737
737
  "type": "text",
738
- "text": f" at {str(datetime.datetime.now().strftime('%B %d, %Y %I:%M:%S %p'))}",
738
+ "text": f" at {str(datetime.now().strftime('%B %d, %Y %I:%M:%S %p'))}",
739
739
  },
740
740
  {"type": "hardBreak"},
741
741
  ]
@@ -0,0 +1,44 @@
1
+ include:
2
+ files:
3
+ - "**/*"
4
+ rules:
5
+ - password
6
+ - uri
7
+ - secret
8
+ - webhook
9
+ - apikey
10
+ - apikey-known
11
+ - apikey-maybe
12
+ - id: username
13
+ group: misc
14
+ description: Variable names refering to user
15
+ message: Secret
16
+ severity: Low
17
+ key:
18
+ regex: ^\S*(user(name?)|login|id|uid|otp)_?(hash)?[0-9]*$
19
+ ignorecase: True
20
+ value:
21
+ minlen: 1
22
+ severity:
23
+ - Critical
24
+ - High
25
+ - Medium
26
+
27
+ exclude:
28
+ files:
29
+ - __pycache__|\.eggs|build|dev|\.vscode|\.git
30
+ - .*/(locale|spec|test|mock)s?/
31
+ - integration|node_modules
32
+ - (package(-lock)?|npm-shrinkwrap)\.json
33
+
34
+ keys:
35
+ - .*(public|project).*
36
+
37
+ values:
38
+ - ^(true|false|yes|no|1|0)$
39
+ - .*_(user|password|token|key|placeholder|name)$
40
+ - ^aws_(access_key_id|secret_access_key|session_token)$
41
+ - ^((cn?trl|alt|shift|del|ins|esc|tab|f[\d]+) ?[\+_\-\\/] ?)+[\w]+$
42
+
43
+
44
+
@@ -4,35 +4,15 @@ import os
4
4
  import re
5
5
  import sys
6
6
  from datetime import datetime
7
- from json import JSONEncoder
8
7
  from pathlib import Path
9
8
  from types import FunctionType, ModuleType
10
9
  from typing import Optional
11
10
 
12
11
  import whispers
13
12
 
13
+ from .config import CONFIG
14
14
  from .utils import logger
15
-
16
-
17
- class _Encoder(JSONEncoder):
18
- """Encoder class for encoding the Episode object to json."""
19
-
20
- def default(self, o):
21
- """This method is used to encode the Episode object to json.
22
-
23
- Args:
24
- o (object): The object to be encoded.
25
-
26
- Returns:
27
- str: The json string.
28
- """
29
- if hasattr(o, "__dict__"):
30
- return o.__dict__
31
- if isinstance(o, datetime):
32
- return o.isoformat()
33
- if isinstance(o, Path):
34
- return str(o)
35
- return JSONEncoder.default(self, o)
15
+ from .utils.common import Encoder
36
16
 
37
17
 
38
18
  class StackSaver:
@@ -68,11 +48,15 @@ class StackSaver:
68
48
  run_args = {}
69
49
  if frame_info["locals"]:
70
50
  for key, value in frame_info["locals"].items():
51
+ if str(key).lower() == "credentials":
52
+ continue
71
53
  if isinstance(value, dict):
72
54
  run_locals[str(key)] = value
73
55
  else:
74
56
  run_locals[str(key)] = str(value)
75
57
  for key, value in frame_info["args"].items():
58
+ if str(key).lower() == "credentials":
59
+ continue
76
60
  if isinstance(value, dict):
77
61
  run_args[str(key)] = value
78
62
  else:
@@ -122,19 +106,30 @@ class StackSaver:
122
106
  with open(file_path, "r") as f:
123
107
  filedata = f.readlines()
124
108
 
125
- secrets = [secret for secret in whispers.secrets(file_path)]
109
+ config_path = Path(__file__).parent.resolve().as_posix() + "/resources/whispers_config.yml"
110
+
111
+ args = f"-c {config_path} {file_path}"
112
+
113
+ secrets = [secret for secret in whispers.secrets(args)]
114
+ unique_secrets = []
115
+ seen = set()
116
+ for secret in secrets:
117
+ item = (secret.key, secret.value, secret.line)
118
+ if item not in seen:
119
+ seen.add(item)
120
+ unique_secrets.append(secret)
126
121
 
127
122
  for index, line in enumerate(filedata):
128
- if not secrets:
123
+ if not unique_secrets:
129
124
  break
130
125
 
131
- for secret in secrets:
126
+ for secret in unique_secrets:
132
127
  if secret.key in line and secret.value in line:
133
128
  filedata[index] = line.replace(secret.value, secret.value[:1] + "***")
134
- secrets.pop(secrets.index(secret))
129
+ unique_secrets.pop(unique_secrets.index(secret))
135
130
  break
136
131
 
137
- if secrets:
132
+ if unique_secrets:
138
133
  logger.warning("Failed to mask credentials")
139
134
  os.remove(file_path)
140
135
  raise Exception("Failed to mask credentials")
@@ -162,7 +157,7 @@ class StackSaver:
162
157
  continue
163
158
  frames.append(frame)
164
159
  tb = tb.tb_next
165
- frames = frames[:3]
160
+ frames = frames[: CONFIG.LIMITS.STACK_SCOPE]
166
161
 
167
162
  for frame in frames:
168
163
  frame_info = {
@@ -176,7 +171,7 @@ class StackSaver:
176
171
  file_path = f"stack_details_{datetime.now().strftime('%Y%m%d%H%M%S')}.json"
177
172
 
178
173
  with open(file_path, "w") as f:
179
- json.dump(stack_details_json, f, indent=4, cls=_Encoder)
174
+ json.dump(stack_details_json, f, indent=4, cls=Encoder)
180
175
 
181
176
  self.mask_credentials(file_path)
182
177
 
@@ -0,0 +1,41 @@
1
+ import traceback
2
+ from datetime import date, datetime
3
+ from json import JSONEncoder
4
+ from pathlib import Path
5
+ from types import TracebackType
6
+ from typing import List
7
+
8
+
9
+ class Encoder(JSONEncoder):
10
+ """This class is used to encode the Episode object to json."""
11
+
12
+ def default(self, o):
13
+ """This method is used to encode the Episode object to json.
14
+
15
+ Args:
16
+ o (object): The object to be encoded.
17
+
18
+ Returns:
19
+ str: The json string.
20
+ """
21
+ if hasattr(o, "__dict__"):
22
+ return o.__dict__
23
+ if isinstance(o, (datetime, date)):
24
+ return o.isoformat()
25
+ if isinstance(o, Path):
26
+ return str(o)
27
+ return JSONEncoder.default(self, o)
28
+
29
+
30
+ def get_frames(exc_traceback: TracebackType) -> List:
31
+ """Get the frames of the exception.
32
+
33
+ Args:
34
+ exc_traceback (TracebackType): The traceback of the exception.
35
+
36
+ Returns:
37
+ List: The frames of the exception.
38
+ """
39
+ return [
40
+ frame for frame in traceback.extract_tb(exc_traceback) if "site-packages" not in str(frame.filename).lower()
41
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
@@ -18,6 +18,7 @@ t_bug_catcher.egg-info/dependency_links.txt
18
18
  t_bug_catcher.egg-info/not-zip-safe
19
19
  t_bug_catcher.egg-info/requires.txt
20
20
  t_bug_catcher.egg-info/top_level.txt
21
+ t_bug_catcher/resources/whispers_config.yml
21
22
  t_bug_catcher/utils/__init__.py
22
23
  t_bug_catcher/utils/common.py
23
24
  t_bug_catcher/utils/logger.py
@@ -1,17 +0,0 @@
1
- import traceback
2
- from types import TracebackType
3
- from typing import List
4
-
5
-
6
- def get_frames(exc_traceback: TracebackType) -> List:
7
- """Get the frames of the exception.
8
-
9
- Args:
10
- exc_traceback (TracebackType): The traceback of the exception.
11
-
12
- Returns:
13
- List: The frames of the exception.
14
- """
15
- return [
16
- frame for frame in traceback.extract_tb(exc_traceback) if "site-packages" not in str(frame.filename).lower()
17
- ]
File without changes
File without changes