Hide the id.* hand-off page while it submits itself
/authorize/resume renders a Continue page that static/assertion.js submits at once, so every sign-in and every app switch that needs an exchange flashed "Continue to Oficina". The copy is now hidden for 1.5 s (estilo-reveal) and appears only if the submit stalls; a noscript rule shows it at once with scripts off. Spec shared-chrome §9.3; the switcher tiles wait on this.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+61
−0
internal/home/handoff_reveal_test.go+47 −0internal/home/templates/assertion.html+14 −0
CI failed — run details
CI log
amadan: .amadan/timeout: this job's budget is 15m0s (this runner allows up to 30m0s) === vet === CGO_ENABLED=0 go vet ./... go: downloading amadan.net/carlos/platform.git/launchctx v0.0.0-20260911135504-fb577f96f7d1 go: downloading amadan.net/oficina/estilo.git v0.0.0-20260911182719-0bcb9287988d internal/home/credits.go:8:2: amadan.net/oficina/estilo.git@v0.0.0-20260911182719-0bcb9287988d: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/bf4984e7a537af013cffcd0a654026b503a4e1566cddf740e3c37d2f6ae937e4: exit status 128: fatal: unable to access 'https://amadan.net/oficina/estilo/': The requested URL returned error: 429 internal/home/app.go:25:2: amadan.net/oficina/estilo.git@v0.0.0-20260911182719-0bcb9287988d: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/bf4984e7a537af013cffcd0a654026b503a4e1566cddf740e3c37d2f6ae937e4: exit status 128: fatal: unable to access 'https://amadan.net/oficina/estilo/': The requested URL returned error: 429 internal/operator/command_linux.go:10:2: amadan.net/carlos/platform.git/launchctx@v0.0.0-20260911135504-fb577f96f7d1: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/55cd75de7b117f7c5cd43edfd800f8d47521af42d6b939d46f385b6d34c14c9a: exit status 128: fatal: unable to access 'https://amadan.net/carlos/platform/': The requested URL returned error: 429 internal/operator/command_linux.go:11:2: amadan.net/carlos/platform.git/launchctx@v0.0.0-20260911135504-fb577f96f7d1: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/55cd75de7b117f7c5cd43edfd800f8d47521af42d6b939d46f385b6d34c14c9a: exit status 128: fatal: unable to access 'https://amadan.net/carlos/platform/': The requested URL returned error: 429 make: *** [Makefile:69: test-vet] Error 1 amadan: step vet failed: exit status 2 amadan: job failed at step vet — its output is above, not at the tail of this log
diff --git a/internal/home/handoff_reveal_test.go b/internal/home/handoff_reveal_test.go| new file mode 100644 |
| index 0000000..28bf21c |
| --- /dev/null |
| +++ b/internal/home/handoff_reveal_test.go |
| @@ -0,0 +1,47 @@ |
| +package home |
| + |
| +import ( |
| + "bytes" |
| + "regexp" |
| + "strings" |
| + "testing" |
| +) |
| + |
| +// TestHandoffInterstitialStaysHiddenWhileItAutoSubmits is spec |
| +// shared-chrome §9.3: the assertion hand-off page submits itself, so its |
| +// fallback copy is hidden for 1.5 s and appears only if the submit |
| +// stalls. Without it every sign-in, and every app switch that needs an |
| +// exchange, flashes "Continue to Oficina" mid-hop. With scripts off |
| +// nothing submits, so a <noscript> rule shows the fallback at once. |
| +func TestHandoffInterstitialStaysHiddenWhileItAutoSubmits(t *testing.T) { |
| + app := newTestApp(t) |
| + var buf bytes.Buffer |
| + if err := app.renderer.pages["assertion.html"].ExecuteTemplate(&buf, "layout", map[string]any{"Action": "https://blue.docs.oficina.works/auth/assertion", "Token": "sample-token"}); err != nil { |
| + t.Fatal(err) |
| + } |
| + page := buf.String() |
| + head, body, ok := strings.Cut(page, "</head>") |
| + if !ok { |
| + t.Fatal("no head") |
| + } |
| + compact := regexp.MustCompile(`\s+`).ReplaceAllString(head, "") |
| + for _, want := range []string{ |
| + "[estilo-handoff]{animation:estilo-reveal0s1.5sboth;}", |
| + "@keyframesestilo-reveal{from{visibility:hidden}to{visibility:visible}}", |
| + "<noscript><style>[estilo-handoff]{animation:none;}</style></noscript>", |
| + } { |
| + if !strings.Contains(compact, want) { |
| + t.Fatalf("head lacks %q:\n%s", want, head) |
| + } |
| + } |
| + // Everything the person could read or press is inside the hidden |
| + // wrapper, and the form the script submits is still the one there. |
| + main := body[strings.Index(body, "<main"):strings.Index(body, "</main>")] |
| + inner := strings.TrimSpace(main[strings.Index(main, ">")+1:]) |
| + if !strings.HasPrefix(inner, "<div estilo-handoff>") || !strings.HasSuffix(inner, "</div>") { |
| + t.Fatalf("content not wrapped:\n%s", main) |
| + } |
| + if !strings.Contains(inner, `data-assertion-handoff`) || !strings.Contains(inner, `<button type="submit" rst-btn="primary">Continue</button>`) { |
| + t.Fatalf("hand-off form changed:\n%s", inner) |
| + } |
| +} |
diff --git a/internal/home/templates/assertion.html b/internal/home/templates/assertion.html| index c70e695..6b1e5e6 100644 |
| --- a/internal/home/templates/assertion.html |
| +++ b/internal/home/templates/assertion.html |
| @@ -1,10 +1,24 @@ |
| {{define "title"}}Continue to Oficina · Oficina{{end}} |
| +{{define "head"}} |
| +{{/* The page submits itself (static/assertion.js), so its fallback copy |
| + stays hidden for 1.5 s and shows only if the submit stalls. With |
| + scripts off nothing submits, so noscript shows it at once. Spec |
| + shared-chrome §9.3; the rule moves to estilo chrome.css when the |
| + id.* pages adopt the shared chrome. */}} |
| +<style> |
| +[estilo-handoff] { animation: estilo-reveal 0s 1.5s both; } |
| +@keyframes estilo-reveal { from { visibility: hidden } to { visibility: visible } } |
| +</style> |
| +<noscript><style>[estilo-handoff] { animation: none; }</style></noscript> |
| +{{end}} |
| {{define "content"}} |
| +<div estilo-handoff> |
| <h1>Continue to Oficina</h1> |
| <p>Select Continue if this page does not move on.</p> |
| <form method="post" action="{{.Action}}" rst-form data-assertion-handoff> |
| <input type="hidden" name="assertion" value="{{.Token}}"> |
| <button type="submit" rst-btn="primary">Continue</button> |
| </form> |
| +</div> |
| {{end}} |
| {{define "scripts"}}<script src="/static/assertion.js" defer></script>{{end}} |