From b0667f53b54e7a9d0074918967d930a9aa7dff5e Mon Sep 17 00:00:00 2001 From: Md Nurnobi Date: Tue, 18 Aug 2026 11:58:40 -0700 Subject: [PATCH 1/3] docs: establish production-readiness control plan --- .../00_OFFICIAL_BASELINE_FREEZE.md | 82 +++++ ...01_PRODUCTION_READINESS_FORENSIC_REPORT.md | 311 ++++++++++++++++++ .../02_TWO_PHASE_A_TO_Z_ROADMAP.md | 289 ++++++++++++++++ .../03_UPDATE_PHASE_COMPLETION_LOG.md | 136 ++++++++ .../04_ERROR_HANDLING_REGISTER_AND_PLAN.md | 159 +++++++++ .../05_ACTUAL_IMPLEMENTATION_STATUS.md | 126 +++++++ ...6_UI_DESIGN_REFERENCE_AND_DEFECT_MATRIX.md | 131 ++++++++ .../07_PRODUCTION_ACCEPTANCE_GATE.md | 162 +++++++++ .../08_CHANGE_CONTROL_AND_SCOPE_LOCK.md | 108 ++++++ .../09_RELEASE_AND_UPDATE_EXECUTION_POLICY.md | 83 +++++ .../10_TEST_AND_ACCEPTANCE_MATRIX.md | 133 ++++++++ ...ISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md | 114 +++++++ docs/production-readiness/README.md | 58 ++++ 13 files changed, 1892 insertions(+) create mode 100644 docs/production-readiness/00_OFFICIAL_BASELINE_FREEZE.md create mode 100644 docs/production-readiness/01_PRODUCTION_READINESS_FORENSIC_REPORT.md create mode 100644 docs/production-readiness/02_TWO_PHASE_A_TO_Z_ROADMAP.md create mode 100644 docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md create mode 100644 docs/production-readiness/04_ERROR_HANDLING_REGISTER_AND_PLAN.md create mode 100644 docs/production-readiness/05_ACTUAL_IMPLEMENTATION_STATUS.md create mode 100644 docs/production-readiness/06_UI_DESIGN_REFERENCE_AND_DEFECT_MATRIX.md create mode 100644 docs/production-readiness/07_PRODUCTION_ACCEPTANCE_GATE.md create mode 100644 docs/production-readiness/08_CHANGE_CONTROL_AND_SCOPE_LOCK.md create mode 100644 docs/production-readiness/09_RELEASE_AND_UPDATE_EXECUTION_POLICY.md create mode 100644 docs/production-readiness/10_TEST_AND_ACCEPTANCE_MATRIX.md create mode 100644 docs/production-readiness/11_EXISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md create mode 100644 docs/production-readiness/README.md diff --git a/docs/production-readiness/00_OFFICIAL_BASELINE_FREEZE.md b/docs/production-readiness/00_OFFICIAL_BASELINE_FREEZE.md new file mode 100644 index 0000000..d827bd4 --- /dev/null +++ b/docs/production-readiness/00_OFFICIAL_BASELINE_FREEZE.md @@ -0,0 +1,82 @@ +# Official Baseline Freeze — MailStack v1.3.3 + +## Freeze decision + +`v1.3.3` is the official frozen baseline for the next production-readiness update cycle. + +### Canonical baseline identity + +| Field | Frozen value | +|---|---| +| Product | MailStack | +| Version | `1.3.3` | +| Tag | `v1.3.3` | +| Commit | `21dff33219afab3819e7bd1ae1e0a0cc2e7d3698` | +| Tree | `74682033f3164a6a0069a381ae5a38661aad1669` | +| Release archive | `mailstack-1.3.3-source.zip` | +| Release archive SHA-256 | `9e2016ce486f1e1f7e30361c73fa50ff73e7c9c72f87dd0941c1a9b5ed2e9964` | +| Live installed version | `1.3.3` | +| Live previous version marker | `1.3.0-rc.1` | +| Live source-fidelity check | PASS | +| Upgrade rollback snapshot | Verified during live upgrade | +| Coordinated data backup | Verified during live upgrade | + +## Evidence reconciliation + +### [CONFLICT] Uploaded candidate baseline versus published baseline + +The uploaded `MailStack_v1.3.3_Baseline.zip` has SHA-256 +`b25d693caef36b8370c279bdf5c59d97a1e8d100d8485eccbc8fd74bb4d1370f`, and its accompanying freeze +record explicitly classifies it as `OWNER-FROZEN_CANDIDATE` with release/live gates pending. + +The production server was later upgraded using the published v1.3.3 release archive with SHA-256 +`9e2016ce486f1e1f7e30361c73fa50ff73e7c9c72f87dd0941c1a9b5ed2e9964`, and the deployed source-fidelity +check passed against that published source. + +**Resolution:** the published/live-verified release identity above is authoritative for future implementation. +The candidate ZIP remains evidence/reference only. + +## Frozen architecture and behavior + +Unless a later owner approval explicitly expands scope, the following are immutable: + +- receive-only product model; +- Internet SMTP -> Postfix -> Dovecot LMTP -> Maildir -> ingestion -> MariaDB -> Django/browser flow; +- no outbound send/reply/forward, SMTP submission, IMAP, POP3, campaigns or public registration; +- mailbox ownership/membership and object authorization semantics; +- user/admin permission model and destructive-action permissions; +- message read/unread and soft-delete semantics; +- attachment authorization and storage confinement; +- database schema unless a migration is separately reviewed and explicitly approved; +- Postfix/Dovecot routing and LMTP contracts; +- installer, backup, upgrade and rollback contracts unless a confirmed defect requires a narrow correction; +- service names, deployment directories, DNS/TLS model and production data locations; +- MailStack name, logo, light-theme product identity and blue-oriented brand color family. + +## Allowed next-cycle scope + +The planned next cycle is restricted to production-readiness corrections identified in the forensic report: + +1. HTML message-rendering integrity and repair of already-indexed affected messages. +2. Safe rendering UX cleanup without weakening sanitization/sandbox/security controls. +3. Confirmed runtime error investigation/closure, including the observed Gunicorn read-only-filesystem control-server log. +4. Compact shared UI geometry and typography using VibTools structural references while retaining MailStack theme. +5. Mailboxes, Inbox, message reader, create-mailbox, user-management, add/edit-user and authenticated-shell responsive refinement. +6. Authenticated footer cleanup. +7. Focused error-handling improvements required by those changes. +8. Automated tests, live acceptance, inbound email E2E and final production-readiness evidence. + +## Prohibited implementation behavior + +- No unrelated refactor or cleanup. +- No feature removal unless explicitly required by approved scope; visual removal of non-operational clutter is allowed only where documented. +- No renaming routes, models, classes, modules, IDs or configuration keys for style preference. +- No data-destructive repair of existing messages. +- No delete-and-reingest strategy for existing email repair. +- No weakening HTML sanitization, iframe sandboxing, referrer protection, CSRF, authentication or object authorization. +- No hidden feature expansion such as compose/reply/forward. + +## Freeze release rule + +Any implementation delta must be compared against this baseline identity. If the base commit/tree differs, +implementation stops until the owner explicitly re-baselines the project. diff --git a/docs/production-readiness/01_PRODUCTION_READINESS_FORENSIC_REPORT.md b/docs/production-readiness/01_PRODUCTION_READINESS_FORENSIC_REPORT.md new file mode 100644 index 0000000..b17873b --- /dev/null +++ b/docs/production-readiness/01_PRODUCTION_READINESS_FORENSIC_REPORT.md @@ -0,0 +1,311 @@ +# Production-Readiness Forensic Report + +## Executive disposition + +MailStack `v1.3.3` is successfully installed and operational at the server/core level, but the application is +**not yet production-ready from an end-user UI/message-reading perspective**. + +### Current high-level disposition + +| Area | Status | Production meaning | +|---|---|---| +| v1.3.3 installation identity | PASS | Correct published source is deployed | +| Database / migration readiness | PASS | No pending migration issue observed | +| Postfix / Dovecot / Nginx config | PASS | Core mail/web configuration checks passed | +| Core health endpoints | PASS | Live and ready endpoints returned healthy state | +| Application verifier | PASS | Maintained verification passed after upgrade | +| Backup / rollback evidence | PASS | Upgrade backup and rollback snapshots verified | +| HTML email reader | **BLOCKER** | Raw CSS appears in message body; mail can be unreadable | +| Existing affected messages | **BLOCKER** | Persisted sanitized bodies will not self-heal | +| Mailbox compactness | FAIL | Desktop/mobile density does not meet approved target | +| Responsive shell | FAIL | Collapsed/mobile presentation remains inconsistent | +| Authenticated footer | FAIL | Public/promotional links leak into internal workspace | +| Gunicorn log finding | OPEN | `Control server error: [Errno 30] Read-only file system` observed | +| Final real inbound E2E after UI corrections | PENDING | Must be rerun after defects are fixed | + +## Evidence basis + +This report combines: + +- the frozen MailStack v1.3.3 source baseline; +- the live upgrade and post-upgrade verification outputs; +- supplied desktop and mobile screenshots; +- VibTools Web UI v2.1.2 design documentation; +- Licora v5.5.0 UI implementation/audit documentation as a structural implementation reference. + +The reference products are used for **structure, typography, density, responsive patterns and component +discipline only**. MailStack retains its own branding, light theme and product color system. + +## Finding PR-001 — HTML email sanitizer leaks CSS text + +**Severity:** Critical / BLOCKER +**State:** [CONFIRMED] + +Current `mailbox-app/apps/ingestion/parser.py` uses Bleach with `strip=True`. The safe-tag set excludes +`style`, while the cleaner is allowed to strip disallowed tags. In the supplied Harpoon email screenshot, +CSS rules such as `#outlook a`, `.ReadMsgBody`, `.ExternalClass`, and table/content rules are visibly emitted +as message text. + +The current sanitizer also rejects the `style` attribute. That restriction is security-conscious, but the +combination means complex marketing/transactional emails can lose intended layout while style-block text +remains user-visible. + +### Required correction + +- remove `head`, `style`, `script`, `noscript`, metadata and other non-body active/style content **with their + contents where appropriate** before the normal safe-HTML sanitization pass; +- preserve the existing deny-by-default sanitizer posture; +- do not enable JavaScript, event attributes, arbitrary CSS or unrestricted remote content; +- maintain safe link protocol validation and attachment isolation; +- add fixtures reproducing the supplied Harpoon-style email and similar style-heavy HTML emails; +- verify rendered output contains readable content and **zero raw style-block CSS**. + +## Finding PR-002 — Already-indexed messages will not automatically repair + +**Severity:** Critical / BLOCKER +**State:** [CONFIRMED] + +Current ingestion checks `(mailbox, source_file_key)` first and returns `duplicate` for an already-indexed +Maildir item. Therefore, changing only the parser/sanitizer fixes **future ingestion** but does not rewrite the +stored `sanitized_html_body` for existing messages. + +### Required correction + +Implement a controlled, idempotent repair/backfill command that: + +- reads the original Maildir source already associated with each message; +- re-parses using the corrected parser; +- updates only approved parser-derived body/metadata fields; +- preserves message UUID, database identity, read/unread state, deletion state, mailbox membership, audit + identity, source key and attachment records unless an explicitly reviewed attachment repair is required; +- supports dry-run, mailbox targeting, bounded batch size and clear result counters; +- records warnings/errors without deleting source mail; +- can be safely re-run. + +See `11_EXISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md`. + +## Finding PR-003 — Visible protected-rendering banner is intrusive + +**Severity:** Major UX +**State:** [CONFIRMED] + +The message template prints `Protected rendering · remote and active content are blocked.` above every HTML +message. The underlying security controls are valid, but a permanent warning strip consumes prime reading +space and makes normal mail feel like an error state. + +### Required correction + +- remove the permanent banner from the normal reading path, or reduce it to an unobtrusive info affordance if + the owner later chooses to retain one; +- **retain** HTML sanitization, iframe sandboxing, no-referrer behavior, attachment authorization and active + content blocking; +- security state must remain testable even if it is no longer visually loud. + +## Finding PR-004 — Remote image stripping creates broken-image residue + +**Severity:** Major UX +**State:** [CONFIRMED from source + screenshot] + +The sanitizer only allows image `src` values beginning with approved `data:image/...;base64,` prefixes. +External image sources are rejected. The screenshot shows a broken image/`intercom` residue at the bottom of +the message. + +### Required correction + +Do not simply allow unrestricted remote images. Instead, ensure rejected remote images do not render as broken +UI. Safe options include removing the unusable image node while preserving meaningful alt text, or rendering a +compact blocked-image placeholder. The implementation must not introduce remote tracking fetches by default. + +## Finding PR-005 — Shared UI geometry is materially larger than the reference contract + +**Severity:** Major UX +**State:** [CONFIRMED] + +Current MailStack foundation values include: + +- base UI font size: `1rem` / approximately `16px`; +- sidebar width: `256px`; +- collapsed sidebar width: `80px`; +- topbar height: `72px`. + +VibTools Web UI v2.1.2 compact structural references define: + +- primary UI text: `13px`; +- sidebar width: `196px`; +- topbar height: `44px`; +- small/medium buttons: `28px` / `32px`; +- small/medium inputs: `30px` / `34px`; +- compact card padding: `10px 12px`; +- small/control/card radii: `6px / 8px / 12px`; +- flat, border-driven cards rather than broad decorative elevation. + +### Required correction + +Create a MailStack compact token mapping that adopts the **structural scale** while preserving MailStack light +colors, semantic colors and branding. Page code must consume shared tokens/components rather than inventing new +sizes per screen. + +## Finding PR-006 — Mailboxes desktop list is too heavy + +**Severity:** Major UX +**State:** [CONFIRMED] + +The current Mailboxes page is a seven-column traditional table with separate `Open inbox`, `Disable`, and +`Delete` actions. It is visually heavy for large mailbox counts and exposes too many simultaneous action +controls. + +### Required correction + +- reduce row height and typography; +- make mailbox address the clear primary item; +- compact Status / Messages / Unread / Last received presentation; +- demote Created metadata; +- consolidate row actions into a compact shared action area/menu while preserving permissions and POST/CSRF + contracts; +- preserve search/status filter behavior and pagination. + +## Finding PR-007 — Mobile Mailboxes layout is excessively tall + +**Severity:** Major UX +**State:** [CONFIRMED] + +At a 400px responsive viewport the current table-to-card transformation creates large vertical records with +labels for every column and multiple full-size action buttons. This is technically responsive but not compact. + +### Required correction + +- use a purpose-built compact mobile mailbox card/list pattern; +- keep address/status/unread/last-received in the first visual region; +- move secondary metadata/action controls into a compact secondary row/menu; +- no horizontal viewport overflow; +- no loss of accessibility labels or destructive-action confirmation. + +## Finding PR-008 — Sidebar collapsed state is visually unfinished + +**Severity:** Major UX +**State:** [CONFIRMED] + +The supplied collapsed-shell screenshot shows an over-wide icon rail and large unused vertical/left visual +space. Current tokens allocate an `80px` collapsed sidebar, larger than required for the shown icons. + +### Required correction + +- align collapse geometry with the compact structural reference; +- preserve tooltips/accessible labels for icon-only navigation; +- keep active-state clarity; +- desktop collapse and mobile off-canvas drawer must be separate, coherent behaviors; +- Escape/backdrop/navigation close behavior must remain reliable on mobile. + +## Finding PR-009 — Authenticated footer contains non-operational public links + +**Severity:** Major UX +**State:** [CONFIRMED] + +The authenticated base template exposes `Source code`, `Open-source hub`, and `Free subdomains` in the +operational workspace. The supplied screenshot marks this region as undesirable. + +### Required correction + +Remove public/promotional footer links from authenticated operational pages. Retain only a minimal product +identity footer if required, or allow the workspace to end without a persistent footer. This is a presentation +change only; configured URLs do not need to be deleted from backend settings unless separately approved. + +## Finding PR-010 — Message reader composition is oversized + +**Severity:** Major UX +**State:** [CONFIRMED] + +The current reader uses a tall fixed/clamped iframe (`460px` to `800px`, around `65vh`) and large header/body +spacing. In combination with broken HTML, this produces a large unusable reading surface and pushes attachments +and footer far down the page. + +### Required correction + +- compact sender/routing/action header; +- readable body width and natural content flow; +- avoid an unnecessarily tall empty/scroll-within-scroll surface; +- attachment section directly follows the message body; +- keep safe iframe isolation where HTML is rendered. + +## Finding PR-011 — Create mailbox form is spatially inefficient + +**Severity:** Medium UX +**State:** [CONFIRMED] + +The form occupies a small left card with a large unused page region. The native size-8 multi-select is tall and +visually dated. + +### Required correction + +- compact content width and page spacing; +- compact input sizing based on shared tokens; +- improved assigned-user selector presentation without changing submitted field names/semantics; +- preserve local-part validation, uniqueness/reservation behavior and admin-only assignment rules. + +## Finding PR-012 — User-management table requires density and responsive correction + +**Severity:** Major UX +**State:** [CONFIRMED] + +The screenshot shows overly large typography/spacing and poor metadata separation (for example username and +Created metadata visually collide). The table has many operational columns and row actions. + +### Required correction + +- compact shared table typography/padding; +- clearer username/created hierarchy; +- status/role chips use subtle compact styles; +- action consolidation; +- responsive strategy that does not produce an unreadable horizontal table or excessively tall generic cards; +- preserve admin restrictions, mailbox counts and permissions. + +## Finding PR-013 — Add/Edit User form is oversized + +**Severity:** Medium UX +**State:** [CONFIRMED] + +The form uses large field heights, large vertical gaps and a visually heavy password help block. + +### Required correction + +- compact form tokens and section rhythm; +- retain Django validation text and password policy; +- preserve autocomplete semantics and all form field names; +- assigned-mailbox and destructive-permission controls remain permission-accurate. + +## Finding PR-014 — Gunicorn read-only-filesystem control-server error + +**Severity:** Operational OPEN +**State:** [CONFIRMED log finding; root cause UNKNOWN] + +Live logs showed: + +`Control server error: [Errno 30] Read-only file system` + +The v1.3.3 systemd unit intentionally uses `ProtectSystem=strict` with explicit `ReadWritePaths` for runtime, +logs, attachments and Maildir. The exact path Gunicorn is attempting to use has not yet been captured in the +provided evidence, so the root cause must not be guessed. + +### Required correction process + +- reproduce/capture the full Gunicorn control-server path/context; +- determine whether the source is Gunicorn 25.1 runtime behavior, service configuration, or host-specific + environment; +- if repo-owned, make the narrowest systemd/command/config correction that preserves confinement; +- if harmless and upstream-only, formally document the disposition with evidence rather than silently ignore it; +- zero repeated control-server filesystem errors during the final bounded observation window. + +## Finding PR-015 — Direct live endpoint guard needs authenticated browser acceptance + +**Severity:** Acceptance gap +**State:** [PARTIALLY CONFIRMED] + +Unauthenticated `/messages/live/` correctly redirects to login. v1.3.3 source contains a direct-navigation guard +and supports background JSON requests. Final production acceptance still requires authenticated browser proof +that direct top-level navigation does not show raw JSON while the live poller continues to receive JSON. + +## Production-ready definition + +MailStack is production-ready only when both implementation phases complete and every blocker/required gate in +`07_PRODUCTION_ACCEPTANCE_GATE.md` passes. Server health alone is not sufficient if users cannot reliably read +received email. diff --git a/docs/production-readiness/02_TWO_PHASE_A_TO_Z_ROADMAP.md b/docs/production-readiness/02_TWO_PHASE_A_TO_Z_ROADMAP.md new file mode 100644 index 0000000..4ed28f9 --- /dev/null +++ b/docs/production-readiness/02_TWO_PHASE_A_TO_Z_ROADMAP.md @@ -0,0 +1,289 @@ +# Two-Phase A-to-Z Production-Readiness Roadmap + +## Roadmap constraint + +The remaining production-readiness update is limited to **a maximum of two implementation phases**. +No third implementation phase is planned. If a new blocker appears, it must be absorbed into one of these two +phases or the owner must explicitly re-plan the roadmap. + +## Phase map + +| Phase | Name | Primary purpose | Start gate | Completion gate | +|---|---|---|---|---| +| **PHASE-006** | Reader Integrity, Data Repair & Runtime Error Closure | Fix mail readability and critical operational findings first | Planning pack approved | Reader/security/backfill/runtime tests and live smoke PASS | +| **PHASE-007** | Compact UI System & Final Production Acceptance | Complete compact responsive UI and perform final production acceptance | PHASE-006 logged complete | Full CI + visual/responsive + real inbound E2E + stability PASS | + +--- + +# PHASE-006 — Reader Integrity, Data Repair & Runtime Error Closure + +## Objective + +Make every received email reliably readable without weakening MailStack's security boundary, repair already +indexed affected messages safely, close the observed Gunicorn runtime finding, and establish reliable error +handling before broad UI refinement. + +## A-Z implementation sequence + +### 006-A — Baseline re-verification +- verify base tag/commit/tree/source SHA against the frozen v1.3.3 identity; +- verify no unrelated local changes; +- verify current test baseline before modifications. + +### 006-B — Reproduction fixtures +- add representative HTML fixtures containing `head`, `style`, media/style rules, remote images, inline safe + content, links, tables, plain-text alternative and malformed HTML; +- include a fixture representative of the observed Harpoon CSS leakage; +- capture expected readable text and forbidden output patterns. + +### 006-C — Sanitizer correction +- remove non-body style/active content safely before Bleach sanitization; +- keep allowlisted structural HTML only; +- keep event-handler/style denial unless a separately reviewed safe CSS policy is explicitly approved; +- keep URL protocol validation; +- ensure no raw style-block CSS appears as visible body text. + +### 006-D — Remote-image graceful handling +- maintain default no-tracking/no-remote-fetch posture; +- remove or convert blocked remote images into a non-broken presentation; +- preserve meaningful alt text when useful; +- do not introduce a remote image proxy in this phase. + +### 006-E — Message reader security UX cleanup +- remove the permanent visible `Protected rendering · remote and active content are blocked.` banner from the + normal reading path; +- retain iframe `sandbox`, `referrerpolicy="no-referrer"`, sanitizer and attachment restrictions; +- add tests that prove security remains active after the visual banner is removed. + +### 006-F — Existing-message repair command +- implement an idempotent management command for re-parsing existing source Maildir messages; +- dry-run first; +- mailbox and message targeting; +- bounded batch operation and result counters; +- preserve UUID/read/delete/membership/source identity; +- do not delete/re-ingest records. + +### 006-G — Existing-message repair verification +- run dry-run against controlled fixtures/test DB; +- run mutation test on copies/fixtures; +- prove second run is safe/idempotent; +- compare field-level before/after contract. + +### 006-H — Reader fallback/error handling +- if safe HTML cannot be produced, prefer usable text body; +- if neither is usable, render a compact non-crashing error/empty state; +- never expose raw parser exception details to ordinary users; +- record useful server-side diagnostics/audit context. + +### 006-I — Gunicorn read-only-filesystem forensic closure +- reproduce with focused logs; +- capture attempted filesystem path/context; +- classify repo-owned vs host/upstream; +- apply narrow fix only if evidence supports it; +- preserve `ProtectSystem=strict` unless a narrower writable path is proven necessary; +- add/revise service contract tests if template changes. + +### 006-J — Authenticated live-endpoint regression +- direct authenticated browser GET `/messages/live/` must redirect into normal app UI, never raw JSON; +- explicit background custom-header request returns JSON; +- cached legacy `Accept: application/json` poller compatibility remains functional. + +### 006-K — Phase verification +- parser/sanitizer unit tests; +- message-reader functional tests; +- backfill command tests; +- auth/access regressions; +- attachment regressions; +- Django checks / migration drift check; +- Ruff/Bandit/dependency audit according to project policy; +- deterministic source forensic audit. + +### 006-L — Controlled live acceptance +- deploy through existing upgrade tooling, not manual source editing; +- verify services and health; +- open previously broken HTML emails and confirm readability; +- verify plain-text email; +- verify no repeated Gunicorn control-server error during bounded observation; +- log PHASE-006 completion before PHASE-007 starts. + +## PHASE-006 must not include + +- broad shell/table/form redesign beyond any minimum reader change necessary for usability; +- database migration unless separately proven necessary and explicitly approved; +- outbound mail features; +- route/model/permission redesign. + +--- + +# PHASE-007 — Compact UI System & Final Production Acceptance + +## Objective + +Apply a coherent compact design system across the authenticated MailStack application, using VibTools Web UI +v2.1.2 for structural geometry/typography and Licora v5.5.0 as an implementation-pattern reference, while +preserving MailStack's light theme, brand colors and all business logic. + +## A-Z implementation sequence + +### 007-A — MailStack compact token mapping +Create shared MailStack light-theme tokens mapped to the VibTools structural reference: + +- primary UI text target: approximately `13px`; +- micro/helper: `11–12px`; +- card/compact heading: `13–14px`; +- section heading: approximately `16px`; +- page-title cap: approximately `20px` where practical; +- regular/medium weights `400/500`, limited `600` emphasis; +- sidebar target: approximately `196px` expanded; +- topbar target: approximately `44px`; +- buttons: `28px` small / `32px` medium target; +- inputs: `30px` small / `34px` medium target; +- card padding around `10px 12px`; +- radii around `6px / 8px / 12px`; +- light, border-driven surfaces; avoid broad decorative shadows. + +Exact final values may be adjusted slightly for MailStack logo/readability, but deviations require documented +reason rather than page-specific hardcoding. + +### 007-B — Shared authenticated shell +- compact expanded sidebar; +- coherent icon-only desktop collapse with tooltips/accessible labels; +- compact topbar; +- mobile/tablet off-canvas navigation; +- no duplicate navigation tree; +- no viewport-level horizontal overflow. + +### 007-C — Authenticated footer cleanup +- remove Source code/Open-source hub/Free subdomains links from operational workspace; +- retain minimal product/legal identity only if needed; +- no large persistent footer consuming mail-reading space. + +### 007-D — Mailboxes desktop redesign +- compact full-width list/table; +- address primary, status/unread/total/last-received secondary; +- demote Created metadata; +- compact action menu/area preserving permission and CSRF/action contracts; +- shared toolbar for search/status filters and pagination. + +### 007-E — Mailboxes mobile redesign +- purpose-built compact mobile list/card; +- essential data above secondary metadata; +- compact action handling; +- no generic seven-row table-card expansion; +- verify 320/360/375/390/400/430px widths. + +### 007-F — Inbox compact refinement +- target denser rows than current 58px baseline; +- sender + subject/preview + attachment state + time hierarchy; +- unread emphasis without oversized weight; +- filter/search toolbar uses compact shared controls; +- live-inserted rows exactly match server-rendered rows. + +### 007-G — Message reader compact refinement +- compact back/action/sender/routing header; +- readable body region without excessive nested scrolling; +- attachments directly follow body; +- no permanent security banner; +- safe HTML and plain fallback remain unified. + +### 007-H — Create mailbox redesign +- compact page width/rhythm; +- compact local-part input group; +- improved user assignment selector while preserving field semantics; +- clear primary action and validation. + +### 007-I — User management redesign +- compact table/list typography and row spacing; +- correct username/created metadata separation; +- role/status chips; +- action consolidation; +- responsive behavior designed specifically for the data. + +### 007-J — Add/Edit user redesign +- compact fields and help text; +- preserve password validation copy; +- compact assigned-mailbox selection; +- clear permission controls; +- no behavior changes to admin restrictions or mailbox assignments. + +### 007-K — Shared feedback/error visual system +- form errors, flash messages, warnings, empty states and 404/500 pages use compact consistent components; +- preserve error semantics and accessibility; +- add 403/400 presentation only if current behavior/test evidence supports it without changing authorization + semantics. + +### 007-L — Responsive/accessibility pass +- keyboard navigation; +- focus visibility; +- accessible icon-only controls; +- aria-current/expanded/controls behavior; +- reduced motion behavior; +- 200% zoom sanity; +- no clipped text or inaccessible action menus. + +### 007-M — Visual regression matrix +- Dashboard; +- Mailboxes desktop/mobile; +- Inbox; +- HTML message; +- plain message; +- attachment message; +- Create mailbox; +- User management; +- Add/Edit user; +- delete/confirmation states; +- empty/loading/error states; +- collapsed and mobile navigation. + +### 007-N — Full regression/CI qualification +- existing application tests; +- UI contract tests; +- parser/backfill tests from PHASE-006; +- release/upgrade tests; +- documentation/forensic gates; +- dependency/security gates; +- deterministic build/release verification. + +### 007-O — Production upgrade rehearsal +- build deterministic release artifact; +- verify checksum/manifest; +- verify upgrade tool sees correct version direction and migration count; +- validate rollback snapshot path and data backup contract in isolated/staging environment when available. + +### 007-P — Production deployment +- use supported upgrade tool in resilient terminal session; +- capture `MAILSTACK_UPGRADE=PASS` and exact source SHA; +- verify installation marker and deployed-source fidelity. + +### 007-Q — Production UI acceptance +- owner visual check against supplied screenshots and approved structure; +- HTML emails readable; +- mobile compactness approved; +- no public footer contamination; +- no raw JSON navigation. + +### 007-R — Real external inbound E2E +At least: +- one normal external email; +- one HTML-rich external email; +- one message with attachment when practical; +- prove Postfix -> Dovecot LMTP -> Maildir -> ingestion -> MariaDB -> browser visibility; +- prove message remains readable and attachment access works. + +### 007-S — Bounded stability observation +- services remain active; +- no repeated Gunicorn read-only-filesystem error; +- no ingestion error growth; +- health remains ready; +- no unexpected 5xx in application logs. + +### 007-T — Final documentation and completion log +- update actual implementation status; +- mark PHASE-007 complete; +- record 2/2 phases complete; +- record final release identity and acceptance evidence; +- no further update phase remains unless the owner opens a new scope. + +## Final roadmap state target + +`PHASE-006 COMPLETE` -> `PHASE-007 COMPLETE` -> `PRODUCTION READY / OWNER ACCEPTED` diff --git a/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md b/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md new file mode 100644 index 0000000..1e24fc6 --- /dev/null +++ b/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md @@ -0,0 +1,136 @@ +# Update Phase Completion Log + +## Purpose + +This is the single progress ledger for the two-phase production-readiness update. It must be updated immediately +when a phase changes state so implementation cannot become unordered or ambiguous. + +## Overall progress + +| Metric | Current value | +|---|---| +| Frozen baseline | MailStack `v1.3.3` | +| Planned implementation phases | **2** | +| Completed phases in this production-readiness cycle | **0 / 2** | +| Remaining phases | **2 / 2** | +| Current implementation state | Planning/documentation only | +| Runtime implementation started | No | +| Production-ready acceptance | Not yet | + +## Phase status ledger + +| Phase | State | What must be completed | Completion evidence | +|---|---|---|---| +| PHASE-006 | **PENDING** | Reader integrity, safe existing-message repair, runtime error closure, reader regressions | Not yet recorded | +| PHASE-007 | **PENDING / BLOCKED BY PHASE-006** | Compact UI system, responsive refinement, final CI/live/E2E acceptance | Not yet recorded | + +--- + +# PHASE-006 completion record + +## Status + +**PENDING** + +## Baseline at phase start + +Must equal the official v1.3.3 frozen identity documented in `00_OFFICIAL_BASELINE_FREEZE.md`. + +## Approved scope + +- HTML sanitizer/rendering correction. +- Remote-image graceful blocked-state handling. +- Removal of intrusive visible protected-rendering banner while retaining security. +- Existing-message repair/backfill tooling. +- Reader fallback/error handling. +- Gunicorn read-only-filesystem control-server finding closure/disposition. +- Authenticated live-endpoint navigation regression. +- Focused tests and live reader acceptance. + +## Features/fixes actually completed + +None yet. This section is replaced with exact implemented items after the phase passes. + +## Files changed + +None yet. + +## Tests/evidence + +None yet. + +## Known residual findings after phase + +Not yet assessed. + +## Phase completion decision + +`PENDING` + +## Remaining after PHASE-006 + +When PHASE-006 becomes complete, exactly one phase remains: PHASE-007. + +--- + +# PHASE-007 completion record + +## Status + +**PENDING / BLOCKED BY PHASE-006** + +## Approved scope + +- compact shared MailStack light-theme token mapping; +- shell/sidebar/topbar refinement; +- authenticated footer cleanup; +- Mailboxes desktop/mobile compact redesign; +- Inbox compact refinement; +- compact message-reader refinement; +- Create mailbox compact form; +- User management compact table/list; +- Add/Edit user compact forms; +- responsive/accessibility/error-state styling; +- final CI, upgrade, production UI, inbound E2E and stability acceptance. + +## Features/fixes actually completed + +None yet. + +## Files changed + +None yet. + +## Tests/evidence + +None yet. + +## Known residual findings after phase + +Not yet assessed. + +## Phase completion decision + +`PENDING` + +## Remaining after PHASE-007 + +Target: `0` production-readiness phases remaining. Any later work is a separately owner-approved scope and must +not be silently appended to this cycle. + +--- + +# Mandatory update procedure for this log + +At each phase completion: + +1. Record exact baseline/source commit at phase start. +2. Replace `PENDING` with `COMPLETE` only after all blocking gates pass. +3. List every user-visible feature/fix actually delivered. +4. List important non-user-visible reliability/error/security changes. +5. List exact changed files or link the phase manifest. +6. Record test counts/results and live evidence. +7. Record unresolved findings explicitly. +8. Recalculate completed/remaining phase counts. +9. Write the exact next phase scope before starting it. +10. Do not start the next phase while the prior phase is still ambiguous or partially logged. diff --git a/docs/production-readiness/04_ERROR_HANDLING_REGISTER_AND_PLAN.md b/docs/production-readiness/04_ERROR_HANDLING_REGISTER_AND_PLAN.md new file mode 100644 index 0000000..fe5fee8 --- /dev/null +++ b/docs/production-readiness/04_ERROR_HANDLING_REGISTER_AND_PLAN.md @@ -0,0 +1,159 @@ +# Error Handling Register and Production Plan + +## Purpose + +Record error handling that is already implemented in v1.3.3, identify gaps exposed by the live forensic audit, +and define additions allowed during the two production-readiness phases. + +## Existing error handling — [CONFIRMED] + +### Authentication and login +- failed login attempts are persisted; +- lockout/rate-limiting is enforced after the configured failure threshold/window; +- successful login clears prior failed attempts for the same normalized username/IP context; +- login success/failure events are audit-recorded; +- unsafe external `next` redirects are rejected by host/scheme validation. + +### Authorization +- admin-only operations call `require_admin()` and raise `PermissionDenied` when unauthorized; +- non-admin mailbox/message queries are restricted to membership-accessible objects; +- unauthorized destructive message/mailbox access is intentionally hidden as 404 in relevant paths; +- delete permissions are separately evaluated for messages and mailboxes. + +### Mailbox validation and provisioning +- local-part validation rejects empty/too-long/path-dangerous/invalid values; +- duplicate/reserved mailbox addresses are rejected; +- provisioning uses a dedicated `ProvisioningError` abstraction; +- provisioning/status/delete operations use transactions and guarded filesystem paths; +- safe provisioning locks prevent conflicting mailbox operations; +- UI catches provisioning failures and surfaces form/flash errors. + +### Message and attachment access +- invalid read-state mutation raises `PermissionDenied`; +- missing/unauthorized messages return 404; +- attachment paths are confined to the configured attachment root; +- missing attachment files return 404; +- downloads set `nosniff` and private/no-store headers. + +### Ingestion +- MIME parser failures fall back to decoded text and record a warning; +- invalid/missing Date and sender metadata produce parse warnings rather than crashing ingestion; +- oversized messages and attachments are bounded; +- attachment storage rollback deletes partially stored attachment files on ingestion failure; +- database creation is transaction-protected; +- ingestion exceptions increment error counters and write audit/log evidence; +- duplicate Maildir source keys are detected and not re-created. + +### Health and readiness +- liveness endpoint returns process-level live state; +- readiness checks database, pending migrations, mail storage, attachment storage and core production config; +- storage writability is tested through temporary healthcheck files; +- readiness returns HTTP 503 when required checks fail. + +### Application error pages +- custom 404 template/handler exists; +- custom 500 template/handler exists. + +### Upgrade/rollback operations +- deterministic archive/checksum verification fails closed; +- migration-history mutation is guarded; +- pre-upgrade source snapshot and coordinated data backup precede source mutation; +- no-new-migration source/runtime failures support automatic source rollback; +- migration-capable failure after schema mutation refuses unsafe automatic source/schema rollback; +- service/config/post-upgrade verification is blocking. + +## Current error-handling gaps / required additions + +### EH-001 — HTML rendering failure must not make mail unreadable +**Phase:** PHASE-006 +**Priority:** BLOCKER + +Required behavior: +- sanitizer strips non-content CSS/style blocks without leaking their text; +- if sanitized HTML is unusable, render the stored plain-text alternative; +- if neither body is usable, show a compact safe message state rather than raw code or an exception; +- record server-side diagnostic context without exposing sensitive source content in user-facing error text. + +### EH-002 — Existing-message repair command needs fail-safe behavior +**Phase:** PHASE-006 +**Priority:** BLOCKER + +Required behavior: +- `--dry-run` default/recommended path; +- bounded selection; +- per-message success/skip/warning/error counters; +- one message failure does not corrupt unrelated messages; +- transaction boundary per message or safe batch strategy; +- preserve original Maildir source; +- idempotence proof; +- non-zero process exit when blocking repair errors occur. + +### EH-003 — Remote-image blocking must degrade gracefully +**Phase:** PHASE-006 + +A rejected remote image must not leave a broken-image icon/layout residue that looks like a rendering failure. +It should disappear cleanly or become a safe compact placeholder/alt representation, without remote tracking. + +### EH-004 — Gunicorn control-server filesystem error must be classified +**Phase:** PHASE-006 +**State:** OPEN + +Required: +- capture exact attempted path and trigger; +- classify whether it affects request serving/reload/control features; +- correct only the necessary writable path/config if repo-owned; +- retain systemd confinement; +- bounded post-fix log observation. + +### EH-005 — 400/403 presentation consistency +**Phase:** PHASE-007 +**State:** REVIEW + +Current source has explicit custom 404/500 pages. Permission failures may use Django's default 403 response. +During UI consolidation, determine whether dedicated 400/403 templates can be added without changing underlying +status codes or authorization semantics. This is presentation-only and must be test-backed. + +### EH-006 — Responsive action-menu failure states +**Phase:** PHASE-007 + +If row actions are consolidated into menus, keyboard/focus/backdrop behavior and failed POST feedback must remain +accessible. No destructive action may become a client-only operation that bypasses existing server-side checks. + +### EH-007 — Empty/loading/filter states +**Phase:** PHASE-007 + +Provide compact consistent states for: +- no mailboxes; +- no messages; +- no filter results; +- unavailable message body; +- missing attachment; +- loading/live-update delay where applicable. + +These states must not claim data loss when the source Maildir remains preserved. + +### EH-008 — User-visible flash/error density +**Phase:** PHASE-007 + +Existing Django form errors and flash messages remain semantically correct. Refine their layout so they are +compact and noticeable without expanding the entire page or hiding validation detail. + +## Error logging rules + +- Never log passwords, secret keys, private signing material, full session tokens or private environment values. +- Do not copy complete raw emails into generic exception logs. +- Prefer identifiers: mailbox address where appropriate, message UUID/source key, error type and bounded warning. +- User-facing messages must be actionable but not reveal filesystem/database internals. +- Security/authorization failures must not disclose object existence to unauthorized users. + +## Final acceptance for error handling + +Error-handling work is accepted only when: + +- no raw CSS/parser exception is shown as normal mail content; +- message reader has a safe fallback path; +- repair command is dry-run capable and idempotent; +- no regression in 404/authorization behavior; +- no repeated unresolved Gunicorn control-server error in the final observation window; +- health/readiness remains accurate; +- automated tests cover all new error branches. diff --git a/docs/production-readiness/05_ACTUAL_IMPLEMENTATION_STATUS.md b/docs/production-readiness/05_ACTUAL_IMPLEMENTATION_STATUS.md new file mode 100644 index 0000000..cacc817 --- /dev/null +++ b/docs/production-readiness/05_ACTUAL_IMPLEMENTATION_STATUS.md @@ -0,0 +1,126 @@ +# Actual Implementation Status + +## Purpose + +Track **what is actually working**, what exists but is defective, what each production-readiness phase adds, +and what remains. This file must reflect evidence, not planned marketing language. + +## Baseline: v1.3.3 actual working state + +### Working and verified at server/core level + +| Capability | State | Notes | +|---|---|---| +| Receive-only SMTP architecture | WORKING | No outbound send/reply/forward feature | +| Postfix inbound service | WORKING | Active and config check passed during live acceptance | +| Dovecot LMTP delivery | WORKING | Active and config check passed | +| Maildir storage | WORKING | Readiness/storage verification passed | +| MariaDB application data | WORKING | Ready check passed | +| Gunicorn web app serving | WORKING WITH OPEN LOG FINDING | HTTP works; control-server read-only-filesystem log remains open | +| Nginx HTTPS app/public routing | WORKING | Config and HTTP checks passed | +| Maildir ingestion worker | WORKING | Verification scan reported zero errors | +| Public contact service | WORKING | Active during live acceptance | +| Backup | WORKING | Coordinated upgrade backup verified | +| Upgrade | WORKING | v1.3.0-rc.1 -> v1.3.3 completed with `MAILSTACK_UPGRADE=PASS` | +| Automatic source/runtime rollback path | WORKING/PROVEN | A failed no-migration upgrade attempt auto-rolled back successfully | +| Health `/health/live/` | WORKING | HTTP 200 live | +| Health `/health/ready/` | WORKING | HTTP 200 ready with all checks true | + +### Working application features + +- login/logout; +- failed-login throttling/lockout and audit events; +- dashboard operational summary; +- mailbox list/search/status filtering/pagination; +- mailbox creation and Maildir provisioning; +- mailbox enable/disable; +- permission-gated mailbox deletion/reservation; +- user list/search; +- user creation/edit/delete rules; +- mailbox assignment to users; +- per-user delete permissions; +- Inbox search by sender/subject; +- read/unread filter; +- attachment/no-attachment filter; +- message row previews; +- message detail route; +- automatic mark-read on open; +- mark-unread action; +- permission-gated soft delete; +- attachment download authorization; +- background live-update endpoint and direct-navigation guard in source; +- plain-text body fallback; +- sanitized-HTML iframe mechanism exists; +- audit records for major user/mailbox/message events. + +## Existing but not production-acceptable + +| Capability | Actual state | Why not accepted | +|---|---|---| +| HTML email reading | **DEFECTIVE / BLOCKER** | Style-block CSS is visible as body text for real emails | +| Existing stored HTML bodies | **DEFECTIVE / BLOCKER** | Parser fix alone will not repair duplicate-indexed messages | +| Remote image blocking presentation | DEFECTIVE UX | Can leave broken-image/alt residue | +| Protected-rendering security notice | FUNCTIONAL BUT REJECTED UX | Permanent banner is intrusive | +| Mailboxes desktop UI | FUNCTIONAL BUT NOT COMPACT | Heavy seven-column table/actions | +| Mailboxes mobile UI | FUNCTIONAL BUT NOT COMPACT | Excessively tall generic card conversion | +| Collapsed sidebar | FUNCTIONAL BUT NOT ACCEPTED | Geometry/spacing visually unfinished | +| Message reader layout | FUNCTIONAL BUT NOT ACCEPTED | Excessive height/nested scrolling/spacing | +| Create mailbox UI | FUNCTIONAL BUT NOT ACCEPTED | Large dead space/native tall multi-select | +| User management UI | FUNCTIONAL BUT NOT ACCEPTED | Density/alignment/action presentation issues | +| Add/Edit user UI | FUNCTIONAL BUT NOT ACCEPTED | Oversized controls/help spacing | +| Authenticated footer | FUNCTIONAL BUT REJECTED UX | Public/promotional links appear in operational app | + +## PHASE-006 expected actual additions + +After PHASE-006 is complete, this section must be converted from `EXPECTED` to `WORKING VERIFIED` with evidence. + +- corrected safe HTML parser/sanitizer; +- readable style-heavy HTML emails; +- no CSS leakage from style blocks; +- graceful blocked remote-image presentation; +- silent retained rendering security controls; +- existing-message repair/backfill management command; +- safe text fallback when sanitized HTML cannot be used; +- authenticated `/messages/live/` document-navigation proof; +- Gunicorn control-server filesystem finding fixed or formally evidenced/dispositioned; +- focused regression tests and live reader acceptance. + +## PHASE-007 expected actual additions + +After PHASE-007 is complete, this section must be converted from `EXPECTED` to `WORKING VERIFIED` with evidence. + +- compact MailStack token system based on VibTools structural sizing; +- compact desktop shell/topbar/sidebar; +- proper mobile off-canvas navigation; +- clean authenticated workspace footer; +- compact Mailboxes desktop list; +- compact Mailboxes mobile list/cards; +- refined compact Inbox; +- refined compact unified reader; +- compact Create mailbox page; +- compact User management page; +- compact Add/Edit user pages; +- consistent responsive/empty/error/feedback components; +- final accessibility checks; +- final deterministic build/CI qualification; +- final production upgrade verification; +- real external inbound E2E including HTML and attachment coverage; +- final bounded stability acceptance. + +## Remaining feature boundary after production readiness + +The following remain intentionally **not implemented** unless a future owner-approved scope changes the product: + +- outbound Compose; +- Reply; +- Forward; +- Sent; +- Drafts; +- SMTP submission for users; +- IMAP; +- POP3; +- public registration; +- campaigns/bulk sending; +- high-availability/multi-node architecture. + +They are not production-readiness defects because MailStack is intentionally receive-only. diff --git a/docs/production-readiness/06_UI_DESIGN_REFERENCE_AND_DEFECT_MATRIX.md b/docs/production-readiness/06_UI_DESIGN_REFERENCE_AND_DEFECT_MATRIX.md new file mode 100644 index 0000000..173a4ec --- /dev/null +++ b/docs/production-readiness/06_UI_DESIGN_REFERENCE_AND_DEFECT_MATRIX.md @@ -0,0 +1,131 @@ +# UI Design Reference and Screenshot Defect Matrix + +## Design authority for the next update + +MailStack keeps its own product identity. The reference inputs are used in this order: + +1. **MailStack v1.3.3 current behavior/business contracts** — functional authority. +2. **Owner-supplied screenshots and annotations** — defect/acceptance authority. +3. **VibTools Web UI v2.1.2** — structural geometry, typography, density and component-system reference. +4. **Licora v5.5.0** — implementation-pattern reference showing how VibTools structure can be mapped onto a + different product theme without copying the reference product's branding. + +## VibTools structural values extracted + +| Role | Reference value | +|---|---:| +| Primary UI text | `13px` | +| Micro labels/badges | `11px` | +| Controls/helper | `12px` | +| Compact heading | `14px` | +| Section header | `16px` | +| Page title cap | `20px` | +| Expanded sidebar | `196px` | +| Topbar | `44px` | +| Small button | `28px` | +| Medium button | `32px` | +| Small input | `30px` | +| Medium input | `34px` | +| Card padding | `10px 12px` | +| Radius small/control/card | `6px / 8px / 12px` | +| Card shadow | none / border-driven | +| Normal transition | `120ms ease` | + +## Current MailStack structural values causing density mismatch + +| Role | v1.3.3 current value | Forensic interpretation | +|---|---:|---| +| Base font | `1rem` (~16px) | materially larger than reference | +| Sidebar | `256px` | too wide for compact target | +| Collapsed sidebar | `80px` | oversized icon rail | +| Topbar | `72px` | too tall for compact target | +| General table cell padding | `13px 15px` | heavy for operational tables | +| Mailbox filter controls | `38px` | above compact control target | +| Inbox row min height | `58px` | denser than old UI but still above compact target | +| Reader HTML iframe | `clamp(460px,65vh,800px)` | large nested scroll surface | +| General radius | `14px` | softer/larger than compact reference | +| General shadow | broad card shadow token | more decorative than reference | + +## Theme preservation rule + +Do not copy VibTools dark colors into MailStack production UI. + +MailStack must retain: +- light application background; +- white/light surfaces; +- existing MailStack blue primary action identity; +- semantic green/amber/red statuses; +- MailStack logo and naming. + +The update changes **structure and scale**, not product identity. + +## Screenshot defect matrix + +| ID | Screen / annotation | Defect | Severity | Target phase | +|---|---|---|---|---| +| BUG-001 | HTML message reader top/body | Protected-rendering banner + raw CSS leakage | BLOCKER | PHASE-006 | +| BUG-002 | HTML reader lower body/footer | Body composition too tall; broken blocked image; public footer links | BLOCKER/Major | 006 + 007 | +| BUG-003 | 400px Mailboxes view | Generic table-card conversion is extremely tall | Major | PHASE-007 | +| BUG-004 | Collapsed navigation/dashboard | Icon rail too wide/unfinished; wasted space | Major | PHASE-007 | +| BUG-005 | Create mailbox | Form card too large/sparse; multi-select dated | Medium | PHASE-007 | +| BUG-006 | User management | Table density/alignment/actions poor | Major | PHASE-007 | +| BUG-007 | Add user | Oversized form controls/help block/dead space | Medium | PHASE-007 | + +## Component-specific target structure + +### Shell +- desktop: fixed compact expanded sidebar; +- optional compact icon collapse; +- tablet/mobile: off-canvas drawer; +- topbar contains context/account only, not duplicate primary navigation; +- workspace width is fluid and does not reserve unnecessary dead space. + +### Mailboxes +Desktop row priority: +1. mailbox address; +2. status; +3. unread / total; +4. last received; +5. compact actions. + +Mobile card/list priority: +1. address + status; +2. unread/total + last received; +3. compact secondary/action row. + +### Inbox +Desktop target: +`status dot | sender | subject + preview | attachment/meta | time` + +Mobile target: +- sender/time first line; +- subject second line; +- preview/meta optional third compact line; +- no oversized row cards. + +### Reader +- one compact header; +- sender/routing metadata expandable; +- action buttons compact; +- body immediately readable; +- no permanent security warning strip; +- attachments immediately follow body; +- no public footer clutter. + +### Forms +- compact input/button height; +- smaller page-title/helper copy; +- clear groups rather than oversized cards; +- responsive widths use available space intelligently; +- validation remains directly adjacent to affected controls. + +## UI anti-regression rules + +- No page-specific hardcoded typography system. +- No new shadow/elevation system. +- No horizontal viewport overflow. +- No action accessible only by hover. +- No icon-only action without accessible label/title. +- No destructive action bypassing server-side permission/CSRF/confirmation. +- No change to route names, field names or JavaScript hooks solely for styling convenience. +- No public-site promotional navigation inside the authenticated operational workspace. diff --git a/docs/production-readiness/07_PRODUCTION_ACCEPTANCE_GATE.md b/docs/production-readiness/07_PRODUCTION_ACCEPTANCE_GATE.md new file mode 100644 index 0000000..f258225 --- /dev/null +++ b/docs/production-readiness/07_PRODUCTION_ACCEPTANCE_GATE.md @@ -0,0 +1,162 @@ +# Production Acceptance Gate + +## Rule + +Production readiness is a **blocking gate**, not a subjective statement. Every `BLOCKING` item below must pass. +A healthy server does not compensate for an unreadable mailbox UI. + +## Gate A — Baseline and source integrity — BLOCKING + +- [ ] base commit/tree equals the frozen v1.3.3 baseline before implementation; +- [ ] final release commit/tag/version are internally consistent; +- [ ] deterministic source archive verifies; +- [ ] SHA-256 and source manifest verify; +- [ ] no unexpected file additions/deletions; +- [ ] deployed source matches the final release source after production upgrade. + +## Gate B — HTML reader integrity — BLOCKING + +- [ ] Harpoon-style fixture renders readable content; +- [ ] zero visible style-block CSS rules; +- [ ] script/event-handler content is removed/blocked; +- [ ] unsafe remote images are not fetched by default; +- [ ] blocked remote image does not show broken-image residue; +- [ ] links remain safely constrained; +- [ ] iframe remains sandboxed; +- [ ] referrer policy remains `no-referrer`; +- [ ] plain-text-only mail renders correctly; +- [ ] malformed HTML falls back safely without 500. + +## Gate C — Existing-message repair — BLOCKING + +- [ ] dry-run command works; +- [ ] targeted mailbox/message selection works; +- [ ] repair uses original Maildir source; +- [ ] UUID/read/delete/membership/source identity is preserved; +- [ ] first mutation run repairs affected body; +- [ ] second run is safe/idempotent; +- [ ] errors are counted/reported without data destruction; +- [ ] production repair has a before/after count report. + +## Gate D — Core functionality regression — BLOCKING + +- [ ] login/logout; +- [ ] login throttling; +- [ ] dashboard; +- [ ] mailbox list/search/filter/pagination; +- [ ] create mailbox; +- [ ] enable/disable mailbox; +- [ ] permission-gated mailbox delete; +- [ ] user list/create/edit/delete rules; +- [ ] mailbox assignment; +- [ ] Inbox search/read/attachment filters; +- [ ] message read/unread; +- [ ] permission-gated message delete; +- [ ] attachment download; +- [ ] live update polling; +- [ ] direct live endpoint does not show raw JSON as a document. + +## Gate E — Compact desktop UI — BLOCKING + +- [ ] topbar/sidebar meet approved compact structure; +- [ ] Mailboxes table/list is compact and legible; +- [ ] Inbox rows are compact; +- [ ] message reader is compact/readable; +- [ ] Create mailbox form is compact; +- [ ] User management is compact; +- [ ] Add/Edit user forms are compact; +- [ ] authenticated public/promotional footer links are absent; +- [ ] owner approves desktop screenshots. + +## Gate F — Responsive/mobile — BLOCKING + +Verify at minimum: `320`, `360`, `375`, `390`, `400`, `430`, `768`, `1024`, desktop widths. + +- [ ] no viewport horizontal overflow; +- [ ] mobile sidebar uses coherent drawer behavior; +- [ ] Mailboxes mobile list is not generic seven-row tall cards; +- [ ] message reader header/body/actions remain usable; +- [ ] forms fit without clipped controls; +- [ ] destructive actions remain accessible; +- [ ] owner approves mobile screenshots. + +## Gate G — Accessibility — BLOCKING + +- [ ] keyboard navigation works; +- [ ] visible focus indicators; +- [ ] icon-only controls have labels/tooltips; +- [ ] active navigation has accessible state; +- [ ] mobile drawer exposes expanded/controls state; +- [ ] Escape/backdrop close works; +- [ ] status is not color-only where text label exists; +- [ ] reduced-motion behavior preserved; +- [ ] 200% zoom sanity check. + +## Gate H — Error handling — BLOCKING + +- [ ] 404 and 500 remain correct; +- [ ] permission failures do not leak object existence; +- [ ] form errors remain visible; +- [ ] parser/render failure has safe fallback; +- [ ] existing-message repair failures are bounded and reported; +- [ ] no repeated unresolved Gunicorn control-server read-only-filesystem error during bounded observation; +- [ ] no unexpected new 5xx burst in application logs. + +## Gate I — Security/static analysis/dependency — BLOCKING + +- [ ] supported Python version test environment; +- [ ] Django system checks; +- [ ] migration drift check; +- [ ] full application tests; +- [ ] focused UI/parser/backfill tests; +- [ ] Ruff; +- [ ] Bandit; +- [ ] dependency audit according to repository policy; +- [ ] documentation/forensic source audit; +- [ ] release/upgrade contract tests. + +## Gate J — Production operational health — BLOCKING + +- [ ] MariaDB active; +- [ ] Postfix active and `postfix check` passes; +- [ ] Dovecot active and `doveconf -n` passes; +- [ ] Nginx active and config test passes; +- [ ] Gunicorn active; +- [ ] ingestion active; +- [ ] public-contact service active; +- [ ] `/health/live/` 200; +- [ ] `/health/ready/` 200 ready; +- [ ] app login page 200; +- [ ] public site 200. + +## Gate K — Real external inbound E2E — BLOCKING + +- [ ] send external normal email to a production mailbox; +- [ ] prove Postfix acceptance; +- [ ] prove Dovecot LMTP/Maildir arrival; +- [ ] prove ingestion creates/recognizes DB message; +- [ ] prove browser shows message; +- [ ] prove message is readable; +- [ ] repeat with HTML-rich email; +- [ ] repeat with attachment when practical; +- [ ] attachment download remains authorized and functional. + +## Gate L — Backup/upgrade/rollback — BLOCKING + +- [ ] final release upgrade artifact/checksum verifies; +- [ ] upgrade detects expected migration count; +- [ ] production backup/snapshot created before mutation; +- [ ] `MAILSTACK_UPGRADE=PASS` captured; +- [ ] installation marker contains final version/SHA; +- [ ] rollback path remains known and intact; +- [ ] no implicit database/Maildir rollback is performed without explicit reviewed need. + +## Final decision states + +Only one of these may be recorded: + +- `PRODUCTION_READY=PASS` +- `PRODUCTION_READY=FAIL` +- `PRODUCTION_READY=BLOCKED` + +`PASS` requires all blocking gates above plus owner visual acceptance. diff --git a/docs/production-readiness/08_CHANGE_CONTROL_AND_SCOPE_LOCK.md b/docs/production-readiness/08_CHANGE_CONTROL_AND_SCOPE_LOCK.md new file mode 100644 index 0000000..2e13ae1 --- /dev/null +++ b/docs/production-readiness/08_CHANGE_CONTROL_AND_SCOPE_LOCK.md @@ -0,0 +1,108 @@ +# Change Control and Scope Lock + +## Scope owner rule + +The frozen baseline may change only inside explicitly approved PHASE-006 and PHASE-007 scope. A useful cleanup, +refactor, rename or redesign is **not authorization** by itself. + +## Change classes + +### Class A — Approved defect correction +Allowed when directly tied to a forensic finding and phase task. + +Examples: +- sanitizer CSS leakage fix; +- existing-message repair command; +- compact UI token mapping; +- responsive Mailboxes fix; +- authenticated footer cleanup; +- confirmed Gunicorn service-template fix. + +### Class B — Required supporting test/documentation +Allowed when necessary to verify Class A work. + +Examples: +- regression fixtures; +- UI contract tests; +- backfill tests; +- phase/change manifests; +- release notes and acceptance evidence. + +### Class C — Requires explicit additional owner approval +Do not implement automatically. + +Examples: +- database schema migration not already approved; +- new external dependency; +- remote-image proxy; +- new mail protocol; +- new user role model; +- route/API redesign; +- new public page/feature; +- new update wrapper command if it changes deployment surface; +- deletion/renaming of existing features or modules. + +## Protected contracts + +Implementation must preserve: + +- URL names and route behavior unless a confirmed defect specifically requires a narrow guard; +- form field names and POST contracts; +- CSRF handling; +- object authorization; +- mailbox membership and delete permissions; +- read/unread semantics; +- soft-delete semantics; +- attachment authorization; +- original Maildir source preservation; +- mail database schema unless separately approved; +- Postfix/Dovecot contracts; +- service names; +- backup/upgrade/rollback behavior; +- receive-only scope. + +## UI reference boundary + +VibTools and Licora are **design references**, not source-code donors for MailStack runtime behavior. + +Allowed to adopt: +- typography scale; +- spacing/density; +- sidebar/topbar geometry; +- component grouping; +- table/action-menu patterns; +- responsive drawer structure; +- accessibility patterns. + +Must not copy without explicit need: +- product branding; +- product-specific colors; +- unrelated business features; +- Licora/PHP updater behavior; +- VibTools dark theme as MailStack's production theme. + +## File-change discipline + +Each implementation phase must produce: + +1. exact changed-file list; +2. exact deleted-file list (normally empty unless owner-approved); +3. SHA-256 for the delta artifact; +4. change manifest mapping each file to an approved task/finding; +5. regression/test report; +6. phase completion-log update. + +Any file not mapped to an approved task is an out-of-scope finding and blocks merge until explained or removed. + +## Stop conditions + +Stop implementation and request review when: + +- base commit/tree does not equal the frozen baseline; +- a migration becomes necessary unexpectedly; +- a fix would weaken sanitizer/security isolation; +- existing mail data would need deletion/re-ingestion; +- a change affects Postfix/Dovecot/mail routing unexpectedly; +- a new dependency becomes necessary; +- repeated test failures indicate a root cause outside approved scope; +- production state differs from release source identity. diff --git a/docs/production-readiness/09_RELEASE_AND_UPDATE_EXECUTION_POLICY.md b/docs/production-readiness/09_RELEASE_AND_UPDATE_EXECUTION_POLICY.md new file mode 100644 index 0000000..14b1a01 --- /dev/null +++ b/docs/production-readiness/09_RELEASE_AND_UPDATE_EXECUTION_POLICY.md @@ -0,0 +1,83 @@ +# Release and Update Execution Policy + +## Current upgrade capability + +MailStack v1.3.3 now contains the generic existing-server upgrade tooling required for normal future releases. +The unusual bootstrap sequence used to move the older `1.3.0-rc.1` production server to v1.3.3 should not be +repeated for ordinary future upgrades. + +## Standard future upgrade contract + +After a future deterministic release archive and matching checksum are present on the server, the supported +upgrade shape is: + +```bash +sudo /opt/vibmail/app/scripts/upgrade.sh \ + --archive /root/releases/mailstack-X.Y.Z-source.zip \ + --checksum /root/releases/mailstack-X.Y.Z-source.zip.sha256 \ + --confirm-upgrade +``` + +`--allow-migrations` is used only after explicit review when the verified target contains new migrations. + +## What the maintained upgrader is expected to automate + +- service/config prechecks; +- current application verification; +- deterministic archive/checksum/manifest/version validation; +- migration-history comparison; +- source rollback snapshot; +- coordinated data backup; +- staged source replacement; +- dependency convergence; +- migration command/contract checks; +- static collection; +- public-site release switch; +- service restart; +- final application and HTTP verification; +- safe source/runtime rollback in eligible no-new-migration failure cases; +- final upgrade identity report. + +## Resilient terminal rule + +Production upgrade runs must occur inside `tmux` or another approved resilient session so an operator terminal +disconnect does not terminate the server-side upgrade process. + +## Single-command auto-update goal + +A true command such as: + +```bash +sudo update-mailstack +``` + +that downloads the release assets and then invokes the maintained upgrader is **not currently part of the +frozen baseline**. It is a potential future operational enhancement, not part of PHASE-006/007 unless the owner +explicitly adds it to scope. + +Until such a wrapper is approved and implemented, the normal process is still short: + +1. obtain official archive + checksum; +2. invoke the single maintained `upgrade.sh` command above; +3. review PASS output and post-upgrade acceptance. + +## Production deployment rule for the two planned phases + +- Never hot-edit `/opt/vibmail/app` as the primary deployment method. +- Build/qualify source in repository workflow first. +- Publish/prepare deterministic artifact. +- Verify exact SHA. +- Use maintained upgrade tooling. +- Capture rollback snapshot/data backup paths. +- Run phase-specific live acceptance. +- Update `03_UPDATE_PHASE_COMPLETION_LOG.md` before continuing. + +## Failure handling + +If upgrade fails: +- do not immediately re-run; +- classify whether mutation started; +- inspect `UPGRADE_FAILURE`, `UPGRADE_FINDING`, `UPGRADE_ROLLBACK` and snapshot paths; +- verify installed source/version/services/health before next action; +- do not manually restore MariaDB/Maildir unless evidence requires it and the owner explicitly approves the + recovery plan. diff --git a/docs/production-readiness/10_TEST_AND_ACCEPTANCE_MATRIX.md b/docs/production-readiness/10_TEST_AND_ACCEPTANCE_MATRIX.md new file mode 100644 index 0000000..64d3bbe --- /dev/null +++ b/docs/production-readiness/10_TEST_AND_ACCEPTANCE_MATRIX.md @@ -0,0 +1,133 @@ +# Test and Acceptance Matrix + +## Purpose + +Define the minimum deterministic test coverage for PHASE-006 and PHASE-007 so visual changes do not silently +break receive-only functionality, security or operational upgrade behavior. + +## PHASE-006 focused matrix + +| Area | Test | Expected | +|---|---|---| +| Sanitizer | style block in head | CSS rules absent from visible sanitized body | +| Sanitizer | script/event attributes | removed | +| Sanitizer | allowed structural HTML | preserved/readable | +| Sanitizer | links | only approved protocols; security callbacks preserved | +| Sanitizer | remote image | no external fetch; no broken residue | +| Sanitizer | data image | accepted only for approved data-image types | +| MIME | multipart alternative | text + HTML parsed correctly | +| MIME | malformed HTML | safe output/fallback, no crash | +| Reader | sanitized HTML present | unified safe HTML reader | +| Reader | plain only | readable plain fallback | +| Reader | neither usable | safe compact empty/error state | +| Reader security | iframe | sandbox remains present | +| Reader security | referrer | no-referrer remains present | +| Reader UX | security banner | permanent banner absent if owner-approved removal is implemented | +| Backfill | dry-run | no DB mutation | +| Backfill | target mailbox | only target scope considered | +| Backfill | mutation | approved fields update only | +| Backfill | identity | UUID/read/delete/source state unchanged | +| Backfill | second run | safe/idempotent | +| Live endpoint | normal authenticated GET | app redirect, not raw JSON | +| Live endpoint | custom live header | JSON | +| Live endpoint | legacy JSON Accept | JSON compatibility preserved | +| Gunicorn | service start/request | no functional regression | +| Gunicorn | bounded logs | no repeated unresolved read-only FS control error | + +## PHASE-007 UI matrix + +### Desktop +- Dashboard 1366/1440/1920 widths. +- Mailboxes with 0, 1, many rows. +- Mailbox search and status filters. +- Inbox with long sender/subject, unread/read, attachments. +- Message reader with long HTML and plain body. +- Create mailbox with/without assigned users. +- User management with long usernames and multiple role/status states. +- Add/Edit user validation errors. +- destructive confirmation screens. + +### Mobile / tablet +Minimum widths: +- 320; +- 360; +- 375; +- 390; +- 400; +- 430; +- 768; +- 1024. + +At each relevant width verify: +- no viewport horizontal overflow; +- menu opens/closes correctly; +- no clipped controls; +- no overlapping text; +- Mailboxes record remains compact; +- table/list actions remain reachable; +- forms fit and labels/errors remain associated; +- reader body is usable without nested unusable scroll traps. + +## Functional regression matrix + +- login success/failure/lockout; +- logout POST; +- admin-only access; +- non-admin mailbox visibility; +- mailbox create unique/reserved validation; +- mailbox enable/disable; +- mailbox delete confirmation and permission; +- user create/edit/delete restrictions; +- mailbox assignment persistence; +- message search/read/attachment filtering; +- read on open; +- mark unread; +- message soft delete; +- attachment access/missing attachment; +- browser live update insertion; +- audit events for key actions. + +## Operational matrix + +- Django deploy check; +- no migration drift; +- mailserver schema verification; +- Maildir storage verification; +- Postfix lookup contract; +- ingestion dry-run; +- Gunicorn socket/app verification; +- live/ready endpoints; +- Postfix/Dovecot/Nginx config tests; +- service activity; +- deterministic archive verification; +- upgrade archive migration comparison; +- backup checksums; +- rollback snapshot checksums. + +## Security/static matrix + +- Ruff; +- Bandit; +- dependency audit; +- sanitizer XSS fixture set; +- path confinement tests; +- permission/object authorization tests; +- CSRF contracts; +- security headers/CSP tests if present in existing suite; +- no secrets in source/log output; +- documentation/forensic inventory checks. + +## Final real-world matrix + +At production acceptance: + +1. external plain/normal email; +2. external HTML-rich email from a modern provider/template; +3. external message with attachment when practical; +4. verify receipt through server chain; +5. verify Inbox live update; +6. verify reader readability; +7. verify attachment download; +8. verify mark unread/read behavior; +9. verify non-admin access boundary where applicable; +10. observe service/app logs for a bounded interval. diff --git a/docs/production-readiness/11_EXISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md b/docs/production-readiness/11_EXISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md new file mode 100644 index 0000000..0738dd8 --- /dev/null +++ b/docs/production-readiness/11_EXISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md @@ -0,0 +1,114 @@ +# Existing Message Repair and Backfill Plan + +## Problem + +The v1.3.3 ingestion service identifies an already-indexed message by mailbox + Maildir `source_file_key` and +returns `duplicate` before parsing it again. Therefore existing rows with a bad `sanitized_html_body` will not +be repaired merely by deploying a corrected parser. + +## Safety objective + +Repair parser-derived presentation data from the preserved original Maildir source **without deleting messages, +changing user state, or re-creating database identities**. + +## Allowed source of truth + +The existing original Maildir message file referenced by each message's mailbox and `source_file_key` is the +repair source. It is already preserved by MailStack's receive-only architecture. + +## Fields that must remain unchanged + +Unless a separately evidenced defect requires a narrower exception: + +- message primary key; +- message UUID; +- mailbox foreign key; +- `source_file_key`; +- existing source identity contract; +- `is_read`; +- `deleted_at`; +- `deleted_by`; +- created timestamp; +- mailbox memberships/permissions; +- attachment rows and files; +- audit identity/history. + +## Candidate parser-derived fields eligible for reviewed update + +Exact implementation must compare current model/parser behavior before coding. Expected candidates include: + +- sender name/address when parser behavior explicitly requires correction; +- recipients/CC; +- subject; +- received date only if parser correction requires it; +- `text_body`; +- `sanitized_html_body`; +- parse status/warning. + +For this production-readiness defect, the preferred narrow mutation is body/render-related fields plus +parse-status/warning only. Broader metadata rewrites require evidence. + +## Required command behavior + +Proposed management-command characteristics: + +- explicit command name related to message resanitization/repair; +- `--dry-run`; +- `--mailbox ` targeting; +- optional message UUID targeting; +- optional bounded `--limit`/batch size; +- clear counters: scanned, eligible, changed, unchanged, skipped, missing-source, warning, error; +- non-zero exit when blocking errors occur; +- no deletion of source files; +- no creation of duplicate Message rows; +- transaction safety per message or appropriately bounded batch; +- audit/log summary without dumping full raw email content. + +## Eligibility strategy + +Prefer an evidence-based eligibility rule rather than rewriting every message blindly. Possible verified +criteria may include: + +- stored HTML contains recognizable leaked CSS patterns from stripped style blocks; +- parser version/repair marker if an implementation introduces one without schema change; +- owner-selected mailbox/message scope; +- explicit all-message mode only after dry-run counts are reviewed. + +The final criterion must be determined by tests against real affected and unaffected source messages. + +## Pre-production test sequence + +1. create fixture message with leaked style-block CSS under old behavior; +2. ingest/store it using controlled test state; +3. run repair dry-run and verify no mutation; +4. run repair mutation; +5. verify sanitized body becomes readable; +6. verify UUID/read/delete/source identity unchanged; +7. verify attachments unchanged; +8. run repair a second time; +9. verify idempotent `unchanged` result; +10. test missing source file and malformed source behavior. + +## Production execution sequence + +1. confirm PHASE-006 release is deployed and healthy; +2. take/confirm normal pre-change operational backup according to existing policy; +3. run repair dry-run and save counters/output; +4. review count of eligible/affected messages; +5. run bounded mutation; +6. verify database/message counts unchanged; +7. open representative previously broken messages in browser; +8. verify read/unread/deleted states are preserved; +9. verify attachment access; +10. rerun dry-run/repair to demonstrate idempotence; +11. record final repair counts in PHASE-006 completion log. + +## Prohibited repair strategies + +- delete database rows and re-ingest; +- delete or move original Maildir mail solely to trigger ingestion; +- reset read/unread state; +- reset soft-delete state; +- create new message UUIDs for repaired records; +- blanket allow CSS/JavaScript/remote assets to avoid sanitizer complexity; +- restore MariaDB from backup merely to repair presentation data. diff --git a/docs/production-readiness/README.md b/docs/production-readiness/README.md new file mode 100644 index 0000000..dfb6f1f --- /dev/null +++ b/docs/production-readiness/README.md @@ -0,0 +1,58 @@ +# MailStack Production-Readiness Documentation Pack + +**Documentation baseline:** MailStack `v1.3.3` +**Prepared:** 2026-08-18 +**Purpose:** Freeze the production-update plan before any further runtime/UI implementation. + +This directory is a planning and forensic control pack. It does not itself change MailStack runtime behavior. +It exists so the next implementation work proceeds in a fixed order, with an explicit baseline, defect register, +phase roadmap, completion log, error-handling register, actual-working-state register, acceptance gates, and +change-control policy. + +## Canonical baseline for the next update + +The next implementation cycle must use the **published and live-verified MailStack v1.3.3 release** as the +canonical source baseline: + +- Release/tag: `v1.3.3` +- Published commit: `21dff33219afab3819e7bd1ae1e0a0cc2e7d3698` +- Published tree: `74682033f3164a6a0069a381ae5a38661aad1669` +- Official release source archive: `mailstack-1.3.3-source.zip` +- Official release source SHA-256: `9e2016ce486f1e1f7e30361c73fa50ff73e7c9c72f87dd0941c1a9b5ed2e9964` +- Live installed version: `1.3.3` +- Live marker previous version: `1.3.0-rc.1` +- Live source fidelity gate: PASS + +The separately uploaded `MailStack_v1.3.3_Baseline.zip` is retained as historical/candidate evidence only. +Its freeze record identifies it as an owner-frozen candidate and its SHA-256 differs from the published release +asset. It must not silently replace the published/live-verified baseline for implementation. + +## Documents + +1. `00_OFFICIAL_BASELINE_FREEZE.md` — baseline identity and freeze boundary. +2. `01_PRODUCTION_READINESS_FORENSIC_REPORT.md` — production-readiness defect report and required corrections. +3. `02_TWO_PHASE_A_TO_Z_ROADMAP.md` — complete update roadmap, limited to two implementation phases. +4. `03_UPDATE_PHASE_COMPLETION_LOG.md` — persistent phase completion and next-work ledger. +5. `04_ERROR_HANDLING_REGISTER_AND_PLAN.md` — existing error handling plus required additions. +6. `05_ACTUAL_IMPLEMENTATION_STATUS.md` — what actually works now, after each phase, and what remains. +7. `06_UI_DESIGN_REFERENCE_AND_DEFECT_MATRIX.md` — screenshot audit plus VibTools/Licora reference extraction. +8. `07_PRODUCTION_ACCEPTANCE_GATE.md` — release blocking acceptance criteria. +9. `08_CHANGE_CONTROL_AND_SCOPE_LOCK.md` — strict baseline/scope lock for implementation. +10. `09_RELEASE_AND_UPDATE_EXECUTION_POLICY.md` — release/upgrade execution policy and future single-command goal. +11. `10_TEST_AND_ACCEPTANCE_MATRIX.md` — deterministic test matrix across functionality, UI, security and operations. +12. `11_EXISTING_MESSAGE_REPAIR_AND_BACKFILL_PLAN.md` — safe repair plan for already-indexed broken HTML emails. + +## Status language + +- `[CONFIRMED]` — directly supported by current source, live output, or supplied screenshots. +- `[INFERRED]` — conclusion strongly supported by evidence but not yet reproduced under a focused test. +- `[UNKNOWN]` — evidence is insufficient; implementation must not guess. +- `[CONFLICT]` — two evidence sources disagree and the authoritative source is explicitly selected. +- `BLOCKER` — production acceptance cannot close while this remains unresolved. +- `OPEN` — must be investigated or explicitly dispositioned before final acceptance. + +## Execution rule + +No application/runtime implementation starts until this planning pack is owner-approved. Once approved, +implementation proceeds only in the order defined by the two-phase roadmap. The completion log is updated at +the end of every phase before the next phase starts. From 90175b7a4549cb67d874692081bd5b0484eddccc Mon Sep 17 00:00:00 2001 From: Md Nurnobi Date: Tue, 18 Aug 2026 13:32:29 -0700 Subject: [PATCH 2/3] fix: restore HTML reader integrity and safe message repair --- CHANGELOG.md | 19 ++ docs/FORENSIC_FILE_INVENTORY.json | 299 +++++++++++++++--- .../03_UPDATE_PHASE_COMPLETION_LOG.md | 30 +- .../05_ACTUAL_IMPLEMENTATION_STATUS.md | 5 +- documents/ADMIN_GUIDE.md | 21 ++ documents/DOCUMENTATION_MANIFEST.json | 22 +- documents/README.md | 3 +- documents/USER_MANUAL.md | 5 +- ...Y-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md | 88 ++++++ .../commands/repair_message_bodies.py | 116 +++++++ mailbox-app/apps/ingestion/parser.py | 85 ++++- mailbox-app/apps/ingestion/repair.py | 100 ++++++ mailbox-app/gunicorn.conf.py | 4 + mailbox-app/templates/messages/detail.html | 1 - .../tests/fixtures/html_style_heavy.eml | 24 ++ .../functional/test_compact_mailbox_reader.py | 2 +- .../integration/test_message_body_repair.py | 141 +++++++++ .../tests/security/test_deployment_assets.py | 8 + mailbox-app/tests/unit/test_parser_storage.py | 30 ++ 19 files changed, 934 insertions(+), 69 deletions(-) create mode 100644 documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md create mode 100644 mailbox-app/apps/ingestion/management/commands/repair_message_bodies.py create mode 100644 mailbox-app/apps/ingestion/repair.py create mode 100644 mailbox-app/gunicorn.conf.py create mode 100644 mailbox-app/tests/fixtures/html_style_heavy.eml create mode 100644 mailbox-app/tests/integration/test_message_body_repair.py diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e4c91..cb021a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ All notable repository-level changes are recorded here. Application history before the open-source conversion remains in `mailbox-app/CHANGELOG.md`. +## Unreleased — PHASE-006 reader integrity and repair + +### Corrected + +- Prevented stripped HTML ` + + + +

