fix(scripts): check-permissions.py flags spec-approved force push and docker rules #56

Closed
opened 2026-08-11 22:44:58 +03:00 by slaid098 · 0 comments
Owner

Контекст

PR #55 (закрывает issue #54) реализует спеку, которая явно одобряет перевод 5 опасных правил из ask → allow для автономной соло-разработки:

  • git push --force* / git push -f* (Изменение 3 спеки #54, строки 387-388)
  • docker rm * (Изменение 4, строка 301)
  • docker system prune* (Изменение 4, строка 307)
  • docker volume rm * (Изменение 4, строка 308)

Спека #54 в разделе "Влияние на связанные компоненты" прямо предвидела конфликт: «check-permissions.py линтер может срабатывать на опасные правила. Проверить, не начнёт ли он ругаться на force push allow / docker rm allow. Если да — возможно нужно обновить линтер, но это вне scope». И в "Вне scope": «Не обновлять check-permissions.py (если он ругается — отдельный issue)».

CI упал на job check (run_id=361, job_id=930) с 5 нарушениями:

FAIL: Dangerous permission rules detected:
  [opencode.json] "docker rm *": allow
    -> remove containers
  [opencode.json] "docker system prune*": allow
    -> prune everything
  [opencode.json] "docker volume rm *": allow
    -> remove volumes
  [opencode.json] "git push --force*": allow
    -> rewrites remote history
  [opencode.json] "git push -f*": allow
    -> rewrites remote history
Total: 5 violation(s)

Линтер .opencode/scripts/check-permissions.py:57-80 имеет безусловные паттерны:

  • r"^git push --force\*" (строка 57) → "rewrites remote history"
  • r"^git push -f\*" (строка 59) → "rewrites remote history"
  • r"^docker system prune\*" (строка 77) → "prune everything"
  • r"^docker rm \*" (строка 78) → "remove containers"
  • r"^docker volume rm \*" (строка 80) → "remove volumes"

check_rules() (строка 137-151) флагает ЛЮБОЕ allow-правило, совпадающее с этими паттернами, без знания о контексте (соло-разработчик, branch protection на Forgejo ловит main на серверной стороне, docker-операции в локальной dev-среде).

Задача

Уточнить логику check-permissions.py так, чтобы он перестал блокировать CI для правил, которые спека #54 (и будущие спеки) явно одобряют для соло-разработчика. Линтер должен отличать «случайный опасный allow» от «сознательно одобренного спекой опасного allow».

Контракты

Файл: /root/workspace/opencode-config/.opencode/scripts/check-permissions.py.

Контракт 1 — разрешить опасные правила через allowlist паттернов

Добавить ALLOWED_DANGEROUS паттерны (или маркер в DANGEROUS_PATTERNS), которые спека #54 явно одобрила. Список (5 шт.):

  • git push --force*
  • git push -f*
  • docker rm *
  • docker system prune*
  • docker volume rm *

Обоснование одобрения (из спеки #54): соло-разработчик, чужой работы нет, branch protection на Forgejo ловит main на серверной стороне, docker-операции в локальной dev-среде.

Контракт 2 — оставить флаги для остальных опасных паттернов

Все остальные паттерны в DANGEROUS_PATTERNS (строки 13-105) остаются активными. Особенно:

  • git push --delete* / git push origin --delete* (строки 58, 60) — НО спека #54 одобряет их как allow (Изменение 2). Решить: либо тоже в allowlist, либо оставить флаг (тогда спека #54 невыполнима без CI-флага). Спека #54 Изменение 2 одобряет git tag -d *, git branch -d *, git push --delete *, git push origin --delete * → allow. Значит их тоже нужно добавить в allowlist.
  • docker rmi * (строка 79), docker network rm * (строка 81) — НЕ одобрены спекой #54, остаются флагами.
  • rm -rf, rm -f /, rm /, rmdir *, shred * — остаются флагами.
  • ssh * опасные команды — остаются флагами (но они в ask, не allow, так что check_rules их не трогает: if action != "allow": continue на строке 141).

Контракт 3 — подход к реализации (выбрать один)

Вариант A (простой): добавить ALLOWED_DANGEROUS_PATTERNS список строк-паттернов, которые check_rules пропускает (continue) перед проверкой DANGEROUS_PATTERNS. Плюс: минимальные изменения. Минус: allowlist растёт с каждой новой спекой.

Вариант B (маркер в спеке): добавить поле approved_dangerous в JSON (или комментарий рядом с правилом) и проверять его. Плюс: самодокументирующийся. Минус: требует формата маркера, которого сейчас нет в JSON.

Вариант C (per-rule scope): добавить третий элемент scope в tuple DANGEROUS_PATTERNS (как уже сделано для agent-only правил: строки 17, 22, 27, 32, 47, 52) со значением "solo-approved" — check_rules пропускает такие паттерны для opencode.json. Плюс: переиспользует существующий механизм. Минус: семантика scope размывается.

Рекомендуется Вариант A (минимальные изменения, явный allowlist одобренных спекой паттернов).

Инварианты

  • check-permissions.py продолжает флагать все allow-правила, не входящие в allowlist одобренных спекой.
  • deny-правила никогда не флагаются (уже так: if action != "allow": continue на строке 141).
  • ask-правила никогда не флагаются (тоже continue).
  • Поведение для agents/*.md frontmatter не меняется (scope="agent" правила остаются).
  • CI workflow .forgejo/workflows/check-permissions.yml (или аналогичный) не меняется — только скрипт.
  • JSON-валидность .opencode/opencode.json не нарушается (скрипт только читает).

Граничные случаи

  1. Будущие спеки одобряют новые опасные правила — allowlist нужно расширять. Документировать в ADR или комментарии в скрипте: «добавлять в ALLOWED_DANGEROUS только через явное одобрение в спеке issue».
  2. git push --delete* (строка 58) и git push origin --delete* (строка 60) — спека #54 Изменение 2 одобряет их как allow. Если их НЕ добавить в allowlist, CI продолжит падать на PR #55 (он переводит их в allow). Значит их тоже нужно добавить.
  3. git -C * push --force* и варианты с -C — спека #54 Изменение 3 одобряет 10 force push записей, включая git -C * варианты (строки 393-397). Линтер сейчас флагает только ^git push --force\* и ^git push -f\* (без -C), но git -C * push --force* не совпадает с ^git push --force\* (начинается с git -C). Значит git -C * варианты сейчас НЕ флагаются — но allowlist должен быть консистентен.
  4. docker restart *, docker stop * — спека #54 Изменение 4 одобряет их как allow, но их НЕТ в DANGEROUS_PATTERNS линтера (он не флагает их). Значит их добавлять в allowlist НЕ нужно (они и так проходят).
  5. git tag -d *, git branch -d * — спека #54 Изменение 2 одобряет, но их НЕТ в DANGEROUS_PATTERNS. Проходят без allowlist.

Влияние на связанные компоненты

  • CI workflow (.forgejo/workflows/) — после фикса линтера CI пройдёт на PR #55 и любых будущих PR, соблюдущих спеку #54.
  • configure-opencode skill (.opencode/skills/configure-opencode/SKILL.md:124) — упоминает check-permissions.py. После фикса обновить комментарий в skill, если нужно.
  • ADR-019 / ADR-NNN — упоминаются в паттернах (строки 16, 21, 26, 31, 36, 41, 46, 51). Не трогать.
  • PR #55 — после фикса этого issue, PR #55 должен пройти CI (правила в PR уже по спеке, фикс линтера разблокирует CI).

Вне scope

  • Не менять правила в .opencode/opencode.json (они по спеке #54, правильные).
  • Не менять CI workflow файлы (только скрипт check-permissions.py).
  • Не трогать agents/*.md frontmatter-парсинг.
  • Не добавлять новые опасные паттерны в DANGEROUS_PATTERNS (только allowlist для одобренных).
  • Не рефакторить структуру скрипта (минимальные изменения).

Критерии приемки

  1. check-permissions.py имеет явный allowlist одобренных спекой опасных паттернов (5 из спеки #54 + 2 для git push --delete* / git push origin --delete* из Изменения 2 = 7 паттернов, либо полный набор из Изменений 2-4).
  2. python3 .opencode/scripts/check-permissions.py на текущем состоянии opencode.json (после merge PR #55) возвращает exit 0, OK: No dangerous permission rules found.
  3. Линтер продолжает флагать docker rmi *, docker network rm *, rm -rf, rm -f /, rm /, rmdir *, shred *, sudo, chmod, chown, mkfs, dd, fdisk, shutdown, reboot, halt, poweroff, ssh * опасные, kubectl delete/scale, kill -9, killall, pkill, npm/pip/cargo install если они allow.
  4. CI на PR #55 (после merge этого issue'а) проходит job check.
  5. Раздел ADR или комментарий в скрипте документирует: «allowlist расширяется только через явное одобрение в спеке issue».
## Контекст PR #55 (закрывает issue #54) реализует спеку, которая **явно одобряет** перевод 5 опасных правил из `ask` → `allow` для автономной соло-разработки: - `git push --force*` / `git push -f*` (Изменение 3 спеки #54, строки 387-388) - `docker rm *` (Изменение 4, строка 301) - `docker system prune*` (Изменение 4, строка 307) - `docker volume rm *` (Изменение 4, строка 308) Спека #54 в разделе "Влияние на связанные компоненты" прямо предвидела конфликт: «check-permissions.py линтер может срабатывать на опасные правила. Проверить, не начнёт ли он ругаться на force push allow / docker rm allow. Если да — возможно нужно обновить линтер, но это вне scope». И в "Вне scope": «Не обновлять check-permissions.py (если он ругается — отдельный issue)». CI упал на job `check` (run_id=361, job_id=930) с 5 нарушениями: ``` FAIL: Dangerous permission rules detected: [opencode.json] "docker rm *": allow -> remove containers [opencode.json] "docker system prune*": allow -> prune everything [opencode.json] "docker volume rm *": allow -> remove volumes [opencode.json] "git push --force*": allow -> rewrites remote history [opencode.json] "git push -f*": allow -> rewrites remote history Total: 5 violation(s) ``` Линтер `.opencode/scripts/check-permissions.py:57-80` имеет безусловные паттерны: - `r"^git push --force\*"` (строка 57) → "rewrites remote history" - `r"^git push -f\*"` (строка 59) → "rewrites remote history" - `r"^docker system prune\*"` (строка 77) → "prune everything" - `r"^docker rm \*"` (строка 78) → "remove containers" - `r"^docker volume rm \*"` (строка 80) → "remove volumes" `check_rules()` (строка 137-151) флагает ЛЮБОЕ `allow`-правило, совпадающее с этими паттернами, без знания о контексте (соло-разработчик, branch protection на Forgejo ловит main на серверной стороне, docker-операции в локальной dev-среде). ## Задача Уточнить логику `check-permissions.py` так, чтобы он перестал блокировать CI для правил, которые спека #54 (и будущие спеки) **явно одобряют** для соло-разработчика. Линтер должен отличать «случайный опасный allow» от «сознательно одобренного спекой опасного allow». ## Контракты Файл: `/root/workspace/opencode-config/.opencode/scripts/check-permissions.py`. ### Контракт 1 — разрешить опасные правила через allowlist паттернов Добавить ALLOWED_DANGEROUS паттерны (или маркер в `DANGEROUS_PATTERNS`), которые спека #54 явно одобрила. Список (5 шт.): - `git push --force*` - `git push -f*` - `docker rm *` - `docker system prune*` - `docker volume rm *` Обоснование одобрения (из спеки #54): соло-разработчик, чужой работы нет, branch protection на Forgejo ловит main на серверной стороне, docker-операции в локальной dev-среде. ### Контракт 2 — оставить флаги для остальных опасных паттернов Все остальные паттерны в `DANGEROUS_PATTERNS` (строки 13-105) остаются активными. Особенно: - `git push --delete*` / `git push origin --delete*` (строки 58, 60) — НО спека #54 одобряет их как allow (Изменение 2). Решить: либо тоже в allowlist, либо оставить флаг (тогда спека #54 невыполнима без CI-флага). Спека #54 Изменение 2 одобряет `git tag -d *`, `git branch -d *`, `git push --delete *`, `git push origin --delete *` → allow. Значит их тоже нужно добавить в allowlist. - `docker rmi *` (строка 79), `docker network rm *` (строка 81) — НЕ одобрены спекой #54, остаются флагами. - `rm -rf`, `rm -f /`, `rm /`, `rmdir *`, `shred *` — остаются флагами. - `ssh *` опасные команды — остаются флагами (но они в `ask`, не `allow`, так что `check_rules` их не трогает: `if action != "allow": continue` на строке 141). ### Контракт 3 — подход к реализации (выбрать один) **Вариант A (простой):** добавить `ALLOWED_DANGEROUS_PATTERNS` список строк-паттернов, которые `check_rules` пропускает (continue) перед проверкой `DANGEROUS_PATTERNS`. Плюс: минимальные изменения. Минус: allowlist растёт с каждой новой спекой. **Вариант B (маркер в спеке):** добавить поле `approved_dangerous` в JSON (или комментарий рядом с правилом) и проверять его. Плюс: самодокументирующийся. Минус: требует формата маркера, которого сейчас нет в JSON. **Вариант C (per-rule scope):** добавить третий элемент `scope` в tuple `DANGEROUS_PATTERNS` (как уже сделано для `agent`-only правил: строки 17, 22, 27, 32, 47, 52) со значением `"solo-approved"` — `check_rules` пропускает такие паттерны для `opencode.json`. Плюс: переиспользует существующий механизм. Минус: семантика `scope` размывается. Рекомендуется **Вариант A** (минимальные изменения, явный allowlist одобренных спекой паттернов). ## Инварианты - `check-permissions.py` продолжает флагать все `allow`-правила, не входящие в allowlist одобренных спекой. - `deny`-правила никогда не флагаются (уже так: `if action != "allow": continue` на строке 141). - `ask`-правила никогда не флагаются (тоже `continue`). - Поведение для `agents/*.md` frontmatter не меняется (scope="agent" правила остаются). - CI workflow `.forgejo/workflows/check-permissions.yml` (или аналогичный) не меняется — только скрипт. - JSON-валидность `.opencode/opencode.json` не нарушается (скрипт только читает). ## Граничные случаи 1. **Будущие спеки одобряют новые опасные правила** — allowlist нужно расширять. Документировать в ADR или комментарии в скрипте: «добавлять в ALLOWED_DANGEROUS только через явное одобрение в спеке issue». 2. **`git push --delete*` (строка 58) и `git push origin --delete*` (строка 60)** — спека #54 Изменение 2 одобряет их как allow. Если их НЕ добавить в allowlist, CI продолжит падать на PR #55 (он переводит их в allow). Значит их тоже нужно добавить. 3. **`git -C * push --force*` и варианты с `-C`** — спека #54 Изменение 3 одобряет 10 force push записей, включая `git -C *` варианты (строки 393-397). Линтер сейчас флагает только `^git push --force\*` и `^git push -f\*` (без `-C`), но `git -C * push --force*` не совпадает с `^git push --force\*` (начинается с `git -C`). Значит `git -C *` варианты сейчас НЕ флагаются — но allowlist должен быть консистентен. 4. **`docker restart *`, `docker stop *`** — спека #54 Изменение 4 одобряет их как allow, но их НЕТ в `DANGEROUS_PATTERNS` линтера (он не флагает их). Значит их добавлять в allowlist НЕ нужно (они и так проходят). 5. **`git tag -d *`, `git branch -d *`** — спека #54 Изменение 2 одобряет, но их НЕТ в `DANGEROUS_PATTERNS`. Проходят без allowlist. ## Влияние на связанные компоненты - **CI workflow** (`.forgejo/workflows/`) — после фикса линтера CI пройдёт на PR #55 и любых будущих PR, соблюдущих спеку #54. - **`configure-opencode` skill** (`.opencode/skills/configure-opencode/SKILL.md:124`) — упоминает check-permissions.py. После фикса обновить комментарий в skill, если нужно. - **ADR-019 / ADR-NNN** — упоминаются в паттернах (строки 16, 21, 26, 31, 36, 41, 46, 51). Не трогать. - **PR #55** — после фикса этого issue, PR #55 должен пройти CI (правила в PR уже по спеке, фикс линтера разблокирует CI). ## Вне scope - Не менять правила в `.opencode/opencode.json` (они по спеке #54, правильные). - Не менять CI workflow файлы (только скрипт `check-permissions.py`). - Не трогать `agents/*.md` frontmatter-парсинг. - Не добавлять новые опасные паттерны в `DANGEROUS_PATTERNS` (только allowlist для одобренных). - Не рефакторить структуру скрипта (минимальные изменения). ## Критерии приемки 1. `check-permissions.py` имеет явный allowlist одобренных спекой опасных паттернов (5 из спеки #54 + 2 для `git push --delete*` / `git push origin --delete*` из Изменения 2 = 7 паттернов, либо полный набор из Изменений 2-4). 2. `python3 .opencode/scripts/check-permissions.py` на текущем состоянии `opencode.json` (после merge PR #55) возвращает exit 0, `OK: No dangerous permission rules found.` 3. Линтер продолжает флагать `docker rmi *`, `docker network rm *`, `rm -rf`, `rm -f /`, `rm /`, `rmdir *`, `shred *`, `sudo`, `chmod`, `chown`, `mkfs`, `dd`, `fdisk`, `shutdown`, `reboot`, `halt`, `poweroff`, `ssh *` опасные, `kubectl delete/scale`, `kill -9`, `killall`, `pkill`, `npm/pip/cargo install` если они `allow`. 4. CI на PR #55 (после merge этого issue'а) проходит job `check`. 5. Раздел ADR или комментарий в скрипте документирует: «allowlist расширяется только через явное одобрение в спеке issue».
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
slaid098/opencode-config#56
No description provided.