Repository navigation
Conversation
A sync that creates a resource and a UserGroup permission on that same resource creates the group, adds its users, reports success, and applies no permission. The symptom appears later and elsewhere, as an API caller being denied a permission the TOML plainly declares. Running the sync a second time applies it, which is what makes it look like a fluke. Cause is ordering. user_groups::run_updates sat under the '// No deps' comment ahead of every resource phase, but a permission target names a resource, so it does have a dependency. get_updates_for_execution, which is where expand_user_group_permissions resolves targets against all_resources_cache, also ran before anything was created. That expansion keeps only the targets it can match, so a permission on a resource this same sync is about to create expands to nothing and is dropped silently. The apply block already documents this class of problem: 'The ordering these are executed does matter, since latter resources may depend on prior synced resources already being updated with the declared state.' Procedure is last with '// Depends on everything'. UserGroups belong there too. Moves the phase after Procedure and recomputes its deltas at that point, because the earlier computation expanded against the pre-sync cache. resource::create refreshes that cache, so the targets resolve by then. The earlier computation is kept solely to feed the existing no-changes early exit. The recompute deliberately does not abort the sync on error. Every resource phase has already been applied by that point, so a '?' there would skip the deploy cache and the sync's own last_sync_ts bookkeeping; the error is logged into the update instead, which matches how run_updates already reports.
A UserGroup permission target is a resource name or a regex over names. A target that matches nothing is dropped by `expand_user_group_permissions` and the sync still reports success, so a permission the TOML declares is never granted and nothing says so. Collect those targets during expansion and report them in the UserGroups log, named by user group and target. An empty target id is reported the same way, since it cannot match either. Reported rather than fatal: a target can match nothing because it names a resource that does not exist, or because a pattern legitimately matches nothing right now, and the sync cannot tell those apart. The report comes from the pass that runs after the resource phases, whose resource cache has been refreshed and so includes resources this sync just created. The no-changes gate consults the earlier pass instead, so a sync whose only finding is a dropped target does not exit "nothing to do" before the report can be written. System targets are excluded: they are not name matched, so a no-match result says nothing about them. The view path discards its list on purpose, since it is recomputed continuously and reporting there would be noise rather than news.
The export and the import disagree about System targets, and the diff resolves that disagreement by deleting data. `convert_user_groups` writes a UserGroup's System permissions into the file untouched, so an export produces TOML that declares them. `expand_user_group_permissions` then drops every System target on the way back in, so the incoming permission list never contains one. `original_permissions` is read from the database with System passed through, and `to_remove` sets every original permission missing from the incoming list to `PermissionLevel::None`. So syncing back a file that Komodo itself exported revokes the group's System permissions. The same asymmetry shows up in the view: `curr` comes from `convert_user_groups` and contains the System permission, the incoming side does not, so the sync displays a permission removal that no edit asked for and that reappears on every refresh until it is applied. Pass System targets through the expansion instead of dropping them. There is nothing to match them against, since a System target names no resource, so pass-through is the whole fix. Scope: this restores round trip fidelity, not access. `get_user_permission_on_target` returns `PermissionLevel::None` for System unconditionally, so a System permission on a group grants nothing today either way. What changes is that the sync stops deleting a permission row a user deliberately created, and stops showing a diff that cannot be settled.
This branch has not been deployed
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.
A sync that creates a resource and a UserGroup permission on that same resource creates the group, adds its users, reports success, and applies no permission. Hit this on a live deployment: a service user was denied
Executeon an Action the TOML grants it, and a second run applied it. Tracing that turned up two more ways the same path loses a permission silently. Three commits, readable one by one; commit 3 is independent of the other two.Commit 1: apply UserGroups after resources, not before
user_groups::run_updatesran in the apply block under// No deps, ahead of every resource phase, anduser_groups::get_updates_for_executionran in the pre-computation block. That is whereexpand_user_group_permissionsresolves each permission target throughMatcheragainstall_resources_cache(), keeping only the targets it can match. A target naming a resource the same sync is about to create expands to nothing and is dropped with no error. The apply block already documents that later phases may depend on earlier ones, andProcedureis last for that reason; a UserGroup permission names a resource, so UserGroups belong there too.The phase moves after
Procedureand recomputes its deltas there, since the pre-computation expanded against the pre-sync cache (resource::createrefreshes it). The early computation is kept only to feed the existing no-changes exit, which is why the TOML is cloned. The recompute does not propagate its error: every resource phase has been applied by then, and a?would add a mid-sync abort that skipsdeploy_from_cacheand thelast_sync_tsbookkeeping. It logs into the update instead, asrun_updatesalready does.Cost: one extra
get_updates_for_executionper sync wheninclude_user_groupsis on (afind_collectover user_groups, one over users, oneListUserTargetPermissionsper group). If you would rather avoid the second pass, the expansion could move insiderun_updates; that is a larger change and I did not want to guess.Interactions checked: with
delete = true,delete_all_permissions_on_resourcepurges a removed resource's rows in the same phase, so the recompute reaches the same end state the old order did by granting then deleting. A failing resource phase still runs the UserGroup phase afterwards, as before. Wildcard targets now expand over resources created by the same sync and no longer emit doomed updates against ones it deleted.Commit 2: report permission targets that match nothing
The remaining case is a target that is not resolvable at all (a typo, a renamed resource, a pattern matching nothing). It was dropped and the sync was green. The expansion now collects each target that expanded to nothing, and
run_updatesprints oneWARNline per unique target into the UserGroups log, naming the group and the target. An empty target id is reported the same way. Reported rather than fatal, because a pattern that legitimately matches nothing right now is supported configuration and the sync cannot tell the two apart.Details worth your attention:
RunSyncno-changes gate, so a sync whose only finding is a dropped target no longer exits "nothing to do" before the report is written. That run now proceeds through the apply block as a no-op and updateslast_sync_ts/last_sync_hash; displayed sync state and the pending-updates alert derive from view-path data and are unaffected. This is the one behavior change beyond the log line.ResourceSyncInfo; say the word if you want it.get_updates_for_executionnow returns a 4-tuple. A struct would read better (precedent inSyncDeltas); I kept the tuple to hold the diff to the bug.Commit 3: stop the sync revoking System permissions it exported itself
convert_user_groupswrites a group's System permissions into the file,expand_user_group_permissionsdrops every System target on the way back in, andto_removesets every original permission missing from the incoming list toPermissionLevel::None. So syncing back a file Komodo itself exported revokes the group's System permissions, and the view shows a permission removal nobody asked for on every refresh. The fix is pass-through: a System target names no resource, so nothing needs expanding.Severity: this restores round-trip fidelity, not access.
get_user_permission_on_targetreturnsNonefor System unconditionally, so the permission grants nothing today either way; what changes is that the sync stops deleting a row a user created and stops rendering an unsettleable diff. The symmetric alternative is to filter System out ofconvert_user_groupsand maketo_removeskip System; I picked pass-through because it is one branch and keeps export and import agreeing.Verification
cargo check -p komodo_coreandcargo check -p komodo_core --testsclean with no new warnings,cargo fmt --checkclean. Reproduced the original failure and the fix against a live Core (a sync creating an Action plus a group grantingExecuteon it: permission missing before, applied after). No test added:bin/corehas no test module and these paths need a database and the resource cache.WARNwithColor::Redfollows the precedent insync/file.rs.