Welcome to Harpoon!

This content must stay readable.

+intercom + + diff --git a/mailbox-app/tests/functional/test_compact_mailbox_reader.py b/mailbox-app/tests/functional/test_compact_mailbox_reader.py index 1fba9c9..a25ab69 100644 --- a/mailbox-app/tests/functional/test_compact_mailbox_reader.py +++ b/mailbox-app/tests/functional/test_compact_mailbox_reader.py @@ -55,7 +55,7 @@ def test_unified_reader_prefers_sanitized_html_and_preserves_sandbox(client, adm assert 'class="email-frame unified-email-frame"' in body assert 'sandbox=""' in body assert 'referrerpolicy="no-referrer"' in body - assert "Protected rendering" in body + assert "Protected rendering" not in body assert "Plain body" not in body assert "Plain text" not in body assert "Safe HTML" not in body diff --git a/mailbox-app/tests/integration/test_message_body_repair.py b/mailbox-app/tests/integration/test_message_body_repair.py new file mode 100644 index 0000000..373a7de --- /dev/null +++ b/mailbox-app/tests/integration/test_message_body_repair.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +from io import StringIO +from pathlib import Path + +import pytest +from django.core.management import call_command +from django.core.management.base import CommandError +from django.utils import timezone + +from apps.ingestion.service import ingest_file +from apps.mailboxes.services import mailbox_paths +from apps.messages.models import Message + + +def _ingest_fixture(mailbox, fixtures_dir: Path, name: str, source_name: str) -> Message: + _root, maildir, _relative = mailbox_paths(mailbox.local_part) + source = maildir / "new" / source_name + source.write_bytes((fixtures_dir / name).read_bytes()) + assert ingest_file(mailbox, source) == "created" + return Message.objects.get(mailbox=mailbox, source_file_key=f"new/{source_name}") + + +@pytest.mark.django_db +def test_repair_message_bodies_requires_explicit_confirmation(mailbox): + with pytest.raises(CommandError, match="--confirm-repair"): + call_command("repair_message_bodies", mailbox=mailbox.local_part) + + +@pytest.mark.django_db +def test_repair_message_bodies_dry_run_then_mutation_preserves_state(mailbox, fixtures_dir): + message = _ingest_fixture(mailbox, fixtures_dir, "html_style_heavy.eml", "repair-html") + message.sanitized_html_body = "#outlook a { padding: 0; } broken body" + message.is_read = True + message.deleted_at = timezone.now() + message.save(update_fields=["sanitized_html_body", "is_read", "deleted_at", "updated_at"]) + + original = { + "pk": message.pk, + "uuid": message.uuid, + "source_file_key": message.source_file_key, + "source_sha256": message.source_sha256, + "mailbox_id": message.mailbox_id, + "is_read": message.is_read, + "deleted_at": message.deleted_at, + } + + dry_output = StringIO() + call_command( + "repair_message_bodies", + mailbox=mailbox.local_part, + dry_run=True, + stdout=dry_output, + ) + assert "would_update=1" in dry_output.getvalue() + message.refresh_from_db() + assert message.sanitized_html_body.startswith("#outlook") + + output = StringIO() + call_command( + "repair_message_bodies", + mailbox=mailbox.local_part, + confirm_repair=True, + stdout=output, + ) + assert "updated=1" in output.getvalue() + + message.refresh_from_db() + assert "Welcome to Harpoon!" in message.sanitized_html_body + assert "#outlook" not in message.sanitized_html_body + assert message.pk == original["pk"] + assert message.uuid == original["uuid"] + assert message.source_file_key == original["source_file_key"] + assert message.source_sha256 == original["source_sha256"] + assert message.mailbox_id == original["mailbox_id"] + assert message.is_read == original["is_read"] + assert message.deleted_at == original["deleted_at"] + + second_output = StringIO() + call_command( + "repair_message_bodies", + mailbox=mailbox.local_part, + confirm_repair=True, + stdout=second_output, + ) + assert "updated=0" in second_output.getvalue() + assert "unchanged=1" in second_output.getvalue() + + +@pytest.mark.django_db +def test_repair_message_bodies_preserves_attachment_identity(mailbox, fixtures_dir): + message = _ingest_fixture(mailbox, fixtures_dir, "one_attachment.eml", "repair-attachment") + attachment = message.attachments.get() + attachment_identity = ( + attachment.pk, + attachment.uuid, + attachment.sha256, + attachment.storage_relative_path, + ) + message.text_body = "stale" + message.save(update_fields=["text_body", "updated_at"]) + + call_command( + "repair_message_bodies", + message=str(message.uuid), + confirm_repair=True, + stdout=StringIO(), + ) + + message.refresh_from_db() + attachment.refresh_from_db() + assert message.text_body.strip() == "One attachment." + assert message.attachments.count() == 1 + assert ( + attachment.pk, + attachment.uuid, + attachment.sha256, + attachment.storage_relative_path, + ) == attachment_identity + + +@pytest.mark.django_db +def test_repair_message_bodies_reports_missing_and_mismatched_sources(mailbox, fixtures_dir): + missing = _ingest_fixture(mailbox, fixtures_dir, "html.eml", "repair-missing") + mismatch = _ingest_fixture(mailbox, fixtures_dir, "plain_text.eml", "repair-mismatch") + + _root, maildir, _relative = mailbox_paths(mailbox.local_part) + (maildir / missing.source_file_key).unlink() + (maildir / mismatch.source_file_key).write_bytes(b"changed source") + + output = StringIO() + call_command( + "repair_message_bodies", + mailbox=mailbox.local_part, + dry_run=True, + stdout=output, + ) + summary = output.getvalue() + assert "missing=1" in summary + assert "mismatch=1" in summary + assert "updated=0" in summary diff --git a/mailbox-app/tests/security/test_deployment_assets.py b/mailbox-app/tests/security/test_deployment_assets.py index ff34256..c3c0202 100644 --- a/mailbox-app/tests/security/test_deployment_assets.py +++ b/mailbox-app/tests/security/test_deployment_assets.py @@ -27,6 +27,14 @@ def test_clean_install_and_deploy_create_mail_roots(): assert "UID/GID 5000" in deploy +def test_gunicorn_25_control_socket_is_disabled_for_hardened_runtime(): + config = read("gunicorn.conf.py") + gunicorn = read("deployment/systemd/vibmail-gunicorn.service") + assert "control_socket_disable = True" in config + assert "WorkingDirectory=/opt/vibmail/app" in gunicorn + assert "ProtectSystem=strict" in gunicorn + + def test_systemd_runtime_directories_are_isolated(): gunicorn = read("deployment/systemd/vibmail-gunicorn.service") ingestion = read("deployment/systemd/vibmail-ingestion.service") diff --git a/mailbox-app/tests/unit/test_parser_storage.py b/mailbox-app/tests/unit/test_parser_storage.py index ab433b1..13c6022 100644 --- a/mailbox-app/tests/unit/test_parser_storage.py +++ b/mailbox-app/tests/unit/test_parser_storage.py @@ -62,15 +62,33 @@ def test_sanitize_html_removes_active_and_remote_content(): assert "onclick" not in lowered assert "javascript:" not in lowered assert "tracker.test" not in lowered + assert "alert(1)" not in lowered + assert "" + "

Readable email content

" + "intercom" + ) + lowered = cleaned.lower() + assert "#outlook" not in lowered + assert ".readmsgbody" not in lowered + assert "tracker.test" not in lowered + assert "intercom" not in lowered + assert " Date: Tue, 18 Aug 2026 15:32:54 -0700 Subject: [PATCH 3/3] chore: prepare 1.3.4-rc.1 live acceptance --- .github/workflows/ci.yml | 4 +- .github/workflows/release.yml | 4 +- CHANGELOG.md | 3 +- VERSION | 2 +- design/DESIGN_MANIFEST.json | 2 +- docs/FORENSIC_FILE_INVENTORY.json | 149 +++++++++--------- docs/PUBLISHING.md | 16 +- docs/RELEASE_NOTES_1.3.4.md | 43 +++++ docs/RELEASE_PROCESS.md | 2 +- .../03_UPDATE_PHASE_COMPLETION_LOG.md | 5 +- documents/ADMIN_GUIDE.md | 2 +- documents/BASELINE.md | 2 +- documents/DOCUMENTATION_MANIFEST.json | 78 ++++----- documents/DOCUMENTATION_POLICY.md | 2 +- documents/HOW_TO_USE.md | 2 +- documents/README.md | 38 ++--- documents/USER_MANUAL.md | 2 +- .../design/ACCESSIBILITY_SPECIFICATION.md | 2 +- documents/design/COMPONENT_MATRIX.md | 2 +- documents/design/FUTURE_UI_ROADMAP.md | 2 +- documents/design/IMPLEMENTATION_STATUS.md | 2 +- documents/design/RESPONSIVE_SPECIFICATION.md | 2 +- documents/design/SCREEN_CATALOG.md | 2 +- documents/design/UI_FOUNDATION.md | 2 +- documents/phases/PHASE-000-BASELINE.md | 2 +- .../PHASE-001-UI-DESIGN-INTAKE-BASELINE.md | 2 +- ...RED-UI-FOUNDATION-AND-APPLICATION-SHELL.md | 2 +- ...COVERY-AND-INBOUND-DELIVERY-RELIABILITY.md | 2 +- ...ASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md | 2 +- ...-RELIABILITY-AND-COMPACT-MAILBOX-READER.md | 2 +- ...Y-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md | 9 +- mailbox-app/pyproject.toml | 2 +- scripts/forensic_audit.py | 1 + scripts/test_release_workflow.py | 2 +- 34 files changed, 225 insertions(+), 171 deletions(-) create mode 100644 docs/RELEASE_NOTES_1.3.4.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76d3bfb..d6e8a0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,5 +131,5 @@ jobs: - name: Release verification run: | python scripts/verify_release.py \ - dist/mailstack-1.3.3-source.zip \ - --checksum dist/mailstack-1.3.3-source.zip.sha256 + dist/mailstack-1.3.4-rc.1-source.zip \ + --checksum dist/mailstack-1.3.4-rc.1-source.zip.sha256 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 62b6326..d4013ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,7 +63,7 @@ jobs: path: | dist/*.zip dist/*.sha256 - docs/RELEASE_NOTES_1.3.3.md + docs/RELEASE_NOTES_1.3.4.md docs/FORENSIC_AUDIT_REPORT.md if-no-files-found: error @@ -121,7 +121,7 @@ jobs: --verify-tag --target "$GITHUB_SHA" --title "MailStack ${RELEASE_VERSION}" - --notes-file docs/RELEASE_NOTES_1.3.3.md + --notes-file docs/RELEASE_NOTES_1.3.4.md ) if [[ "$RELEASE_PRERELEASE" == "true" ]]; then args+=(--prerelease --latest=false) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb021a5..bf7fe87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ All notable repository-level changes are recorded here. Application history befo ### Verification state - Local PHASE-006 focused qualification: 60 tests passed; targeted Ruff, Bandit, Django system check and migration-drift gates passed. -- Full repository qualification, GitHub CI and controlled live acceptance remain pending; PHASE-006 is not yet marked complete. +- PHASE-006 implementation commit `90175b7a4549cb67d874692081bd5b0484eddccc` passed GitHub Actions CI run `32183300485`. +- Owner approved `1.3.4-rc.1` as the PHASE-006 live-acceptance pre-release identity; PR/main/tag publication and controlled live acceptance remain pending. ### Compatibility diff --git a/VERSION b/VERSION index 31e5c84..3f54171 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.3 +1.3.4-rc.1 diff --git a/design/DESIGN_MANIFEST.json b/design/DESIGN_MANIFEST.json index bf41ea7..28a5417 100644 --- a/design/DESIGN_MANIFEST.json +++ b/design/DESIGN_MANIFEST.json @@ -561,7 +561,7 @@ "unsupported_features_inactive": true }, "project": "MailStack", - "release_version": "1.3.3", + "release_version": "1.3.4-rc.1", "schema_version": 1, "source_archive": { "archive_crc": "PASS", diff --git a/docs/FORENSIC_FILE_INVENTORY.json b/docs/FORENSIC_FILE_INVENTORY.json index ef60acb..af5e99e 100644 --- a/docs/FORENSIC_FILE_INVENTORY.json +++ b/docs/FORENSIC_FILE_INVENTORY.json @@ -74,14 +74,14 @@ "kind": "text", "lines": 135, "path": ".github/workflows/ci.yml", - "sha256": "391f3181edec60e6891363e52228f503af929dc120653406f28dbca1c0729e75", - "size_bytes": 4291 + "sha256": "2f522250ea8ae84615843f1dfb5e085b2df30bbee35904d28416b4185fbb605e", + "size_bytes": 4301 }, { "kind": "text", "lines": 131, "path": ".github/workflows/release.yml", - "sha256": "a3112863ee1d7bf8b2a02a3be42a51e39109dbe48f6d07ff17a4b9270289d4dd", + "sha256": "c238c4e4da73e7d5b273a8d21dbe2227b2dcb2c3cfee69abf5d3b153f7a169cc", "size_bytes": 4418 }, { @@ -93,10 +93,10 @@ }, { "kind": "text", - "lines": 185, + "lines": 186, "path": "CHANGELOG.md", - "sha256": "757f89a1f0aa761f5a1bd26af24567935316f5cee539bf9b1e1e9a5e2e5f3a78", - "size_bytes": 17358 + "sha256": "f11d2e2a5df5692ca1980592d6a649e52be46b3f4e85f498f6d957c36c790ffd", + "size_bytes": 17507 }, { "kind": "text", @@ -165,8 +165,8 @@ "kind": "text", "lines": 1, "path": "VERSION", - "sha256": "a74a0cf84ef0b15e01e64746c3465813312b763796f4f6362b092f092dccb8b5", - "size_bytes": 6 + "sha256": "69f1db7c16e74d7c42f7a6edf15adb72c813d5887b9ed2d10da52d93e5165616", + "size_bytes": 11 }, { "kind": "text", @@ -277,8 +277,8 @@ "kind": "text", "lines": 581, "path": "design/DESIGN_MANIFEST.json", - "sha256": "c831c949ca88576a0cc017def8f8c90bee24b7b1b51c426ead7e080ffa9e7c37", - "size_bytes": 21163 + "sha256": "cdfef289335026573159d40fce9bed829b8c04778b9e37d53806f28db3741407", + "size_bytes": 21168 }, { "kind": "text", @@ -623,8 +623,8 @@ "kind": "text", "lines": 67, "path": "docs/PUBLISHING.md", - "sha256": "cf828764d5c7c3a638ccb097f6eee0bbb2f4fa68b7dbe0f16425b96b7a7695a4", - "size_bytes": 3040 + "sha256": "a0715413eb18182e15c49a1decc7d0cfc1c7225b3ac15895cc127145532961bf", + "size_bytes": 3048 }, { "kind": "text", @@ -668,12 +668,19 @@ "sha256": "befdf20ee40d8ff4058b8e97d606f7ab5472f26b7d5f5d816d6868ad09a6c2f5", "size_bytes": 2221 }, + { + "kind": "text", + "lines": 43, + "path": "docs/RELEASE_NOTES_1.3.4.md", + "sha256": "e085bc7d76c20648d993557778626c7c84643853700ce5fabb2ede55bc634727", + "size_bytes": 2388 + }, { "kind": "text", "lines": 16, "path": "docs/RELEASE_PROCESS.md", - "sha256": "6692e68e3366fdc666ea7579168e5594a532adbeedb64cdf83514acfd9f65215", - "size_bytes": 1619 + "sha256": "ff6a64f5d9014a55ab47b62d85922e687150bcffe62c9eae0037b3e40be1c1a1", + "size_bytes": 1624 }, { "kind": "text", @@ -740,10 +747,10 @@ }, { "kind": "text", - "lines": 146, + "lines": 147, "path": "docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md", - "sha256": "72ae140cbf22c9f266f1a0f0f5622a9fc027d00310c78c5f7b157aaaad1d8114", - "size_bytes": 5173 + "sha256": "3d29f2c89f41adbd19c1d7a2189e069a2ae8be4e18d8eaf7ecace5814f747701", + "size_bytes": 5464 }, { "kind": "text", @@ -812,148 +819,148 @@ "kind": "text", "lines": 89, "path": "documents/ADMIN_GUIDE.md", - "sha256": "3e45b2db3b7b3a1e35646e740395a3c84e4a9083356fa74c802be31b9f504641", - "size_bytes": 4713 + "sha256": "aae5dc71c28f2bdba9effc140b69c4e2ce899333ce7bb82bb65080ebc21ffe5f", + "size_bytes": 4718 }, { "kind": "text", "lines": 64, "path": "documents/BASELINE.md", - "sha256": "4e292bf865a6afebe2bf3fe28f1743ac26ecab907cbeabd7e5df8e9c43ee617d", - "size_bytes": 3611 + "sha256": "a919b0348511ae5d9f320dd15ee43f8ab2a7a31155fb530d02832ee8958abd6e", + "size_bytes": 3616 }, { "kind": "text", "lines": 245, "path": "documents/DOCUMENTATION_MANIFEST.json", - "sha256": "2ee291ce9edd3fafc14dd7494d39683d9cc157bbf2d9e0156bc0623095b420c7", - "size_bytes": 9470 + "sha256": "96c64395389516f6aa97a2dff3fd89f2d46c892327bb8b2ac7de440fb809b2a1", + "size_bytes": 9570 }, { "kind": "text", "lines": 76, "path": "documents/DOCUMENTATION_POLICY.md", - "sha256": "1815fb7353fa22f9cd28de8cf18a8f0899b13616795fa20f98f3b686edcc9fae", - "size_bytes": 3184 + "sha256": "a3934cded7b4bf0dccd4d5e4d1e3a8270f722dc9e7fa02e71425fd1813282999", + "size_bytes": 3189 }, { "kind": "text", "lines": 83, "path": "documents/HOW_TO_USE.md", - "sha256": "2a5757aa6f345d3df7c6d51d4472bf89e1fe3184a7a86db0be4e4d3fed7c08e6", - "size_bytes": 3858 + "sha256": "dbddffb7757f1026601322582fabea52a2f86f5f5772908e0e93cc5c186af82f", + "size_bytes": 3863 }, { "kind": "text", "lines": 56, "path": "documents/README.md", - "sha256": "9b778653ccdcf8f9b1a4dfb93f4ab7d5deec074bb046388396f14b0b999045bf", - "size_bytes": 4187 + "sha256": "58b3e1d3dc81bd94026c6fed94bde54e681c1948b762f879c999fc3304b3372f", + "size_bytes": 4282 }, { "kind": "text", "lines": 92, "path": "documents/USER_MANUAL.md", - "sha256": "3ff5d681629e0e429fa823ebc6e44416dce9608af0a8336fb63df1a506f1db93", - "size_bytes": 5111 + "sha256": "370afb15269ed191b6369cab7317b074ac2c7bf88aa51fcdce072bfbfa1639e9", + "size_bytes": 5116 }, { "kind": "text", "lines": 46, "path": "documents/design/ACCESSIBILITY_SPECIFICATION.md", - "sha256": "278c6a4b427b09330d4be2488440ae6955ccba40579911e87c7b0d0e493a94e8", - "size_bytes": 2182 + "sha256": "a741efe02f43fa556aed42f4ebc70d9bde0413056159b2001657320b7e75fdbb", + "size_bytes": 2187 }, { "kind": "text", "lines": 55, "path": "documents/design/COMPONENT_MATRIX.md", - "sha256": "6eec7042e88f8c49385167e7da0fe438157751e07dfa3eeb21932073f29d1f4e", - "size_bytes": 3460 + "sha256": "aa0a8f86849df308df243f1cba8084c8a21a9d64a5e1a74da6211109e8988da4", + "size_bytes": 3465 }, { "kind": "text", "lines": 52, "path": "documents/design/FUTURE_UI_ROADMAP.md", - "sha256": "1a00207cd0bd1b32ce66e5253b4dc77838215586aa37caf259d8456302d4cd13", - "size_bytes": 1562 + "sha256": "4c18ff9a6e977b07d17f675a7ba5d02da5009b6d9f336ed2228b5c89beddaabd", + "size_bytes": 1567 }, { "kind": "text", "lines": 48, "path": "documents/design/IMPLEMENTATION_STATUS.md", - "sha256": "71c75905bd097977838855090269865aba4fe7f10d2c8ee2a1236641b92fd758", - "size_bytes": 2691 + "sha256": "b43ae530191f14a07dcaa8eb9efb3890df20292458c66e925a85eda190e5893d", + "size_bytes": 2696 }, { "kind": "text", "lines": 51, "path": "documents/design/RESPONSIVE_SPECIFICATION.md", - "sha256": "0fae978b691e5c460e919668ec3cc1d870f1ac510f7b1613b3f61b286cd80984", - "size_bytes": 2022 + "sha256": "1ba7ffed7946c06b88e46a7db9abd3630066ac9553dcb06f748e5db6325ec7ea", + "size_bytes": 2027 }, { "kind": "text", "lines": 65, "path": "documents/design/SCREEN_CATALOG.md", - "sha256": "ecc0b62d2f30a09f704a7a1e70b1e72a0f85746cd5d5c13ad9c431e6967b697c", - "size_bytes": 3480 + "sha256": "0e42e1be101f84362f591354041fb96d511014b5f5e067e5bfbf367ee91199bf", + "size_bytes": 3485 }, { "kind": "text", "lines": 89, "path": "documents/design/UI_FOUNDATION.md", - "sha256": "5082d1f28afe1414d59a3c97f83a08a45d9c3242c2a057dae6d30b09b4c57785", - "size_bytes": 3753 + "sha256": "9f0afa77383bf80723f21c055c642fccb3a6b2bcab824e9fc1f2f6810092163c", + "size_bytes": 3758 }, { "kind": "text", "lines": 59, "path": "documents/phases/PHASE-000-BASELINE.md", - "sha256": "0ca507b4dfe36daf118b81ebb9de19472c2c161d0e45256805513c8895a83574", - "size_bytes": 2538 + "sha256": "b5fa1216b48e77769b2084895e6fa6519f54f473908b4d3687fbe0fb417d0794", + "size_bytes": 2543 }, { "kind": "text", "lines": 68, "path": "documents/phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md", - "sha256": "af6bb679cac06f760e00c5a40cfafee4ed30306a22782dc5b82e1b5039df36a6", - "size_bytes": 2765 + "sha256": "fa03c2cf487766e107ff25f4ba2d5e441b6020eb25720f6b1640dde4d01bc99c", + "size_bytes": 2770 }, { "kind": "text", "lines": 98, "path": "documents/phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md", - "sha256": "e3c8edf18c64865786c6be6d11f9424b37a54d98f095a05948bdf0773cfc8de0", - "size_bytes": 5488 + "sha256": "a152ecfb079d21ce9aac1a108850e4913f1784a57c290801f083e11799d9de41", + "size_bytes": 5493 }, { "kind": "text", "lines": 86, "path": "documents/phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md", - "sha256": "bb6a6a8eb7d41ca882b9e9f83c3371fe78325e43472c3065e130e5923da78e96", - "size_bytes": 5050 + "sha256": "e4b23d66b5140c3de6822aee0094f652eee2d0f13ba9c72b820201091101a2d5", + "size_bytes": 5055 }, { "kind": "text", "lines": 153, "path": "documents/phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md", - "sha256": "f45403765474a74f72607b1c37ca5cb0df6d0a546a4e436500ef427dcaf64f16", - "size_bytes": 10061 + "sha256": "48a1516924d8bf7e2a10be8bc4640cb5bc908520db67f2b28f7f278450911aa5", + "size_bytes": 10066 }, { "kind": "text", "lines": 102, "path": "documents/phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md", - "sha256": "198f20d9732395701ac5ebb57d2e3d3a74d437e7b1a657630f697cf46a60b545", - "size_bytes": 6080 + "sha256": "3e23b169d1daa5ea1fdb678a0e9a17a74d684a6c29d10dd2f84e4fe3071ba13d", + "size_bytes": 6085 }, { "kind": "text", - "lines": 88, + "lines": 89, "path": "documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md", - "sha256": "78f216009e84b7decbb5061c0214ea7d6ac6ea178f401eccd8d7d6d027cc71ab", - "size_bytes": 4125 + "sha256": "bd254488c228d34015773d055c8c64778b4f5a15c8657ea0572382f864480c1a", + "size_bytes": 4263 }, { "kind": "text", @@ -3382,8 +3389,8 @@ "kind": "text", "lines": 84, "path": "mailbox-app/pyproject.toml", - "sha256": "8f46570ed6b7458b712e653ef9462f41de5c703fd10c82d63dc678f04aa9285e", - "size_bytes": 2524 + "sha256": "6bba5916f706b0cf1ef3888af89f8c2a97d157dac87f2d4a1c61d0992ecfd53b", + "size_bytes": 2527 }, { "kind": "text", @@ -5033,7 +5040,7 @@ }, { "kind": "text", - "lines": 408, + "lines": 409, "path": "scripts/forensic_audit.py", "python": { "classes": [], @@ -5059,8 +5066,8 @@ ], "methods": [] }, - "sha256": "b5dab090e769878e424e7d2e9bbedb5dcf3011cb0f00fde35d3f2ac3d4dfadd5", - "size_bytes": 14937 + "sha256": "ae3d6cf6030d546cce59b54d8aa906f617122d5b226a6ff624839b1670a0ffcd", + "size_bytes": 14972 }, { "kind": "text", @@ -5432,7 +5439,7 @@ ], "methods": [] }, - "sha256": "fddfa48bb4763d5c33034d2501ae5c0b25a7a875b1fbd5a156d921bd0fe323b6", + "sha256": "f831a38ba7dea8f9ca4317319172532addd0930d1c4b17c229bfc0da4d735677", "size_bytes": 6570 }, { @@ -5544,7 +5551,7 @@ "size_bytes": 6930 } ], - "release_version": "1.3.3", + "release_version": "1.3.4-rc.1", "schema_version": 1, "scope": "All maintained repository files excluding generated archives, caches, build output and this inventory file itself.", "self_entry": { @@ -5553,15 +5560,15 @@ }, "summary": { "binary_files": 25, - "files": 434, + "files": 435, "python_classes": 84, "python_files": 153, "python_functions": 464, "python_methods": 71, "shell_files": 15, "shell_functions": 41, - "text_files": 409, - "total_bytes": 31896022, - "total_text_lines": 31989 + "text_files": 410, + "total_bytes": 31899344, + "total_text_lines": 32036 } } diff --git a/docs/PUBLISHING.md b/docs/PUBLISHING.md index 1464983..5e85c73 100644 --- a/docs/PUBLISHING.md +++ b/docs/PUBLISHING.md @@ -12,10 +12,10 @@ This repository is prepared for public hosting on GitHub, GitLab, Codeberg, or a 4. Build and verify the deterministic release archive: ```bash - python scripts/build_release.py --root . --version 1.3.3 + python scripts/build_release.py --root . --version 1.3.4-rc.1 python scripts/verify_release.py \ - dist/mailstack-1.3.3-source.zip \ - --checksum dist/mailstack-1.3.3-source.zip.sha256 + dist/mailstack-1.3.4-rc.1-source.zip \ + --checksum dist/mailstack-1.3.4-rc.1-source.zip.sha256 ``` 5. Complete the clean Ubuntu 24.04 acceptance checklist before promoting a release candidate to production-ready. @@ -27,7 +27,7 @@ From the audited repository root: ```bash git init git add . -git commit -m "Prepare MailStack 1.3.3 candidate" +git commit -m "Prepare MailStack 1.3.4-rc.1 candidate" git branch -M main git remote add origin git push -u origin main @@ -37,8 +37,8 @@ Create the annotated stable-looking tag only after the intended release commit i `main` head and the exact `main` SHA has a successful push CI run: ```bash -git tag -a v1.3.3 -m "MailStack 1.3.3" -git push origin v1.3.3 +git tag -a v1.3.4-rc.1 -m "MailStack 1.3.4-rc.1" +git push origin v1.3.4-rc.1 ``` The tag push triggers `.github/workflows/release.yml`. It fails closed unless the tag matches @@ -46,11 +46,11 @@ The tag push triggers `.github/workflows/release.yml`. It fails closed unless th has no existing GitHub Release. The workflow rebuilds and verifies the deterministic source archive, keeps a GitHub Actions artifact, and automatically creates the GitHub Release with: -- `mailstack-1.3.3-source.zip` +- `mailstack-1.3.4-rc.1-source.zip` - `mailstack-1.3.3-source.zip.sha256` RC tags are published as pre-releases and are explicitly not marked latest; stable tags are normal -latest releases. `v1.3.1` remains the frozen published baseline; the `1.3.3` PHASE-005A line must not be tagged until its branch/PR/main CI gates and release-owner review pass. Manual `workflow_dispatch` is validation/build-only and cannot publish. Existing +latest releases. published `v1.3.3` remains the frozen production baseline; `1.3.4-rc.1` is the PHASE-006 live-acceptance pre-release candidate. Manual `workflow_dispatch` is validation/build-only and cannot publish. Existing releases are never automatically edited, clobbered, or overwritten. ## Repository settings diff --git a/docs/RELEASE_NOTES_1.3.4.md b/docs/RELEASE_NOTES_1.3.4.md new file mode 100644 index 0000000..d995208 --- /dev/null +++ b/docs/RELEASE_NOTES_1.3.4.md @@ -0,0 +1,43 @@ +# MailStack 1.3.4-rc.1 — PHASE-006 live-acceptance candidate + +## Purpose + +`1.3.4-rc.1` is the owner-approved PHASE-006 pre-release identity for controlled production +acceptance of the reader-integrity, existing-message repair, and Gunicorn runtime-finding fixes. +The frozen production baseline remains published/live-verified `v1.3.3`. + +This pre-release does not mark PHASE-006 complete. Controlled upgrade, dry-run/backfill evidence, +reader acceptance, health checks, and bounded log observation remain blocking. + +## Included corrections + +- remove style/head/active block contents before allowlist sanitization so raw CSS is not visible; +- keep scripts, event handlers, unsafe URLs, style attributes and unrestricted remote assets blocked; +- remove blocked remote-image nodes instead of leaving broken-image residue; +- retain sandbox/no-referrer HTML isolation and plain-text fallback; +- remove the permanent protected-rendering notice while retaining the protections; +- add bounded, dry-run-first existing-message body repair from preserved Maildir source; +- preserve UUID/database identity, mailbox, read/deleted state, source identity and attachments; +- disable the unused Gunicorn control interface without weakening `ProtectSystem=strict`. + +## Qualification evidence + +PHASE-006 implementation commit `90175b7a4549cb67d874692081bd5b0484eddccc` passed GitHub Actions +CI run `32183300485`, including source safety, documentation/metadata, forensic inventory, +deployment/installer/backup/upgrade contracts, dependency audit, Ruff, Bandit, full tests+coverage, +Django checks, shell syntax, full forensic audit, deterministic build and release verification. + +The release-identity delta must pass a new branch CI run, then PR/main CI and exact-main tag +publication before live deployment. + +## Compatibility + +No database migration, Postfix/Dovecot/LMTP/Maildir routing change, authorization redesign, outbound +mail capability, or PHASE-007 broad UI redesign is included. + +## Live acceptance sequence + +Use the maintained upgrader with the official deterministic ZIP/checksum, verify services and health, +run repair dry-run first, review counters, run only the approved bounded mutation, verify previously +broken HTML plus plain-text/attachments/state preservation, demonstrate idempotence, and observe logs +for absence of the repeated Gunicorn control-server read-only-filesystem finding. diff --git a/docs/RELEASE_PROCESS.md b/docs/RELEASE_PROCESS.md index 9e42afe..c2f0c8f 100644 --- a/docs/RELEASE_PROCESS.md +++ b/docs/RELEASE_PROCESS.md @@ -7,7 +7,7 @@ 5. Run the online dependency audit in CI. 6. Test a clean installation on an isolated Ubuntu Server 24.04 LTS VPS. 7. Verify external inbound SMTP, login, authorization boundaries, live updates, safe HTML, and attachment downloads. -8. Build with `python scripts/build_release.py --root . --version 1.3.3` and verify the ZIP/checksum with `python scripts/verify_release.py`. +8. Build with `python scripts/build_release.py --root . --version 1.3.4-rc.1` and verify the ZIP/checksum with `python scripts/verify_release.py`. 9. Merge the intended release commit to `main` and require a successful `main` push CI run for the exact SHA. 10. Create the matching `v` tag on the current `main` head and push that tag. Do not create a release manually first. 11. The tag workflow validates tag/version/package identity, exact `main` head, successful `main` CI, and release absence; it then builds/verifies the deterministic archive and creates the GitHub Release with ZIP/SHA assets. diff --git a/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md b/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md index 14f07d6..0650238 100644 --- a/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md +++ b/docs/production-readiness/03_UPDATE_PHASE_COMPLETION_LOG.md @@ -10,6 +10,7 @@ when a phase changes state so implementation cannot become unordered or ambiguou | Metric | Current value | |---|---| | Frozen baseline | MailStack `v1.3.3` | +| PHASE-006 live-acceptance target | MailStack `v1.3.4-rc.1` pre-release | | Planned implementation phases | **2** | | Completed phases in this production-readiness cycle | **0 / 2** | | Remaining phases | **2 / 2** | @@ -65,7 +66,7 @@ documentation/generated metadata are synchronized before branch qualification. ## Tests/evidence Local focused qualification: `60 passed`; targeted Ruff PASS; Bandit PASS; Django system check PASS; -migration drift NONE. Full repository qualification, GitHub CI and controlled live acceptance remain pending. +migration drift NONE. Implementation commit `90175b7a4549cb67d874692081bd5b0484eddccc` passed GitHub Actions CI run `32183300485`; owner-approved `1.3.4-rc.1` publication and controlled live acceptance remain pending. ## Known residual findings after phase @@ -113,7 +114,7 @@ documentation/generated metadata are synchronized before branch qualification. ## Tests/evidence Local focused qualification: `60 passed`; targeted Ruff PASS; Bandit PASS; Django system check PASS; -migration drift NONE. Full repository qualification, GitHub CI and controlled live acceptance remain pending. +migration drift NONE. Implementation commit `90175b7a4549cb67d874692081bd5b0484eddccc` passed GitHub Actions CI run `32183300485`; owner-approved `1.3.4-rc.1` publication and controlled live acceptance remain pending. ## Known residual findings after phase diff --git a/documents/ADMIN_GUIDE.md b/documents/ADMIN_GUIDE.md index 4122587..8c98fe1 100644 --- a/documents/ADMIN_GUIDE.md +++ b/documents/ADMIN_GUIDE.md @@ -4,7 +4,7 @@ title: MailStack Administrator Guide document_type: admin-guide audience: mailstack-administrators status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/BASELINE.md b/documents/BASELINE.md index 35c1450..28473b6 100644 --- a/documents/BASELINE.md +++ b/documents/BASELINE.md @@ -4,7 +4,7 @@ title: MailStack Baseline document_type: baseline audience: maintainers-and-operators status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 baseline_id: MAILSTACK-1.3.1-OFFICIAL-SOURCE-BASELINE-001 source_commit: 039a6e6eea6e198b4b15612db9d2f208b6305a16 diff --git a/documents/DOCUMENTATION_MANIFEST.json b/documents/DOCUMENTATION_MANIFEST.json index eb5762b..9551e99 100644 --- a/documents/DOCUMENTATION_MANIFEST.json +++ b/documents/DOCUMENTATION_MANIFEST.json @@ -9,10 +9,10 @@ "last_reviewed": "2026-08-18", "path": "documents/ADMIN_GUIDE.md", "phase_id": null, - "sha256": "3e45b2db3b7b3a1e35646e740395a3c84e4a9083356fa74c802be31b9f504641", + "sha256": "aae5dc71c28f2bdba9effc140b69c4e2ce899333ce7bb82bb65080ebc21ffe5f", "status": "active", "title": "MailStack Administrator Guide", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "maintainers-and-operators", @@ -21,10 +21,10 @@ "last_reviewed": "2026-08-18", "path": "documents/BASELINE.md", "phase_id": null, - "sha256": "4e292bf865a6afebe2bf3fe28f1743ac26ecab907cbeabd7e5df8e9c43ee617d", + "sha256": "a919b0348511ae5d9f320dd15ee43f8ab2a7a31155fb530d02832ee8958abd6e", "status": "active", "title": "MailStack Baseline", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "contributors-and-maintainers", @@ -33,10 +33,10 @@ "last_reviewed": "2026-08-18", "path": "documents/DOCUMENTATION_POLICY.md", "phase_id": null, - "sha256": "1815fb7353fa22f9cd28de8cf18a8f0899b13616795fa20f98f3b686edcc9fae", + "sha256": "a3934cded7b4bf0dccd4d5e4d1e3a8270f722dc9e7fa02e71425fd1813282999", "status": "active", "title": "Documentation Policy", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "mailbox-users-and-administrators", @@ -45,10 +45,10 @@ "last_reviewed": "2026-08-18", "path": "documents/HOW_TO_USE.md", "phase_id": null, - "sha256": "2a5757aa6f345d3df7c6d51d4472bf89e1fe3184a7a86db0be4e4d3fed7c08e6", + "sha256": "dbddffb7757f1026601322582fabea52a2f86f5f5772908e0e93cc5c186af82f", "status": "active", "title": "How to Use MailStack", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "mailbox-users", @@ -57,10 +57,10 @@ "last_reviewed": "2026-08-18", "path": "documents/USER_MANUAL.md", "phase_id": null, - "sha256": "3ff5d681629e0e429fa823ebc6e44416dce9608af0a8336fb63df1a506f1db93", + "sha256": "370afb15269ed191b6369cab7317b074ac2c7bf88aa51fcdce072bfbfa1639e9", "status": "active", "title": "MailStack User Manual", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -69,10 +69,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/ACCESSIBILITY_SPECIFICATION.md", "phase_id": null, - "sha256": "278c6a4b427b09330d4be2488440ae6955ccba40579911e87c7b0d0e493a94e8", + "sha256": "a741efe02f43fa556aed42f4ebc70d9bde0413056159b2001657320b7e75fdbb", "status": "active", "title": "MailStack Accessibility Specification", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -81,10 +81,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/COMPONENT_MATRIX.md", "phase_id": null, - "sha256": "6eec7042e88f8c49385167e7da0fe438157751e07dfa3eeb21932073f29d1f4e", + "sha256": "aa0a8f86849df308df243f1cba8084c8a21a9d64a5e1a74da6211109e8988da4", "status": "active", "title": "MailStack UI Component Matrix", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -93,10 +93,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/FUTURE_UI_ROADMAP.md", "phase_id": null, - "sha256": "1a00207cd0bd1b32ce66e5253b4dc77838215586aa37caf259d8456302d4cd13", + "sha256": "4c18ff9a6e977b07d17f675a7ba5d02da5009b6d9f336ed2228b5c89beddaabd", "status": "active", "title": "MailStack Future UI Roadmap", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -105,10 +105,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/IMPLEMENTATION_STATUS.md", "phase_id": null, - "sha256": "71c75905bd097977838855090269865aba4fe7f10d2c8ee2a1236641b92fd758", + "sha256": "b43ae530191f14a07dcaa8eb9efb3890df20292458c66e925a85eda190e5893d", "status": "active", "title": "MailStack UI Implementation Status", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -117,10 +117,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/RESPONSIVE_SPECIFICATION.md", "phase_id": null, - "sha256": "0fae978b691e5c460e919668ec3cc1d870f1ac510f7b1613b3f61b286cd80984", + "sha256": "1ba7ffed7946c06b88e46a7db9abd3630066ac9553dcb06f748e5db6325ec7ea", "status": "active", "title": "MailStack Responsive Specification", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -129,10 +129,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/SCREEN_CATALOG.md", "phase_id": null, - "sha256": "ecc0b62d2f30a09f704a7a1e70b1e72a0f85746cd5d5c13ad9c431e6967b697c", + "sha256": "0e42e1be101f84362f591354041fb96d511014b5f5e067e5bfbf367ee91199bf", "status": "active", "title": "MailStack UI Screen Catalog", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "designers-developers-and-maintainers", @@ -141,10 +141,10 @@ "last_reviewed": "2026-08-18", "path": "documents/design/UI_FOUNDATION.md", "phase_id": null, - "sha256": "5082d1f28afe1414d59a3c97f83a08a45d9c3242c2a057dae6d30b09b4c57785", + "sha256": "9f0afa77383bf80723f21c055c642fccb3a6b2bcab824e9fc1f2f6810092163c", "status": "active", "title": "MailStack UI Foundation", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-and-maintainers", @@ -153,10 +153,10 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-000-BASELINE.md", "phase_id": "PHASE-000", - "sha256": "0ca507b4dfe36daf118b81ebb9de19472c2c161d0e45256805513c8895a83574", + "sha256": "b5fa1216b48e77769b2084895e6fa6519f54f473908b4d3687fbe0fb417d0794", "status": "active", "title": "Documentation and Feature Baseline", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-designers-and-maintainers", @@ -165,10 +165,10 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md", "phase_id": "PHASE-001", - "sha256": "af6bb679cac06f760e00c5a40cfafee4ed30306a22782dc5b82e1b5039df36a6", + "sha256": "fa03c2cf487766e107ff25f4ba2d5e441b6020eb25720f6b1640dde4d01bc99c", "status": "active", "title": "UI Design Intake Baseline", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-designers-and-maintainers", @@ -177,10 +177,10 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md", "phase_id": "PHASE-002", - "sha256": "e3c8edf18c64865786c6be6d11f9424b37a54d98f095a05948bdf0773cfc8de0", + "sha256": "a152ecfb079d21ce9aac1a108850e4913f1784a57c290801f083e11799d9de41", "status": "active", "title": "Shared UI Foundation and Application Shell", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-and-maintainers", @@ -189,10 +189,10 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md", "phase_id": "PHASE-003", - "sha256": "bb6a6a8eb7d41ca882b9e9f83c3371fe78325e43472c3065e130e5923da78e96", + "sha256": "e4b23d66b5140c3de6822aee0094f652eee2d0f13ba9c72b820201091101a2d5", "status": "active", "title": "Installation, Recovery and Inbound Delivery Reliability", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-and-maintainers", @@ -201,10 +201,10 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md", "phase_id": "PHASE-004", - "sha256": "f45403765474a74f72607b1c37ca5cb0df6d0a546a4e436500ef427dcaf64f16", + "sha256": "48a1516924d8bf7e2a10be8bc4640cb5bc908520db67f2b28f7f278450911aa5", "status": "active", "title": "Release, Upgrade and Operational Reliability", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-designers-and-maintainers", @@ -213,10 +213,10 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md", "phase_id": "PHASE-005", - "sha256": "198f20d9732395701ac5ebb57d2e3d3a74d437e7b1a657630f697cf46a60b545", + "sha256": "3e23b169d1daa5ea1fdb678a0e9a17a74d684a6c29d10dd2f84e4fe3071ba13d", "status": "active", "title": "UI Navigation Reliability and Compact Mailbox Reader", - "version": "1.3.3" + "version": "1.3.4-rc.1" }, { "audience": "users-operators-and-maintainers", @@ -225,14 +225,14 @@ "last_reviewed": "2026-08-18", "path": "documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md", "phase_id": "PHASE-006", - "sha256": "78f216009e84b7decbb5061c0214ea7d6ac6ea178f401eccd8d7d6d027cc71ab", + "sha256": "bd254488c228d34015773d055c8c64778b4f5a15c8657ea0572382f864480c1a", "status": "active", "title": "Reader Integrity, Data Repair and Runtime Error Closure", - "version": "1.3.3" + "version": "1.3.4-rc.1" } ], "project": "MailStack", - "release_version": "1.3.3", + "release_version": "1.3.4-rc.1", "schema_version": 1, "scope": "Managed user, administrator, how-to, policy, baseline, and phase Markdown documents.", "summary": { diff --git a/documents/DOCUMENTATION_POLICY.md b/documents/DOCUMENTATION_POLICY.md index 739a4d9..aac46cc 100644 --- a/documents/DOCUMENTATION_POLICY.md +++ b/documents/DOCUMENTATION_POLICY.md @@ -4,7 +4,7 @@ title: Documentation Policy document_type: documentation-policy audience: contributors-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/HOW_TO_USE.md b/documents/HOW_TO_USE.md index 50f2f20..db42d7b 100644 --- a/documents/HOW_TO_USE.md +++ b/documents/HOW_TO_USE.md @@ -4,7 +4,7 @@ title: How to Use MailStack document_type: how-to audience: mailbox-users-and-administrators status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/README.md b/documents/README.md index b83e422..3c1ad66 100644 --- a/documents/README.md +++ b/documents/README.md @@ -27,25 +27,25 @@ required documentation update. | Document | Type | Audience | Status | Version | |---|---|---|---|---| -| [MailStack Administrator Guide](ADMIN_GUIDE.md) | Admin Guide | mailstack-administrators | active | 1.3.3 | -| [MailStack Baseline](BASELINE.md) | Baseline | maintainers-and-operators | active | 1.3.3 | -| [MailStack Accessibility Specification](design/ACCESSIBILITY_SPECIFICATION.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [MailStack Future UI Roadmap](design/FUTURE_UI_ROADMAP.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [MailStack Responsive Specification](design/RESPONSIVE_SPECIFICATION.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [MailStack UI Component Matrix](design/COMPONENT_MATRIX.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [MailStack UI Foundation](design/UI_FOUNDATION.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [MailStack UI Implementation Status](design/IMPLEMENTATION_STATUS.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [MailStack UI Screen Catalog](design/SCREEN_CATALOG.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.3 | -| [Documentation Policy](DOCUMENTATION_POLICY.md) | Documentation Policy | contributors-and-maintainers | active | 1.3.3 | -| [How to Use MailStack](HOW_TO_USE.md) | How To | mailbox-users-and-administrators | active | 1.3.3 | -| [Documentation and Feature Baseline](phases/PHASE-000-BASELINE.md) | Phase | users-operators-and-maintainers | active | 1.3.3 | -| [Installation, Recovery and Inbound Delivery Reliability](phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md) | Phase | users-operators-and-maintainers | active | 1.3.3 | -| [Reader Integrity, Data Repair and Runtime Error Closure](phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md) | Phase | users-operators-and-maintainers | active | 1.3.3 | -| [Release, Upgrade and Operational Reliability](phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md) | Phase | users-operators-and-maintainers | active | 1.3.3 | -| [Shared UI Foundation and Application Shell](phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md) | Phase | users-operators-designers-and-maintainers | active | 1.3.3 | -| [UI Design Intake Baseline](phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md) | Phase | users-operators-designers-and-maintainers | active | 1.3.3 | -| [UI Navigation Reliability and Compact Mailbox Reader](phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md) | Phase | users-operators-designers-and-maintainers | active | 1.3.3 | -| [MailStack User Manual](USER_MANUAL.md) | User Manual | mailbox-users | active | 1.3.3 | +| [MailStack Administrator Guide](ADMIN_GUIDE.md) | Admin Guide | mailstack-administrators | active | 1.3.4-rc.1 | +| [MailStack Baseline](BASELINE.md) | Baseline | maintainers-and-operators | active | 1.3.4-rc.1 | +| [MailStack Accessibility Specification](design/ACCESSIBILITY_SPECIFICATION.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack Future UI Roadmap](design/FUTURE_UI_ROADMAP.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack Responsive Specification](design/RESPONSIVE_SPECIFICATION.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack UI Component Matrix](design/COMPONENT_MATRIX.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack UI Foundation](design/UI_FOUNDATION.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack UI Implementation Status](design/IMPLEMENTATION_STATUS.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack UI Screen Catalog](design/SCREEN_CATALOG.md) | Design Reference | designers-developers-and-maintainers | active | 1.3.4-rc.1 | +| [Documentation Policy](DOCUMENTATION_POLICY.md) | Documentation Policy | contributors-and-maintainers | active | 1.3.4-rc.1 | +| [How to Use MailStack](HOW_TO_USE.md) | How To | mailbox-users-and-administrators | active | 1.3.4-rc.1 | +| [Documentation and Feature Baseline](phases/PHASE-000-BASELINE.md) | Phase | users-operators-and-maintainers | active | 1.3.4-rc.1 | +| [Installation, Recovery and Inbound Delivery Reliability](phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md) | Phase | users-operators-and-maintainers | active | 1.3.4-rc.1 | +| [Reader Integrity, Data Repair and Runtime Error Closure](phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md) | Phase | users-operators-and-maintainers | active | 1.3.4-rc.1 | +| [Release, Upgrade and Operational Reliability](phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md) | Phase | users-operators-and-maintainers | active | 1.3.4-rc.1 | +| [Shared UI Foundation and Application Shell](phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md) | Phase | users-operators-designers-and-maintainers | active | 1.3.4-rc.1 | +| [UI Design Intake Baseline](phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md) | Phase | users-operators-designers-and-maintainers | active | 1.3.4-rc.1 | +| [UI Navigation Reliability and Compact Mailbox Reader](phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md) | Phase | users-operators-designers-and-maintainers | active | 1.3.4-rc.1 | +| [MailStack User Manual](USER_MANUAL.md) | User Manual | mailbox-users | active | 1.3.4-rc.1 | ## Scope boundary diff --git a/documents/USER_MANUAL.md b/documents/USER_MANUAL.md index f20bde4..bf1e130 100644 --- a/documents/USER_MANUAL.md +++ b/documents/USER_MANUAL.md @@ -4,7 +4,7 @@ title: MailStack User Manual document_type: user-manual audience: mailbox-users status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/ACCESSIBILITY_SPECIFICATION.md b/documents/design/ACCESSIBILITY_SPECIFICATION.md index e4c3d4a..2f66b37 100644 --- a/documents/design/ACCESSIBILITY_SPECIFICATION.md +++ b/documents/design/ACCESSIBILITY_SPECIFICATION.md @@ -4,7 +4,7 @@ title: MailStack Accessibility Specification document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/COMPONENT_MATRIX.md b/documents/design/COMPONENT_MATRIX.md index f6e35e9..5900122 100644 --- a/documents/design/COMPONENT_MATRIX.md +++ b/documents/design/COMPONENT_MATRIX.md @@ -4,7 +4,7 @@ title: MailStack UI Component Matrix document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/FUTURE_UI_ROADMAP.md b/documents/design/FUTURE_UI_ROADMAP.md index 6b55639..b9e0a21 100644 --- a/documents/design/FUTURE_UI_ROADMAP.md +++ b/documents/design/FUTURE_UI_ROADMAP.md @@ -4,7 +4,7 @@ title: MailStack Future UI Roadmap document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/IMPLEMENTATION_STATUS.md b/documents/design/IMPLEMENTATION_STATUS.md index d5c3aeb..6c51035 100644 --- a/documents/design/IMPLEMENTATION_STATUS.md +++ b/documents/design/IMPLEMENTATION_STATUS.md @@ -4,7 +4,7 @@ title: MailStack UI Implementation Status document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/RESPONSIVE_SPECIFICATION.md b/documents/design/RESPONSIVE_SPECIFICATION.md index 85ad5b9..17e47a7 100644 --- a/documents/design/RESPONSIVE_SPECIFICATION.md +++ b/documents/design/RESPONSIVE_SPECIFICATION.md @@ -4,7 +4,7 @@ title: MailStack Responsive Specification document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/SCREEN_CATALOG.md b/documents/design/SCREEN_CATALOG.md index 5f52170..6adc9b9 100644 --- a/documents/design/SCREEN_CATALOG.md +++ b/documents/design/SCREEN_CATALOG.md @@ -4,7 +4,7 @@ title: MailStack UI Screen Catalog document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/design/UI_FOUNDATION.md b/documents/design/UI_FOUNDATION.md index 9df98b8..8e76993 100644 --- a/documents/design/UI_FOUNDATION.md +++ b/documents/design/UI_FOUNDATION.md @@ -4,7 +4,7 @@ title: MailStack UI Foundation document_type: design-reference audience: designers-developers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 --- diff --git a/documents/phases/PHASE-000-BASELINE.md b/documents/phases/PHASE-000-BASELINE.md index 315a935..ff00c48 100644 --- a/documents/phases/PHASE-000-BASELINE.md +++ b/documents/phases/PHASE-000-BASELINE.md @@ -4,7 +4,7 @@ title: Documentation and Feature Baseline document_type: phase audience: users-operators-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-000 --- diff --git a/documents/phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md b/documents/phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md index c6be0e5..5d8a9bb 100644 --- a/documents/phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md +++ b/documents/phases/PHASE-001-UI-DESIGN-INTAKE-BASELINE.md @@ -4,7 +4,7 @@ title: UI Design Intake Baseline document_type: phase audience: users-operators-designers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-001 --- diff --git a/documents/phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md b/documents/phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md index 7195c04..e6a062e 100644 --- a/documents/phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md +++ b/documents/phases/PHASE-002-SHARED-UI-FOUNDATION-AND-APPLICATION-SHELL.md @@ -4,7 +4,7 @@ title: Shared UI Foundation and Application Shell document_type: phase audience: users-operators-designers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-002 --- diff --git a/documents/phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md b/documents/phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md index 2485f15..9578f59 100644 --- a/documents/phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md +++ b/documents/phases/PHASE-003-INSTALLATION-RECOVERY-AND-INBOUND-DELIVERY-RELIABILITY.md @@ -4,7 +4,7 @@ title: Installation, Recovery and Inbound Delivery Reliability document_type: phase audience: users-operators-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-003 --- diff --git a/documents/phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md b/documents/phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md index 46b49f7..0173656 100644 --- a/documents/phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md +++ b/documents/phases/PHASE-004-RELEASE-UPGRADE-AND-OPERATIONAL-RELIABILITY.md @@ -4,7 +4,7 @@ title: Release, Upgrade and Operational Reliability document_type: phase audience: users-operators-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-004 --- diff --git a/documents/phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md b/documents/phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md index 68a1a21..367828f 100644 --- a/documents/phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md +++ b/documents/phases/PHASE-005-UI-NAVIGATION-RELIABILITY-AND-COMPACT-MAILBOX-READER.md @@ -4,7 +4,7 @@ title: UI Navigation Reliability and Compact Mailbox Reader document_type: phase audience: users-operators-designers-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-005 --- diff --git a/documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md b/documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md index b76113b..ab9b54a 100644 --- a/documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md +++ b/documents/phases/PHASE-006-READER-INTEGRITY-DATA-REPAIR-AND-RUNTIME-ERROR-CLOSURE.md @@ -4,7 +4,7 @@ title: Reader Integrity, Data Repair and Runtime Error Closure document_type: phase audience: users-operators-and-maintainers status: active -version: 1.3.3 +version: 1.3.4-rc.1 last_reviewed: 2026-08-18 phase_id: PHASE-006 --- @@ -73,9 +73,10 @@ disables the unused control interface through `gunicorn.conf.py`; it does not re ## Verification Local focused qualification on Python 3.12 completed with 60 PHASE-006 tests passing. Targeted Ruff, -Bandit, Django system checks and migration-drift checks passed after one import-order-only Ruff -correction. Full repository qualification, GitHub CI and controlled live acceptance remain required -before PHASE-006 is marked complete. +Bandit, Django system checks and migration-drift checks passed. Implementation commit +`90175b7a4549cb67d874692081bd5b0484eddccc` then passed GitHub Actions CI run `32183300485`. +The owner approved `1.3.4-rc.1` as the PHASE-006 live-acceptance pre-release identity. PR/main/tag +publication and controlled live acceptance remain required before PHASE-006 is complete. Controlled live acceptance must verify representative style-heavy HTML, plain-text fallback, dry-run and bounded existing-message repair, health/service status, and absence of the previously observed diff --git a/mailbox-app/pyproject.toml b/mailbox-app/pyproject.toml index 45054ee..24a8181 100644 --- a/mailbox-app/pyproject.toml +++ b/mailbox-app/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mailstack" -version = "1.3.3" +version = "1.3.4rc1" description = "MailStack self-hosted receive-only mail server and shared team inbox" authors = [{ name = "Vib Tools" }] maintainers = [{ name = "Vib Tools" }] diff --git a/scripts/forensic_audit.py b/scripts/forensic_audit.py index cdc1378..b7186ed 100644 --- a/scripts/forensic_audit.py +++ b/scripts/forensic_audit.py @@ -56,6 +56,7 @@ "docs/RELEASE_NOTES_1.3.1.md", "docs/RELEASE_NOTES_1.3.2.md", "docs/RELEASE_NOTES_1.3.3.md", + "docs/RELEASE_NOTES_1.3.4.md", "documents/README.md", "documents/USER_MANUAL.md", "documents/HOW_TO_USE.md", diff --git a/scripts/test_release_workflow.py b/scripts/test_release_workflow.py index b236380..0835640 100644 --- a/scripts/test_release_workflow.py +++ b/scripts/test_release_workflow.py @@ -188,7 +188,7 @@ def test_workflow_contract() -> None: "--latest", 'dist/*.zip', 'dist/*.sha256', - 'docs/RELEASE_NOTES_1.3.3.md', + 'docs/RELEASE_NOTES_1.3.4.md', ) for marker in required: assert marker in text, marker