From 6913f9d79c64bca5114401c650cf88f896ed03d5 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 28 Jan 2026 13:45:12 -0800 Subject: [PATCH 1/9] Fix: fix user checks in management scripts (#11928) --- docker/management_script.sh | 7 ++++++- docker/rootfs/usr/local/bin/convert_mariadb_uuid | 9 +++++++-- docker/rootfs/usr/local/bin/createsuperuser | 9 +++++++-- docker/rootfs/usr/local/bin/decrypt_documents | 9 +++++++-- docker/rootfs/usr/local/bin/document_archiver | 9 +++++++-- .../rootfs/usr/local/bin/document_create_classifier | 11 ++++++++++- docker/rootfs/usr/local/bin/document_exporter | 9 +++++++-- docker/rootfs/usr/local/bin/document_fuzzy_match | 9 +++++++-- docker/rootfs/usr/local/bin/document_importer | 9 +++++++-- docker/rootfs/usr/local/bin/document_index | 9 +++++++-- docker/rootfs/usr/local/bin/document_renamer | 9 +++++++-- docker/rootfs/usr/local/bin/document_retagger | 9 +++++++-- docker/rootfs/usr/local/bin/document_sanity_checker | 9 +++++++-- docker/rootfs/usr/local/bin/document_thumbnails | 9 +++++++-- docker/rootfs/usr/local/bin/mail_fetcher | 9 +++++++-- docker/rootfs/usr/local/bin/manage_superuser | 9 +++++++-- docker/rootfs/usr/local/bin/prune_audit_logs | 9 +++++++-- 17 files changed, 121 insertions(+), 32 deletions(-) diff --git a/docker/management_script.sh b/docker/management_script.sh index 91a6336d0..6d5e84549 100755 --- a/docker/management_script.sh +++ b/docker/management_script.sh @@ -7,6 +7,11 @@ cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then python3 manage.py management_command "$@" -elif [[ $(id -un) == "paperless" ]]; then +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py management_command "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py management_command "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/convert_mariadb_uuid b/docker/rootfs/usr/local/bin/convert_mariadb_uuid index 019c558f1..7adb0a1af 100755 --- a/docker/rootfs/usr/local/bin/convert_mariadb_uuid +++ b/docker/rootfs/usr/local/bin/convert_mariadb_uuid @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py convert_mariadb_uuid "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py convert_mariadb_uuid "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py convert_mariadb_uuid "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py convert_mariadb_uuid "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/createsuperuser b/docker/rootfs/usr/local/bin/createsuperuser index 2b56869f6..b91cee3c5 100755 --- a/docker/rootfs/usr/local/bin/createsuperuser +++ b/docker/rootfs/usr/local/bin/createsuperuser @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py createsuperuser "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py createsuperuser "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py createsuperuser "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py createsuperuser "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/decrypt_documents b/docker/rootfs/usr/local/bin/decrypt_documents index 27f0a21fe..65d035b70 100755 --- a/docker/rootfs/usr/local/bin/decrypt_documents +++ b/docker/rootfs/usr/local/bin/decrypt_documents @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py decrypt_documents "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py decrypt_documents "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py decrypt_documents "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py decrypt_documents "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_archiver b/docker/rootfs/usr/local/bin/document_archiver index 8d7771d26..4200aa7aa 100755 --- a/docker/rootfs/usr/local/bin/document_archiver +++ b/docker/rootfs/usr/local/bin/document_archiver @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_archiver "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_archiver "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_archiver "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_archiver "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_create_classifier b/docker/rootfs/usr/local/bin/document_create_classifier index 23acc6741..518551a4b 100755 --- a/docker/rootfs/usr/local/bin/document_create_classifier +++ b/docker/rootfs/usr/local/bin/document_create_classifier @@ -6,7 +6,16 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_create_classifier "$@" + python3 manage.py document_create_classifier "$@" +elif [[ $(id -u) == 0 ]]; then + s6-setuidgid paperless python3 manage.py document_create_classifier "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_create_classifier "$@" +else + echo "Unknown user." + exit 1 +fi +er "$@" elif [[ $(id -un) == "paperless" ]]; then s6-setuidgid paperless python3 manage.py document_create_classifier "$@" fi diff --git a/docker/rootfs/usr/local/bin/document_exporter b/docker/rootfs/usr/local/bin/document_exporter index d55f01d48..a82d70a16 100755 --- a/docker/rootfs/usr/local/bin/document_exporter +++ b/docker/rootfs/usr/local/bin/document_exporter @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_exporter "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_exporter "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_exporter "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_exporter "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_fuzzy_match b/docker/rootfs/usr/local/bin/document_fuzzy_match index c6e4edadc..b97c2a9ba 100755 --- a/docker/rootfs/usr/local/bin/document_fuzzy_match +++ b/docker/rootfs/usr/local/bin/document_fuzzy_match @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_fuzzy_match "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_fuzzy_match "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_fuzzy_match "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_fuzzy_match "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_importer b/docker/rootfs/usr/local/bin/document_importer index 07c92bb04..dbfb40a57 100755 --- a/docker/rootfs/usr/local/bin/document_importer +++ b/docker/rootfs/usr/local/bin/document_importer @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_importer "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_importer "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_importer "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_importer "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_index b/docker/rootfs/usr/local/bin/document_index index 47c893c10..b05f765da 100755 --- a/docker/rootfs/usr/local/bin/document_index +++ b/docker/rootfs/usr/local/bin/document_index @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_index "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_index "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_index "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_index "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_renamer b/docker/rootfs/usr/local/bin/document_renamer index 3406182ee..720edc0d8 100755 --- a/docker/rootfs/usr/local/bin/document_renamer +++ b/docker/rootfs/usr/local/bin/document_renamer @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_renamer "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_renamer "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_renamer "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_renamer "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_retagger b/docker/rootfs/usr/local/bin/document_retagger index b0d1047ff..6cbe03c19 100755 --- a/docker/rootfs/usr/local/bin/document_retagger +++ b/docker/rootfs/usr/local/bin/document_retagger @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_retagger "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_retagger "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_retagger "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_retagger "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_sanity_checker b/docker/rootfs/usr/local/bin/document_sanity_checker index d792124fc..8fff13a52 100755 --- a/docker/rootfs/usr/local/bin/document_sanity_checker +++ b/docker/rootfs/usr/local/bin/document_sanity_checker @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_sanity_checker "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_sanity_checker "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_sanity_checker "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_sanity_checker "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/document_thumbnails b/docker/rootfs/usr/local/bin/document_thumbnails index 71d80e00d..3c0f0de4c 100755 --- a/docker/rootfs/usr/local/bin/document_thumbnails +++ b/docker/rootfs/usr/local/bin/document_thumbnails @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py document_thumbnails "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_thumbnails "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py document_thumbnails "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py document_thumbnails "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/mail_fetcher b/docker/rootfs/usr/local/bin/mail_fetcher index 654c07389..762b850b9 100755 --- a/docker/rootfs/usr/local/bin/mail_fetcher +++ b/docker/rootfs/usr/local/bin/mail_fetcher @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py mail_fetcher "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py mail_fetcher "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py mail_fetcher "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py mail_fetcher "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/manage_superuser b/docker/rootfs/usr/local/bin/manage_superuser index a6e41168c..8f550cd1a 100755 --- a/docker/rootfs/usr/local/bin/manage_superuser +++ b/docker/rootfs/usr/local/bin/manage_superuser @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py manage_superuser "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py manage_superuser "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py manage_superuser "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py manage_superuser "$@" +else + echo "Unknown user." + exit 1 fi diff --git a/docker/rootfs/usr/local/bin/prune_audit_logs b/docker/rootfs/usr/local/bin/prune_audit_logs index 04446df17..8a3ab3299 100755 --- a/docker/rootfs/usr/local/bin/prune_audit_logs +++ b/docker/rootfs/usr/local/bin/prune_audit_logs @@ -6,7 +6,12 @@ set -e cd "${PAPERLESS_SRC_DIR}" if [[ -n "${USER_IS_NON_ROOT}" ]]; then - python3 manage.py prune_audit_logs "$@" -elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py prune_audit_logs "$@" +elif [[ $(id -u) == 0 ]]; then s6-setuidgid paperless python3 manage.py prune_audit_logs "$@" +elif [[ $(id -un) == "paperless" ]]; then + python3 manage.py prune_audit_logs "$@" +else + echo "Unknown user." + exit 1 fi From e4b861d76f2da302136cd2b10c26fcf2f213b974 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:29:30 -0800 Subject: [PATCH 2/9] Fix: prevent note deletion outside doc --- src/documents/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/documents/views.py b/src/documents/views.py index a91ad8594..f6bec1f0d 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -1099,7 +1099,7 @@ class DocumentViewSet( ): return HttpResponseForbidden("Insufficient permissions to delete notes") - note = Note.objects.get(id=int(request.GET.get("id"))) + note = Note.objects.get(id=int(request.GET.get("id")), document=doc) if settings.AUDIT_LOG_ENABLED: LogEntry.objects.log_create( instance=doc, From 836c81e0371ca380b6ae675dc3972f357edf1eb0 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:49:22 -0800 Subject: [PATCH 3/9] Chore: add note about ordering --- .../app/components/manage/saved-views/saved-views.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src-ui/src/app/components/manage/saved-views/saved-views.component.html b/src-ui/src/app/components/manage/saved-views/saved-views.component.html index 10487fec8..2f5ef3338 100644 --- a/src-ui/src/app/components/manage/saved-views/saved-views.component.html +++ b/src-ui/src/app/components/manage/saved-views/saved-views.component.html @@ -51,6 +51,7 @@ @if (displayFields) { } + Note: ordering is not preserved From c8c4c7c749f5531259c5fd4d8e0b7cae28216920 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:14:18 -0800 Subject: [PATCH 4/9] Security: enforce permissions for post_document --- src/documents/tests/test_api_documents.py | 11 +++++++++++ src/documents/views.py | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/documents/tests/test_api_documents.py b/src/documents/tests/test_api_documents.py index f40ef157f..700f56568 100644 --- a/src/documents/tests/test_api_documents.py +++ b/src/documents/tests/test_api_documents.py @@ -1216,6 +1216,17 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase): self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) + def test_upload_insufficient_permissions(self): + self.client.force_authenticate(user=User.objects.create_user("testuser2")) + + with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f: + response = self.client.post( + "/api/documents/post_document/", + {"document": f}, + ) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + def test_upload_empty_metadata(self): self.consume_file_mock.return_value = celery.result.AsyncResult( id=str(uuid.uuid4()), diff --git a/src/documents/views.py b/src/documents/views.py index f6bec1f0d..5a0f83699 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -1703,6 +1703,8 @@ class PostDocumentView(GenericAPIView): parser_classes = (parsers.MultiPartParser,) def post(self, request, *args, **kwargs): + if not request.user.has_perm("documents.add_document"): + return HttpResponseForbidden("Insufficient permissions") serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) From 5cc3c087d90c669ee1e3c2430fb1b2e67b007185 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:55:55 -0800 Subject: [PATCH 5/9] Security: enforce ownership for permission updates --- src/documents/serialisers.py | 14 ++++++ src/documents/tests/test_api_permissions.py | 53 +++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index e96400eff..75e73d878 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -40,6 +40,7 @@ from guardian.utils import get_group_obj_perms_model from guardian.utils import get_user_obj_perms_model from rest_framework import fields from rest_framework import serializers +from rest_framework.exceptions import PermissionDenied from rest_framework.fields import SerializerMethodField from rest_framework.filters import OrderingFilter @@ -436,6 +437,19 @@ class OwnedObjectSerializer( return instance def update(self, instance, validated_data): + user = getattr(self, "user", None) + is_superuser = user.is_superuser if user is not None else False + is_owner = instance.owner == user if user is not None else False + is_unowned = instance.owner is None + + if ( + ("owner" in validated_data and validated_data["owner"] != instance.owner) + or "set_permissions" in validated_data + ) and not (is_superuser or is_owner or is_unowned): + raise PermissionDenied( + _("Insufficient permissions."), + ) + if "set_permissions" in validated_data: self._set_permissions(validated_data["set_permissions"], instance) self.validate_unique_together(validated_data, instance) diff --git a/src/documents/tests/test_api_permissions.py b/src/documents/tests/test_api_permissions.py index bc81dabe9..31b860745 100644 --- a/src/documents/tests/test_api_permissions.py +++ b/src/documents/tests/test_api_permissions.py @@ -441,6 +441,59 @@ class TestApiAuth(DirectoriesMixin, APITestCase): self.assertTrue(checker.has_perm("change_document", doc)) self.assertIn("change_document", get_perms(group1, doc)) + def test_document_permissions_change_requires_owner(self): + owner = User.objects.create_user(username="owner") + editor = User.objects.create_user(username="editor") + editor.user_permissions.add( + *Permission.objects.all(), + ) + + doc = Document.objects.create( + title="Ownered doc", + content="sensitive", + checksum="abc123", + mime_type="application/pdf", + owner=owner, + ) + + assign_perm("view_document", editor, doc) + assign_perm("change_document", editor, doc) + + self.client.force_authenticate(editor) + response = self.client.patch( + f"/api/documents/{doc.pk}/", + json.dumps( + { + "set_permissions": { + "view": { + "users": [editor.id], + "groups": [], + }, + "change": { + "users": None, + "groups": None, + }, + }, + }, + ), + content_type="application/json", + ) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + self.client.force_authenticate(editor) + response = self.client.patch( + f"/api/documents/{doc.pk}/", + json.dumps( + { + "owner": editor.id, + }, + ), + content_type="application/json", + ) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + def test_dynamic_permissions_fields(self): user1 = User.objects.create_user(username="user1") user1.user_permissions.add(*Permission.objects.filter(codename="view_document")) From 3e41d99a82555694a6a0d32c198391dba2315fb8 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 30 Jan 2026 17:59:55 -0800 Subject: [PATCH 6/9] Bump version to 2.20.6 --- pyproject.toml | 2 +- src-ui/package.json | 2 +- src-ui/src/environments/environment.prod.ts | 2 +- src/paperless/version.py | 2 +- uv.lock | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ee1748cc3..e1693ead0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "paperless-ngx" -version = "2.20.5" +version = "2.20.6" description = "A community-supported supercharged document management system: scan, index and archive all your physical documents" readme = "README.md" requires-python = ">=3.10" diff --git a/src-ui/package.json b/src-ui/package.json index 6d9046f65..dbd26cb8c 100644 --- a/src-ui/package.json +++ b/src-ui/package.json @@ -1,6 +1,6 @@ { "name": "paperless-ngx-ui", - "version": "2.20.5", + "version": "2.20.6", "scripts": { "preinstall": "npx only-allow pnpm", "ng": "ng", diff --git a/src-ui/src/environments/environment.prod.ts b/src-ui/src/environments/environment.prod.ts index 9ebf29d16..3ce1d16cc 100644 --- a/src-ui/src/environments/environment.prod.ts +++ b/src-ui/src/environments/environment.prod.ts @@ -6,7 +6,7 @@ export const environment = { apiVersion: '9', // match src/paperless/settings.py appTitle: 'Paperless-ngx', tag: 'prod', - version: '2.20.5', + version: '2.20.6', webSocketHost: window.location.host, webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', webSocketBaseUrl: base_url.pathname + 'ws/', diff --git a/src/paperless/version.py b/src/paperless/version.py index aeeee68e0..ec6eaed08 100644 --- a/src/paperless/version.py +++ b/src/paperless/version.py @@ -1,6 +1,6 @@ from typing import Final -__version__: Final[tuple[int, int, int]] = (2, 20, 5) +__version__: Final[tuple[int, int, int]] = (2, 20, 6) # Version string like X.Y.Z __full_version_str__: Final[str] = ".".join(map(str, __version__)) # Version string like X.Y diff --git a/uv.lock b/uv.lock index ac7763525..b09a025e0 100644 --- a/uv.lock +++ b/uv.lock @@ -2115,7 +2115,7 @@ wheels = [ [[package]] name = "paperless-ngx" -version = "2.20.5" +version = "2.20.6" source = { virtual = "." } dependencies = [ { name = "babel", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, From 4363567fa79cd7bbc40adcca58ee458dca27d9ef Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:49:43 -0800 Subject: [PATCH 7/9] Remove commitish --- .github/release-drafter.yml | 1 - .github/workflows/ci.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 2b8169f24..89c8a96ea 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -44,7 +44,6 @@ include-labels: - 'notable' exclude-labels: - 'skip-changelog' -filter-by-commitish: true category-template: '### $TITLE' change-template: '- $TITLE @$AUTHOR ([#$NUMBER]($URL))' change-title-escapes: '\<*_&#@' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1169f664..f8eb6c832 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -617,7 +617,6 @@ jobs: version: ${{ steps.get_version.outputs.version }} prerelease: ${{ steps.get_version.outputs.prerelease }} publish: true # ensures release is not marked as draft - commitish: ${{ github.sha }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload release archive From c5bb5b237baffa6cf2d9077265ba0d2a413a4bcc Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 30 Jan 2026 22:19:48 -0800 Subject: [PATCH 8/9] Fix commitish config --- .github/release-drafter.yml | 1 + .github/workflows/ci.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 89c8a96ea..2b8169f24 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -44,6 +44,7 @@ include-labels: - 'notable' exclude-labels: - 'skip-changelog' +filter-by-commitish: true category-template: '### $TITLE' change-template: '- $TITLE @$AUTHOR ([#$NUMBER]($URL))' change-title-escapes: '\<*_&#@' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8eb6c832..98f4272e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -617,6 +617,7 @@ jobs: version: ${{ steps.get_version.outputs.version }} prerelease: ${{ steps.get_version.outputs.prerelease }} publish: true # ensures release is not marked as draft + commitish: main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload release archive From d27a5f688a2bd283d2b535fc04951f228d5c37c4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 23:34:22 -0800 Subject: [PATCH 9/9] Changelog v2.20.6 - GHA (#11952) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- docs/changelog.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index f222a7305..d6a87e299 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,24 @@ # Changelog +## paperless-ngx 2.20.6 + +### Bug Fixes + +- Fix: extract all ids for nested tags [@shamoon](https://github.com/shamoon) ([#11888](https://github.com/paperless-ngx/paperless-ngx/pull/11888)) +- Fixhancement: change date calculation for 'this year' to include future documents [@shamoon](https://github.com/shamoon) ([#11884](https://github.com/paperless-ngx/paperless-ngx/pull/11884)) +- Fix: Running management scripts under rootless could fail [@stumpylog](https://github.com/stumpylog) ([#11870](https://github.com/paperless-ngx/paperless-ngx/pull/11870)) +- Fix: use correct field id for overrides [@shamoon](https://github.com/shamoon) ([#11869](https://github.com/paperless-ngx/paperless-ngx/pull/11869)) + +### All App Changes + +
+3 changes + +- Fix: extract all ids for nested tags [@shamoon](https://github.com/shamoon) ([#11888](https://github.com/paperless-ngx/paperless-ngx/pull/11888)) +- Fixhancement: change date calculation for 'this year' to include future documents [@shamoon](https://github.com/shamoon) ([#11884](https://github.com/paperless-ngx/paperless-ngx/pull/11884)) +- Fix: use correct field id for overrides [@shamoon](https://github.com/shamoon) ([#11869](https://github.com/paperless-ngx/paperless-ngx/pull/11869)) +
+ ## paperless-ngx 2.20.5 ### Bug Fixes