Fold the approving review: the tree diagram, the CSP test, the mailer
Approved by Fable at round seven. Three follow-ups folded in rather than left for the executor to trip over. The File Structure still put rpid_test.go under internal/guardstest while Task 7 puts it in internal/home, with the reason — it reads the app's own config through a helper over the unexported App, which a guards-package test cannot reach. The CSP test would not have compiled: defaultCSP is unexported in serve.go. It asserts Options.CSP stays empty and the served header carries no unsafe-inline, which is the same property from the outside — and notes that rastrillo's default already delivers §11's script-src self through default-src self, so there is nothing to override. And mail.Sender and signin.Mailer have identical method sets, so the capturing test sender plugs into Flow.Mailer with no adapter.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 file changed,
+14
−2
docs/superpowers/plans/2026-09-03-home-signin.md+14 −2
CI passed — run details
diff --git a/docs/superpowers/plans/2026-09-03-home-signin.md b/docs/superpowers/plans/2026-09-03-home-signin.md| index aca9eb0..3cc10c1 100644 |
| --- a/docs/superpowers/plans/2026-09-03-home-signin.md |
| +++ b/docs/superpowers/plans/2026-09-03-home-signin.md |
| @@ -204,10 +204,13 @@ internal/home/ |
| templates/ Scriptless screens, attribute spelling |
| (ruling 20; the seven utilities keep class). |
| logtest/ Gate 9. Already on main (9162ee5). |
| + rpid_test.go Rulings 13/16: the RP ID is the full host. |
| + Package home, not guardstest: it reads |
| + the app's own passkey.Config. |
| + noscript_test.go §11 + ruling 21's allowlist. |
| internal/guardstest/ |
| logsinks_test.go Already landed. Forbids non-slog sinks. |
| noaddress_test.go Gate 2's schema half. |
| - rpid_test.go Rulings 13/16: the RP ID is the full host. |
| ``` |
| --- |
| @@ -869,7 +872,9 @@ lost or would have had to write: |
| Configuration: `Origin: "https://id.oficina.works"`, `LinkPath: |
| "/signin/verify"`, a non-zero `Key` from config (it seals the pending blob |
| and **must not** come from an instance data key — sign-in runs before any |
| -session exists), `Mailer`, `Classifier`, and `Keymail` **with |
| +session exists), `Mailer` (rastrillo's `mail.Sender` and `signin.Mailer` have identical |
| +method sets, so the capturing test sender plugs straight in with no |
| +adapter), `Classifier`, and `Keymail` **with |
| `RedirectPath: "/signin/callback"`** — its default is `/auth/callback`, so |
| mounting the route without setting this leaves the two disagreeing. |
| @@ -1334,6 +1339,13 @@ func TestNoScriptTagOutsideTheAllowlist(t *testing.T) { |
| } |
| // The carve-out must not widen into unsafe-inline behind our backs. |
| +// |
| +// Do NOT reference rastrillo's defaultCSP — it is an unexported const in |
| +// serve.go. Assert that the app leaves Options.CSP empty and that the |
| +// SERVED header's default-src and script-src carry no 'unsafe-inline'. |
| +// (§11 says the credential origin moves to script-src 'self'; rastrillo's |
| +// default already delivers that via default-src 'self', so there is |
| +// nothing to override — which is the point of asserting it stays empty.) |
| func TestServedCSPIsRastrillosDefault(t *testing.T) |
| // And the one screen that carries script must still work without it: |