Test MAS addresses against real Postfix; close MAS-WP-0002, add MAS-WP-0003

- experiments/postfix-probe: Postfix 3.7 -> pipe -> mas-gateway -> ticket
  service in Docker; 14 address forms x 5 configurations. 13/14 arrive
  byte-identical everywhere; quoted "ticket=PR42" is unquoted in transit.
  Legacy bang/percent rewrites never fire for MAS addresses.
- docs/experiment-review.md: Email infrastructure section with results
- MAS-WP-0003: provider-side live test on a real subdomain (needs DNS/MX)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 623586@bnt-lap001
Assistant-Session: 10b30928-5b3b-4c11-9934-5ecca07367d8
This commit is contained in:
tegwick 2026-10-08 00:51:27 +02:00
parent 8d3878d9c8
commit e19d557a4c
13 changed files with 1179 additions and 20 deletions

View file

@ -5,11 +5,12 @@ Status of MAS-WP-0002, Milestone 9. The answers below come from building
and from running the test suite (135 tests, all offline except the
loopback fixture servers).
**Scope caveat:** every "email path" here is simulated. Raw RFC 5322
messages go through the real `mas-gateway pipe` entrypoint, but no
production MTA or mailbox provider was involved. The *Email infrastructure*
question is therefore still open and needs the live test described at the
end.
**Scope:** the MTA half of the email path was tested against a real
Postfix (3.7.11, Debian bookworm, in Docker). The setup was SMTP → Postfix
→ `pipe` transport → `mas-gateway` → reference ticket service
(`experiments/postfix-probe/`). Mailbox providers (Gmail, Outlook,
corporate gateways) and public DNS/MX were not involved. That half moves
to **MAS-WP-0003**.
## Answers to the review questions
@ -62,11 +63,43 @@ Facets have no statute declaration at all, so they are always reported as
they recognise.
### Email infrastructure: which forms were rewritten or rejected?
**Not yet tested.** Known risks to check:
- `=` overlaps with SRS (`SRS0=...`) and VERP encodings.
- `!` is UUCP bang-path syntax. Some validators and web forms reject it.
- Postfix `recipient_delimiter = +` strips the facet for lookups. That fits
the facet-degradation design.
**Postfix (tested):** 14 address forms were sent through 5 Postfix
configurations (`experiments/postfix-probe/results/`):
- relay domain with defaults;
- local rewrite context, with and without `swap_bangpath` /
`allow_percent_hack`;
- domain in `mydestination` (local delivery class), with and without those
two settings.
The results:
- **13 of 14 forms arrived byte-identical in every configuration.** That
includes `ticket!callback`, `ticket=ID+comments`, `ticket==X1`,
`ticket=PR%2B42`, `ticket=ID+comments!callback` and `ticket=PR42$4.99`.
`recipient_delimiter = +` does not change the envelope recipient that
`pipe` passes on as `${recipient}`. Upper case is preserved.
- **The quoted local-part `"ticket=PR42"` arrived unquoted** as
`ticket=PR42`. Postfix drops quotes that are not needed (RFC 5321
treats the two forms as equivalent), so a form the spec calls
non-canonical became canonical in transit. **Spec gap:** §4 should say
that a quoted local-part whose content is a valid dot-string is
equivalent to the unquoted form, because an MAS receiver after an MTA
cannot tell them apart.
- **The `!` and `%` legacy rewrites did not trigger** for any MAS address,
even with Postfix defaults and the domain in `mydestination`. In 3.7 the
bang-path swap fired only for a bare `site!user` with no `@domain`
(checked via local `sendmail`: it was rerouted to `site`). MAS addresses
always carry an `@domain`. Setting `swap_bangpath = no` and
`allow_percent_hack = no` is still a sensible hardening default for MAS
hosts.
- `$` passed through SMTP untouched. Rejecting it is purely a MAS parser
decision. The gateway forwarded it as `valid: false`, and the app
ignored it.
**Still untested (MAS-WP-0003):**
- whether senders' providers and web forms accept `!` and `=` in recipient
addresses;
- overlap with SRS (`SRS0=...`) and VERP when forwarding;
- facet stripping by providers.
### Resource addressing: did it improve correlation?
Yes. The service replies *from* `ticket=GS-…@great-service.example`, so an
@ -107,10 +140,10 @@ That is also an injection and spam vector. Ticket ids are non-guessable
(10 Crockford base32 characters), but sender policy belongs to the
application, not to MAS.
## Recommended next step (before the decision gate)
Run the live path: a real domain, the static statute served at
`/.well-known/mas`, Postfix with the `mas-gateway pipe` transport, and test
mail sent from Gmail, Outlook and one corporate gateway to
`ticket!callback@`, `ticket=ID@` and `ticket=ID+comments@`. Record which
addresses arrive unchanged. That evidence answers the open
*Email infrastructure* question.
## Next step (MAS-WP-0003, before the decision gate)
Run the provider half on a real subdomain:
- an MX pointing to a Postfix configured like the probe;
- the statute served at `https://<sub>/.well-known/mas`;
- test mail from Gmail, Outlook and one corporate gateway to
`ticket!callback@`, `ticket=ID@` and `ticket=ID+comments@`, plus replies
to the service's `ticket=ID@` From address.