Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Processing rule-patterns from default configuration files #482

Merged
merged 1 commit into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Features:
* [#479](https://github.com/godaddy/tartufo/pull/479) - Remove upward traversal logic for config discovery

Bug fixes:
* [#482](https://github.com/godaddy/tartufo/pull/482) - Code updates to process rule-patterns set up in the target's default config file i.e. tartufo.toml or pyproject.toml
* [#467](https://github.com/godaddy/tartufo/issues/467) - Multiple fixes to configuration
file processing:
- If multiple configuration files were specified, only the last was processed
Expand Down
24 changes: 23 additions & 1 deletion tartufo/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class ScannerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
logger: logging.Logger
_scan_lock: threading.Lock = threading.Lock()
_excluded_signatures: Optional[Tuple[str, ...]] = None
_rule_patterns: Optional[Iterable[Dict[str, str]]] = None
_config_data: MutableMapping[str, Any] = {}
_issue_list: List[Issue] = []
_issue_file: Optional[IO] = None
Expand Down Expand Up @@ -333,7 +334,7 @@ def rules_regexes(self) -> Set[Rule]:
try:
self._rules_regexes = config.configure_regexes(
include_default=self.global_options.default_regexes,
rule_patterns=self.global_options.rule_patterns,
rule_patterns=self.rule_patterns,
rules_repo=self.global_options.git_rules_repo,
rules_repo_files=self.global_options.git_rules_files,
)
Expand Down Expand Up @@ -372,6 +373,27 @@ def should_scan(self, file_path: str) -> bool:
return False
return True

@cached_property
def rule_patterns(self) -> Optional[Iterable[Dict[str, str]]]:
"""Get a list of patterns to the to search in the target repository or folder being scanned

:returns: The regular expression patterns to searched in the target
@return:
"""
if self._rule_patterns is None:
rules: List[Dict[str, str]] = []
for rule in tuple(self.global_options.rule_patterns or []) + tuple(
self.config_data.get("rule_patterns", [])
):
if isinstance(rule, dict):
rules.append(rule)
else:
raise types.ConfigException(
f"{type(rule).__name__} pattern is illegal in rule-patterns"
)
self._rule_patterns = rules
return self._rule_patterns

@cached_property
def excluded_signatures(self) -> Tuple[str, ...]:
"""Get a list of the signatures of findings to be excluded from the scan results.
Expand Down
39 changes: 38 additions & 1 deletion tests/test_base_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,10 @@ def test_populated_regex_list_does_not_recompute(self):

def test_regex_rules_are_computed_when_first_accessed(self):
self.options.default_regexes = True
self.options.rule_patterns = "oof" # type: ignore
self.options.git_rules_repo = "bar"
self.options.git_rules_files = "baz" # type: ignore
test_scanner = TestScanner(self.options)
test_scanner._rule_patterns = "oof" # pylint: disable=protected-access
test_scanner.rules_regexes # pylint: disable=pointless-statement
self.mock_configure.assert_called_once_with(
include_default=True,
Expand All @@ -283,6 +283,43 @@ def test_regex_rules_are_computed_when_first_accessed(self):
rules_repo_files="baz",
)

def test_rule_patterns_with_rules_in_default_config(self):
rule_patterns = [
{
"reason": "RSA private key 2",
"pattern": "-----BEGIN default PRIVATE KEY-----",
}
]
self.options.rule_patterns = []
test_scanner = TestScanner(self.options)
test_scanner.config_data = {"rule_patterns": rule_patterns}
self.assertEqual(test_scanner.rule_patterns, rule_patterns)

def test_rule_patterns_with_rules_in_custom_config(self):
rule_patterns = [
{
"reason": "RSA private key 2",
"pattern": "-----BEGIN default PRIVATE KEY-----",
}
]
self.options.rule_patterns = rule_patterns
test_scanner = TestScanner(self.options)
test_scanner.config_data = {}
self.assertEqual(test_scanner.rule_patterns, rule_patterns)

def test_rule_patterns_with_rule_patterns_syntax_issue(self):
rule_patterns = {
"reason": "RSA private key 2",
"pattern": "-----BEGIN default PRIVATE KEY-----",
}
self.options.rule_patterns = rule_patterns
test_scanner = TestScanner(self.options)
test_scanner.config_data = {}
with self.assertRaisesRegex(
types.ConfigException, "str pattern is illegal in rule-patterns"
):
test_scanner.rule_patterns # pylint: disable=pointless-statement


class SignatureTests(ScannerTestCase):
@mock.patch("tartufo.util.generate_signature")
Expand Down