| M1-43/1 |
2026-10-14 |
Base int/m1-wave13 at 82693e50, branch feat/M1-43-identity-trusted-header in its own worktree; not merged locally and not pushed, the PR lane ports it. Text this ticket adds is English, also in German chapters. |
Instructions of the launcher, which override the brief's merge step and language (as M1-37/1). |
| M1-43/2 |
2026-10-14 |
W4 is resolved as PLAN section 7 and 16 section 4.3 state it: a trusted_header provider without a loopback public listener does not stop the start. The driver stays off (loginWithTrustedHeader answers 404), the readiness check trusted_header_requires_loopback fails while such a provider is enabled, and identity_provider.manage refuses to enable it with 409 conflict, reason: trusted_header_requires_loopback and a hint naming server.listen_addr. platform/config has no start-time cross-check of the driver, so nothing was removed there. |
The driver is a runtime setting of the owner; a mistake in it must fail closed without preventing the start (08 section 2.4 rule 1, ID-T08, SEC-T01). |
| M1-43/3 |
2026-10-14 |
The loopback flag is not a field of app.Config but state of app.TrustedHeaderDriver: internal/wire sets it from trustedheader.IsLoopbackListener of the bound public listener after the listen and registers the readiness check then; tests set it with Identity.SetPublicListenerLoopback. It starts as false (fail closed); the role worker opens no public listener and never registers the check. |
config.Bind refuses an exported field without a key, and the bound address exists only after the listen, which runs after the identity step. |
| M1-43/4 |
2026-10-14 |
kernel/reqmeta.Transport (TCP peer from RemoteAddr, the request header, the route's action) is set by the authenticate stage of platform/httpserver; the header login handler and the per-request binding read it. Two files outside the brief's scope change for this: kernel/reqmeta (new file) and platform/httpserver/stages.go (three lines). |
The generated strict handlers and the actor.Authenticator receive no *http.Request; the brief requires the raw peer and the configured headers in the use case and the binding check in the shared Authenticator. |
| M1-43/5 |
2026-10-14 |
The binding check also runs in refreshToken (inside its unit of work, after the family key matched; the revocation commits like a reuse and the answer is 401 session_revoked). |
The brief says the check covers refreshToken "because the authenticator is shared", but refreshToken is anonymous and never reaches the Authenticator; rule 5 of 08 section 2.4 binds every later request. A proof of another key still never revokes (ID-T17). |
| M1-43/6 |
2026-10-14 |
The binding reads the identity and the provider of a trusted_header session with two queries after the session lookup instead of joining them into GetAuthState. |
Only sessions of this driver with the switch on pay the reads; the shared lookup and its sqlc code stay unchanged. |
| M1-43/7 |
2026-10-14 |
The refusal of enabling the driver is audited as a deny of identity_provider.manage with the new reason trusted_header_requires_loopback, added to the closed list of 07 section 4.1 (row "no authorize result", like malware_detected) and to the reason lists of kernel/auditing and authz/domain. |
The brief asks for an audit deny; a deny needs a reason of the closed list, and none of the existing ones describes the refusal. |
| M1-43/8 |
2026-10-14 |
The handle of a provisioned person follows the rule of brief M1-41 (part of the login before @, lower case, only a-z0-9._-, starting with a letter or digit, cut to principal.handle_max_chars, user when nothing remains; a taken handle gets - and four random Crockford Base32 characters). M1-41 is not merged, so the rule lives in domain/trustedheader (HandleFromLogin, HandleWithSuffix) until both drivers share one helper. |
Brief M1-43 Design notes, step 5. |
| M1-43/9 |
2026-10-14 |
CompleteLogin gains AllowPending (a pending person logs in, 08 section 3.1 item 3 and R-ID-14) and ProviderID (recorded as provider_id in the allow entry). A known identity of a pending person logs in with the header too; disabled and deleted people never do. Several field lines of the login header are absent; a comma inside one value is part of the value. |
Brief M1-43 step 6; 08 section 2.4 rule 6 speaks of several values, which HTTP represents as several field lines. |
| M1-43/10 |
2026-10-14 |
When the binding fails at the Authenticator, the deny entry names the route's action from reqmeta.Transport; a caller without a route (the gateway before M1-64) records auth.login.complete. |
The audit row needs an action code; M1-64 owns the gateway binding and its action. |
| M1-43/11 |
2026-10-14 |
The integration tests of the driver run in five worlds: one each for ID-T08, SEC-T01 and the binding switch off, TestTrustedHeaderLogin (binding on, no provisioning) with the cases ID-T09, ID-T10, the missing header, a disabled person, several values, no mapping and the enrollment code as ordered subtests, and TestTrustedHeaderProvisioning with provisioning and TestTrustedHeaderNeverLogged. The test-first red runs were taken by mutation of the finished code (binding always bound, peer not checked, loopback ignored, missing header accepted), each turning its test red. |
With one world per case the package identity/adapters/httpapi passed the default timeout of go test in make test on the loaded host (as M1-44/13); the code and the tests were written in one step, so the mutations show the tests catch the behaviour. |
| M1-43/12 |
2026-10-15 |
Port onto main: code and tests are taken byte for byte from the integration squash, with LoginCompletion.AllowPending, loginAttrs, ServiceDeps.Random and the refresh order as INT-W14/5 states them (AllowPending itself came with M1-41). Code comments and the chapter key of auth.trusted_header_bind_requests name 08-identity.md; the regenerated config-schema.json carries the key. The language gate (tools/docs/language_check.py) allows the non-ASCII test values Röbin and ÄÖÜ of this ticket and Ünal of M1-41 as words of tools/docs/language-allow.txt. |
The gate reads every tracked file and also decodes escaped umlauts, so these RFC 2047 and handle test vectors failed make docs; one allow list entry per value keeps the vectors unchanged and fixes the class in one place. |