findings of the reviews of audit stage 2
test / test (push) Canceled after 0s

Technical review (Opus) and security review (Fable) of a59e3d4..cb5a4a2;
reports in the session's scratchpad. Nothing critical, high or medium; no
outright bug. Fixed:

- F2, F3 (0008 backfill, before it runs on the live database): rows are
  filled by the rule new rows follow - the application's domain, then the
  name's - and only by a domain and application that existed when the row
  was written (created_at); the inbound log likewise. Test: the migration's
  UPDATEs re-run on prepared rows (before the domain, after, null sender,
  application gone, a stranger's name). Dry run on a copy of the live
  database: 68/68 and 10/10 rows filled, none disagreeing with its login's
  domain, integrity ok.
- V2, F4: an application's statistics and level-2 count are its login's
  rows of its domain (appByLogin), and StatsWindow starts no earlier than
  the entity's creation; the message page's "may send as" only for a login
  still of the row's domain. Test: a login taken again in another domain
  starts at zero.
- F7: MAIL FROM:<> is held to the domain limit of its login
  (ApplicationByLogin fills DomainName).
- V3: an imported DKIM selector is held to DNS labels (validate.Selector).
- F5, F6: an imported auto limit's numbers are dropped and recalculated
  right after the import; its mode is stored trimmed.
- V6: the store refuses a role that is neither global nor domain.
- F9: SaveUser keeps the stored hash when no new password is given (the
  form no longer writes back the hash it read). F10: a reach naming a
  domain deleted meanwhile is ErrNoSuchDomain, answered on the form.
- V4, F12: from-lines-other.txt - lines naming another sender ({other}) in
  a quoted string, a quoted pair, capitals, a comment, an encoded word, a
  quoted local part; the unit test wants each refused, the e2e
  (lines_naming_another_sender_never_signed_for_it) wants each refused and
  none signed for it. The passed list gained a.{DOMAIN}, a comment after
  the angle address, a quoted local part, and "b@ {other}" - passed by
  design (security.md), and the e2e shows it signed for the own domain.
- F13: e2e login_in_other_capitals_does_not_authenticate - AUTH with the
  login upper-cased gets 535.

Not changed, written down: V1/F1 - L8 is half closed (refused or passed
still tells an application which domains are hosted here); security.md's
accepted risks and the CHANGELOG say so, and the owner is asked whether to
refuse every foreign address in a display name (changes the 2.4.0 rule).
F11 - deleting a domain rewrites its rows' domain_id (seconds at 1e5 rows),
accepted at this size. F8 (test cannot tell write-first from read-first;
the reviewer verified it with two stores, 30/30), V5, V7, P2: noted.

Evidence on the test server for this tree: go vet clean, go test ./... 23
packages ok, make e2e exit 0 with the three new cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-14 16:17:57 +03:00
co-authored by Claude Opus 5.5
parent 8b53d63160
commit ef18ef21a0
26 changed files with 552 additions and 40 deletions
+23 -8
View File
@@ -70,14 +70,28 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
with nothing assigned. Saving and creating a user are now one transaction
each, the e-mail included (audit 2026-10-12, M9).
- **The users form keeps a password changed meanwhile, and says when a
domain it offered is gone.** Saving a user wrote back the password hash
read when the form was opened, which undid a password the user changed on
Account in between; a domain deleted while the form was open ended in an
error page.
- **A domain import is checked like the forms.** The import trusted the file
for the report address, the rate limits and the client addresses: a limit
with a window of no seconds counted nothing, and an address that was not
one made the application refuse every client without a word. The file is
now held to the forms' rules before anything is created, and refused with
the form's own message, naming the field and the application (audit
2026-10-12, M10).
the form's own message, naming the field and the application; the DKIM
selector is held to DNS labels; an auto limit's numbers are worked out on
this server right after the import rather than taken from the file
(audit 2026-10-12, M10).
- **An application's numbers are its own.** Statistics, the level-2 count
and an auto limit's recalculation counted every row of the login, so an
application created with the login of a deleted one - in another domain,
even - started with the old one's traffic. They now count the login's rows
of its domain, from the application's creation on. A message with an empty
envelope sender (`MAIL FROM:<>`) is held to its domain's level-2 limit by
its login, like the application's other mail.
- **A domain added again starts with an empty log.** Send-log rows belonged
to a domain by its name, so a domain deleted and added again showed its
earlier mail to whoever it was assigned to next, and its statistics and
@@ -86,12 +100,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
registry); the rows of a deleted domain are the global role's alone. The
inbound log follows the same rule (audit 2026-10-12, L12).
- **A refusal no longer says which other domain sends from this server.**
A `From:` line that named another sender of the server was refused with
that sender's domain in the reply, which confirmed to whoever tried names
that it is hosted here. The reply now stops at "it names another sender of
this server"; the line as written stays in the reply and on the refused
message's page (audit 2026-10-12, L8).
- **A refusal no longer names the other domain.** A `From:` line that named
another sender of the server was refused with that sender's domain in the
reply. The reply now stops at "it names another sender of this server";
the line as written stays in the reply and on the refused message's page.
That such a line is refused at all still tells the sending application
that the domain is hosted here (security.md, accepted risks) (audit
2026-10-12, L8).
### Added