diff --git a/docs/configuration.md b/docs/configuration.md index 3257a815c..b42397da1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1315,29 +1315,19 @@ valid crontab(5) expression describing when to run. #### [`PAPERLESS_CONVERT_MEMORY_LIMIT=`](#PAPERLESS_CONVERT_MEMORY_LIMIT) {#PAPERLESS_CONVERT_MEMORY_LIMIT} -: On smaller systems, or even in the case of Very Large Documents, the -consumer may explode, complaining about how it's "unable to extend -pixel cache". In such cases, try setting this to a reasonably low -value, like 32. The default is to use whatever is necessary to do -everything without writing to disk, and units are in megabytes. +!!! warning - For more information on how to use this value, you should search the - web for "MAGICK_MEMORY_LIMIT". - - Defaults to 0, which disables the limit. + This option is deprecated and has no effect. It only applied to PDF + thumbnail generation via ImageMagick, which no longer happens. It will be + removed in a future release and can be removed from your configuration now. #### [`PAPERLESS_CONVERT_TMPDIR=`](#PAPERLESS_CONVERT_TMPDIR) {#PAPERLESS_CONVERT_TMPDIR} -: Similar to the memory limit, if you've got a small system and your -OS mounts /tmp as tmpfs, you should set this to a path that's on a -physical disk, like /home/your_user/tmp or something. ImageMagick -will use this as scratch space when crunching through very large -documents. +!!! warning - For more information on how to use this value, you should search the - web for "MAGICK_TMPDIR". - - Default is none, which disables the temporary directory. + This option is deprecated and has no effect. It only applied to PDF + thumbnail generation via ImageMagick, which no longer happens. It will be + removed in a future release and can be removed from your configuration now. #### [`PAPERLESS_APPS=`](#PAPERLESS_APPS) {#PAPERLESS_APPS} diff --git a/docs/setup.md b/docs/setup.md index 206e3107a..ba6e90af3 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -177,7 +177,7 @@ to a positive number to enable polling and disable native filesystem notificatio - `pkg-config` for mysqlclient (python dependency) - `fonts-liberation` for generating thumbnails for plain text files - - `imagemagick` >= 6 for PDF conversion + - `imagemagick` >= 6 for image alpha handling - `gnupg` for decrypting GPG-encrypted email - `libpq-dev` for PostgreSQL - `libmagic-dev` for mime type detection @@ -416,11 +416,11 @@ to a positive number to enable polling and disable native filesystem notificatio You may need to change the path in the files. Example: `ExecStart=/opt/paperless/.local/bin/celery --app paperless worker --loglevel INFO` -12. Configure ImageMagick to allow processing of PDF documents and disable - formats that Paperless-ngx does not use. Most distributions disable PDF - processing by default, since PDF documents can contain malware. - Paperless-ngx no longer passes PDF documents to ImageMagick, so enabling - PDF processing is not required. +12. Harden ImageMagick by disabling formats that Paperless-ngx does not use. + Most distributions disable PDF processing by default, since PDF documents + can contain malware. Paperless-ngx no longer passes PDF documents to + ImageMagick, so enabling PDF processing is not required and should be left + disabled. Configure the active ImageMagick policy file (commonly `/etc/ImageMagick-6/policy.xml` or `/etc/ImageMagick-7/policy.xml`) and diff --git a/paperless.conf.example b/paperless.conf.example index e2cedf63c..740bc9429 100644 --- a/paperless.conf.example +++ b/paperless.conf.example @@ -50,8 +50,6 @@ PAPERLESS_SECRET_KEY=change-me #PAPERLESS_OCR_ROTATE_PAGES=true #PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD=12.0 #PAPERLESS_OCR_USER_ARGS={} -#PAPERLESS_CONVERT_MEMORY_LIMIT=0 -#PAPERLESS_CONVERT_TMPDIR=/var/tmp/paperless # Software tweaks diff --git a/src/paperless/checks.py b/src/paperless/checks.py index 5d9da91c4..ba94eb266 100644 --- a/src/paperless/checks.py +++ b/src/paperless/checks.py @@ -337,6 +337,37 @@ def check_deprecated_v2_ocr_env_vars( return warnings +DEPRECATED_CONVERT_ENV_VARS: dict[str, str] = { + "PAPERLESS_CONVERT_MEMORY_LIMIT": "paperless.W004", + "PAPERLESS_CONVERT_TMPDIR": "paperless.W005", +} + + +@register() +def check_deprecated_convert_env_vars( + app_configs: object, + **kwargs: object, +) -> list[Warning]: + """Warn when the deprecated ImageMagick convert environment variables are set. + + PDF thumbnails no longer use ImageMagick, so these variables are ignored. + """ + warnings: list[Warning] = [] + + for var, check_id in DEPRECATED_CONVERT_ENV_VARS.items(): + if os.environ.get(var): + warnings.append( + Warning( + f"{var} is deprecated, has no effect and will be removed " + "in a future release.", + hint="It can be removed from your environment or configuration.", + id=check_id, + ), + ) + + return warnings + + def get_tesseract_langs(): proc = subprocess.run( [shutil.which("tesseract"), "--list-langs"], diff --git a/src/paperless/settings/__init__.py b/src/paperless/settings/__init__.py index 7ca3bb66e..7a5ce30b9 100644 --- a/src/paperless/settings/__init__.py +++ b/src/paperless/settings/__init__.py @@ -986,8 +986,6 @@ GNUPG_HOME = os.getenv("HOME", "/tmp") # Convert is part of the ImageMagick package CONVERT_BINARY = os.getenv("PAPERLESS_CONVERT_BINARY", "convert") -CONVERT_TMPDIR = os.getenv("PAPERLESS_CONVERT_TMPDIR") -CONVERT_MEMORY_LIMIT = os.getenv("PAPERLESS_CONVERT_MEMORY_LIMIT") GS_BINARY = os.getenv("PAPERLESS_GS_BINARY", "gs") diff --git a/src/paperless/tests/test_checks_v3.py b/src/paperless/tests/test_checks_v3.py index a87a19727..bafd0075a 100644 --- a/src/paperless/tests/test_checks_v3.py +++ b/src/paperless/tests/test_checks_v3.py @@ -1,4 +1,4 @@ -"""Tests for v3 system checks: deprecated v2 OCR env var warnings.""" +"""Tests for v3 system checks: deprecated environment variable warnings.""" from __future__ import annotations @@ -7,6 +7,7 @@ from typing import TYPE_CHECKING import pytest +from paperless.checks import check_deprecated_convert_env_vars from paperless.checks import check_deprecated_v2_ocr_env_vars if TYPE_CHECKING: @@ -62,3 +63,94 @@ class TestDeprecatedV2OcrEnvVarWarnings: warning = result[0] assert warning.id == expected_id assert expected_fragment in warning.msg + + +class TestDeprecatedConvertEnvVarWarnings: + def test_no_deprecated_vars_returns_empty(self, mocker: MockerFixture) -> None: + """ + GIVEN: + - Neither deprecated convert variable is set + WHEN: + - The deprecated convert check runs + THEN: + - No warnings are returned + """ + mocker.patch.dict(os.environ, {}, clear=True) + assert check_deprecated_convert_env_vars(None) == [] + + def test_empty_value_returns_empty(self, mocker: MockerFixture) -> None: + """ + GIVEN: + - A deprecated convert variable is set to an empty string + WHEN: + - The deprecated convert check runs + THEN: + - No warnings are returned + """ + mocker.patch.dict( + os.environ, + {"PAPERLESS_CONVERT_TMPDIR": ""}, + clear=True, + ) + assert check_deprecated_convert_env_vars(None) == [] + + @pytest.mark.parametrize( + ("env_var", "env_value", "expected_id"), + [ + pytest.param( + "PAPERLESS_CONVERT_MEMORY_LIMIT", + "32", + "paperless.W004", + id="memory-limit-warns", + ), + pytest.param( + "PAPERLESS_CONVERT_TMPDIR", + "/var/tmp/paperless", + "paperless.W005", + id="tmpdir-warns", + ), + ], + ) + def test_deprecated_var_produces_one_warning( + self, + mocker: MockerFixture, + env_var: str, + env_value: str, + expected_id: str, + ) -> None: + """ + GIVEN: + - One deprecated convert variable is set + WHEN: + - The deprecated convert check runs + THEN: + - Exactly one warning naming that variable is returned + """ + mocker.patch.dict(os.environ, {env_var: env_value}, clear=True) + result = check_deprecated_convert_env_vars(None) + + assert len(result) == 1 + assert result[0].id == expected_id + assert env_var in result[0].msg + assert "no effect" in result[0].msg + + def test_both_vars_produce_two_warnings(self, mocker: MockerFixture) -> None: + """ + GIVEN: + - Both deprecated convert variables are set + WHEN: + - The deprecated convert check runs + THEN: + - One warning per variable is returned + """ + mocker.patch.dict( + os.environ, + { + "PAPERLESS_CONVERT_MEMORY_LIMIT": "32", + "PAPERLESS_CONVERT_TMPDIR": "/var/tmp/paperless", + }, + clear=True, + ) + result = check_deprecated_convert_env_vars(None) + + assert {w.id for w in result} == {"paperless.W004", "paperless.W005"}