fix(config): rename CONTEX7 typo + update stale config/scripts paths (#44)

* fix(config): rename CONTEX7_API_KEY to CONTEXT7_API_KEY

* fix(permissions): update stale config/scripts paths to .opencode/scripts

* test(config): add tests for typo fix and updated paths

* docs(handoff): add handoff and ADR-018 for hotfix

* docs(handoff): set PR number

---------

Co-authored-by: opencode-agent <agent@slaid098.dev>
This commit is contained in:
Sergey 2026-07-24 17:50:33 +03:00 committed by GitHub
parent 67174b4879
commit f06c9f2422
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 129 additions and 10 deletions

View file

@ -9,7 +9,7 @@ OPENCODE_SERVER_PASSWORD=your-opencode-server-password
GITHUB_TOKEN=your-github-token-here
# Context7 MCP
CONTEX7_API_KEY=your-context7-api-key-here
CONTEXT7_API_KEY=your-context7-api-key-here
# Telegram (optional)
TELEGRAM_API_ID=your-telegram-api-id

View file

@ -58,12 +58,12 @@ permission:
"echo *": allow
"python3*": allow
"python3 *pipeline-status.py*": deny
"python3 config/scripts/pipeline-status.py*": deny
"python3 .opencode/scripts/pipeline-status.py*": deny
"python3 */pipeline-status.py*": deny
"python *pipeline-status.py*": deny
"python */pipeline-status.py*": deny
"python3 *spec-status.py*": deny
"python3 config/scripts/spec-status.py*": deny
"python3 .opencode/scripts/spec-status.py*": deny
"python3 */spec-status.py*": deny
"python *spec-status.py*": deny
"python */spec-status.py*": deny

View file

@ -69,12 +69,12 @@ permission:
"python3*": allow
"python *": allow
"python3 *pipeline-status.py*": deny
"python3 config/scripts/pipeline-status.py*": deny
"python3 .opencode/scripts/pipeline-status.py*": deny
"python3 */pipeline-status.py*": deny
"python *pipeline-status.py*": deny
"python */pipeline-status.py*": deny
"python3 *spec-status.py*": deny
"python3 config/scripts/spec-status.py*": deny
"python3 .opencode/scripts/spec-status.py*": deny
"python3 */spec-status.py*": deny
"python *spec-status.py*": deny
"python */spec-status.py*": deny

View file

@ -215,12 +215,12 @@
"npm *": "allow",
"python*": "allow",
"python3 *pipeline-status.py*": "deny",
"python3 config/scripts/pipeline-status.py*": "deny",
"python3 .opencode/scripts/pipeline-status.py*": "deny",
"python3 */pipeline-status.py*": "deny",
"python *pipeline-status.py*": "deny",
"python */pipeline-status.py*": "deny",
"python3 *spec-status.py*": "deny",
"python3 config/scripts/spec-status.py*": "deny",
"python3 .opencode/scripts/spec-status.py*": "deny",
"python3 */spec-status.py*": "deny",
"python *spec-status.py*": "deny",
"python */spec-status.py*": "deny",
@ -366,7 +366,7 @@
"-y",
"@upstash/context7-mcp",
"--api-key",
"{env:CONTEX7_API_KEY}"
"{env:CONTEXT7_API_KEY}"
],
"enabled": true
},

View file

