docs: rewrite security/operator docs for the multi-user panel (P2)
test / test (push) Has been cancelled
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>
This commit is contained in:
@@ -6,13 +6,18 @@
|
||||
// it. TLS certificates (the reverse proxy's responsibility) and the Postfix
|
||||
// queue are deliberately excluded (architecture.md § Persistence).
|
||||
//
|
||||
// Restore is intentionally not a separate code path: a backup is extracted
|
||||
// into the /data bind mount before first start, and the panel regenerates
|
||||
// Postfix and OpenDKIM from the restored SQLite state exactly as on any normal
|
||||
// start. The only restore-specific step is CheckRestore, which refuses to boot
|
||||
// if the manifest's version does not match the running binary, so
|
||||
// schema/format skew between versions cannot silently corrupt state
|
||||
// (architecture.md § Persistence).
|
||||
// Restore is not a separate code path in the panel: a backup is extracted into
|
||||
// the /data bind mount before first start, and the archive already carries
|
||||
// everything the mail path needs — DKIM keys, sasldb2, and Postfix's sender
|
||||
// map — so nothing needs to be regenerated from SQLite for the daemons to
|
||||
// start correctly. The only restore-specific step the panel runs is
|
||||
// CheckRestore, which refuses to boot if the manifest's version does not match
|
||||
// the running binary, so schema/format skew between versions cannot silently
|
||||
// corrupt state (architecture.md § Persistence). If a daemon's on-disk state
|
||||
// ever drifts from what SQLite records — for example after a manual edit
|
||||
// under /data — the Status page's "Reload configuration" button re-derives
|
||||
// OpenDKIM's tables and the Postfix sender map from the database; that is a
|
||||
// deliberate, operator-triggered heal, not something restore does on its own.
|
||||
package backup
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Package store owns the SelfPost SQLite database: the single file under /data
|
||||
// that persists the administrator account, sending domains and applications,
|
||||
// the send log and rate-limit settings (architecture.md § Persistence). It
|
||||
// exposes typed queries so the rest of the panel never builds SQL by hand.
|
||||
// that persists panel users (global administrators and domain-admins), sending
|
||||
// domains and applications, the send log and rate-limit settings
|
||||
// (architecture.md § Persistence). It exposes typed queries so the rest of the
|
||||
// panel never builds SQL by hand.
|
||||
package store
|
||||
|
||||
import (
|
||||
|
||||
@@ -16,8 +16,9 @@ const setupTokenTTL = 10 * time.Minute
|
||||
|
||||
// setupManager owns the one-time administrator setup token. The token itself is
|
||||
// ephemeral (regenerated on restart or expiry) and lives only in memory; the
|
||||
// persistent "setup complete" fact is the presence of the admin row in the
|
||||
// store, so once that exists the token is gone for good (security.md).
|
||||
// persistent "setup complete" fact is the presence of any row in the store's
|
||||
// users table (`store.UserExists`), so once the first global administrator is
|
||||
// created the token is gone for good (security.md).
|
||||
type setupManager struct {
|
||||
store *store.Store
|
||||
hostname string
|
||||
|
||||
Reference in New Issue
Block a user