From 2b19ed27d29ed8f2a63924fe2b74a3ddc9651c1f Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 8 Nov 2026 22:15:54 +0100 Subject: [PATCH] =?UTF-8?q?Answer=20prose=20round=201:=201=20=F0=9F=94=B4,?= =?UTF-8?q?=204=20=F0=9F=9F=A1=20(0=20misread);=20correct=20the=20older=20?= =?UTF-8?q?changelog=20entries,=20keep=20each=20fact=20in=20one=20home,=20?= =?UTF-8?q?rewrap=20the=20Keto=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 18 ++++++++---------- .../plugins/auth-admin/admin-grants.test.ts | 2 -- .../views/partials/permission-picker.ejs | 2 -- src/auth/keto-client.ts | 4 ++-- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9001d8e..fbe1b75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,18 +16,17 @@ The host's contract version is now 0.5.0, so discovery refuses a plugin whose `a `transactTuples({ delete, insert })` sends both lists to Keto in one `PATCH /admin/relation-tuples`, so all of them apply or none does. A `KetoClient` you build by hand, such as a test stub, must add the -method. The admin example saves a user's or group's permissions through it: a Keto failure now -changes nothing and answers with the error page, instead of a "stopped part-way" report. Its -catalogs lose `admin.grants.partial`. +method. The admin example saves a user's or group's permissions through it, so a Keto failure leaves +every grant as it was and answers with the error page. ### The admin example lists a user's or group's grants that no installed plugin declares, with a Remove A direct grant of a name no installed plugin declares, such as one left by an uninstalled plugin, used to stay invisible and unchangeable, and reinstalling the plugin silently reactivated it. The user and group pages now list these apart from the checkboxes, each with a Remove button (hidden from -a `:read`-only holder). The example's catalogs gain `admin.grants.remove`, `admin.grants.undeclaredHint` -and `admin.grants.undeclaredLegend`, and its routes gain `POST /auth-admin/users/:id/permissions/remove` -and `POST /auth-admin/groups/:name/permissions/remove`. +a `:read`-only holder). The example's catalogs gain `admin.grants.remove`, `admin.grants.removed`, +`admin.grants.undeclaredHint` and `admin.grants.undeclaredLegend`, and its routes gain +`POST /auth-admin/users/:id/permissions/remove` and `POST /auth-admin/groups/:name/permissions/remove`. ### An operator can hide or rename a plugin's profile-menu entry @@ -174,14 +173,13 @@ page's `baseline` field. ### The admin example confirms a permission save and reports a partial one -A save now lands on the page with "Permissions saved." If the permission service fails midway, the -page says the save stopped part-way instead of showing the generic error page. On a user, the -changes that landed still reach the user's live sessions at once when the revocation denylist is on. +A save now lands on the page with "Permissions saved." On a user, a changed grant reaches the user's +live sessions at once when the revocation denylist is on. ### A read-only holder sees View, not Edit, on the admin example's users list A holder of `users:read` without `users:write` gets a "View" row action with an eye icon. The admin -example's catalogs gain `admin.grants.partial`, `admin.grants.saved`, `admin.grants.stale` and +example's catalogs gain `admin.grants.saved`, `admin.grants.stale` and `admin.users.view`, so a translated catalog mounted under `locales/plugins/auth-admin/` must add them. ### Every page carries a smaller icon sprite diff --git a/examples/plugins/auth-admin/admin-grants.test.ts b/examples/plugins/auth-admin/admin-grants.test.ts index 498ca6e..3b213d9 100644 --- a/examples/plugins/auth-admin/admin-grants.test.ts +++ b/examples/plugins/auth-admin/admin-grants.test.ts @@ -126,8 +126,6 @@ test("applyGrants sends the whole change as one Keto transaction, and a failure await assert.rejects(applyGrants(keto(true), userSubject("u1"), diff), /boom/); }); -// grantDiff never touches a held name nobody declares, so the picker lists them apart and offers a -// Remove for each. A reader is told what is held but offered no button. test("buildPermissionPicker lists direct grants no plugin declares, with a remove action only for a writer", () => { const direct = ["zed:read", "users:read", "old:write"]; const picker = buildPermissionPicker({ action: "/auth-admin/users/u1/permissions", declared, direct }); diff --git a/examples/plugins/auth-admin/views/partials/permission-picker.ejs b/examples/plugins/auth-admin/views/partials/permission-picker.ejs index a66fc91..9c7ae01 100644 --- a/examples/plugins/auth-admin/views/partials/permission-picker.ejs +++ b/examples/plugins/auth-admin/views/partials/permission-picker.ejs @@ -9,8 +9,6 @@ Locals: csrfToken, permissions ({ action, baseline, choices, empty, error, field, hint, inheritedNote, legend, notice, pending, readOnly, submit, undeclared }). - `undeclared` lists direct grants of names no plugin declares, outside the form above because grantDiff - never revokes one. Each has its own Remove form, and a reader gets the names without the button. %>

<%= permissions.legend %>

diff --git a/src/auth/keto-client.ts b/src/auth/keto-client.ts index 28420d8..2757d23 100644 --- a/src/auth/keto-client.ts +++ b/src/auth/keto-client.ts @@ -1,7 +1,7 @@ // Keto client: typed `fetch` wrappers over Ory Keto's relation-tuple APIs — // `check` a permission, `listRelations`/`expand` to inspect them (read API), `writeTuple`/ -// `deleteTuple`/`transactTuples` to grant/revoke them (write API). Built-in `fetch` only, no SDK dep (AGENTS.md); -// `fetchImpl`-injectable like the kratos clients. Read/write split onto the two ports config.ts +// `deleteTuple`/`transactTuples` to grant/revoke them (write API). Built-in `fetch` only, no SDK dep +// (AGENTS.md); `fetchImpl`-injectable like the kratos clients. Read/write split onto the two ports config.ts // targets (ketoReadUrl 4466 / ketoWriteUrl 4467). // A subject set: a relation on another object (e.g. Group:eng#members), resolved