fix(config): allow Read tool to open .env.example and .env.template #38

Closed
opened 2026-08-11 15:00:25 +03:00 by slaid098 · 0 comments
Owner

Контекст

Файл .env.example — это placeholder-шаблон без реальных секретов. Он уже закоммичен в git и виден на Forgejo remote. Однако текущая конфигурация permission.read в .opencode/opencode.json ЗАПРЕЩАЕТ чтение этого файла через Read tool — это баг (misconfiguration), поскольку безопасный placeholder-файл, уже находящийся в git, не должен блокироваться.

Текущее состояние

.opencode/opencode.json (строки 161–173), блок permission:

"permission": {
  "edit": "allow",
  "external_directory": "allow",
  "doom_loop": "deny",
  "read": {
    "*.env": "deny",
    ".env": "deny",
    "**/.env": "deny",
    "**/.env*": "deny",           ← ЭТО ловит .env.example (glob .env* совпадает с .env.example)
    "**/id_ed25519": "deny",
    "**/id_rsa": "deny",
    "**/id_ed25519.pub": "allow"   ← ПРЕЦЕДЕНТ: публичный ключ разрешён ПОСЛЕ deny приватного (findLast)
  },

Механизм (findLast)

opencode read permission использует glob-паттерны с findLast-семантикой — ПОСЛЕДНЕЕ совпадающее правило побеждает. Паттерн **/.env* (deny) на строке 169 совпадает с .env.example, и более позднего allow для него нет → DENY побеждает. Существующий **/id_ed25519.pub: allow (строка 172) демонстрирует тот же паттерн: помести allow-правило ПОСЛЕ совпадающего deny, и findLast позволит ему выиграть для конкретного имени файла.

.env (реальные секреты)

Сейчас запрещён 4 перекрывающимися правилами (*.env, .env, **/.env, **/.env*). Корректно защищён — должен остаться запрещённым. Файла .env в репо не существует (gitignored в .gitignore:33).

.env.template

Имя зарезервировано в .gitignore:36 (!.env.template), файл пока не существует. Future-proofing — та же логическая сущность, что .env.example (шаблон без секретов).

CI/validator

check-permissions.py инспектирует только bash allow-правила, НЕ блок read. Добавление read allow НЕ сломает CI.

Тесты

tests/test_permissions.py НЕ имеет тестов для блока read (только bash-правила). Нужен новый тест, фиксирующий структуру.

Документационный баг в .opencode/skills/configure-opencode/SKILL.md:115

Описывает read как "массив glob-паттернов" (массив allow-паттернов), но согласно официальной схеме opencode И фактическому конфигу, read — это ОБЪЕКТ, отображающий glob → action (allow/deny/ask). Нужно однострочное исправление.

Задача

Внести 3 правки в /root/workspace/opencode-config/:

Правка 1 — .opencode/opencode.json, блок permission.read

После строки 169 ("**/.env*": "deny",) вставить ДВЕ новые строки:

"**/.env.example": "allow",
"**/.env.template": "allow",

Результат (строки 169–172):

"**/.env*": "deny",
"**/.env.example": "allow",
"**/.env.template": "allow",

findLast гарантирует, что allow побеждает только для ТОЧНЫХ имён файлов .env.example и .env.template. .env (секреты) остаётся запрещённым — его 4 правила не трогаются, а .env.example/.env.template не подпадают под *.env/.env/**/.env (те требуют, чтобы путь ЗАКАНЧИВАЛСЯ на .env).

Правка 2 — tests/test_permissions.py

Добавить новую тестовую функцию, проверяющую структуру блока read:

  • "**/.env*" == "deny" (сохранено — секреты защищены)
  • "**/.env.example" == "allow" (новое)
  • "**/.env.template" == "allow" (новое)
  • "**/id_ed25519.pub" == "allow" (без регрессии)

Также протестировать, что содержимое .env.example остаётся placeholder-only (без реальных секретов) — прочитать файл в тесте, regex'ом проверить очевидные паттерны секретов, упасть, если найден реальный секрет. Это защитная сетка (safety net).

Следовать существующему стилю тестов в tests/test_permissions.py (посмотреть, как bash-тесты грузят config JSON и ассертят правила). Тест должен загрузить .opencode/opencode.json, перейти в permission.read и assert ключи/значения выше.

Правка 3 — .opencode/skills/configure-opencode/SKILL.md:115

Исправить описание: read — это объект pattern → action (allow/deny/ask), НЕ массив allow-паттернов. Одна строка.

Контракты

  • Блок permission.read в .opencode/opencode.json — объект с findLast-семантикой: последнее совпадающее правило побеждает.
  • Порядок правил в JSON детерминирован (объекты JSON сохраняют порядок вставки в Python json.load).
  • **/.env* (deny) ДОЛЖЕН остаться в конфиге и остаться ДО **/.env.example/**/.env.template (allow), чтобы findLast позволил allow выиграть для конкретных имён.
  • **/id_ed25519.pub: allow — существующий прецедент того же паттерна (allow после deny), не должен регрессировать.
  • Тесты грузят конфиг через json.load по образцу существующих bash-тестов в tests/test_permissions.py.

Инварианты

  • .env (реальные секреты) остаётся DENY (4 правила не трогаются: *.env, .env, **/.env, **/.env*).
  • .env.example — placeholder, уже в git, уже виден на Forgejo remote.
  • .env.template — зарезервирован в .gitignore:36, файл пока не существует.
  • check-permissions.py не инспектирует блок read → правки не ломают CI.
  • Никаких изменений в bash allow/deny правилах.

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

  • .env.production, .env.local, .env.staging — подпадают под **/.env* (deny), явного allow для них НЕТ → остаются DENY. Корректно (могут быть реальные секреты).
  • .env.example в поддиректории (например, packages/foo/.env.example) — **/.env.example совпадает через ** → allow побеждает. Корректно (placeholder в любом месте репо безопасен).
  • Точно .env в корне — *.env, .env, **/.env совпадают, все deny, более позднего allow для .env нет → DENY. Корректно.
  • Регистр: .ENV.example — не совпадает ни с одним allow (glob чувствителен к регистру на Linux) → остаётся под **/.env* deny. Корректно.

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

  • check-permissions.py — не затронут (инспектирует только bash-правила).
  • tests/test_permissions.py — добавляется новая тестовая функция; существующие bash-тесты не затрагиваются.
  • .opencode/skills/configure-opencode/SKILL.md — однострочное исправление описания read (объект, не массив).
  • Read tool в opencode — теперь сможет открывать .env.example и .env.template; все остальные .env* файлы остаются под deny.
  • CI — не ломается (read-блок вне зоны проверки check-permissions.py).

Вне scope

  • bash cat .env.example — Read tool каноничен (AGENTS.md:78 "Use tools instead of bash"). Прецедент **/id_ed25519.pub НЕ трогал bash. НЕ добавлять cat .env.example* allow в bash.
  • .env (реальные секреты) — остаётся denied, это корректно. Никаких изменений в 4 deny-правилах, его защищающих.
  • Любые другие изменения permission кроме 3 правок выше.
  • Создание самого файла .env.template (пока только future-proofing в конфиге).

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

  • В .opencode/opencode.json после "**/.env*": "deny", стоят две новые строки: "**/.env.example": "allow", и "**/.env.template": "allow", (в указанном порядке).
  • 4 deny-правила для .env (*.env, .env, **/.env, **/.env*) сохранены без изменений.
  • **/id_ed25519.pub: allow сохранён без изменений.
  • В tests/test_permissions.py добавлена тестовая функция, ассертящая 4 указанных ключа/значения блока read.
  • Тест также проверяет, что .env.example не содержит реальных секретов (regex-проверка placeholder-содержимого).
  • Новый тест проходит локально (pytest tests/test_permissions.py).
  • Существующие тесты tests/test_permissions.py не регрессируют.
  • В .opencode/skills/configure-opencode/SKILL.md:115 описание read исправлено на "объект pattern → action (allow/deny/ask)".
  • CI зелёный после PR.
## Контекст Файл `.env.example` — это placeholder-шаблон без реальных секретов. Он уже закоммичен в git и виден на Forgejo remote. Однако текущая конфигурация `permission.read` в `.opencode/opencode.json` ЗАПРЕЩАЕТ чтение этого файла через Read tool — это баг (misconfiguration), поскольку безопасный placeholder-файл, уже находящийся в git, не должен блокироваться. ### Текущее состояние `.opencode/opencode.json` (строки 161–173), блок `permission`: ```json "permission": { "edit": "allow", "external_directory": "allow", "doom_loop": "deny", "read": { "*.env": "deny", ".env": "deny", "**/.env": "deny", "**/.env*": "deny", ← ЭТО ловит .env.example (glob .env* совпадает с .env.example) "**/id_ed25519": "deny", "**/id_rsa": "deny", "**/id_ed25519.pub": "allow" ← ПРЕЦЕДЕНТ: публичный ключ разрешён ПОСЛЕ deny приватного (findLast) }, ``` ### Механизм (findLast) opencode `read` permission использует glob-паттерны с findLast-семантикой — ПОСЛЕДНЕЕ совпадающее правило побеждает. Паттерн `**/.env*` (deny) на строке 169 совпадает с `.env.example`, и более позднего `allow` для него нет → DENY побеждает. Существующий `**/id_ed25519.pub: allow` (строка 172) демонстрирует тот же паттерн: помести `allow`-правило ПОСЛЕ совпадающего `deny`, и findLast позволит ему выиграть для конкретного имени файла. ### `.env` (реальные секреты) Сейчас запрещён 4 перекрывающимися правилами (`*.env`, `.env`, `**/.env`, `**/.env*`). Корректно защищён — должен остаться запрещённым. Файла `.env` в репо не существует (gitignored в `.gitignore:33`). ### `.env.template` Имя зарезервировано в `.gitignore:36` (`!.env.template`), файл пока не существует. Future-proofing — та же логическая сущность, что `.env.example` (шаблон без секретов). ### CI/validator `check-permissions.py` инспектирует только `bash` allow-правила, НЕ блок `read`. Добавление `read` allow НЕ сломает CI. ### Тесты `tests/test_permissions.py` НЕ имеет тестов для блока `read` (только bash-правила). Нужен новый тест, фиксирующий структуру. ### Документационный баг в `.opencode/skills/configure-opencode/SKILL.md:115` Описывает `read` как "массив glob-паттернов" (массив allow-паттернов), но согласно официальной схеме opencode И фактическому конфигу, `read` — это ОБЪЕКТ, отображающий glob → action (allow/deny/ask). Нужно однострочное исправление. ## Задача Внести 3 правки в `/root/workspace/opencode-config/`: ### Правка 1 — `.opencode/opencode.json`, блок `permission.read` После строки 169 (`"**/.env*": "deny",`) вставить ДВЕ новые строки: ```json "**/.env.example": "allow", "**/.env.template": "allow", ``` Результат (строки 169–172): ```json "**/.env*": "deny", "**/.env.example": "allow", "**/.env.template": "allow", ``` findLast гарантирует, что `allow` побеждает только для ТОЧНЫХ имён файлов `.env.example` и `.env.template`. `.env` (секреты) остаётся запрещённым — его 4 правила не трогаются, а `.env.example`/`.env.template` не подпадают под `*.env`/`.env`/`**/.env` (те требуют, чтобы путь ЗАКАНЧИВАЛСЯ на `.env`). ### Правка 2 — `tests/test_permissions.py` Добавить новую тестовую функцию, проверяющую структуру блока `read`: - `"**/.env*"` == "deny" (сохранено — секреты защищены) - `"**/.env.example"` == "allow" (новое) - `"**/.env.template"` == "allow" (новое) - `"**/id_ed25519.pub"` == "allow" (без регрессии) Также протестировать, что содержимое `.env.example` остаётся placeholder-only (без реальных секретов) — прочитать файл в тесте, regex'ом проверить очевидные паттерны секретов, упасть, если найден реальный секрет. Это защитная сетка (safety net). Следовать существующему стилю тестов в `tests/test_permissions.py` (посмотреть, как bash-тесты грузят config JSON и ассертят правила). Тест должен загрузить `.opencode/opencode.json`, перейти в `permission.read` и assert ключи/значения выше. ### Правка 3 — `.opencode/skills/configure-opencode/SKILL.md:115` Исправить описание: `read` — это объект `pattern → action` (allow/deny/ask), НЕ массив allow-паттернов. Одна строка. ## Контракты - Блок `permission.read` в `.opencode/opencode.json` — объект с findLast-семантикой: последнее совпадающее правило побеждает. - Порядок правил в JSON детерминирован (объекты JSON сохраняют порядок вставки в Python `json.load`). - `**/.env*` (deny) ДОЛЖЕН остаться в конфиге и остаться ДО `**/.env.example`/`**/.env.template` (allow), чтобы findLast позволил allow выиграть для конкретных имён. - `**/id_ed25519.pub: allow` — существующий прецедент того же паттерна (allow после deny), не должен регрессировать. - Тесты грузят конфиг через `json.load` по образцу существующих bash-тестов в `tests/test_permissions.py`. ## Инварианты - `.env` (реальные секреты) остаётся DENY (4 правила не трогаются: `*.env`, `.env`, `**/.env`, `**/.env*`). - `.env.example` — placeholder, уже в git, уже виден на Forgejo remote. - `.env.template` — зарезервирован в `.gitignore:36`, файл пока не существует. - `check-permissions.py` не инспектирует блок `read` → правки не ломают CI. - Никаких изменений в `bash` allow/deny правилах. ## Граничные случаи - `.env.production`, `.env.local`, `.env.staging` — подпадают под `**/.env*` (deny), явного allow для них НЕТ → остаются DENY. Корректно (могут быть реальные секреты). - `.env.example` в поддиректории (например, `packages/foo/.env.example`) — `**/.env.example` совпадает через `**` → allow побеждает. Корректно (placeholder в любом месте репо безопасен). - Точно `.env` в корне — `*.env`, `.env`, `**/.env` совпадают, все deny, более позднего allow для `.env` нет → DENY. Корректно. - Регистр: `.ENV.example` — не совпадает ни с одним allow (glob чувствителен к регистру на Linux) → остаётся под `**/.env*` deny. Корректно. ## Влияние на связанные компоненты - `check-permissions.py` — не затронут (инспектирует только bash-правила). - `tests/test_permissions.py` — добавляется новая тестовая функция; существующие bash-тесты не затрагиваются. - `.opencode/skills/configure-opencode/SKILL.md` — однострочное исправление описания `read` (объект, не массив). - Read tool в opencode — теперь сможет открывать `.env.example` и `.env.template`; все остальные `.env*` файлы остаются под deny. - CI — не ломается (read-блок вне зоны проверки `check-permissions.py`). ## Вне scope - `bash` `cat .env.example` — Read tool каноничен (AGENTS.md:78 "Use tools instead of bash"). Прецедент `**/id_ed25519.pub` НЕ трогал bash. НЕ добавлять `cat .env.example*` allow в bash. - `.env` (реальные секреты) — остаётся denied, это корректно. Никаких изменений в 4 deny-правилах, его защищающих. - Любые другие изменения permission кроме 3 правок выше. - Создание самого файла `.env.template` (пока только future-proofing в конфиге). ## Критерии приемки - [ ] В `.opencode/opencode.json` после `"**/.env*": "deny",` стоят две новые строки: `"**/.env.example": "allow",` и `"**/.env.template": "allow",` (в указанном порядке). - [ ] 4 deny-правила для `.env` (`*.env`, `.env`, `**/.env`, `**/.env*`) сохранены без изменений. - [ ] `**/id_ed25519.pub: allow` сохранён без изменений. - [ ] В `tests/test_permissions.py` добавлена тестовая функция, ассертящая 4 указанных ключа/значения блока `read`. - [ ] Тест также проверяет, что `.env.example` не содержит реальных секретов (regex-проверка placeholder-содержимого). - [ ] Новый тест проходит локально (`pytest tests/test_permissions.py`). - [ ] Существующие тесты `tests/test_permissions.py` не регрессируют. - [ ] В `.opencode/skills/configure-opencode/SKILL.md:115` описание `read` исправлено на "объект pattern → action (allow/deny/ask)". - [ ] CI зелёный после PR.
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#38
No description provided.