Forgejo's secret now lives at platform/workloads/keycape/forgejo, as derived by
oidc-browser-relying-party 1.0 (net-kingdom 074b3a0). KEY-WP-0039 answers
railiance-platform's CCR-2026-0038 question with one-mismatch probe registrations
instead of an issuer path that could mint arbitrary claims.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 779409@bnt-lap001
Assistant-Session: c658ca06-19b5-468d-be64-2985dc20bfd3
Remove the draft key-cape.oidc-client-registration declaration; net-kingdom
declares net-kingdom.keycape-client-registration beside the live deployment
machinery.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
No hand-built rollout; depends on net-kingdom NK-WP-0048-T06.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
Updated by fix-consistency on 2026-10-08:
- workplan status: ready → active
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
Non-secret claim contract for founder acceptance and railiance-apps agreement.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 132360@bnt-lap001
Assistant-Session: 769b1afd-4330-4c86-96b2-e510e26db42b
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 132360@bnt-lap001
Assistant-Session: 769b1afd-4330-4c86-96b2-e510e26db42b
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 132360@bnt-lap001
Assistant-Session: 769b1afd-4330-4c86-96b2-e510e26db42b
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 132360@bnt-lap001
Assistant-Session: 769b1afd-4330-4c86-96b2-e510e26db42b
The founder resolved 632a8893 as the custody boundary only. T02 is done.
T03 waits on the still-open live registration decision caafe4be.
Assistant: grok
Assistant-Session: 01a10938-ab49-7280-877a-c06f64c06ddd
setPublicOriginHeaders (key-cape@3b0446e) annotated only the token
exchange with X-Forwarded-Proto/Host so Authelia can derive the public
issuer in a split-horizon deployment. idTokenVerifier's separate
provider-metadata/JWKS fetch never got the same treatment, so an
in-cluster discovery request reached Authelia unmarked and Authelia
4.38 failed closed on it ("invalid X-Forwarded-Proto header value
'http'"), breaking every login regardless of client.
Extracted setPublicOriginHeaders to a package-level function and gave
idTokenVerifier the same resolved public base URL so its discovery/JWKS
requests carry the same headers as the token exchange.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 169987@bnt-lap001
Assistant-Session: 322ef1ef-9048-4021-8570-b6d6f6347999
completeAuthorization reused an existing kc_login session's IssuedAt as
authTime whenever one existed for the same user, even at the two call
sites that had just validated an MFA token in this exact request. A
platform-root sign-in that stepped up with fresh MFA while an older
browser session cookie was still around got that older timestamp
stamped onto the new authentication, understating freshness for every
downstream binding-grade check (flex-auth's 900s review window denied
informed-decision's infd-20260927-b01 approval as a result).
Add a freshMFA parameter so only the carried-forward-assurance call
site (no MFA challenge in this request) reuses the prior session's
IssuedAt; the two call sites following a successful
MFA.ValidateMFAToken always stamp authTime to now.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 169987@bnt-lap001
Assistant-Session: 322ef1ef-9048-4021-8570-b6d6f6347999
Authelia 4.38 refuses prompt=login for every real login because it registers
the authorization request after authentication. Send a bounded max_age
upstream and check the verified upstream auth_time against prompt=login /
max_age in the callback, failing closed when auth_time is missing.
Also update the service-client example count left stale by 651625c/1620ce2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 352750@bnt-lap001
Assistant-Session: de41ef1c-2113-4dd2-9b92-f318ffa7f98b
Set flavor on open workplans from origin/prose/status. Copy existing
depends_on aliases only. Do not promote residuals.
Assistant: grok
Assistant-Session: 01a09dc1-b21e-77e1-919e-fcad2f82b267
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
KEY-WP-0014-T04 sat `wait` with nothing outstanding, which is a contradiction.
Its title is admit rotation and verify consumer handoff, and both are delivered:
the semantics are published, the executor, authority and transport are named, the
CCR will be prepared on request, and step 4 shipped as keycape verify-client;
ops-warden took option (a) for the reason given, with both lanes owner-confirmed
and no route changed. Executing a rotation was never its deliverable, so treating
the owner's deferral as an open item would have kept the task open against work
it was not scoped to do. The deferral stands separately, revisited on evidence.
GH-DEC-2026-016 §5 applies A-16 to what makes a principal human. Verified against
source that `human` has exactly one route here -- a literal on the
authorization-code path after an upstream login resolved to a directory user,
with no configuration able to assert it -- so A-16 does not yet bite and no
provenance claim is warranted. Adding one would encode a distinction that does
not exist.
Asserting the behaviour would not protect that: a test checking a human token
says human passes just as happily when the value starts coming from a
registration. The guard parses the package and requires every principal_type
assignment to be a string literal, the set being exactly human and service. It
covers both shapes -- the browser path assigns into a map, the service path uses
a key-value pair in a map literal -- and checking only assignments found one of
two routes and passed, which the pinned literal set caught. Verified by mutation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
informed-decision submitted client_id informed-decision-approver and redirect
https://decisions.coulomb.social/auth/callback, with the origin already live and
verified by them rather than reported: both / and /auth/callback return 200 on a
Let's Encrypt certificate valid to 2026-12-09. The host is decisions, not the
decide of an earlier draft. Its path serves a placeholder for now, which does not
matter -- the redirect is matched as an exact string and never fetched.
Published as a public authorization_code client with S256 PKCE, audience
approval-engine, scopes openid/approval:read/approval:approve, mfaRequired true
and a declared tenant:platform. No secretRef, since PKCE is the whole proof.
TestApproverRegistrationShapeIsExact pins every field, so widening a scope or
relaxing MFA fails the build rather than reading as an edit, and asserts the
registration passes startup validation -- proving the KEY-WP-0028 tenant
exemption holds for the registration that actually depends on it.
Two existing guards fired on the way in and neither was loosened. The tenant pin
refused an unreviewed client carrying a tenant, which is its purpose, so the
approver was added to its reviewed set deliberately. And the audience test
panicked slicing secretRef[4:], an assumption that held while the fixture had
only confidential clients; the approver is the first public one, so the loop now
guards on the env: prefix.
The declared tenant reaches the token by the GH-DEC-2026-013 gap route by
construction, and tenant_source says so: registration, never directory.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
The repository owner declined to schedule the rotation now. Recorded with the
reasoning rather than as a bare status so it is revisited on evidence instead of
re-litigated: nothing indicates compromise, the offer stands open, and one
founder-attended window is already pending for the fail-closed startup changes.
Names what should reopen it -- an actual or suspected exposure, the secret's age
becoming a stated concern, a consumer requiring proof of rotation, or a decision
to prove rotation step 4 before relying on it -- and says plainly that a calendar
date is not one of them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016uV8zoCKpA1WRAxsKRYbdH
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1182213@bnt-lap001
Assistant-Session: 966597b9-ae61-46a4-8b9e-1594ab3ec4ad
The Qonto rotation blocker is narrowed from an open question to a schedulable
act: railiance-platform named the executor, transport and authority, and will
prepare the CCR if KeyCape asks. Not asked -- requesting a production credential
rotation with a restart window is the operator's decision, so it was put to him.
Established first that this rotation has no incident driver. The 2026-08-23
exposure covered credentials embedded in config.yaml and the signing key; the
rapp-qonto secret is an env: secretRef in a separate Secret and was not in that
payload. Lifecycle hygiene, not remediation -- which changes what a reasonable
window looks like, and means nobody should be carrying it as leftover incident
work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6