Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,5 @@ jobs:
- name: Release verification
run: |
python scripts/verify_release.py \
dist/mailstack-1.3.1-source.zip \
--checksum dist/mailstack-1.3.1-source.zip.sha256
dist/mailstack-1.3.3-source.zip \
--checksum dist/mailstack-1.3.3-source.zip.sha256
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
path: |
dist/*.zip
dist/*.sha256
docs/RELEASE_NOTES_1.3.1.md
docs/RELEASE_NOTES_1.3.3.md
docs/FORENSIC_AUDIT_REPORT.md
if-no-files-found: error

Expand Down Expand Up @@ -121,7 +121,7 @@ jobs:
--verify-tag
--target "$GITHUB_SHA"
--title "MailStack ${RELEASE_VERSION}"
--notes-file docs/RELEASE_NOTES_1.3.1.md
--notes-file docs/RELEASE_NOTES_1.3.3.md
)
if [[ "$RELEASE_PRERELEASE" == "true" ]]; then
args+=(--prerelease --latest=false)
Expand Down
39 changes: 37 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,42 @@

All notable repository-level changes are recorded here. Application history before the open-source conversion remains in `mailbox-app/CHANGELOG.md`.

## 1.3.1 — Unpublished source baseline
## 1.3.3 — PHASE-005A qualification correction

### Corrected

- Synchronized the 1.3.3 release identity across VERSION, CI/release workflows, deterministic artifact paths, managed documentation, and release-workflow contract tests after the failed qualification run exposed stale 1.3.2 metadata.
- Removed the accidental empty repository-root `85%` file created when non-comment CMD guidance containing `>=85%` was interpreted as output redirection.
- Corrected PHASE-005A import-order lint findings and regenerated forensic/document metadata so source-safety and Ruff gates evaluate the intended source tree.
- Preserved live updates for browsers that still hold the previously immutable-cached `app.js`: the live endpoint accepts either the new explicit `X-MailStack-Live-Request: 1` header or the legacy `Accept: application/json` poll signature, while ordinary document navigation continues to redirect to the dashboard instead of exposing raw JSON.
- Replaced the prose-paste handoff with an executable Windows CMD script whose explanatory lines are `REM` comments and whose gates stop on failure.

### Compatibility

- No model, migration, parser/sanitizer, mailbox permission, ingestion, Postfix/Dovecot, Maildir, MariaDB, attachment, installer, deployment-template, backup/restore, or upgrade/rollback behavior changes.
- Published `v1.3.1` remains immutable official release provenance; `1.3.2` is retained only as failed development-qualification history and is not promoted as a release baseline.

## 1.3.2 — PHASE-005A development

### UI navigation reliability

- Hardened the authenticated live-update transport so `/messages/live/` returns JSON only to MailStack background polling requests carrying the explicit `X-MailStack-Live-Request: 1` header; ordinary authenticated document navigation redirects to the dashboard instead of rendering raw JSON.
- Preserved same-origin credentials, no-store responses, authorization filtering, bounded live payloads, polling backoff, notifications, and mailbox counter updates.

### Compact mailbox and unified reader

- Replaced the oversized mailbox header and generic message grid with a compact webmail-style inbox surface, integrated search/read/attachment filters, denser unread rows, message previews, attachment/size metadata, and responsive desktop/mobile behavior.
- Added preview text derived only from the existing indexed plain body or sanitized HTML text; no model, migration, parser, or persistence change is introduced.
- Removed the visible `Plain text` / `Safe HTML` tabs and replaced them with one message reader that automatically shows the existing sanitized HTML in the retained sandbox/no-referrer frame, or the indexed plain-text body when no HTML body exists.
- Compact sender/routing metadata, actions, warnings, and attachments into the unified reader while preserving mark-unread, deletion permissions, attachment authorization, sanitizer policy, CSP, and receive-only boundaries.

### Qualification and release metadata

- Added PHASE-005A regression coverage for direct live-endpoint navigation, background JSON polling, compact inbox rendering, HTML-derived previews, unified HTML rendering, and plain-only fallback.
- Synchronized the approved target identity to `1.3.2`, including CI deterministic-artifact verification and release-note file selection, without changing release-gate semantics.
- Froze published `v1.3.1` as `MAILSTACK-1.3.1-OFFICIAL-SOURCE-BASELINE-001`, anchored to commit `039a6e6eea6e198b4b15612db9d2f208b6305a16`, tree `9437ba2ebac2033a229accd190268b8711d5b26e`, and deterministic source SHA-256 `517778967ca491974f315d231dfd43b3dba85fe86b47dcfc63e4c7051d1010bd`.

## 1.3.1 — 2026-08-18

### Documentation and forensic baseline

Expand Down Expand Up @@ -35,7 +70,7 @@ All notable repository-level changes are recorded here. Application history befo
### Compatibility

- PHASE-004C changes maintained operational tooling only; it does not add a database migration, application route, authorization/UI/mail-flow behavior, installer behavior, deployment-template rewrite, DNS/TLS change, or automatic host-configuration migration.
- `v1.3.0-rc.4` and its published source identity remain immutable. `1.3.1` is the next frozen source-baseline version mark and remains unpublished until its GitHub/main CI and operational release gates are accepted.
- `v1.3.0-rc.4` remains immutable historical release provenance. `v1.3.1` is the current frozen published source/release baseline; PHASE-005A develops `1.3.2` from that exact source without rewriting either historical tag.

## Unreleased — MailStack repository bootstrap

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

It combines **Postfix**, **Dovecot LMTP**, **Django**, **MariaDB**, **Maildir**, **Gunicorn**, and **Nginx** in a hardened single-node reference deployment. MailStack provides a private browser-based inbox, administrator-managed users, object-level mailbox access, safe email rendering, protected attachments, live inbox updates, operational audit logs, backup and restore tooling, a public website, and an isolated contact service.

> **Release status:** `v1.3.0-rc.4` remains the latest published release candidate. The repository source baseline is now marked `1.3.1` for the PHASE-004C verification/fix freeze; this version is not yet a published GitHub release or a production-readiness claim. PHASE-003 staging validated real external SMTP/LMTP delivery after the accepted fixes; backup/restore, restart/reboot, clean-host, legal, and final release-owner acceptance remain separate operational gates.
> **Release status:** `v1.3.1` remains the current published, deterministic source/release baseline. PHASE-005A is being corrected as `1.3.3` after the failed `1.3.2` qualification attempt; it hardens the live-update UI boundary, preserves legacy cached-poller compatibility, and delivers the compact mailbox/unified message reader. The existing VPS has not yet been upgraded to this development line; live upgrade acceptance remains a separate post-release operational gate.

## Why MailStack

Expand All @@ -38,7 +38,7 @@ MailStack is designed for teams that need:
- shared mailbox access with per-user authorization;
- a receive-only mail security model;
- durable Maildir storage and recoverable indexing;
- protected attachment delivery and sanitized HTML email;
- protected attachment delivery and unified sanitized-HTML/plain-text message reading;
- auditable administration and operational recovery;
- reproducible installation and release tooling.

Expand All @@ -52,7 +52,7 @@ MailStack is **not** intended to be a complete replacement for Gmail, Microsoft
- Object-level mailbox isolation
- Shared mailbox memberships
- Mailbox create, enable, disable, and soft-delete lifecycle
- Search, pagination, read/unread state, and attachment filters
- Compact webmail-style inbox with search, pagination, read/unread state, attachment filters, and message previews
- Live inbox polling and browser notification support

### Receive-only mail stack
Expand Down Expand Up @@ -211,8 +211,8 @@ Build and verify a deterministic source release:
```bash
python scripts/build_release.py --root .
python scripts/verify_release.py \
dist/mailstack-1.3.1-source.zip \
--checksum dist/mailstack-1.3.1-source.zip.sha256
dist/mailstack-1.3.3-source.zip \
--checksum dist/mailstack-1.3.3-source.zip.sha256
```

## Security
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3.1
1.3.3
6 changes: 3 additions & 3 deletions design/DESIGN_MANIFEST.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,11 @@
"format": "PNG",
"has_alpha": false,
"height": 1024,
"implementation_phase": null,
"implementation_phase": "PHASE-005",
"lifecycle_status": "current-redesign",
"mode": "RGB",
"path": "design/intake/original/Inbox.png",
"review_note": "The three-pane direction is approved; reply, forward, sent, drafts, spam, and move actions are outside the current receive-only feature set.",
"review_note": "PHASE-005A implements a compact receive-only inbox list and unified message reader; reply, forward, sent, drafts, spam, and move actions remain outside scope.",
"screen_id": "UI-011",
"sha256": "94ff5f7d0988a93a402bb5d41a743d11c8a852f9213294cf560e225efd669f70",
"size_bytes": 1242692,
Expand Down Expand Up @@ -561,7 +561,7 @@
"unsupported_features_inactive": true
},
"project": "MailStack",
"release_version": "1.3.1",
"release_version": "1.3.3",
"schema_version": 1,
"source_archive": {
"archive_crc": "PASS",
Expand Down
4 changes: 3 additions & 1 deletion docs/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ MailStack does not expose a public REST API in this release. The supported inter
| Mailboxes | `/mailboxes/` | authenticated, object scoped |
| Mailbox administration | `/mailboxes/create/`, status/delete routes | authorized administrators |
| Messages | `/messages/`, detail/read/delete routes | authenticated, object scoped |
| Live updates | `/messages/live/` | authenticated, membership filtered |
| Live updates | `/messages/live/` | authenticated, membership filtered, MailStack background-request header required for JSON |
| User management | `/accounts/users/` | MailStack administrators |
| Health | `/health/` | service probe |
| Readiness | `/ready/` | service/database probe |

Route names and exact patterns are defined in `mailbox-app/config/urls.py` and each app's `urls.py`.

The live-update route is an internal browser transport, not a document page. MailStack JavaScript sends `X-MailStack-Live-Request: 1`; an authenticated top-level navigation without that header redirects to the dashboard instead of returning raw JSON.

## Public contact endpoint

`POST /api/contact/` accepts a JSON contact submission protected by a one-time CSRF token, SameSite cookie, honeypot, timing checks, size limits and rate limits. The service sends only a fixed local notification through `/usr/sbin/sendmail`.
Expand Down
6 changes: 3 additions & 3 deletions docs/BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ python scripts/forensic_audit.py --root . --full
```bash
python scripts/build_release.py --root .
python scripts/verify_release.py \
dist/mailstack-1.3.1-source.zip \
--checksum dist/mailstack-1.3.1-source.zip.sha256
dist/mailstack-1.3.3-source.zip \
--checksum dist/mailstack-1.3.3-source.zip.sha256
```

The builder normalizes archive timestamps, preserves executable permissions, writes a source manifest, excludes generated/runtime artifacts and emits a SHA-256 checksum.
Expand All @@ -38,4 +38,4 @@ missing successful `main` CI, and pre-existing releases fail closed.

## Stable promotion

The `1.3.1` source baseline is an unpublished version mark. Do not create or push a stable release tag until every required human/operational gate in `docs/PUBLIC_RELEASE_CHECKLIST.md` passes.
`v1.3.1` remains the immutable published source/release baseline. `1.3.3` is the PHASE-005A development target and must not be tagged until branch, PR, main, and release gates pass; live existing-VPS acceptance remains a separate post-release operational step.
5 changes: 3 additions & 2 deletions docs/FEATURE_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ The open-source work was performed as an additive and compatibility-preserving c
| Maildir ingestion and restart-safe duplicate protection | Preserved | Reliability, parser/storage, and ingestion tests |
| Oversized-message handling | Preserved | Ingestion tests |
| Safe MIME parsing and HTML sanitization | Preserved | Parser and security tests |
| Unified message reader | Added presentation layer | Sanitized-HTML auto-selection, plain fallback, retained sandbox/no-referrer tests |
| Attachment isolation and protected downloads | Preserved | Storage, authorization, and Nginx template checks |
| Search, pagination, counters, read/unread state | Preserved | Message and integration tests |
| Live inbox polling and new-message notification payloads | Preserved | Live-access integration tests |
| Search, pagination, counters, read/unread state | Preserved with compact inbox presentation | Message and PHASE-005A functional/integration tests |
| Live inbox polling and new-message notification payloads | Preserved and UI-guarded | Live-access tests plus direct-navigation/background-header PHASE-005A regression |
| Audit trail and health endpoints | Preserved and hardened | Audit/service tests and production deploy checks |
| Public static website | Preserved and parameterized | Public-site renderer and template audit |
| CSRF-protected, rate-limited contact form | Preserved and parameterized | Contact-service test suite |
Expand Down
43 changes: 30 additions & 13 deletions docs/FORENSIC_AUDIT_REPORT.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Forensic audit report — MailStack 1.3.1 source baseline verification
# Forensic audit report — MailStack 1.3.3 PHASE-005A correction verification

**PHASE-004C audit date:** 2026-08-17
**Repository source-baseline version:** `1.3.1`
**Latest published release candidate:** `v1.3.0-rc.4`
**PHASE-005A audit date:** 2026-08-18
**Immutable official baseline:** `v1.3.1` / `039a6e6eea6e198b4b15612db9d2f208b6305a16` / tree `9437ba2ebac2033a229accd190268b8711d5b26e`
**Corrected development target:** `1.3.3`
**Target runtime:** Ubuntu Server 24.04 LTS and CPython 3.12
**Current classification:** 1.3.1 owner-marked source-baseline correction locally structurally qualified; GitHub requalification and live PHASE-004D acceptance remain pending
**Current classification:** 1.3.2 qualification failed; 1.3.3 corrective candidate under requalification; live-VPS acceptance pending

## Executive disposition

Expand Down Expand Up @@ -176,6 +176,14 @@ findings, and the focused upgrade/archive/rollback contract suite. No live VPS u
PHASE-004D is the real existing-server acceptance boundary. GitHub CI requalification remains pending
after the PHASE-004C delta is applied and pushed.

## PHASE-005A UI/navigation reliability boundary

The PHASE-005A delta starts from the exact released 1.3.1 Git tree and is restricted to the mailbox/message presentation layer, the live-polling request header/guard, focused tests, version-specific CI/release metadata, and required documentation/manifests. It does not change models, migrations, parser/sanitizer rules, object authorization, message deletion semantics, attachment storage/download authorization, Postfix/Dovecot, Maildir, MariaDB, installer, deployment templates, backup/restore, or PHASE-004 upgrade/rollback behavior.

The raw-JSON failure mode is closed by requiring `X-MailStack-Live-Request: 1` before the authenticated live endpoint returns JSON. MailStack JavaScript sends that header; ordinary authenticated document navigation redirects to the dashboard. The compact inbox and unified reader remove the visible body-format tabs while preserving the existing sanitized-HTML sandbox/no-referrer boundary and plain-text fallback.

Dependency-free/local qualification completed with 18 managed documents/6 phases, 25 verified design PNGs, 4 documentation tests, 4 design tests, 8 UI-foundation contracts, 13 deployment templates, installer and operations contracts, 7 release-workflow contracts, upgrade/rollback contracts, generated forensic inventory, and a structural forensic scan of 415 files / 149 Python / 15 shell with zero blocking findings. The artifact environment has Python 3.13 only and no package-network access, so the supported Python 3.12 Django/Ruff/Bandit/pip-audit suite is not fabricated here and remains mandatory in the user's isolated environment and GitHub CI.

## Security review

The RC4 source remains pinned to Django 5.2.16, Python 3.12, and `sqlparse==0.6.0`. The blocking
Expand All @@ -197,13 +205,22 @@ privilege, systemd confinement, archive safety, checksum verification, and fail-
6. Confirm copyright ownership and third-party license compatibility.
7. Obtain final release-owner acceptance before promoting `1.3.0` stable.

## PHASE-005A 1.3.2 failure and 1.3.3 corrective findings

The Windows qualification captured Python 3.12.8, 202 passed plus one host-capability symlink skip,
94.97% coverage, Django system-check PASS, no migration drift, dependency audit with no known
vulnerabilities, Bandit PASS, and contact-service PASS. Ruff reported three `I001` import-order
findings. The malformed prose-paste CMD handoff also created an unintended empty `85%` file. GitHub
Actions run `32128090322` for commit `76540ccf48d1a4d44175b5e3b120e91d0b8c226e` failed in the
source-safety audit because the extra file made `docs/FORENSIC_FILE_INVENTORY.json` stale, so later
CI gates were skipped and that SHA is not qualified.

A separate compatibility review found that the released Nginx static policy caches `/static/` for
seven days with `immutable`, while the legacy poller sends `Accept: application/json` without the new
custom header. Requiring only the custom header would therefore temporarily break live polling for
a browser retaining old JavaScript across upgrade. The 1.3.3 guard accepts either trusted polling
signature while continuing to reject ordinary document navigation.

## Final disposition

The published `v1.3.0-rc.4` source is a qualified release candidate and is the official frozen source
baseline for PHASE-004. PHASE-004A corrects the documentation evidence around that baseline but does
not retroactively modify or retag RC4. The owner-marked working source baseline is `1.3.1` and remains unpublished. PHASE-004B branch CI
has passed. PHASE-004C GitHub Actions run `32097491341` reached Ruff after all earlier gates passed,
then failed on five style findings in the new archive verifier; downstream runtime/release gates were
skipped. This scoped correction removes only those Ruff findings and synchronizes the requested 1.3.1
baseline/release metadata. A fresh GitHub CI run is required before remote qualification, and no live
upgrade is claimed until the separately approved PHASE-004D acceptance campaign.
Published `v1.3.1` remains the immutable official source/release baseline for PHASE-005A. The corrected `1.3.3` development delta closes the raw-JSON document-navigation boundary and implements the compact inbox/unified message reader without changing receive-only business/data/mail-flow contracts. Local structural and deterministic-build gates pass; supported Python 3.12 dependency-backed regression, GitHub branch/PR/main CI, tag/release publication, and the later controlled existing-VPS upgrade remain explicit follow-on gates.
Loading
Loading