diff --git a/socorro/signature/generator.py b/socorro/signature/generator.py index 258f3d9117..84dd92dabe 100644 --- a/socorro/signature/generator.py +++ b/socorro/signature/generator.py @@ -18,6 +18,7 @@ SignatureIPCMessageName, SignatureRunWatchDog, SignatureShutdownTimeout, + SigPrintableCharsOnly, SigTruncate, StackOverflowSignature, StackwalkerErrorSignatureRule, @@ -37,6 +38,7 @@ StackOverflowSignature, HungProcess, # NOTE(willkg): These should always come last and in this order + SigPrintableCharsOnly, SigFixWhitespace, SigTruncate, ] diff --git a/socorro/signature/rules.py b/socorro/signature/rules.py index 007e23fe4f..9fca7aebe3 100644 --- a/socorro/signature/rules.py +++ b/socorro/signature/rules.py @@ -918,6 +918,20 @@ def action(self, crash_data, result): return True +class SigPrintableCharsOnly(Rule): + """Remove non-printable characters from signature.""" + + def action(self, crash_data, result): + original_sig = result.signature + sig = "".join( + [c for c in original_sig.strip() if c.isascii() and c.isprintable()] + ) + if sig != original_sig: + result.set_signature(self.name, sig) + result.info(self.name, "unprintable characters removed") + return True + + class SigFixWhitespace(Rule): """Fix whitespace in signatures. diff --git a/socorro/signature/tests/test_rules.py b/socorro/signature/tests/test_rules.py index 9a48175534..eaf82b0f09 100644 --- a/socorro/signature/tests/test_rules.py +++ b/socorro/signature/tests/test_rules.py @@ -1718,6 +1718,30 @@ def test_action_non_ascii_abort_message(self): assert result.signature == "Abort | unknown | hello" +class TestSigPrintableCharsOnly: + @pytest.mark.parametrize( + "signature, expected", + [ + ("everything | fine", "everything | fine"), + # Non-printable null character + ("libxul.so\x00 | frame2", "libxul.so | frame2"), + # Non-ascii emoji + ("libxul.so\U0001f600 | frame2", "libxul.so | frame2"), + ], + ) + def test_whitespace_fixing(self, signature, expected): + rule = rules.SigPrintableCharsOnly() + result = generator.Result() + result.signature = signature + action_result = rule.action({}, result) + assert action_result is True + assert result.signature == expected + if signature != expected: + assert result.notes == [ + "SigPrintableCharsOnly: unprintable characters removed" + ] + + class TestSigFixWhitespace: @pytest.mark.parametrize( "signature, expected",