diff --git a/.derived/codebase-index/by-package/stagecraft-ing.json b/.derived/codebase-index/by-package/statecrafting.json similarity index 60% rename from .derived/codebase-index/by-package/stagecraft-ing.json rename to .derived/codebase-index/by-package/statecrafting.json index b5a5fed..484e467 100644 --- a/.derived/codebase-index/by-package/stagecraft-ing.json +++ b/.derived/codebase-index/by-package/statecrafting.json @@ -5,5 +5,5 @@ "path": "" }, "schemaVersion": "1.1.0", - "shardHash": "332c69f0508aa2a0fad69e29fff540bb2ba48a94b8518069eb9f0d11a2b69b91" + "shardHash": "930b8ea0e110a3959b85f101d4069c4eef4e31ac207b7da134fe77efbe78ca01" } diff --git a/.derived/codebase-index/by-spec/001-site-scaffold.json b/.derived/codebase-index/by-spec/001-site-scaffold.json index 4e3f292..8d72209 100644 --- a/.derived/codebase-index/by-spec/001-site-scaffold.json +++ b/.derived/codebase-index/by-spec/001-site-scaffold.json @@ -130,5 +130,5 @@ "specStatus": "approved" }, "schemaVersion": "1.1.0", - "shardHash": "56b49c1558488eab3f5cb972d30096fed9b7246bc09971f4166dbad291128d44" + "shardHash": "0d3f141aebbbbe2531bcc4a6a71d06cafa697a7fe1dedc96be92e08d4cc1ce59" } diff --git a/.derived/codebase-index/by-spec/002-launch-content.json b/.derived/codebase-index/by-spec/002-launch-content.json index 03f6031..5be4db2 100644 --- a/.derived/codebase-index/by-spec/002-launch-content.json +++ b/.derived/codebase-index/by-spec/002-launch-content.json @@ -96,5 +96,5 @@ "specStatus": "approved" }, "schemaVersion": "1.1.0", - "shardHash": "700b2e8542253ba588ef946dd09af0f469841b2cdc3d8c9740bf9aa322c37735" + "shardHash": "09741cfe5707b14d4d2d66d714076b665963f7da01a24eb7fc6383367a9380cd" } diff --git a/.derived/codebase-index/by-spec/003-product-family-registry.json b/.derived/codebase-index/by-spec/003-product-family-registry.json index d8c1b8b..04ca924 100644 --- a/.derived/codebase-index/by-spec/003-product-family-registry.json +++ b/.derived/codebase-index/by-spec/003-product-family-registry.json @@ -29,5 +29,5 @@ "specStatus": "approved" }, "schemaVersion": "1.1.0", - "shardHash": "f67213b8d876fc39de9b8310b56754fb24fab04c30d445f95b862af2427c619e" + "shardHash": "433eb99012f76eda5b5940890a1cf35a223c0b32acaee0446d074f251cb555fa" } diff --git a/.derived/codebase-index/by-spec/004-marketing-surfaces.json b/.derived/codebase-index/by-spec/004-marketing-surfaces.json index bf1eb1c..36acbc4 100644 --- a/.derived/codebase-index/by-spec/004-marketing-surfaces.json +++ b/.derived/codebase-index/by-spec/004-marketing-surfaces.json @@ -285,5 +285,5 @@ "specStatus": "approved" }, "schemaVersion": "1.1.0", - "shardHash": "17cae3aae14beeeda1c9cc036ee10a1fa5f8bb808278529665a3ab98182a78be" + "shardHash": "54603e584b25d89162b0994334e673457fe637edb4b9416a18368c708f219ff2" } diff --git a/.derived/spec-registry/by-spec/001-site-scaffold.json b/.derived/spec-registry/by-spec/001-site-scaffold.json index 4b3e418..90870a2 100644 --- a/.derived/spec-registry/by-spec/001-site-scaffold.json +++ b/.derived/spec-registry/by-spec/001-site-scaffold.json @@ -50,6 +50,6 @@ "summary": "The marketing and docs site, built as a fully static React Router v7 app (framework mode, prerendered, no SSR at runtime) deployed to GitHub Pages under statecraft.ing. Amended 2026-07-14: React Router v7 replaces the earlier Astro choice, harvesting the OAP-era statecraft web app (ecosystem content, the spec-registry viewer) and keeping the whole product family on one frontend stack. The registry viewer runs over build-time-baked shards from the public repos, so the site stays static and every claim stays checkable. The apex DNS cutover is authorized: the legacy control plane no longer owns the domain.\n", "title": "statecraft.ing: React Router v7 static site, Pages deploy, apex cutover" }, - "shardHash": "b49f22920be2a1d5873fe38da81d44466129e9422159399541c6f41c3dc4e69f", + "shardHash": "682dd850ced9322c7a546df654d56d1e90c5bb2fe92cc6468d41bc96a09ae88a", "specVersion": "1.1.0" } diff --git a/.derived/spec-registry/by-spec/002-launch-content.json b/.derived/spec-registry/by-spec/002-launch-content.json index dfa3bd5..1df842c 100644 --- a/.derived/spec-registry/by-spec/002-launch-content.json +++ b/.derived/spec-registry/by-spec/002-launch-content.json @@ -43,6 +43,6 @@ "summary": "The words on the site at launch. One index page that states what Statecraft is in the builder's own register (creator-led, OSS-credible, no startup theater), a product-family section presenting the roster owned by spec 003, and an honest status section tied to the public milestone ladder. The positioning facts are inlined here so the implementing session needs no external archive.\n", "title": "Launch content: positioning, product family, honest status" }, - "shardHash": "69cf21c7547a8181c8c517b14673b7776e8e5379a8075a849ea9165a370a9bff", + "shardHash": "74fc364be034aa600e430f16f3c552efdc71ea595728b913b156ff453b6450b4", "specVersion": "1.1.0" } diff --git a/.derived/spec-registry/by-spec/003-product-family-registry.json b/.derived/spec-registry/by-spec/003-product-family-registry.json index 0f0a4d7..ac02948 100644 --- a/.derived/spec-registry/by-spec/003-product-family-registry.json +++ b/.derived/spec-registry/by-spec/003-product-family-registry.json @@ -30,6 +30,6 @@ "summary": "The canonical registry of the Statecraft product family: each repo's name, role, SPDX license, and URL, encoded once in app/lib/product-family.ts and consumed by the index family section, the footer, and the /registry viewer's repoMeta lookup. This spec gives that module a single explicit owner so a roster change (a repo added, removed, or re-described) is an ordinary authoring edit here plus the module, with no coupling waiver and no edit to the scaffold (001) or launch-content (002) specs. It owns the roster data, not the rendering.\n", "title": "Product-family registry: a single owner for the shared repo list" }, - "shardHash": "cb8d0cd1171faee3ce246ccacab44f0ecdceca15d9c52d962ca22250e0e51cb8", + "shardHash": "69d16df0efddc33e2ef09a97626c9662efa2a8be3f0c4b5a092b21649239526a", "specVersion": "1.1.0" } diff --git a/.derived/spec-registry/by-spec/004-marketing-surfaces.json b/.derived/spec-registry/by-spec/004-marketing-surfaces.json index 01b7404..2c5828b 100644 --- a/.derived/spec-registry/by-spec/004-marketing-surfaces.json +++ b/.derived/spec-registry/by-spec/004-marketing-surfaces.json @@ -102,9 +102,9 @@ ], "specPath": "specs/004-marketing-surfaces/spec.md", "status": "approved", - "summary": "Restores the richer marketing experience the OAP-era statecraft web app carried, ported onto the static apex: a products/architecture page, a papers index with a full whitepaper reader (sticky TOC, reading-progress, scroll-spy, inline references) and an interactive clickable-SVG architecture explorer, and a get-started walkthrough. It expands the site chrome (Products, Papers, Get Started in the nav) and adds a sign-in link that hands off to the control plane's Rauthy OIDC flow at app.statecraft.ing/auth/rauthy. All content is re-authored to be truthful and checkable against the current public repos (no fabricated hashes, spec counts, signatures, or dead subsystems): the OAP name becomes Statecraft, and factory-encore / template-encore become enrahitu. The site stays fully static and prerendered, with zero runtime off-origin requests; sign-in is a plain outbound link, not an auth flow this site runs.\n", + "summary": "Restores the richer marketing experience the OAP-era statecraft web app carried, ported onto the static apex: a products/architecture page, a papers index with a full whitepaper reader (sticky TOC, reading-progress, scroll-spy, inline references) and an interactive clickable-SVG architecture explorer, and a get-started walkthrough. It expands the site chrome (Products, Papers, Get Started in the nav) and adds a sign-in link that hands off to the control plane's login initiator at app.statecraft.ing/api/v1/auth/login. All content is re-authored to be truthful and checkable against the current public repos (no fabricated hashes, spec counts, signatures, or dead subsystems): the OAP name becomes Statecraft, and factory-encore / template-encore become enrahitu. The site stays fully static and prerendered, with zero runtime off-origin requests; sign-in is a plain outbound link, not an auth flow this site runs.\n", "title": "Rich marketing surfaces: products, whitepaper, get-started, sign-in" }, - "shardHash": "3448aef607e5b5bf973fa2570dc2717d151c9b47d4a6d751b8a187f90da808c2", + "shardHash": "d9657ee52f8b1c641079278a7eb2921e121a080d584da65e18685bb9fd2725ce", "specVersion": "1.1.0" } diff --git a/app/components/sign-in-link.tsx b/app/components/sign-in-link.tsx index 0d03cc0..16026f0 100644 --- a/app/components/sign-in-link.tsx +++ b/app/components/sign-in-link.tsx @@ -1,11 +1,15 @@ import type { ReactNode } from "react"; // Sign-in hand-off (spec 004 section 3.2). The static apex runs no auth flow: -// it links out to the control plane's Rauthy OIDC kickoff at the same -// /auth/rauthy path the app used before the apex cutover, now on the app host. +// it links out to the control plane's driver-agnostic login initiator, which +// 302s to the active auth driver's OIDC kickoff (rauthy today). The bare +// `/auth/rauthy` path this used before is the rauthy proxy passthrough, not a +// login route, and a top-level navigation to it is refused by rauthy's CSRF +// guard with "cross-origin request forbidden"; `/api/v1/auth/login` is the +// route the app's own sign-in button uses and it allows cross-site navigation. // A plain absolute URL so it renders identically in prerendered HTML with no // client JavaScript, and so middle-click / cmd-click behave. -export const SIGN_IN_URL = "https://app.statecraft.ing/auth/rauthy"; +export const SIGN_IN_URL = "https://app.statecraft.ing/api/v1/auth/login"; export function SignInLink({ className, diff --git a/specs/004-marketing-surfaces/spec.md b/specs/004-marketing-surfaces/spec.md index 0b74097..2e7b95d 100644 --- a/specs/004-marketing-surfaces/spec.md +++ b/specs/004-marketing-surfaces/spec.md @@ -35,8 +35,8 @@ summary: > scroll-spy, inline references) and an interactive clickable-SVG architecture explorer, and a get-started walkthrough. It expands the site chrome (Products, Papers, Get Started in the nav) and adds a sign-in link - that hands off to the control plane's Rauthy OIDC flow at - app.statecraft.ing/auth/rauthy. All content is re-authored to be truthful + that hands off to the control plane's login initiator at + app.statecraft.ing/api/v1/auth/login. All content is re-authored to be truthful and checkable against the current public repos (no fabricated hashes, spec counts, signatures, or dead subsystems): the OAP name becomes Statecraft, and factory-encore / template-encore become enrahitu. The @@ -103,15 +103,25 @@ the header (and the mobile drawer), rendered by `sign-in-link.tsx`. ### 3.2 Sign-in -Sign-in is an outbound link to `https://app.statecraft.ing/auth/rauthy`: -the same `/auth/rauthy` OIDC kickoff path the app used before the apex -cutover, now on the control-plane host (the static apex no longer serves -it). This site runs no auth flow, sets no cookie, and reads no session; it -hands off to the control plane, which owns identity (Rauthy is the live -OIDC signer). The link is a plain absolute URL so it works identically in -prerendered HTML with no client JavaScript. If the control plane is not -deployed at that host yet, the link simply leads to the plane's own -status; this site makes no claim that sign-in succeeds. +Sign-in is an outbound link to `https://app.statecraft.ing/api/v1/auth/login`, +the control plane's driver-agnostic login initiator: it 302s to the active +auth driver's OIDC kickoff (rauthy today), so this link survives a driver +change without an edit here. This site runs no auth flow, sets no cookie, and +reads no session; it hands off to the control plane, which owns identity +(Rauthy is the live OIDC signer). The link is a plain absolute URL so it works +identically in prerendered HTML with no client JavaScript. If the control +plane is not deployed at that host yet, the link simply leads to the plane's +own status; this site makes no claim that sign-in succeeds. + +**Corrected 2026-07-21.** This first pointed at `https://app.statecraft.ing/auth/rauthy`, +described as "the same `/auth/rauthy` OIDC kickoff path the app used before the +apex cutover". That was wrong on the live control plane: `/auth/rauthy` is the +rauthy proxy passthrough, not a login route, and a top-level navigation to it +is refused by rauthy's own CSRF guard with a `BadRequest` / +"cross-origin request forbidden for this resource". The login initiator is +`/api/v1/auth/login`, which is what the app's own sign-in button uses and which +permits cross-site navigation. Verified live: the old path returns the CSRF +refusal, the new one 302s through to `/oidc/authorize`. ### 3.3 Products / architecture (`/products`) @@ -168,7 +178,7 @@ unchanged. and `/get-started` into static HTML; `npm run typecheck` is clean. - The header and mobile nav expose Products, Papers, Get Started, and a Sign in link; the Sign in link resolves to - `https://app.statecraft.ing/auth/rauthy`. + `https://app.statecraft.ing/api/v1/auth/login`. - The whitepaper reader renders the flagship paper with a working TOC, reading-progress, references, and at least one interactive architecture diagram. @@ -205,7 +215,7 @@ Implemented and verified; section 4 holds end to end. inline references, a positioning table, three interactive architecture explorers), and `/get-started` (runs-today vs on-the-ladder, every step linked to its governing spec). Chrome gained Products, Papers, Get Started, - and a Sign in link to `https://app.statecraft.ing/auth/rauthy`. + and a Sign in link to `https://app.statecraft.ing/api/v1/auth/login`. - **Honesty**: content re-authored around the real family; no fabricated hash, signature, spec count, or dead subsystem in any user-facing surface. Maturity is rolled up from the baked registry wherever it is shown (the