Skip to content

Commit ff11a68

Browse files
committed
Add integration test for JSON/YAML auth can-i equivalence.
Verify update/revoke using matching JSON and YAML permission fixtures produce the same auth can-i transition on an existing service account (deny -> allow -> deny). Made-with: Cursor
1 parent eeff860 commit ff11a68

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

tests/test_provider_kubeconfig.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,18 @@ def _current_cluster_server(self):
288288
out, _ = _run_command(cmd)
289289
return (out or "").strip().strip("'")
290290

291+
def _auth_can_i(self, namespace, sa, verb, resource):
292+
"""Run auth can-i for an impersonated ServiceAccount and return normalized output."""
293+
out, err = _run_command(
294+
"kubectl auth can-i " + verb + " " + resource
295+
+ " -n " + namespace
296+
+ " --as=system:serviceaccount:" + namespace + ":" + sa
297+
+ self.kubeconfig_flag
298+
)
299+
if err and ("unable to connect to the server" in err.lower() or "i/o timeout" in err.lower()):
300+
self.skipTest("Skipping authz assertion due to transient API connectivity issue: " + err.strip())
301+
return (out or "").strip().lower()
302+
291303
def test_provider_kubeconfig_all_fields_nonempty(self):
292304
"""Provider kubeconfig: every field that should exist is non-empty."""
293305
ns = "kubeplus-test-prov-" + uuid.uuid4().hex[:8]
@@ -436,6 +448,74 @@ def test_consumer_can_create_deployment_but_not_pod(self):
436448
_run_command("kubectl delete deployment --all -n " + ns + self.kubeconfig_flag + " 2>/dev/null")
437449
self._delete_for_cleanup(ns, sa=consumer_sa)
438450

451+
def test_update_revoke_json_yaml_have_same_auth_can_i_effect(self):
452+
"""
453+
update/revoke with equivalent JSON and YAML permission files should yield same auth outcome:
454+
baseline deny -> allow after update -> deny after revoke.
455+
"""
456+
ns = "kubeplus-test-uprev-" + uuid.uuid4().hex[:8]
457+
sa = "uprev-sa"
458+
json_file = os.path.join("tests", "permission_files", "permissions-example1.json")
459+
yaml_file = os.path.join("tests", "permission_files", "permissions-example1.yaml")
460+
self.assertTrue(os.path.exists(os.path.join(ROOT, json_file)))
461+
self.assertTrue(os.path.exists(os.path.join(ROOT, yaml_file)))
462+
try:
463+
_run_command("kubectl create ns " + ns + self.kubeconfig_flag)
464+
_run_command("kubectl create sa " + sa + " -n " + ns + self.kubeconfig_flag)
465+
466+
def run_flow(permission_file):
467+
baseline = self._auth_can_i(ns, sa, "create", "secrets")
468+
self.assertIn(baseline, ["yes", "no"])
469+
proc_update = subprocess.run(
470+
[
471+
sys.executable,
472+
os.path.join(ROOT, SCRIPT),
473+
"update",
474+
ns,
475+
"-c",
476+
sa,
477+
"-p",
478+
permission_file,
479+
] + self.kubeconfig_arg,
480+
cwd=ROOT,
481+
capture_output=True,
482+
text=True,
483+
timeout=120,
484+
)
485+
self.assertEqual(proc_update.returncode, 0, proc_update.stderr)
486+
after_update = self._auth_can_i(ns, sa, "create", "secrets")
487+
proc_revoke = subprocess.run(
488+
[
489+
sys.executable,
490+
os.path.join(ROOT, SCRIPT),
491+
"revoke",
492+
ns,
493+
"-c",
494+
sa,
495+
"-p",
496+
permission_file,
497+
] + self.kubeconfig_arg,
498+
cwd=ROOT,
499+
capture_output=True,
500+
text=True,
501+
timeout=120,
502+
)
503+
self.assertEqual(proc_revoke.returncode, 0, proc_revoke.stderr)
504+
after_revoke = self._auth_can_i(ns, sa, "create", "secrets")
505+
return baseline, after_update, after_revoke
506+
507+
json_result = run_flow(json_file)
508+
yaml_result = run_flow(yaml_file)
509+
self.assertEqual(json_result, yaml_result)
510+
self.assertEqual(json_result[1], "yes")
511+
self.assertEqual(json_result[2], "no")
512+
finally:
513+
_run_command("kubectl delete clusterrole " + sa + "-update" + self.kubeconfig_flag + " 2>/dev/null")
514+
_run_command("kubectl delete clusterrolebinding " + sa + "-update" + self.kubeconfig_flag + " 2>/dev/null")
515+
_run_command("kubectl delete configmap " + sa + "-perms -n " + ns + self.kubeconfig_flag + " 2>/dev/null")
516+
_run_command("kubectl delete sa " + sa + " -n " + ns + self.kubeconfig_flag + " 2>/dev/null")
517+
_run_command("kubectl delete namespace " + ns + " --ignore-not-found --wait=false" + self.kubeconfig_flag)
518+
439519

440520
if __name__ == "__main__":
441521
unittest.main()

0 commit comments

Comments
 (0)