Commit Graph

13 Commits

Author SHA1 Message Date
mix 1cf8bfcbe2 docs: rewrite security/operator docs for the multi-user panel (P2)
test / test (push) Has been cancelled
The CSRF ADR, guide.md, architecture.md route table, the internal/backup
package comment, roadmap/dmarc-reports admin.dmarc_report_email references,
the e2e coverage summary, and the setupManager/store package comments still
described the pre-1.2.0 single-administrator panel or stale implementation
details. Closes P2 of docs/plans/code-review.md; no behaviour change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 16:15:14 +03:00
mix 236cb07769 docs: translate security.md and the last Russian source comments
security.md is linked from the README documentation table and now from
SECURITY.md, so a reader following either link landed in a Russian document
while everything around it was English. Translated in full; the requirements,
the accepted risks, and the CSRF ADR are unchanged in substance.

The reviewing model is no longer named in the text — that the pre-release
review ran, and when, is what a reader needs; who ran it is process detail
kept in development.md.

extract-cert.sh keeps its spec 10.3 quotation, translated. In sasl.go the
quotation from the closed plan is dropped rather than translated: rendered in
English it restated the sentence it hung off.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 22:39:53 +03:00
mixeme 178424eaf6 release: cut 1.0.0
Pin compose and local trial to ghcr.io/mixeme/selfpost:1.0.0, close the
CHANGELOG cut, and retire implementation-plan / v1.x-closure-plan.

Includes the post-cut startup fixes needed for a green release e2e gate:
root-owned TLS copies for postfix check, maillog_file_prefixes for /data,
hostname gate and traversable /data, panel /healthz before setup, and
setup-token / TempDir reclaim via docker exec.

Co-Authored-By: Composer <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-09 12:33:29 +03:00
mixeme 18880a8286 docs: spell out .spbk and .spde extensions
SelfPost backup / SelfPost domain export — in the guide, security notes,
architecture, and Backup/Export panel copy.

Co-Authored-By: Composer <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-09 00:49:43 +03:00
mixeme 1f548dfc7a fix(logtail): keep mail.log in /data and reconcile stuck rows (v1.x closure phase 2)
Move the delivery log from the ephemeral /var/log to /data/log/mail.log so
the lines that resolve a queued send-log row survive a container recreate.
postlogd writes it as postfix, the panel reads it through the selfpost group
(dir 2750, file 0640, normalised every start); backups exclude log/.

Close the residual gap with a queue sweep: rows queued for over two minutes
whose id postqueue -p no longer lists are marked bounced. The sweep waits
until the tailer has read the log to its end and does nothing when the queue
cannot be listed, so a message in flight is never touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 11:35:27 +03:00
mix a92d583053 feat: log-tailer offset persistence + in-flight L2 rate-limit accounting (code-review.md § Phase 3)
- logtail: persist the read position (offset + fingerprint of the log's
  first 512 bytes) in a new logtail_state table (migration 0003) and
  resume from it on start, so delivery lines written while the panel was
  down are parsed instead of skipped and their send-log rows no longer
  stay "queued" forever. Fingerprint mismatch (rotated/recreated while
  down) reads the file from the start — re-parsing is idempotent; a
  first-ever start with nothing stored still begins at end-of-file.
  Writes are throttled to one per 5s, forced on rotation and shutdown.

- milter: count messages that passed the level-2 check but have not
  reached the send log yet (internal/milter/inflight.go), so concurrent
  SMTP sessions cannot each spend the same last slot. A literal
  count+insert transaction, as the review suggested, is not possible:
  the count happens at MAIL FROM and the insert at end-of-message.
  Reservations are released after the insert, on ABORT, and after a
  10-minute TTL — a client that drops mid-transaction must not be able
  to hold a slot, since the limiter is fail-open by design.

Docs: architecture.md (log tailer, persistence, L2 counting),
security.md and roadmap.md (restart gap closed, container recreate
remains), CHANGELOG, progress.md, code-review.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:12:37 +03:00
mix 6a7d010868 feat: optional password encryption for backup and domain export (code-review.md § Phase 1.5)
Both secret-bearing downloads can now be sealed with a password. Unticked, the
forms produce exactly the files they did before.

