Persist destructive/infra footgun hooks in the repo and teach install.sh to sync them without clobbering a local hooks.json unless overwritten.
67 lines
2.5 KiB
Python
67 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Self-test Cursor infra/destructive hooks without embedding deny patterns in the shell command line."""
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
|
|
INFRA = "/Users/macilia/.cursor/hooks/block-infra-footguns.sh"
|
|
DEST = "/Users/macilia/.cursor/hooks/block-destructive-shell.sh"
|
|
|
|
|
|
def run(script: str, cmd: str):
|
|
p = subprocess.run(
|
|
["bash", script],
|
|
input=json.dumps({"command": cmd}).encode(),
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
out = json.loads(p.stdout.decode() or "{}")
|
|
return out.get("permission"), out
|
|
|
|
|
|
def main() -> int:
|
|
# Build patterns without writing them as contiguous deny strings in this file's
|
|
# execution path for the outer shell — this file is executed as a path only.
|
|
ap = "ansible" + "-playbook"
|
|
av = "ansible" + "-vault"
|
|
nv = "--" + "no-verify"
|
|
rfm = "rm" + " -" + "rf"
|
|
|
|
cases = [
|
|
("playbook no check", f"{ap} playbooks/x.yml", "deny"),
|
|
("playbook check", f"{ap} playbooks/x.yml --check --diff", "allow"),
|
|
("playbook override", f"ALLOW_ANSIBLE_APPLY=1 {ap} playbooks/x.yml", "allow"),
|
|
("vault deny", f"{av} view inventories/production/group_vars/all/vault.yml", "deny"),
|
|
("vault override", f"ALLOW_VAULT=1 {av} view inventories/production/group_vars/all/vault.yml", "allow"),
|
|
("make apply deny", "make sites-static-apply", "deny"),
|
|
("make check allow", "make sites-static-check", "allow"),
|
|
("make apply with CHECK", "make maintenance CHECK=true", "allow"),
|
|
("make ping allow", "make ping HOST=edge", "allow"),
|
|
("no-verify deny", f"git commit {nv} -m msg", "deny"),
|
|
("edit-vault deny", "make edit-group-vault", "deny"),
|
|
("vault-export allow", "make vault-export-env", "allow"),
|
|
("make help allow", "make help", "allow"),
|
|
("make dev deny", "make -C ansible dev HOST=x", "deny"),
|
|
]
|
|
fail = 0
|
|
for label, cmd, expect in cases:
|
|
perm, out = run(INFRA, cmd)
|
|
ok = perm == expect
|
|
print(("OK " if ok else "FAIL"), label, "→", perm, "" if ok else out)
|
|
fail += 0 if ok else 1
|
|
|
|
for label, cmd, expect in [
|
|
("rm deny", f"{rfm} /tmp/foo", "deny"),
|
|
("echo allow", "echo hi", "allow"),
|
|
]:
|
|
perm, out = run(DEST, cmd)
|
|
ok = perm == expect
|
|
print(("OK " if ok else "FAIL"), label, "→", perm, "" if ok else out)
|
|
fail += 0 if ok else 1
|
|
|
|
return fail
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|