Repository navigation
feat: add patches with per-patch roles, app links and a patches claim - #288
Merged
Merged
Conversation
…d members to a group that holds one
…role import, and add a patch role directory filter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Weave now models patches. Each patch has its own roles and can have linked OAuth apps. Apps read a person's patch roles from a new
patchesclaim. Quilt uses the claim to let a patch lead read the pool and their own patches only (patchworklabsorg/quilt, branchfeature-patch-access).Patches: a new
patchestable (slug, name, description), with admin pages at/admin/patches. The database refuses a slug change (patches_slug_fixedtrigger) and a bad slug (patches_slug_format). The migration creates a patch for each program key inconfig/kyc/knot.yml(ganymedetoday).bin/rails patches:syncand the seeds do the same, and are safe to run again.KnotSettingsnow refuses a program key that is not a valid patch slug.Patch roles, defined per patch: like app roles, each patch has its own role keys (
PatchRole), given to a person or to a manual group (PatchRoleAssignment).patch_leadstays the governance role (locked rules unchanged), and shows aslead. The keyleadis reserved.Who changes what: only a superadmin creates, renames or deletes a role, and gives one. Any admin removes an assignment, so access is quick to take away. A system group (
everyone,staff, ...) cannot hold a patch role. When a group holds a patch role, only a superadmin adds members, by every path (group managers, access requests, admin panel, rake tasks).The
patchesclaim: a new user scopepatches. The claim maps each patch slug to the sorted keys the person holds there, for example{"ganymede": ["lead", "quilt:viewer", "reviewer"]}. It is{}when the person has none. Only an app whose scopes field listspatchesgets it. Every app of a patch gets the same claim, so a role meant for one app takes that app's prefix (quilt:viewer). The directory API sends the same object to apps with the scope.App links: an OAuth app can belong to one patch. Only a superadmin sets the link. Introspection of the app's
client_credentialstokens adds"patch": "<slug>".Moving app roles:
bin/rails patches:import_app_roles APP=<app> PATCH=<slug> PREFIX=<prefix> ACTOR=<superadmin email> [APPLY=1]copies an app's roles and assignments into patch roles. Dry run by default. It refuses an app that is not linked to the patch, reportsconflict,previously removedandinvaliditems, and never touches the app roles.Directory filter:
GET /api/v1/directory/users?patch=<slug>&patch_role=<key>(patch_role=leadfor leads) lists holders, direct or through an active group membership. Only for an app that listspatchesand is linked to that patch (403 without the scope, 404 for another patch or an unknown key).flowchart LR P[(patches)] --> UR[user_roles: patch_lead, scope = slug] P --> R[patch_roles: quilt:viewer, reviewer ...] R --> RA[patch_role_assignments: user or manual group] UR --> PR[PatchRoles] RA --> PR PR --> C["patches claim: {ganymede: [lead, quilt:viewer]}"] C --> Q[Quilt: pool + own patches, read only] A[OAuth app] -- patch_id --> P A --> I["introspection: patch = slug"]Rollout order
Each step is safe to stop after.
main. Then deploy production. Migrations only add tables and a column, and createganymede. Apps that do not ask forpatchessee no change.ganymedepatch. Addpatchesto the scopes of the Quilt and Krater apps. Check thatkrater-reviewersandkrater-adminsare manual groups. If the Quilt app is restricted, give the leads access grants. Check that Adam holdspatch_leadforganymede.bin/rails patches:import_app_roles APP=<krater> PATCH=ganymede PREFIX=krater ACTOR=<superadmin email>, read the plan, then the same withAPPLY=1. After this, only a superadmin adds members to a group that holds a patch role: tell the group managers first.invalid_scope.bun run sync:docsininternal.quilt:viewerroles where needed. A Krater PR drops the app roles from its mapping. Then remove Krater's app roles in Weave.Rollback: Weave migrations only add, so redeploy the old image and keep the tables. Krater and Quilt go back to their previous images; the extra scope on their Weave apps is harmless. The import never changes app roles: to undo it, remove the patch role assignments.
Checks
bundle exec rspec: 2864 examples, 0 failures.bin/rubocop: no offenses.bin/brakeman: 0 warnings.zeitwerk:check: all good.patches, key prefix).Not done
docs/UI.mdasks.active_directory:add_ou_to_groupadds members with noadded_by, so it now fails for a group that holds a patch role. That is on purpose.Related: patchworklabsorg/quilt#63, patchworklabsorg/krater#66, patchworklabsorg/internal-docs#11, patchworklabsorg/infra#98.