feat: implement DeleteCurrentUserPAT RPC by AmanGIT07 · Pull Request #1460 · raystack/frontier
Script used to verify tuples for a pat_id:
#!/usr/bin/env python3
"""
Check if any SpiceDB tuples still exist for a given PAT ID.
Usage:
python3 scripts/check_pat_tuples.py <pat-id>
python3 scripts/check_pat_tuples.py 34b04e9e-14ee-4bd6-9175-9787d77c1295
"""
import argparse
import subprocess
import sys
def zed_read(resource: str, relation: str, subject: str, zed_flags: list[str]) -> str:
"""Read relationships from SpiceDB using positional args.
Usage: zed relationship read <resource_type:optional_id> <optional_relation> <optional_subject_type:optional_id>
"""
cmd = ["zed", "relationship", "read", resource]
if relation:
cmd.append(relation)
if subject:
cmd.append(subject)
cmd += zed_flags
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0 and result.stderr.strip():
print(f" zed error: {result.stderr.strip()}")
return result.stdout.strip()
def main():
parser = argparse.ArgumentParser(description="Check SpiceDB tuples for a PAT")
parser.add_argument("pat_id", help="The PAT UUID to check")
parser.add_argument("--endpoint", default="localhost:50051", help="SpiceDB gRPC endpoint")
parser.add_argument("--token", default="frontier", help="SpiceDB preshared key")
args = parser.parse_args()
zed_flags = [
"--endpoint", args.endpoint,
"--token", args.token,
"--insecure",
"--consistency-full",
]
pat_subject = f"app/pat:{args.pat_id}"
found_any = False
# 1. Check rolebinding bearer tuples: app/rolebinding:X#bearer@app/pat:<id>
print(f"\n1. Rolebinding bearer tuples (app/rolebinding where subject = {pat_subject}):")
rels = zed_read("app/rolebinding", "bearer", pat_subject, zed_flags)
if rels:
for line in rels.split("\n"):
if line.strip():
print(f" {line.strip()}")
found_any = True
else:
print(" (none)")
# 2. Check grant tuples on organizations/projects for each rolebinding
rolebinding_ids = []
if rels:
for line in rels.split("\n"):
# format: app/rolebinding:<id> bearer app/pat:<pat_id>
stripped = line.strip()
if stripped and "app/rolebinding:" in stripped:
rb_id = stripped.split()[0].replace("app/rolebinding:", "")
rolebinding_ids.append(rb_id)
if rolebinding_ids:
print(f"\n2. Grant tuples for rolebindings ({len(rolebinding_ids)} found):")
for rb_id in rolebinding_ids:
rb_subject = f"app/rolebinding:{rb_id}"
# Check org grants (granted and pat_granted relations)
for relation in ["granted", "pat_granted"]:
org_rels = zed_read("app/organization", relation, rb_subject, zed_flags)
if org_rels:
for line in org_rels.split("\n"):
if line.strip():
print(f" {line.strip()}")
found_any = True
# Check project grants
proj_rels = zed_read("app/project", "granted", rb_subject, zed_flags)
if proj_rels:
for line in proj_rels.split("\n"):
if line.strip():
print(f" {line.strip()}")
found_any = True
else:
print(f"\n2. Grant tuples: (skipped, no rolebindings found)")
# 3. Check role tuples: app/rolebinding:X#role@app/role:Y
if rolebinding_ids:
print(f"\n3. Role tuples for rolebindings:")
for rb_id in rolebinding_ids:
role_rels = zed_read(f"app/rolebinding:{rb_id}", "", "", zed_flags)
if role_rels:
for line in role_rels.split("\n"):
if line.strip():
print(f" {line.strip()}")
found_any = True
else:
print(f"\n3. Role tuples: (skipped, no rolebindings found)")
# Summary
print(f"\n{'=' * 60}")
if found_any:
print(f"RESULT: Tuples STILL EXIST for PAT {args.pat_id}")
sys.exit(1)
else:
print(f"RESULT: No tuples found for PAT {args.pat_id} - deletion successful")
if __name__ == "__main__":
main()