Operator-auth conformance
index.mjs exports registerOperatorAuthConformance({ test, adapter }).
Read the Markdown source ↗index.mjs exports registerOperatorAuthConformance({ test, adapter }). Import
that function once in a seed's Node test file and pass its existing Node test
registrar plus a test-only adapter for the seed's real Worker. The suite registers
checks for the HTTP contract, the same native session store, the seed's protected
private API, test-captured mail outcomes, and its configured limits. It does not
replace createOperatorAuth, use an in-memory auth fake, or require IdP credentials.
The frozen adapter contract is declared in index.d.mts. Its open method
receives a fresh test-only AuthConfig, one IF-056-shaped mail result, and an
explicit no-mail switch. It returns call for the actual Worker /auth/*
surface, privateRequest for one actual protected consumer API (with optional
test-only request headers for Host-boundary probes), mails for
messages captured by the test-only sender, and close for disposing all runtime
and D1 state. The test runtime must apply the consumer's actual numbered core
schema and use real workerd/D1; keep synthetic mail capture inside the test
adapter. Never expose this adapter or its fixture routes in application builds.
The default presentation remains asset-free. A consumer that intentionally adds
self-hosted fonts sets adapter.confirmationFonts: true. That profile requires
same-origin stylesheet and font-preload links, verifies the exact inline style
hash plus only same-origin style/font permissions, and still rejects external
origins, scripts, images and unsafe inline attributes. Mail stays self-contained.
A consumer that configures branding.productName or a seed theme
(branding.theme, its served rer-theme.css) or an installation mark
(branding.mark, for example /brand/mark.svg) declares the same values as
adapter.branding: { productName, theme, mark }. Mail and confirmation must then
carry that name, and a themed confirmation must hold exactly that one theme
stylesheet link and the CSP style-src 'self' 'sha256-…'; font-src 'self'; img-src 'self'. A declared mark requires exactly that image, with product-name
alt text, 32×32 dimensions and asynchronous decoding beside the text name;
without a theme its CSP adds only img-src 'self'. Every other resource rule
above still applies, and mail stays image-free.
The Base conformance registration is executable at
../tests/conformance.test.ts, and its D1/Worker
adapter lives in this directory's tests/worker.mjs and tests/runtime.mjs.
An adopting seed should map these methods to its actual Hono/Worker dispatcher
and native private API, then import and call the exported registration from its
existing test discovery path. No Base manifest or workflow is changed here.
The registered cases prove:
- first-owner bootstrap with no mail dependency, one owner, a native session, no duplicate owner claim, and no private API access without a session;
- GET and HEAD confirmation previews without cookie issuance, followed by one
POST confirmation to the original safe
returnToand rejection of replay; - neutral branding in magic/invitation previews and both mail parts, exact-byte stylesheet CSP, HEAD parity, single hidden POST token, plain subjects, one confirmation URL per mail part and configured invalid-link recovery;
- owner/admin/member boundaries, session revocation and session invalidation after an operator role change;
- local review issuance and subsequent session/private-API checks reject attacker-controlled Host values even when forwarded-Host headers claim loopback;
- allow-list masking and independent IP/email rate limits before mail effects;
- accepted, rejected and uncertain IF-056 mail results. Only
acceptedmakes the link usable; rejected or uncertain delivery revokes it and returnsmail_unavailable; - optionally, owner-authorized provider sign-in enablement through the public
settings route, then a first verified OIDC admission into an existing unbound owner
through
admitVerifiedIdentity, followed by access through the same native session route. This is a no-provider-key seam check, not an OIDC protocol check. The protocol, keys, PKCE, state, nonce and callback behavior remain covered bymodules/operator-auth/identity/oidc/tests/.
The optional seam is enabled by setting adapter.oidcIssuer to one exact HTTPS
issuer and implementing runtime.admitVerifiedIdentity. It must call the real
trusted core seam with the issuer included in externalIssuers; the conformance
case starts from a fresh owner with no prior external identity binding. It makes
no claim that a changed issuer/subject can bind by matching email. Do not route
request-body identity data to this seam in the application.
The test sender returns only the IF-056 result shape. accepted is API
acceptance, not inbox delivery, and may have a null provider message ID. A real
adopter uses the selected modules/mail/index.mjs createMailSender with its
configured provider; a test sender is never a production path.
Custom branding is additionally checked against real D1 in the module runtime
suite. These shared cases are also consumed by default-seed; no provider sends are
required. Browser responsiveness, keyboard focus and pinned axe-core 4.10.3
audits run in ../tests/presentation-browser.test.mjs at 1440 and 390 pixels,
with light/dark schemes and black/white accents, retaining production CSP.