fix(permissions): harden bash rules against repo destruction (#218)

* feat(permissions): deny gh api DELETE and repo transfer

* feat(permissions): ask on force push and tag delete

* test(permissions): cover hardened bash deny/ask rules

---------

Co-authored-by: opencode-agent <agent@opencode.local>
This commit is contained in:
Sergey 2026-08-01 06:54:33 +03:00 committed by GitHub
parent 1dc2b0fa41
commit b7b1920385
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 1 deletions

View file

@ -276,7 +276,26 @@
"git commit *": "deny",
"gh pr create *": "deny",
"gh pr merge *": "deny",
"gh issue create *": "deny"
"gh issue create *": "deny",
"gh api * -X DELETE *": "deny",
"gh api -X DELETE *": "deny",
"gh api * --method DELETE *": "deny",
"gh api * --method delete *": "deny",
"gh repo transfer *": "deny",
"git push --force*": "ask",
"git push -f*": "ask",
"git push * --force*": "ask",
"git push * -f*": "ask",
"git push * :*": "ask",
"git tag -d *": "ask",
"git -C * push --force*": "ask",
"git -C * push -f*": "ask",
"git -C * push * --force*": "ask",
"git -C * push * -f*": "ask",
"git -C * push * :*": "ask",
"git -C * tag -d *": "ask"
}
},
"agent": {

View file

@ -120,6 +120,45 @@ def test_deny_rules_override_earlier_allows():
)
def test_bash_destructive_deny_ask_rules_present():
"""Harden rules (issue #217) exist in permission.bash with correct actions.
Deny covers gh api DELETE variants and repo transfer; ask covers force
push, refspec deletion and tag deletion, including ``git -C *`` mirrors.
Also asserts findLast ordering: all new rules come after the last
pre-existing rule (``gh issue create *``), so no earlier allow shadows them.
"""
bash = _load_config()["permission"]["bash"]
expected = {
"gh api * -X DELETE *": "deny",
"gh api -X DELETE *": "deny",
"gh api * --method DELETE *": "deny",
"gh api * --method delete *": "deny",
"gh repo transfer *": "deny",
"git push --force*": "ask",
"git push -f*": "ask",
"git push * --force*": "ask",
"git push * -f*": "ask",
"git push * :*": "ask",
"git tag -d *": "ask",
"git -C * push --force*": "ask",
"git -C * push -f*": "ask",
"git -C * push * --force*": "ask",
"git -C * push * -f*": "ask",
"git -C * push * :*": "ask",
"git -C * tag -d *": "ask",
}
for pattern, action in expected.items():
assert pattern in bash, f"missing rule: {pattern}"
assert bash[pattern] == action, f"{pattern}: expected {action}, got {bash[pattern]}"
keys = list(bash.keys())
last_old_rule = "gh issue create *"
assert keys.index(last_old_rule) < min(keys.index(p) for p in expected), (
f"new rules must come after '{last_old_rule}' (findLast: last wins)"
)
# ── agent.general.tools ────────────────────────────────────────────────────