chore(permissions): allow deletion ssh curl and fs operations #37
Loading…
Reference in a new issue
No description provided.
Delete branch "chore/permissions/allow-deletion-ssh-curl"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что сделано
Второе расширение allow-list
permission.bashв.opencode/opencode.json(продолжение issue #34 / PR #35). 4 логических коммита:Bucket A — read-only + docker exec (
4dad9c0):curl *,git reflog *,docker images*,docker inspect*,docker stats*→ allowdocker exec *→ allow (был ask) + carve-outs:docker exec * rm */rmdir *→ deny,docker exec * sh */bash *→ askBucket B — fs + local git mutations (
0f198db):cp,mv,touch,ln,tar,zip,unzip,wget→ allowgit switch *,git stash*,git tag,git config *→ allowBucket D — удаление + secret carve-outs (
54baffc):rm *,git rm *,git branch -D *,git -C * branch -D *→ allowrm *: allow:rm .env*,rm *id_ed25519*,rm *.pem*,rm *secrets*→ denyBucket E — ssh catch-all + fix дубля (
a333fc6):ssh *→ allow (был ask), перенесён в начало ssh-секции (см. Watch out)git commit *: allow(осталсяgit commit *: deny)Почему
Анализ 56 ask-событий за 5 дней (6-10 августа) показал два главных stall-узла:
rm *(20 ask, 19 stall) иssh *(20 ask, 17 stall). Overnight-задача залипала наrm(удаление файлов). Также не покрыты первым расширением:git branch -D *(5 ask) иdocker exec *(2 ask). Docker-изоляция + git history делают большинство операций восстанавливаемыми — пользователь явно принимает риск.Watch out
curl *<curl * -X DELETE *FORGEJO_URL*,docker exec *<docker exec * rm */sh *,rm *<rm .env*/*.pem*,ssh *<ssh * rm */mkfs*/reboot*и т.д. Проверено программно (все 8 парallow < carveOK).ssh *" — но в реальном файлеssh *(стр. 356) шёл ПОСЛЕ carve-outs (300-354). Простая заменаssh *: ask→allowна месте сломала бы все destructive carve-outs (ssh * rm *,ssh * mkfs*,ssh * reboot*стали бы allow — security regression). Поэтомуssh *: allowперенесён в начало ssh-секции (послеnohup *: ask, доcat *id_ed25519*), а старая строкаssh *: askудалена. Критерий приёмки "carve-outs идут ПОСЛЕssh *: allow" соблюдён.ssh * cat *— БЕЗ carve-out (user declined):ssh * cat rclone.confбудет allow. Принятый риск (creds нужны для деплоя, балансы маленькие, solo).&&-chaining: opencode матчит всю строку —rm /tmp/x && git statusне матчит ниrm *, ниgit status*→ catch-all. Mitigation: дисциплина в промптах.rm .env*защищает только prefix.env*—rm /path/to/.envНЕ защищён. Acceptable risk (user confirmed).docker exec * rm *→ deny, ноdocker exec forgejo sh -c "rm /tmp/x"матчитdocker exec * sh *: ask(НЕrm *: deny, т.к.rmвнутри кавычек безrmс пробелом). Acceptable.git tag(exact) — allow;git tag -d *(delete) — остаётся ask.git push --force*/--delete(ask),git reset */git clean *(deny),kill */docker rm */docker stop */docker restart *(ask), reviewer.md, memory-syncer.md.Pending
—
Closes #36
Closes #36
Code Review Summary
PR расширяет allow-list
permission.bashв.opencode/opencode.json(удаление, ssh, curl, fs-операции). Все findLast ordering инварианты проверены — каждый deny/ask carve-out стоит ПОСЛЕ соответствующего allow. Дубльgit commit *: allowудалён. Guard-скриптcheck-permissions.pyпроходит. Изменён только.opencode/opencode.json.Positives
findLast ordering — все 8 пар allow→carve-out проверены (последнее совпадающее правило побеждает):
rm *: allow(стр. 307) → ДОrm .env*/*id_ed25519*/.pem/secrets: deny (308-311) ✅ssh *: allow(стр. 323) → ДО ВСЕХ destructive carve-outs:mkfs*/dd */fdisk*deny (326-328),rm */rmdir */reboot*/shutdown*/systemctl restart*/stop*/apt */yum */mv */chmod */chown */docker restart*/stop*/rm*/rmi*/update*/cat *.env*/cat .env*/powershell Set-*/New-*/Remove-*/Restart-*/Stop-*ask (358-380) ✅curl *: allow(стр. 228) → ДОcurl * -X DELETE *FORGEJO_URL*: deny(стр. 383) ✅docker exec *: allow(стр. 300) → ДОdocker exec * rm */rmdir *: deny(301-302),sh */bash *: ask(303-304) ✅Критический ssh-fix верифицирован:
ssh *: allowперенесён в НАЧАЛО ssh-секции (стр. 323, послеnohup *: ask, доcat *id_ed25519*). Старая строкаssh *: ask(которая шла ПОСЛЕ carve-outs) удалена. Простая заменаask→allowна месте сломала бы все destructive carve-outs (security regression) — implement subagent правильно это распознал и перенёс правило.Дубль
git commit *убран:git commit *: allowудалён, остался единственныйgit commit *: deny(стр. 382) ✅Запрещённые НЕ добавлены:
gh pr merge *отсутствует,git push --force*/-f*/--delete *остались ask (385-396),git reset */git clean *остались deny (315-316),kill */docker rm */docker stop */docker restart *остались ask (297-299, 320),python3 *в memory-syncer не тронут ✅ssh * cat *: askНЕ добавлен (user declined) — только pre-existingssh * cat *.env*/.env*(specific to .env) остаются ✅Scope: изменён ТОЛЬКО
.opencode/opencode.json(31+/7-). reviewer.md, memory-syncer.md НЕ тронуты ✅Валидация: JSON валиден (
json.loadOK), guard-скриптpython3 .opencode/scripts/check-permissions.py→ "OK: No dangerous permission rules found." ✅PR body: 4 heading'а (
## Что сделано,## Почему,## Watch out,## Pending=—) +Closes #36✅. Watch out подробно документирует findLast ordering, ssh-fix, отклонениеssh * cat *carve-out,&&-chaining gotcha,rm .env*prefix-only limitation.CI: green (pipeline-status confirmed).
Suggestions (info, not blocking)
Closes #36появляется дважды в конце body. Forgejo всё равно закроет issue, но дубликат можно убрать.rm .env*защищает только prefix-match (.env*в начале строки).rm /path/to/.envНЕ защищён (т.к. pattern не содержит*/.env). Уже задокументировано в Watch out как accepted risk — без действия.Verdict: APPROVE