diff --git a/CHANGELOG.md b/CHANGELOG.md index 52dbc2f..5e02001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,18 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/). ## [Unreleased] +## [1.2.1] - 2026-10-03 + +> This cumulative source release gathers changes since the published `v1.2.0` (2026-05-02). The duplicate September `[1.2.0]` heading below was a historical changelog label, not a separate published release. + ### Fixed - **RFC 3501 IMAP Date Format Locale Isolation (IMAP-003):** - Resolved query syntax errors (`BAD Invalid date in SEARCH command`) during `older_than_days` IMAP rule searches on non-English (e.g. German `de_DE`) host locales. - Implemented `format_imap_date` in `imap_client.py` using fixed RFC 3501 English month tokens (`Jan`..`Dec`) rather than runtime-locale-dependent `strftime("%d-%b-%Y")` (which produced localized abbreviations like `Mrz`, `Mai`, `Okt`, `Dez`). - Added test coverage in `tests/test_imap_service.py` verifying RFC 3501 date-text formatting across all 12 calendar months and explicitly under active German locale. +- **IMAP filter control-character rejection (2026-10-03):** + - Rejects CR, LF, and NUL in sender and subject inputs before trimming, so malformed rules do not reach IMAP `SEARCH` or deletion. + - Skips the entire invalid rule while continuing other safe rules; quoted-string backslash and quote escaping remains intact. ### Added - **Pfad B Discoverability, Visual 4-View Architecture, Level 1 SBOM Stand 2026-10-03 & Contract Test Expansion (2026-10-03):** @@ -69,7 +76,9 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/). - Authored comprehensive bilingual Security Policy (`SECURITY.md`) establishing 48-hour response SLA and 5-day triage (`INV-SLA-10`), supported versions lifecycle (1.2.x), direct security coordinator contacts, private vulnerability advisory paths, and architectural local-first / zero-egress / non-elevated user-mode guarantees. - Added 6 automated metadata contract tests in `tests/test_metadata.py` validating CI timeouts and concurrency, stale lifecycle automation, gitignore multi-host and lock defense, PEP 621 URL definitions and pytest options, bilingual security policy invariants, and changelog/marketing log recency. -## [1.2.0] - 2026-09-12 +### Historical September work (originally labelled `[1.2.0]` on 2026-09-12) + +> Correction: this is a historical work entry, not a published `1.2.0` release. The published `v1.2.0` is dated 2026-05-02; this September work is included cumulatively in `1.2.1`. ### Added - **Pfad B Discoverability, Visual Architecture & Governance Parity (2026-09-12):** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 547661f..d9fd69d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ UniversalMailCleaner operates entirely in standard user mode (`RunAsInvoker`). C ### Strict Version Freeze Discipline -Under policy `T-20260920-167562623`, the current version `1.2.0` is strictly frozen. Routine hygiene, CI matrix, and documentation changes must not bump version numbers; all updates are recorded under `## [Unreleased]` in `CHANGELOG.md`. +Policy `T-20260920-167562623` keeps versions frozen by default. The user-authorized versioned source release recorded in master ticket `T-20261003-933110552` sets the current source-release version to `1.2.1`. Routine hygiene, CI matrix, and documentation changes must not bump it; interim changes are recorded under `## [Unreleased]` in `CHANGELOG.md`. Further version bumps require another explicitly authorized versioned release. ### Plan D Local Development Workflow @@ -89,4 +89,4 @@ Die Anwendung läuft vollständig im unprivilegierten Standard-Benutzermodus ohn ### Version-Freeze-Disziplin (T-20260920-167562623) -Die Version `1.2.0` bleibt eingefroren. Alle Änderungen werden unter `## [Unreleased]` im `CHANGELOG.md` erfasst. +Die Freeze-Richtlinie `T-20260920-167562623` hält Versionen standardmäßig eingefroren. Die im Masterticket `T-20261003-933110552` dokumentierte Nutzerautorisierung setzt `1.2.1` als aktuelle Quellrelease-Version. Alltägliche Hygiene-, CI- und Dokumentationsänderungen erhöhen sie nicht; Zwischenänderungen stehen unter `## [Unreleased]` im `CHANGELOG.md`. Weitere Versionssprünge benötigen eine ausdrücklich autorisierte Versionsveröffentlichung. diff --git a/MARKETING-LOG.txt b/MARKETING-LOG.txt index 0786208..dad209e 100644 --- a/MARKETING-LOG.txt +++ b/MARKETING-LOG.txt @@ -1,6 +1,27 @@ # MARKETING-LOG — doc-bricks/UniversalMailCleaner # Tracked Pfad B Discoverability, Visual Architecture, Governance & Verification Milestones +================================================================================ +[2026-10-03 21:38 CEST] [VERSIONED_SOURCE_RELEASE_1_2_1_PREPARATION] +Repository: doc-bricks/UniversalMailCleaner +Branch: release/universalmailcleaner-1.2.1-20261003 +Version: 1.2.1 (user-authorized source-release candidate; master ticket T-20261003-933110552) +License: MIT (SPDX-License-Identifier: MIT) +Maintainer: Lukas Geiger (support@lukasgeiger.com) +Security Contact: security@open-bricks.org, security@doc-bricks.org + +- Prepared the 1.2.1 version surfaces and cumulative changelog from the actual + published v1.2.0 release dated 2026-05-02; retained the September work entry + while correcting its duplicate historical 1.2.0 label. +- Recorded IMAP sender/subject control-character rejection (CR, LF, NUL) and + per-rule fail-closed behavior while preserving safe rules and quoted-string + escaping. +- Source release packaging will use the exact reviewed release commit with + `git archive --format=zip`; the archive will contain tracked repository files + only, excluding `.git` and untracked user profiles, with a SHA256SUMS.txt sidecar. +- This entry records release preparation; it does not claim a tag, published + GitHub asset, Store package, or installed application. + ================================================================================ [2026-09-12 16:00 CEST] [PFAD_B_DISCOVERABILITY_AND_DESIGN] Repository: doc-bricks/UniversalMailCleaner diff --git a/README-DE.md b/README-DE.md index 5bb0101..91f0c96 100644 --- a/README-DE.md +++ b/README-DE.md @@ -8,7 +8,7 @@ [![Lizenz: MIT](https://img.shields.io/badge/Lizenz-MIT-green)](LICENSE) [![Hinweis: Urheberrecht](https://img.shields.io/badge/Hinweis-Urheberrecht-blue)](NOTICE) -[![Version](https://img.shields.io/badge/Version-v1.2.0-blue)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-v1.2.1-blue)](CHANGELOG.md) [![Plattform: Windows](https://img.shields.io/badge/Plattform-Windows-blue?logo=windows)](#sec-10) [![PySide6](https://img.shields.io/badge/UI-PySide6-41cd52)](https://pypi.org/project/PySide6/) [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue?logo=python)](pyproject.toml) diff --git a/README.md b/README.md index 3b245d6..1a90d85 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-green)](LICENSE) [![Notice: Attribution](https://img.shields.io/badge/Notice-Attribution-blue)](NOTICE) -[![Version](https://img.shields.io/badge/Version-v1.2.0-blue)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-v1.2.1-blue)](CHANGELOG.md) [![Platform: Windows](https://img.shields.io/badge/Platform-Windows-blue?logo=windows)](#quick-start--setup) [![PySide6](https://img.shields.io/badge/UI-PySide6-41cd52)](https://pypi.org/project/PySide6/) [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue?logo=python)](pyproject.toml) diff --git a/README_de.md b/README_de.md index 5bb0101..91f0c96 100644 --- a/README_de.md +++ b/README_de.md @@ -8,7 +8,7 @@ [![Lizenz: MIT](https://img.shields.io/badge/Lizenz-MIT-green)](LICENSE) [![Hinweis: Urheberrecht](https://img.shields.io/badge/Hinweis-Urheberrecht-blue)](NOTICE) -[![Version](https://img.shields.io/badge/Version-v1.2.0-blue)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-v1.2.1-blue)](CHANGELOG.md) [![Plattform: Windows](https://img.shields.io/badge/Plattform-Windows-blue?logo=windows)](#sec-10) [![PySide6](https://img.shields.io/badge/UI-PySide6-41cd52)](https://pypi.org/project/PySide6/) [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue?logo=python)](pyproject.toml) diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index 67b07f9..eb98170 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -4,7 +4,7 @@ **Canonical Project License:** MIT License (`MIT`)
**Audit Date:** 2026-10-03 (Pfad B Discoverability & Architecture; Previous: 2026-10-01, 2026-09-26, 2026-09-22)
**Auditor:** Antigravity / Gemini (via GithubBot Pfad B)
-**Version:** `1.2.0`
+**Version:** `1.2.1`
**Umbrella Ecosystem:** `open-bricks` / `doc-bricks`
**Notice Attribution:** See canonical root [`NOTICE`](NOTICE) file. diff --git a/THIRD_PARTY_LICENSES.txt b/THIRD_PARTY_LICENSES.txt index 23086c7..7e93cf0 100644 --- a/THIRD_PARTY_LICENSES.txt +++ b/THIRD_PARTY_LICENSES.txt @@ -4,7 +4,7 @@ Project: UniversalMailCleaner (doc-bricks/UniversalMailCleaner) Canonical License: MIT License (SPDX: MIT) Audit Date: 2026-10-03 (Pfad B Discoverability & Architecture; Previous: 2026-10-01, 2026-09-26) Auditor: Antigravity / Gemini (via GithubBot Pfad B) -Version: 1.2.0 (Strictly frozen per T-20260920-167562623) +Version: 1.2.1 (Strictly frozen per T-20260920-167562623) Umbrella Ecosystem: open-bricks / doc-bricks Attribution: See canonical root NOTICE file. diff --git a/llms.txt b/llms.txt index ef750db..c5eca58 100644 --- a/llms.txt +++ b/llms.txt @@ -9,7 +9,7 @@ UniversalMailCleaner is a local-first Windows desktop app for cleaning IMAP and - Ecosystem Umbrella: open-bricks (https://github.com/open-bricks) - License: MIT License (SPDX: `MIT`) - Canonical Attribution: `NOTICE` -- Version: 1.2.0 +- Version: 1.2.1 - Main app entry point: `mail_imap_cleaner_v1.py` - Core modules: `imap_client.py`, `gmail_service.py`, `workers.py`, `models.py`, `scheduler_widget.py`, `profile_exchange.py` - Third-Party License Inventory & Level 1 SBOM: `THIRD_PARTY_LICENSES.md` & `THIRD_PARTY_LICENSES.txt` diff --git a/mail_imap_cleaner_v1.py b/mail_imap_cleaner_v1.py index d9f6a53..0237234 100644 --- a/mail_imap_cleaner_v1.py +++ b/mail_imap_cleaner_v1.py @@ -74,7 +74,7 @@ # ==================== CONFIGURATION ==================== -__version__ = "1.2.0" +__version__ = "1.2.1" APP_NAME = "UniversalMailCleaner" APP_VERSION = __version__ BASE_DIR = Path.home() / ".mail_cleaner" diff --git a/pyproject.toml b/pyproject.toml index d3fccc0..a5c2a6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "universalmailcleaner" -version = "1.2.0" +version = "1.2.1" description = "Local-first Windows desktop app for cleaning IMAP and Gmail mailboxes." readme = "README.md" requires-python = ">=3.9" diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 384d631..be44c3e 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -92,7 +92,7 @@ def test_version_parity(): with open(pyproject_path, "rb") as f: pyproject_data = tomllib.load(f) version = pyproject_data["project"]["version"] - assert version == "1.2.0", f"Unexpected version in pyproject.toml: {version}" + assert version == "1.2.1", f"Unexpected version in pyproject.toml: {version}" # 2. mail_imap_cleaner_v1.py main_py = ROOT / "mail_imap_cleaner_v1.py" @@ -114,6 +114,16 @@ def test_version_parity(): content = readme_path.read_text(encoding="utf-8") assert f"Version-v{version}-blue" in content or f"v{version}" in content + # 5. Machine-readable and third-party license version surfaces + version_markers = { + "llms.txt": f"- Version: {version}", + "THIRD_PARTY_LICENSES.md": f"**Version:** `{version}`
", + "THIRD_PARTY_LICENSES.txt": f"Version: {version}", + } + for filename, marker in version_markers.items(): + content = (ROOT / filename).read_text(encoding="utf-8") + assert marker in content, f"Current version missing from {filename}" + def test_manifest_files_exist(): """Verify all critical repo files exist and are non-empty.""" @@ -338,11 +348,11 @@ def test_statutory_notice_and_version_freeze(): assert "§ 521 BGB" in de_content assert "Gefälligkeitsrecht" in de_content - # Strict version freeze: version must be 1.2.0 across pyproject and main + # Strict version freeze after authorized versioned source release: 1.2.1 pyproject_path = ROOT / "pyproject.toml" with open(pyproject_path, "rb") as f: data = tomllib.load(f) - assert data["project"]["version"] == "1.2.0" + assert data["project"]["version"] == "1.2.1" def test_utf8_hygiene(): @@ -542,7 +552,8 @@ def test_contributing_guide_present_and_invariants(): assert "RunAsInvoker" in content assert "INV-USER-02" in content assert "T-20260920-167562623" in content - assert "1.2.0" in content + assert "T-20261003-933110552" in content + assert "1.2.1" in content assert "Plan D" in content for inv in INVARIANTS: assert inv in content, f"Invariant {inv} missing in CONTRIBUTING.md"