|
|
a20f3507e0
|
§8 review convergence (todo §8); re-ran the architecture + product reviewers to convergence — 5 rounds, until both returned zero new actionable findings. Fixed across rounds 1-4 (tests-first): bounded every outbound Ory fetch with a timeout (src/fetch-timeout.ts withTimeout + ORY_TIMEOUT_SEC default 5, incl. the http JWKS fetch) so a hung Ory can't park a request handler; anonymous on a permission-gated plugin route now 303→/login (was a dead-end 403; signed-in-without-role still 403); an already-signed-in user is sent home from /login + /registration; the onRequest hook short-circuit now sets the fresh CSRF cookie; admin-users malformed :id → 404 (was 500) via safeDecode; parseJwks validates key element shape (fails loud at load); removed the dead COOKIE_SECRET (loaded + enforced + documented but never read); documented HYDRA_ADMIN_URL; admin recovery shows the code + links to the public /recovery instead of the browser-unreachable admin-API link; reference-plugin breadcrumb-label + pagination/datetime README notes; corrected the contract doc to not over-promise a post-login "retry". Declined: unconditional base-ctx chrome (would build the menu per request, regressing the lazy hot path). Deferred → §9: return_to-preservation for deep-link login. Stability-reviewer on the cumulative diff: APPROVE, no Critical/High (addressed its Low nits). typecheck + 310 units + the full scripts/ci.sh gate (visual 9 · auth 1 · oauth 2 · full 6) green.
|
2026-06-20 00:42:23 +02:00 |
|
|
|
bd20d00714
|
§8 review checkpoint (todo §8); ran the architecture + product reviewers on the whole project and addressed findings. Critical (arch): "Testing & CI" shipped no CI automation — added scripts/ci.sh, the whole gate in one command (pin-lockstep check → typecheck → units (count guard) → the 4 E2E suites, each on its own named fresh stack with guaranteed down -v + non-zero exit on first failure). The gate immediately caught a latent bug: the auth-refresh suite booted Hydra (inherited §6 web→hydra dep) but the e2e overlays don't run Hydra with --dev, so it never went healthy — dropped Hydra from the auth suite's web deps (it never needed it). Product 🔴: the README Status note claimed auth/Hydra were unbuilt (false after §4/§6/§8) — corrected it + dropped the now-false _(planned)_ markers on the Auth/MVP sections. Product 🟡: added a login-only "Forgot password?" link (the recovery flow was unreachable from /login) and a data-table empty-state row (blank list tables, recurring deferral) — both tests-first. Docs: README Layout e2e line + e2e/package.json updated for the §8 suites. Stability-reviewer APPROVE-with-nits; addressed both (per-suite compose project names; grep || true) and fixed a project-name dot bug it introduced. Corrected a reviewer error (bootstrap uses restart on-failure:5, not unless-stopped). typecheck + 306 units green; scripts/ci.sh green end-to-end (visual 9 · auth 1 · oauth 2 · full 6), all stacks torn down. Deferred to §9: the app.ts internal route-table (raised urgency), visual-parity for admin/consent screens, a key-rotation E2E; L3 (plugin-api barrel in shifts.test) → the §8 test-cleanup item.
|
2026-06-19 20:08:48 +02:00 |
|
|
|
1c324b18e3
|
Built-in OAuth2 client-registration admin screen (todo §6); /admin/clients lists/registers/deletes the Hydra OAuth2 clients other apps log in through us with. New src/admin-clients.ts (pure builders + handleAdminClients, mirroring the §5 Users/Roles screens): list (search/paginate over one fetched Hydra page), register (GET form + POST), read-only detail, delete-confirm. src/hydra-admin.ts gains the client half of the admin API — createClient/listClients/getClient/deleteClient over /admin/clients (+ a nextPageToken Link parser like kratos-admin) and the registration fields on OAuth2Client. Register builds a standard authorization-code client (+ refresh_token), confidential (client_secret_basic) or public (PKCE/none), with an optional first-party auto-consent flag; Hydra returns the client_secret once, so the register POST renders the new client's detail page with the one-time secret directly (no PRG) and it is never re-shown (getClient carries no secret; the detail test asserts it). Writes go only to Hydra; gated admin-only (anon->/login, non-admin->403) + every mutation CSRF-guarded via requireAdmin/guardedForm like §5; a Hydra 4xx (bad redirect/scope) re-renders the form (400), a 5xx -> 500 (mirrors oauth-login.ts); :id via safeDecode (malformed->404). Wired into app.ts (/admin/clients, gated on the hydra client present) and the shared adminSection (Users.Groups.Roles.OAuth2 clients, i-globe) so it shows for admins and is invisible otherwise. New views (admin/clients, client-form, client-detail + partials/client-{form,detail}-body) reuse the shell/filter-bar/data-table/field blocks; one .detail-list CSS rule; README Layout/§6 updated. Tests-first: hydra-admin.test.ts (client CRUD contracts incl. Link pagination/404->null/204), admin-clients.test.ts (builder/validation/payload matrix), app.test.ts HTTP integration (gate/list/register-shows-secret-once/invalid+CSRF-reject/detail-hides-secret/delete + malformed-%->404). Stability-reviewer run as a local PR: APPROVE, no Critical/High; addressed its one nit (dropped a dead URL.protocol check in validateClientInput). Boot-verified the client CRUD live against real Hydra v26.2.0 (create->201 w/ one-time secret -> list finds it -> get -> delete -> get null); torn down. typecheck + 274 units green.
|
2026-06-19 11:23:27 +02:00 |
|
|
|
a016a0131e
|
Built-in Roles & permissions admin screen (todo §5); /admin/roles list (search/sort/paginate) + create/delete + assign-to-users/groups + "effective access" (Keto expand → transitive members), writing only to Keto — gated admin-only + CSRF-guarded like Users/Groups (Kratos read only to label members). A role = Keto subject set Role:<name>#members; reuses the Groups membership helpers (now-exported pagedTuples/memberCandidates/safeDecode); added a Roles nav entry (i-shield) + a .plain-list CSS rule. Stability-reviewer run as a local PR: APPROVE, no Critical/High; addressed its explicit-expand-depth nit. Live boot-verify caught a real bug the tests missed — Keto v26.2.0 nests the expand subject under tuple (not node top-level as the §4 ExpandTree type guessed), so expandToEffectiveUsers returned []; fixed type+walker+fixtures, re-verified a group-only member surfaces in effective access. 237→243 units + typecheck green; expand chain boot-verified live then torn down.
|
2026-06-18 18:18:18 +02:00 |
|
|
|
32e5e2f7eb
|
Built-in Groups admin screen (todo §5); /admin/groups list (search/sort/paginate) + create/delete + membership (add/remove users & nested groups), writing only to Keto — gated admin-only + CSRF-guarded like Users (Kratos read only to label pickers). A group = Keto subject set Group:<name>#members, exists while it has ≥1 member: create writes the first-member tuple, delete removes all by partial-filter. Extracted shared admin-nav.ts (Dashboard·Users·Groups); new generic rowHeader <th scope=row> data-table cell. Stability-reviewer run as a local PR: symmetric subject UUID-validation, duplicate-name rejection, malformed-%→404. 228→237 units + typecheck green; core Keto interactions boot-verified live
|
2026-06-18 17:40:36 +02:00 |
|
|
|
79cfa2ee7f
|
Built-in Users admin screen (todo §5); /admin/users list (filter/sort/paginate) + create/edit/deactivate/delete + trigger-recovery, writing only to Kratos via the admin client — gated admin-only (anon→/login, non-admin→403) and CSRF-guarded like logout. New kratosAdmin.createRecoveryCode; reserved the "admin" plugin id; views:[viewsDir] so subfolder views reuse partials/. Reviewer §5 opener: extracted shell-context.ts (buildShellContext/shellUser) shared by dashboard+admin, threading the real signed-in user (drops the hardcoded demo profile). 217→228 units + 8 visual E2E green; boot-verified full CRUD+recovery live on the Ory stack
|
2026-06-18 12:26:19 +02:00 |
|
|
|
4b2173cb84
|
Secure cookie flags + CSRF for our own POST forms (todo §4); SECURE_COOKIES toggle on session/CSRF cookies; csrf.ts signed double-submit token + body.ts form reader; logout is now a CSRF-guarded POST form
|
2026-06-18 11:12:32 +02:00 |
|
|
|
0928f9dd39
|
Render Kratos self-service flows as themed pages (todo §4); buildFlowView + views/auth.ejs + login/registration/recovery/verification/settings routes
|
2026-06-17 17:55:56 +02:00 |
|
|
|
ff7b55be4c
|
Wire branding into the app shell (todo §2); render config logo + default theme, fall back to the brand mark
|
2026-06-16 16:07:24 +02:00 |
|
|
|
645a316419
|
Make markup semantic + add semantic DOM principle (todo §1); page <h1>, skip link, row-header <th scope=row>, descriptive error pages
|
2026-06-15 16:53:07 +02:00 |
|
|
|
bddc1f891d
|
Add menu/popover + theme-switch partials (todo §1); data-driven .menu (items/check-groups/positioning), Light/Auto/Dark switch, shell reuses both
|
2026-06-15 13:27:44 +02:00 |
|
|
|
30db8216e6
|
Move foundation CSS into public/css (todo §1); drop placeholder style.css, repoint views + mockups
|
2026-06-15 11:25:43 +02:00 |
|