@ -7,8 +7,8 @@ import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
AGENTS_DIR = REPO_ROOT / "config" / "agents"
OPENCODE_JSON = REPO_ROOT / "config" / "opencode.json"
AGENTS_DIR = REPO_ROOT / ".opencode" / "agents"
OPENCODE_JSON = REPO_ROOT / ".opencode" / "opencode.json"
DANGEROUS_PATTERNS = [
(r"^gh api\*?$", "broad — allows gh api -X DELETE/PUT/POST"),

View file

@ -0,0 +1,39 @@
# ADR-018: Hotfix CONTEX7 typo + stale config/scripts paths
## Статус
Accepted (2026-07-24)
## Контекст
После миграции `config/``.opencode/` (PR#23, ADR-002) остались stale пути в deny rules, check-permissions.py и agent frontmatter. Также обнаружен typo `CONTEX7_API_KEY` (должно быть `CONTEXT7_API_KEY`) в 2 активных файлах — Context7 MCP не резолвит API key из-за несовпадения имён env var (`{env:CONTEX7_API_KEY}` в opencode.json не матчит `CONTEXT7_API_KEY` в окружении, и наоборот).
Зафиксировано как known issue:
- PR#24 digest: "env var `CONTEX7_API_KEY` (typo) захардкожена в 3 файлах... Не исправлено в PR#24 (вне scope). Следующий PR должен rename."
- PR#40 watch out: "check-permissions.py пути: скрипт использует `config/agents` и `config/opencode.json`, но файлы в `.opencode/`... Исправление путей — отдельный PR."
Stale `config/scripts/` deny rules в opencode.json (lines 218, 223) — мёртвый код (широкие паттерны `python3 *pipeline-status.py*` / `python3 */pipeline-status.py*` уже работали, матчат любой путь). Узкие `python3 config/scripts/...` — нет, т.к. директория мигрировала.
## Решение
### 1. CONTEX7 typo fix (2 файла)
- `.env.example:12``CONTEX7_API_KEY``CONTEXT7_API_KEY`
- `.opencode/opencode.json:369``"{env:CONTEX7_API_KEY}"``"{env:CONTEXT7_API_KEY}"`
Исторические `docs/handoff/pr-27-*` и `docs/decisions/007-pr-27-*` НЕ тронуты — это историческая документация миграции, не активный код. `CONTEX7` в них описывает что было dropped.
### 2. Stale config/scripts paths → .opencode/scripts (4 файла)
- `.opencode/opencode.json:218,223` — deny rules `python3 config/scripts/pipeline-status.py*` / `python3 config/scripts/spec-status.py*``.opencode/scripts/...`
- `.opencode/scripts/check-permissions.py:10-11``REPO_ROOT / "config" / "agents"` / `REPO_ROOT / "config" / "opencode.json"``.opencode/agents` / `.opencode/opencode.json`
- `.opencode/agents/reviewer.md:72,77` — deny rules → `.opencode/scripts/...`
- `.opencode/agents/docs-reviewer.md:61,66` — deny rules → `.opencode/scripts/...`
Узкие deny паттерны обновлены (НЕ удалены) — explicit > implicit. Широкие паттерны `python3 *pipeline-status.py*` / `python3 */pipeline-status.py*` уже покрывали (матчат любой путь), но узкие паттерны документируют конкретный path и добавляют defense-in-depth.
### 3. Тесты (6 новых)
- `tests/test_permissions.py` — 4 теста: `CONTEXT7_API_KEY` present в `.env.example` и `opencode.json`; `CONTEX7_API_KEY` (typo) absent из обоих.
- `tests/test_check_permissions.py` — 2 теста: `AGENTS_DIR` points to `.opencode/agents/` (exists); `OPENCODE_JSON` points to `.opencode/opencode.json` (exists).
## Альтернативы
- **Удалить узкие deny паттерны вместо обновления** — отклонено: issue допускал оба варианта, но обновление сохраняет explicit path documentation + defense-in-depth. Удаление оставило бы gap если широкие паттерны когда-то изменят. Consistency с actual `.opencode/scripts/` path.
- **Тронуть исторические `CONTEX7` references в docs/handoff/pr-27 и docs/decisions/007** — отклонено: issue явно запрещает ("НЕ трогать `docs/handoff/pr-27-*` и `docs/decisions/007-pr-27-*` — исторические"). Это историческая документация миграции, `CONTEX7` описывает что было dropped в PR#27.
- **Fix all `config/scripts` references (docstrings, prompt body)** — отклонено: вне scope hotfix. Issue перечисляет конкретные строки (deny rules, check-permissions.py paths, agent frontmatter deny rules). Cosmetic references в docstrings/usage comments (pipeline-status.py:10-11,319; spec-status.py:12-13; scaffold-handoff.sh:3; reviewer.md:99; docs-reviewer.md:111; spec/SKILL.md:28) — potential follow-up cleanup PR.
- **Добавить auto-migration для `.env` пользователей** — отклонено: `.env` gitignored, скрипт не может его редактировать. User-facing note в handoff Watch out — достаточно.

View file

@ -0,0 +1,37 @@
---
pr: 44
title: rename CONTEX7 typo + update stale config/scripts paths
---
# PR: rename CONTEX7 typo + update stale config/scripts paths
## Что сделано
- `.env.example:12``CONTEX7_API_KEY``CONTEXT7_API_KEY` (typo fix). Context7 MCP теперь резолвит API key.
- `.opencode/opencode.json:369``"{env:CONTEX7_API_KEY}"``"{env:CONTEXT7_API_KEY}"` (typo fix в context7 MCP server config).
- `.opencode/opencode.json:218,223` — deny rules `python3 config/scripts/pipeline-status.py*` / `python3 config/scripts/spec-status.py*``.opencode/scripts/...` (stale paths после миграции config/ → .opencode/ PR#23). Широкие паттерны `python3 *pipeline-status.py*` / `python3 */pipeline-status.py*` уже работали (матчат любой путь); узкие `config/scripts/...` — мёртвый код. Узкие обновлены на актуальный путь.
- `.opencode/scripts/check-permissions.py:10-11``REPO_ROOT / "config" / "agents"` / `REPO_ROOT / "config" / "opencode.json"``.opencode/agents` / `.opencode/opencode.json`. Скрипт был бесполезен (paths не существовали → `AGENTS_DIR.exists()` / `OPENCODE_JSON.exists()` → False → false negative "OK").
- `.opencode/agents/reviewer.md:72,77` — deny rules `python3 config/scripts/...``.opencode/scripts/...` (консистентно с global opencode.json).
- `.opencode/agents/docs-reviewer.md:61,66` — deny rules `python3 config/scripts/...``.opencode/scripts/...` (консистентно с global opencode.json).
- `tests/test_permissions.py` — 4 новых теста: `CONTEXT7_API_KEY` present в `.env.example` и `opencode.json`; `CONTEX7_API_KEY` (typo) absent из обоих файлов.
- `tests/test_check_permissions.py` — 2 новых теста: `AGENTS_DIR` points to `.opencode/agents/` (exists); `OPENCODE_JSON` points to `.opencode/opencode.json` (exists).
- ADR-018 + этот handoff
## Почему
После миграции `config/``.opencode/` (PR#23) остались stale пути в deny rules, check-permissions.py и agent frontmatter (зафиксировано в PR#24 digest как known issue, в PR#40 watch out как pre-existing). Также обнаружен typo `CONTEX7_API_KEY` (должно быть `CONTEXT7_API_KEY`) — Context7 MCP не резолвит env var из-за несовпадения имён.
Этот PR — hotfix, чинит 2 проблемы в минимальном scope:
1. Typo `CONTEX7``CONTEXT7` в 2 активных файлах (`.env.example`, `.opencode/opencode.json`). Исторические `docs/handoff/pr-27-*` и `docs/decisions/007-pr-27-*` НЕ тронуты — это историческая документация, не активный код.
2. Stale `config/scripts/``.opencode/scripts/` в deny rules (opencode.json), check-permissions.py paths, agent frontmatter (reviewer.md, docs-reviewer.md). Узкие deny паттерны актуализированы (широкие уже работали).
Остальные `config/scripts` references (docstrings в pipeline-status.py, spec-status.py, scaffold-handoff.sh usage comment, prompt-body explanations в agents/skills) — ВНЕ scope этого hotfix. Они cosmetic (не functional — deny rules и paths исправлены), cleanup возможен в отдельном PR.
## Pending
- Cosmetic `config/scripts` references в docstrings/usage comments (pipeline-status.py:10-11,319; spec-status.py:12-13; scaffold-handoff.sh:3; reviewer.md:99 prompt body; docs-reviewer.md:111 prompt body; spec/SKILL.md:28) — вне scope этого hotfix, potential follow-up cleanup PR.
- `CONTEX7_API_KEY` в `.env` пользователей (если скопировали из старого `.env.example`) — rename не автоматический, user-facing note может потребоваться.
## Watch out
- **`.env` пользователей НЕ обновляется автоматически** — typo fix только в `.env.example`. Пользователи, скопировавшие `.env` из старого `.env.example`, имеют `CONTEX7_API_KEY` (typo) в своём `.env`. После pull им нужно вручную rename в `.env``CONTEXT7_API_KEY`, иначе context7 MCP не резолвит key.
- **Исторические `CONTEX7` references сохранены**`docs/handoff/pr-27-configure-opencode-rewrite.md:6` и `docs/decisions/007-pr-27-configure-opencode-rewrite.md:11` НЕ тронуты (историческая документация). `check-adr-refs.py` не падает — эти файлы не содержат `ADR-NNN` refs к `CONTEX7`.
- **Узкие deny паттерны обновлены, НЕ удалены** — issue допускал оба варианта (обновить ИЛИ удалить, т.к. широкие `python3 *pipeline-status.py*` / `python3 */pipeline-status.py*` покрывают). Решено обновить (consistency с `.opencode/scripts/` actual path, explicit > implicit). Удаление оставило бы gap если широкие паттерны когда-то изменят.
- **check-permissions.py теперь реально проверяет конфиги** — до фикса скрипт возвращал false negative "OK" (paths не существовали → violations=[] → exit 0). После фикса он находит `.opencode/agents/*.md` и `.opencode/opencode.json` и реально валидирует. Существующие тесты `test_check_permissions_passes` / `test_clean_configs_pass` подтверждают exit 0 (конфиги чистые).
- ADR number = sequential (018), НЕ PR number. Проверить ADR naming в handoff до push (эволюция паттерна PR#26 docs-reviewer typo).

View file

@ -39,6 +39,21 @@ def _load_script():
cp = _load_script()
# ── paths point to .opencode (issue #43) ────────────────────────────────────
def test_agents_dir_points_to_opencode():
"""AGENTS_DIR points to .opencode/agents/ and the directory exists."""
assert cp.AGENTS_DIR == REPO_ROOT / ".opencode" / "agents"
assert cp.AGENTS_DIR.exists(), f"AGENTS_DIR does not exist: {cp.AGENTS_DIR}"
def test_opencode_json_path_points_to_opencode():
"""OPENCODE_JSON points to .opencode/opencode.json and the file exists."""
assert cp.OPENCODE_JSON == REPO_ROOT / ".opencode" / "opencode.json"
assert cp.OPENCODE_JSON.exists(), f"OPENCODE_JSON does not exist: {cp.OPENCODE_JSON}"
# ── clean configs (subprocess black-box) ────────────────────────────────────

View file

@ -19,6 +19,7 @@ from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
OPENCODE_JSON = REPO_ROOT / ".opencode" / "opencode.json"
CHECK_PERM_SCRIPT = REPO_ROOT / ".opencode" / "scripts" / "check-permissions.py"
ENV_EXAMPLE = REPO_ROOT / ".env.example"
def _load_config() -> dict:
@ -26,6 +27,33 @@ def _load_config() -> dict:
return json.load(f)
# ── CONTEXT7_API_KEY typo fix (issue #43) ────────────────────────────────────
def test_context7_api_key_present_in_env_example():
"""CONTEXT7_API_KEY (correct) is present in .env.example."""
content = ENV_EXAMPLE.read_text()
assert "CONTEXT7_API_KEY=" in content, "CONTEXT7_API_KEY missing from .env.example"
def test_context7_api_key_absent_in_env_example():
"""CONTEX7_API_KEY (typo) is absent from .env.example."""
content = ENV_EXAMPLE.read_text()
assert "CONTEX7_API_KEY=" not in content, "typo CONTEX7_API_KEY still in .env.example"
def test_context7_api_key_present_in_opencode_json():
"""CONTEXT7_API_KEY (correct) is referenced in opencode.json (context7 MCP)."""
content = OPENCODE_JSON.read_text()
assert "{env:CONTEXT7_API_KEY}" in content, "CONTEXT7_API_KEY missing from opencode.json"
def test_context7_api_key_absent_in_opencode_json():
"""CONTEX7_API_KEY (typo) is absent from opencode.json."""
content = OPENCODE_JSON.read_text()
assert "{env:CONTEX7_API_KEY}" not in content, "typo CONTEX7_API_KEY still in opencode.json"
# ── global deny rules ───────────────────────────────────────────────────────