fix(provisioning): a Management API consumer's first run is one file, one apply - #237
Merged
Merged
Conversation
… one apply
Reported from the field (amZettel, 2026-09-18) with the standard first manifest of a
Management API consumer: a role on the system app, a service account with a credential,
and a group binding the two — handles throughout. Three things stood in the way, and
none of them was the apply:
1. Service accounts applied AFTER groups, so "#mgmt-sa" in a group's Members was refused
up front as Manifest.HandleAppliedTooLate. A credential only references apps and
scopes, both applied earlier, so the account moves before groups — like users. The
plan already listed the sections in that order; applier and order check now agree.
2. The planner canonicalized and resolved group Members against USERS only. The exporter
writes a service-account member as { Key, Id } like any other, so re-planning an export
announced "Member 'x' — this realm has no such entity" on an unchanged group, and the
id-only spelling of the same member read as an update. Members now resolve against
users, nested groups and service accounts — the three kinds the applier's member
resolver has accepted since the always-staged wave.
3. The planner took its app catalog off the EXPORT, which leaves the system app out on
purpose (seeded, not authored). A role on "modgud" — where oauth-authorization:* and
the other Management API permissions live — was therefore announced as "the apply
SKIPS this role entirely. Import the app first", while the apply created it fine: its
app resolver is seeded from the live query. The plan now reads the realm's apps live,
as the apply does; the same fix covers a client, API or scope pointing at the system
app.
Test: A_management_api_consumer_provisions_role_service_account_and_group_in_one_run —
plan without a manifest error or a phantom note, apply lands role + account + group +
membership in one run, export re-plans as unchanged and note-free, and the id-only member
spelling is the same membership. The field report is the red run on the released build.
Docs: the reference paragraph in realm-provisioning names all three member kinds and the
apply order; the Members field description and the identity check's comment no longer
claim service accounts apply after groups.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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
Reported from the field by a Management API consumer (amZettel) with the standard first manifest: a role on the system app, a service account with a credential, and a group binding the two — handles throughout. Three things stood in the way. None of them was the apply; two were the plan lying and one was the section order.
"#mgmt-sa"in a group'sMembersrefused up front asManifest.HandleAppliedTooLateMember 'x' — this realm has no such entityon an unchanged group; the id-only spelling of the same member read as an updateMembersagainst users only, while the exporter writes a service-account member as{ Key, Id }like any othermodgudannounced asthe apply SKIPS this role entirely. Import the app first— while the apply created it fineThe Management API permissions (
oauth-authorization:*,app-scope:read,position:read, …) live on the system app, so #3 hits every consumer of the surface #236 added.Not changed
resource=on the device-authorization endpoint is rejected withinvalid_targetalthough RFC 8707 §2 allows it there. A separate OAuth item, not the planner.ClientSecret is ignored for an existing clientplan note stays: it is the honest signal that the file carries dead weight.Test plan
A_management_api_consumer_provisions_role_service_account_and_group_in_one_run— plan without a manifest error or a phantom note, apply lands role + account + group + membership in one run, export re-plans as unchanged and note-free, id-only member spelling is the same membership. The field report is the red run on the released build.A_handle_that_cannot_honour_its_promise_is_refused_or_reported) still green — positions still apply after groups.🤖 Generated with Claude Code