Skip to content

Commit f1c5bb1

Browse files
committed
Round 14 fixes: align revoke key form with create path, wildcard short-circuit
- _retained_keys_for_rule emits bare resource names (matching the create path's _all_resources_from_rules), not the permission-file 'resource/resourceName::foo' form. The perms configmap stores bare names from create; the old form meant revoke's touched_keys/retained_keys computed against a key space the configmap never used, so 'dropped' was always empty for resourceName-qualified grants and the configmap never reflected the revoke. - Remove _permission_keys helper — no remaining callers after the above simplification. - If retained_keys contains '*', short-circuit the configmap filter to preserve every current resource. A surviving rule with resources:['*'] grants everything the configmap lists, so nothing should be dropped even when specific revokes touched it. - Update the 2 unit tests that asserted the old qualified-key form.
1 parent 7d5a611 commit f1c5bb1

2 files changed

Lines changed: 18 additions & 20 deletions

File tree

provider-kubeconfig.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -210,20 +210,19 @@ def _strip_verbs(self, existing_verbs, revoke_verbs):
210210
remaining = [v for v in existing_list if v not in revoke_set]
211211
return remaining or None
212212

213-
def _permission_keys(self, resource, resource_names):
214-
"""Permission-file key form used by _parse_permission_rules / the perms configmap."""
215-
if resource_names:
216-
return [resource + RESOURCE_NAME_SEP + rn for rn in resource_names]
217-
return [resource]
218-
219213
def _retained_keys_for_rule(self, rule):
220-
"""All permission-file keys covered by an (unmodified) k8s rule."""
214+
"""Resource keys covered by a rule, in the form stored in the perms configmap.
215+
216+
The create path's _all_resources_from_rules writes bare resource names, so
217+
revoke must emit the same form to diff against current_resources. URL and
218+
resourceName granularity is intentionally dropped here — the configmap
219+
doesn't carry it.
220+
"""
221221
keys = []
222222
for url in rule.get("nonResourceURLs") or []:
223223
keys.append(NON_RESOURCE_URL_PREFIX + url)
224-
resource_names = rule.get("resourceNames") or []
225224
for res in rule.get("resources") or []:
226-
keys.extend(self._permission_keys(res, resource_names))
225+
keys.append(res)
227226
return keys
228227

229228
def _dim_matches(self, revoke_dim, existing_dim):
@@ -841,8 +840,12 @@ def _revoke_rbac(self, permissionfile, sa, namespace, kubeconfig):
841840
self._kubectl_or_raise("delete clusterrolebinding " + rolebinding_name, kubeconfig)
842841

843842
current_resources = self._read_perm_configmap_resources(sa, namespace, kubeconfig)
844-
dropped = touched_keys - retained_keys
845-
remaining_resources = [res for res in current_resources if res not in dropped]
843+
if "*" in retained_keys:
844+
# A surviving '*' rule grants everything the configmap still lists.
845+
remaining_resources = list(current_resources)
846+
else:
847+
dropped = touched_keys - retained_keys
848+
remaining_resources = [res for res in current_resources if res not in dropped]
846849
self._write_perm_configmap_resources(sa, namespace, kubeconfig, remaining_resources)
847850
return True
848851

@@ -945,10 +948,7 @@ def _split_rule_after_revoke(self, rule, matched_revoke_rules, retained_keys):
945948
updated.pop("resourceNames", None)
946949
updated["verbs"] = list(verbs_key)
947950
out_rules.append(updated)
948-
group_names = names if has_names else []
949-
for res in ress:
950-
for key in self._permission_keys(res, group_names):
951-
retained_keys.add(key)
951+
retained_keys.update(ress)
952952
else:
953953
for (ag, res, rn) in cells:
954954
updated = dict(rule)
@@ -960,9 +960,7 @@ def _split_rule_after_revoke(self, rule, matched_revoke_rules, retained_keys):
960960
updated.pop("resourceNames", None)
961961
updated["verbs"] = list(verbs_key)
962962
out_rules.append(updated)
963-
cell_names = [rn] if rn is not None else []
964-
for key in self._permission_keys(res, cell_names):
965-
retained_keys.add(key)
963+
retained_keys.add(res)
966964
return out_rules
967965

968966
def _atomic_rule_after_revoke(self, rule, matched_revoke_rules, retained_keys):

tests/test_provider_kubeconfig.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def test_split_rule_resourcename_qualified_partial_revoke(self):
198198
result = self.generator._split_rule_after_revoke(rule, matched, retained)
199199
self.assertEqual(len(result), 1)
200200
self.assertEqual(sorted(result[0]["verbs"]), ["get"])
201-
self.assertIn("configmaps/resourceName::foo", retained)
201+
self.assertIn("configmaps", retained)
202202

203203
def test_split_rule_nonresource_urls_partial_revoke(self):
204204
rule = {"nonResourceURLs": ["/metrics", "/healthz"], "verbs": ["get"]}
@@ -269,7 +269,7 @@ def test_split_rule_partial_resourcename_revoke(self):
269269
self.assertEqual(by_name[("b",)], ["delete", "get"])
270270
self.assertEqual(
271271
retained,
272-
{"configmaps/resourceName::a", "configmaps/resourceName::b"},
272+
{"configmaps"},
273273
)
274274

275275
def test_split_rule_non_rectangular_emits_per_cell(self):

0 commit comments

Comments
 (0)