- internal/secretfile: envelope format — magic/type/scrypt params/salt/nonce
  prefix header, then 64 KiB AES-256-GCM chunks each authenticated with the
  header, its counter and an end-of-stream flag, so truncation, reordering and
  tampering fail to open instead of restoring a plausible prefix. Streams both
  ways, so a full backup never sits in memory.
- Panel: "Encrypt with a password" checkbox on the full-backup and
  domain-export forms (shared partial, toggled from panel.js — no inline
  script); domain import detects an encrypted export by magic bytes, not by
  extension, and asks for the password.
- selfpost-backup: writes .spbk when given a password and converts one back
  with -decrypt, which a restore needs. The password comes from
  SELFPOST_BACKUP_PASSWORD or -password-file, never argv.
- Docs: README, security.md (+ accepted risk: encryption stays opt-in),
  architecture.md, progress.md, CHANGELOG.

Verified locally: panel-encrypted archive decrypts through the CLI and unpacks;
wrong password and password mismatch are refused; UI checked in a browser.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 16:43:28 +03:00
mix 670982fb3e docs/chore: Phase 1 doc/code hygiene (code-review.md § Phase 1)
Removes ~30 stale "Phase N" / historical-staging comment references from
code and shell scripts now that v1.0 is done; fixes a stale dashboard
comment claiming applications/send-log were unimplemented; adds a CSRF ADR
to security.md documenting the Origin-check-over-tokens decision; resolves
docs/logo in roadmap.md (directory doesn't exist, criterion already met);
adds a gofmt -l check to CI so unformatted Go fails the build.

The known-limitations write-up for the log-tailer offset gap (the other
Phase 1 item) was already present in architecture.md § Log tailer, so no
change was needed there.

gofmt/go vet/go test clean on both Go modules (main + test/e2e), verified
on the dev server.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 16:13:36 +03:00
mix e93a277ee7 security: phase D pre-release review — pass; harden saslpasswd2 argv
Fable review of the full diff from the v1.0 audit (Phase 11, 65a420d) to
HEAD plus a complete pass over the docs/security.md checklist (former spec
7.6). No exploitable findings. One defence-in-depth fix: the application
login is passed to saslpasswd2 behind a -- end-of-options marker so a
login starting with - can never be parsed as a flag. Accepted risks
unchanged; plan § D closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 13:32:52 +03:00
mix 00983cce39 docs: plan backup encryption and drop session-restore risk
Update code-review with phase 1.5 (optional .spbk/.spde encryption, checkbox UI). Remove session resurrection from backup as an accepted risk in security.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 22:07:48 +03:00
mix 60addd56c8 docs: trim implementation-plan to open release gate
Leave only pre-release security review (section D) in implementation-plan.md. Move closed B.1-C.4 as-built detail to architecture.md and development.md; document accepted risks in security.md; optional send-log follow-ups in roadmap.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 00:50:13 +03:00
mix baaed5991b docs: D6-D9 — HEALTHCHECK, env regression test, new docs, archive spec
Add Docker HEALTHCHECK and mail-path /healthz liveness; env-doc regression
test; architecture.md and development.md; product.md and expanded security.md;
retire live specification.md to docs/archive/.

Co-Authored-By: Claude <claude-opus-5-thinking-high@noreply@anthropic.com>
2026-08-05 00:33:49 +03:00
mix db6abaefc7 docs: move the accepted security risks into docs/security.md
The plan holds undone work; an accepted risk is a decision, not a task
— it has no place in a queue, only a condition for revisiting it. Both
risks (POST with neither Sec-Fetch-Site nor Origin, no session-bound
CSRF tokens) move verbatim into a new docs/security.md, which also
states where D.5 findings land. Section letters and item numbering in
the plan stay as they were, since progress.md and the commit history
reference them; a note in their place points at the new file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 23:12:50 +03:00