Skip to content

Commit

Permalink
secrets: add hide patters, make it default, add readme, add example
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy Landy committed Feb 19, 2025
1 parent 8bd8d66 commit 8a02aa9
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 23 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![Example](https://raw.githubusercontent.com/andy-landy/traceback_with_variables/master/header.png)

<h2 align="center">Python Traceback (Error Message) Printing Variables</h2>
<p align="center">Very simple to use, but versatile when needed. Try for debug and keep for production.</p>
<p align="center">Very simple to use, but versatile when needed. Try for debug and keep for small-scale production.</p>

<p align="center">
<a href="https://github.com/andy-landy/traceback_with_variables/actions"><img alt="Actions Status" src="https://github.com/andy-landy/traceback_with_variables/workflows/tests/badge.svg"></a>
Expand Down Expand Up @@ -109,11 +109,12 @@ Using a logger [<a href="https://github.com/andy-landy/traceback_with_variables/

<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/format_customized.py">Customize</a> any of the previous examples:
```python
from traceback_with_variables import fmt
fmt.max_value_str_len = 10000
fmt.skip_files_except = 'my_project'
fmt.custom_var_printers = [] # show all variables, no skips, no hides
```


### Colors

![Example](https://raw.githubusercontent.com/andy-landy/traceback_with_variables/master/color_schemes.png)
Expand Down Expand Up @@ -247,8 +248,8 @@ Using a logger [<a href="https://github.com/andy-landy/traceback_with_variables/

* — Should I use it after debugging is over, i.e. *in production*?

Yes, of course! That way it might save you even more time (watch out for sensitive data
like passwords and tokens in you logs, use skip_files_except to hide code from libs AND custom_var_printers to hide own locals). Note: you can deploy more serious frameworks, e.g. `Sentry`
Yes, of course! That way it might save you even more time (<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/secret_data.py">watch out</a> for sensitive data
like <span style="color:red">passwords and tokens</span> in you logs). Note: you can deploy more serious monitoring frameworks, e.g. `Sentry`

<br/>

Expand Down Expand Up @@ -279,6 +280,7 @@ Using a logger [<a href="https://github.com/andy-landy/traceback_with_variables/
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/work_with_traceback_lines.py">get traceback lines for custom things</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/flask.py">using with `flask`</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/format_customized.py">customize the output</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/secret_data.py">passwords and tokens in logs</a>

### Reference

Expand Down
10 changes: 6 additions & 4 deletions README.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![Example]({{ content_url }}/header.png)

<h2 align="center">Python Traceback (Error Message) Printing Variables</h2>
<p align="center">Very simple to use, but versatile when needed. Try for debug and keep for production.</p>
<p align="center">Very simple to use, but versatile when needed. Try for debug and keep for small-scale production.</p>

<p align="center">
<a href="{{ repo_url }}/actions"><img alt="Actions Status" src="{{ repo_url }}/workflows/tests/badge.svg"></a>
Expand Down Expand Up @@ -109,11 +109,12 @@ Using a logger [<a href="{{ examples_code_url }}/log_for_function.py">with a dec

<a href="{{ examples_code_url }}/format_customized.py">Customize</a> any of the previous examples:
```python
from traceback_with_variables import fmt
fmt.max_value_str_len = 10000
fmt.skip_files_except = 'my_project'
fmt.custom_var_printers = [] # show all variables, no skips, no hides
```


### Colors

![Example]({{ content_url }}/color_schemes.png)
Expand Down Expand Up @@ -247,8 +248,8 @@ Using a logger [<a href="{{ examples_code_url }}/log_for_function.py">with a dec

* — Should I use it after debugging is over, i.e. *in production*?

Yes, of course! That way it might save you even more time (watch out for sensitive data
like passwords and tokens in you logs, use skip_files_except to hide code from libs AND custom_var_printers to hide own locals). Note: you can deploy more serious frameworks, e.g. `Sentry`
Yes, of course! That way it might save you even more time (<a href="{{ examples_code_url }}/secret_data.py">watch out</a> for sensitive data
like <span style="color:red">passwords and tokens</span> in you logs). Note: you can deploy more serious monitoring frameworks, e.g. `Sentry`

<br/>

Expand Down Expand Up @@ -279,6 +280,7 @@ Using a logger [<a href="{{ examples_code_url }}/log_for_function.py">with a dec
* <a href="{{ examples_code_url }}/work_with_traceback_lines.py">get traceback lines for custom things</a>
* <a href="{{ examples_code_url }}/flask.py">using with `flask`</a>
* <a href="{{ examples_code_url }}/format_customized.py">customize the output</a>
* <a href="{{ examples_code_url }}/secret_data.py">passwords and tokens in logs</a>

### Reference

Expand Down
14 changes: 9 additions & 5 deletions examples/format_customized.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from traceback_with_variables import Format, ColorSchemes, is_ipython_global, fmt, hide, skip


# approach 1
# approach 1 for simples usage

fmt.max_value_str_len = 10000

# show all vars, no hides, no skips:

# approach 2
fmt.custom_var_printers = []


# approach 2 for explicit format passing

fmt2 = Format(
before=3,
Expand All @@ -27,10 +31,10 @@
(['secret', dict, (lambda name, *_: 'asd' in name)], lambda v: '???'), # by different things, print const str
]
)
# print_exc(fmt=fmt2)
print_exc(fmt=fmt2)


# approach 3
# approach 3 for explicit format passing, less code

fmt3 = defaults.replace(max_value_str_len=10000)
# print_exc(fmt=fmt3)
print_exc(fmt=fmt3)
49 changes: 49 additions & 0 deletions examples/secret_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
When you deal with secrets like passwords or tokens any debug report system
puts you at risk of exposing those secrets.
Why? Some secrets are stored securely in databases and are kept decrypted only
for short time in memory while being used in code. So any traceback printout
will save them explicitly for you to read later.
Its not a huge problem if the secret is stored unencrypted, i.e. its your
(not users') secret and the machine is secure. User passwords are a problem.
How to prevent secret vars from being printed? You might
* correctly guess how the secret variables in your code are called
* hide the 3rd party well-established library code totally
It will look like this: some of variables in your code will have
"...hidden..." values, and all library files (where secret variables might go
with unrelated names like "s", "part", "msg" etc.) will be skipped totally.
Default settings include all frequent patters for your variables:
PATTERN_TO_HIDE = '.*(?i:pass|secret|token|key|api_key|cred|pwd)/*'
Which will hide a bit too much, names like "keyword" or "compassion". Address
examples below to fit the hiding.
To hide libraries address examples below, note that you can only allow code,
not deny it, so all 3rd party libraries will be hidden if you use this
setting.
"""

# simple tools usage, for more manual approach address format_customized.py


# hide all libraries except couple

from traceback_with_variables import fmt, hide
fmt.brief_files_except = ['.*my_project.*', '.*some_library_1.*', '.*some_library_2.*']


# show all variables

fmt.custom_var_printers = []


# hide variables differently

fmt.custom_var_printers = [
('.*(precious|ring).*', hide), # by name
(MySecret, hide), # by class
]
26 changes: 26 additions & 0 deletions tests/dumps/test_default_global_hooks.patterns_to_hide.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Traceback with variables (most recent call last):
File "...omitted for tests only.../test_default_global_hooks.py", line...omitted for tests only..., in check
f()
tb_reg = <bound method Reg.match_tb_text of <tests.test_utils.Reg object at 0x...omitted for tests only...>>
fmt = traceback_with_variables.core.Format(after=0, before=0, brief_files_except=[], color_scheme=None, custom_var_printers=[(<function _var_filter_to_should_print.<locals>.should_print at 0x...omitted for tests only...>, <function hide at 0x...omitted for tests only...>)], ellipsis_='...', ellipsis_rel_pos=0.7, max_exc_str_len=10000, max_value_str_len=1000, objects_details=1, skip_files_except=[])
File "...omitted for tests only.../test_default_global_hooks.py", line...omitted for tests only..., in f
return f(n - 1)
n = 1
money = '1000'
password = ...hidden...
secret_word = ...hidden...
monkey_species = ...hidden...
my_pAssWOrd_2 = ...hidden...
mySecretN = ...hidden...
card_number = '1234 5678 1234 5678'
File "...omitted for tests only.../test_default_global_hooks.py", line...omitted for tests only..., in f
raise ValueError('planned exception')
n = 0
money = '1000'
password = ...hidden...
secret_word = ...hidden...
monkey_species = ...hidden...
my_pAssWOrd_2 = ...hidden...
mySecretN = ...hidden...
card_number = '1234 5678 1234 5678'
builtins.ValueError: planned exception
31 changes: 31 additions & 0 deletions tests/test_default_global_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest

from traceback_with_variables import fmt, format_exc

from tests.test_utils import tb_reg


def f(n = 1):
money = '1000'
password = 'qwerty'
secret_word = 'please'
monkey_species = 'gorilla'
my_pAssWOrd_2 = 'qwerty'
mySecretN = 5
card_number = '1234 5678 1234 5678'

if n > 0:
return f(n - 1)

raise ValueError('planned exception')


def check(tb_reg, fmt):
try:
f()
except Exception: # noqa
tb_reg(format_exc(fmt=fmt))


def test_patterns_to_hide(tb_reg):
check(tb_reg, fmt)
18 changes: 11 additions & 7 deletions traceback_with_variables/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
from traceback_with_variables.fast_capped_str_casts import to_capped_str


Patterns = Union[None, str, List[str]]
Print = Callable[[Any], Optional[str]]
ShouldPrint = Callable[[str, Type, str, bool], bool]
VarFilterItem = Union[str, Type, ShouldPrint]
VarFilter = Union[VarFilterItem, List[VarFilterItem]]
VarPrinters = List[Tuple[ShouldPrint, Print]]
Patterns = Union[None, str, List[str]] # file filter

ShouldPrint = Callable[[str, Type, str, bool], bool] # extended var filter
VarFilterItem = Union[str, Type, ShouldPrint] # any var filter
VarFilter = Union[VarFilterItem, List[VarFilterItem]] # full final var filter

Print = Callable[[Any], Optional[str]] # how to print
VarPrinters = List[Tuple[ShouldPrint, Print]] # pairs for filters and printers


def skip(obj: Any) -> Optional[str]: # noqa: U100
Expand Down Expand Up @@ -329,4 +331,6 @@ def should_print(name: str, type_: Type, file: str, is_global: bool) -> bool:
return should_print


default_format = Format()
default_format = Format(custom_var_printers=[
('.*(?i:pass|secret|token|key|api_key|cred|pwd).*', hide),
])
20 changes: 17 additions & 3 deletions traceback_with_variables/default_global_hooks.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
from traceback_with_variables.color import ColorSchemes
from traceback_with_variables.global_hooks import global_print_exc_in_ipython, global_print_exc, is_ipython_global, in_ipython
from traceback_with_variables.core import (
hide,
show,
skip,
)
from traceback_with_variables.global_hooks import (
global_print_exc_in_ipython,
global_print_exc,
is_ipython_global,
in_ipython,
)
from traceback_with_variables import default_format


def default_global_print_exc():
default_format.custom_var_printers = [((lambda n, t, fn, is_global: is_global), lambda v: None)] # noqa: U100
default_format.custom_var_printers += [
((lambda n, t, fn, is_global: is_global), skip), # noqa: U100
]
global_print_exc()


def default_global_print_exc_in_ipython():
default_format.custom_var_printers = [(is_ipython_global, lambda v: None)] # noqa: U100
default_format.custom_var_printers += [
(is_ipython_global, skip),
]
default_format.color_scheme = ColorSchemes.common
global_print_exc_in_ipython()

Expand Down

0 comments on commit 8a02aa9

Please sign in to comment.