mirror of
https://github.com/data-privacy-stack/presidio.git
synced 2026-09-21 05:27:53 -05:00
* fix(cli): make --no-warnings, the exit code and -f github work PIIProblem never got the `level` attribute that show_problems() reads for --no-warnings, so the flag crashed with AttributeError as soon as a file had a finding. Findings now have level "error" (score 1.0) or "warning", the same split the colored output already used. show_problems() always returned 0 and run() overwrote its result for every file, so the CLI exited with 0 even when it reported PII. show_problems() now returns the number of findings it printed and run() adds them up, so the exit code is 1 when any finding is reported. -f github printed `::<score> file=...`, which is not a workflow command, so GitHub Actions never created annotations. It now prints ::warning and ::error commands with escaped property values and message, and drops the ./ prefix that `presidio .` adds to file paths. The problems test fixture used Mock objects, which create any attribute on access and so hid the missing `level`; it now builds real PIIProblem objects. * fix(cli): validate the threshold read from the config file PresidioCLIConfig.parse() range-checked the current threshold (the default 0) instead of the configured value, and only converted the configured value afterwards. `threshold: 5` was accepted and filtered out every finding, and `threshold: abc` raised an uncaught ValueError. The configured value is now converted and range-checked before it is stored, and invalid values raise PresidioCLIConfigError. This also covers YAML booleans such as `true`, which float() would accept as 1.0, and integers too large for a float.
91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
import os
|
|
import pytest
|
|
|
|
from presidio_cli import config
|
|
|
|
|
|
def test_parse_config():
|
|
new = config.PresidioCLIConfig(
|
|
"entities:\n" " - PERSON\n" " - IP_ADDRESS\n" " - CREDIT_CARD\n" "threshold: 1.0\n" "locale: en_US.UTF-8\n"
|
|
)
|
|
|
|
assert new.entities == ["PERSON", "IP_ADDRESS", "CREDIT_CARD"]
|
|
|
|
|
|
def test_invalid_conf():
|
|
with pytest.raises(config.PresidioCLIConfigError):
|
|
config.PresidioCLIConfig("not: valid: yaml")
|
|
|
|
|
|
def test_invalid_extend_conf(temp_workspace):
|
|
with open(os.path.join(temp_workspace, "notvalid.yml"), "w") as f:
|
|
f.write("not: valid: yaml")
|
|
with pytest.raises(config.PresidioCLIConfigError):
|
|
config.PresidioCLIConfig(os.path.join(temp_workspace, "notvalid.yml"))
|
|
|
|
|
|
def test_not_dict():
|
|
with pytest.raises(config.PresidioCLIConfigError):
|
|
config.PresidioCLIConfig("example")
|
|
|
|
|
|
def test_unknown_entity():
|
|
with pytest.raises(config.PresidioCLIConfigError) as excinfo:
|
|
config.PresidioCLIConfig("entities:\n" " - NOTEXISTS\n")
|
|
assert "invalid config: no such entity NOTEXISTS" in str(excinfo.value)
|
|
|
|
|
|
def test_is_file(temp_workspace, config):
|
|
for f in [
|
|
os.path.join(temp_workspace, "empty.txt"),
|
|
os.path.join(temp_workspace, "sub", "directory.txt", "empty.txt"),
|
|
os.path.join(temp_workspace, "non-ascii", "éçäγλνπ¥", "utf-8"),
|
|
os.path.join(temp_workspace, "dos.yml"),
|
|
os.path.join(temp_workspace, *["s"] * 15, "file"),
|
|
]:
|
|
assert config.is_text_file(f)
|
|
|
|
assert not config.is_text_file(os.path.join(temp_workspace, "binary_file"))
|
|
|
|
|
|
def test_invalid_value(temp_workspace):
|
|
with pytest.raises(config.PresidioCLIConfigError):
|
|
config.PresidioCLIConfig("ignore: 1\n")
|
|
|
|
with pytest.raises(config.PresidioCLIConfigError):
|
|
config.PresidioCLIConfig("locale: 1\n")
|
|
|
|
|
|
def test_run_with_ignored_path(temp_workspace):
|
|
new = config.PresidioCLIConfig("ignore: |\n" " .git\n" " s/*\n" " dos.yml\n")
|
|
assert new.is_file_ignored("./dos.yml")
|
|
assert new.is_file_ignored("./.git/hooks/README.sample")
|
|
assert not new.is_file_ignored("notignored")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("value", "message"),
|
|
[
|
|
("5", "Invalid threshold value: 5. Threshold must be between 0 and 1"),
|
|
("-0.1", "Invalid threshold value: -0.1. Threshold must be between 0 and 1"),
|
|
(".nan", "Invalid threshold value: nan. Threshold must be between 0 and 1"),
|
|
("abc", "Invalid threshold value: abc. Threshold must be a number"),
|
|
("[]", "Invalid threshold value: []. Threshold must be a number"),
|
|
("true", "Invalid threshold value: True. Threshold must be a number"),
|
|
pytest.param(
|
|
"1" + "0" * 400,
|
|
f"Invalid threshold value: 1{'0' * 400}. Threshold must be a number",
|
|
id="int-too-large-for-float",
|
|
),
|
|
],
|
|
)
|
|
def test_invalid_threshold_raises_config_error(value, message):
|
|
with pytest.raises(config.PresidioCLIConfigError) as excinfo:
|
|
config.PresidioCLIConfig(f"threshold: {value}\n")
|
|
assert str(excinfo.value) == message
|
|
|
|
|
|
@pytest.mark.parametrize(("value", "expected"), [("0", 0.0), ("0.7", 0.7), ("1", 1.0)])
|
|
def test_threshold_is_read_from_config(value, expected):
|
|
assert config.PresidioCLIConfig(f"threshold: {value}\n").threshold == expected
|