From 0e35acaef548695f28a944c706d757dcec9804b4 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 21 Sep 2025 13:21:40 -0700 Subject: [PATCH] Fix: add extra error handling to _consume for file checks (#10897) --- .../management/commands/document_consumer.py | 14 ++++++++++++- .../tests/test_management_consumer.py | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/documents/management/commands/document_consumer.py b/src/documents/management/commands/document_consumer.py index 35d79288e..97027e02d 100644 --- a/src/documents/management/commands/document_consumer.py +++ b/src/documents/management/commands/document_consumer.py @@ -82,6 +82,13 @@ def _is_ignored(filepath: Path) -> bool: def _consume(filepath: Path) -> None: + # Check permissions early + try: + filepath.stat() + except (PermissionError, OSError): + logger.warning(f"Not consuming file {filepath}: Permission denied.") + return + if filepath.is_dir() or _is_ignored(filepath): return @@ -323,7 +330,12 @@ class Command(BaseCommand): # Also make sure the file exists still, some scanners might write a # temporary file first - file_still_exists = filepath.exists() and filepath.is_file() + try: + file_still_exists = filepath.exists() and filepath.is_file() + except (PermissionError, OSError): # pragma: no cover + # If we can't check, let it fail in the _consume function + file_still_exists = True + continue if waited_long_enough and file_still_exists: _consume(filepath) diff --git a/src/documents/tests/test_management_consumer.py b/src/documents/tests/test_management_consumer.py index 821fd82e0..38b9eadda 100644 --- a/src/documents/tests/test_management_consumer.py +++ b/src/documents/tests/test_management_consumer.py @@ -209,6 +209,26 @@ class TestConsumer(DirectoriesMixin, ConsumerThreadMixin, TransactionTestCase): # assert that we have an error logged with this invalid file. error_logger.assert_called_once() + @mock.patch("documents.management.commands.document_consumer.logger.warning") + def test_permission_error_on_prechecks(self, warning_logger): + filepath = Path(self.dirs.consumption_dir) / "selinux.txt" + filepath.touch() + + original_stat = Path.stat + + def raising_stat(self, *args, **kwargs): + if self == filepath: + raise PermissionError("Permission denied") + return original_stat(self, *args, **kwargs) + + with mock.patch("pathlib.Path.stat", new=raising_stat): + document_consumer._consume(filepath) + + warning_logger.assert_called_once() + (args, _) = warning_logger.call_args + self.assertIn("Permission denied", args[0]) + self.consume_file_mock.assert_not_called() + @override_settings(CONSUMPTION_DIR="does_not_exist") def test_consumption_directory_invalid(self): self.assertRaises(CommandError, call_command, "document_consumer", "--oneshot")