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:
parent
67174b4879
commit
f06c9f2422
9 changed files with 129 additions and 10 deletions
|
|
@ -9,7 +9,7 @@ OPENCODE_SERVER_PASSWORD=your-opencode-server-password
|
||||||
GITHUB_TOKEN=your-github-token-here
|
GITHUB_TOKEN=your-github-token-here
|
||||||
|
|
||||||
# Context7 MCP
|
# Context7 MCP
|
||||||
CONTEX7_API_KEY=your-context7-api-key-here
|
CONTEXT7_API_KEY=your-context7-api-key-here
|
||||||
|
|
||||||
# Telegram (optional)
|
# Telegram (optional)
|
||||||
TELEGRAM_API_ID=your-telegram-api-id
|
TELEGRAM_API_ID=your-telegram-api-id
|
||||||
|
|
|
||||||
|
|
@ -58,12 +58,12 @@ permission:
|
||||||
"echo *": allow
|
"echo *": allow
|
||||||
"python3*": allow
|
"python3*": allow
|
||||||
"python3 *pipeline-status.py*": deny
|
"python3 *pipeline-status.py*": deny
|
||||||
"python3 config/scripts/pipeline-status.py*": deny
|
"python3 .opencode/scripts/pipeline-status.py*": deny
|
||||||
"python3 */pipeline-status.py*": deny
|
"python3 */pipeline-status.py*": deny
|
||||||
"python *pipeline-status.py*": deny
|
"python *pipeline-status.py*": deny
|
||||||
"python */pipeline-status.py*": deny
|
"python */pipeline-status.py*": deny
|
||||||
"python3 *spec-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
|
"python3 */spec-status.py*": deny
|
||||||
"python *spec-status.py*": deny
|
"python *spec-status.py*": deny
|
||||||
"python */spec-status.py*": deny
|
"python */spec-status.py*": deny
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,12 @@ permission:
|
||||||
"python3*": allow
|
"python3*": allow
|
||||||
"python *": allow
|
"python *": allow
|
||||||
"python3 *pipeline-status.py*": deny
|
"python3 *pipeline-status.py*": deny
|
||||||
"python3 config/scripts/pipeline-status.py*": deny
|
"python3 .opencode/scripts/pipeline-status.py*": deny
|
||||||
"python3 */pipeline-status.py*": deny
|
"python3 */pipeline-status.py*": deny
|
||||||
"python *pipeline-status.py*": deny
|
"python *pipeline-status.py*": deny
|
||||||
"python */pipeline-status.py*": deny
|
"python */pipeline-status.py*": deny
|
||||||
"python3 *spec-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
|
"python3 */spec-status.py*": deny
|
||||||
"python *spec-status.py*": deny
|
"python *spec-status.py*": deny
|
||||||
"python */spec-status.py*": deny
|
"python */spec-status.py*": deny
|
||||||
|
|
|
||||||
|
|
@ -215,12 +215,12 @@
|
||||||
"npm *": "allow",
|
"npm *": "allow",
|
||||||
"python*": "allow",
|
"python*": "allow",
|
||||||
"python3 *pipeline-status.py*": "deny",
|
"python3 *pipeline-status.py*": "deny",
|
||||||
"python3 config/scripts/pipeline-status.py*": "deny",
|
"python3 .opencode/scripts/pipeline-status.py*": "deny",
|
||||||
"python3 */pipeline-status.py*": "deny",
|
"python3 */pipeline-status.py*": "deny",
|
||||||
"python *pipeline-status.py*": "deny",
|
"python *pipeline-status.py*": "deny",
|
||||||
"python */pipeline-status.py*": "deny",
|
"python */pipeline-status.py*": "deny",
|
||||||
"python3 *spec-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",
|
"python3 */spec-status.py*": "deny",
|
||||||
"python *spec-status.py*": "deny",
|
"python *spec-status.py*": "deny",
|
||||||
"python */spec-status.py*": "deny",
|
"python */spec-status.py*": "deny",
|
||||||
|
|
@ -366,7 +366,7 @@
|
||||||
"-y",
|
"-y",
|
||||||
"@upstash/context7-mcp",
|
"@upstash/context7-mcp",
|
||||||
"--api-key",
|
"--api-key",
|
||||||
"{env:CONTEX7_API_KEY}"
|
"{env:CONTEXT7_API_KEY}"
|
||||||
],
|
],
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||||
AGENTS_DIR = REPO_ROOT / "config" / "agents"
|
AGENTS_DIR = REPO_ROOT / ".opencode" / "agents"
|
||||||
OPENCODE_JSON = REPO_ROOT / "config" / "opencode.json"
|
OPENCODE_JSON = REPO_ROOT / ".opencode" / "opencode.json"
|
||||||
|
|
||||||
DANGEROUS_PATTERNS = [
|
DANGEROUS_PATTERNS = [
|
||||||
(r"^gh api\*?$", "broad — allows gh api -X DELETE/PUT/POST"),
|
(r"^gh api\*?$", "broad — allows gh api -X DELETE/PUT/POST"),
|
||||||
|
|
|
||||||
39
docs/decisions/018-pr-44-hotfix-config-paths.md
Normal file
39
docs/decisions/018-pr-44-hotfix-config-paths.md
Normal 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 — достаточно.
|
||||||
37
docs/handoff/pr-44-hotfix-config-paths.md
Normal file
37
docs/handoff/pr-44-hotfix-config-paths.md
Normal 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).
|
||||||
|
|
@ -39,6 +39,21 @@ def _load_script():
|
||||||
cp = _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) ────────────────────────────────────
|
# ── clean configs (subprocess black-box) ────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ from pathlib import Path
|
||||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
OPENCODE_JSON = REPO_ROOT / ".opencode" / "opencode.json"
|
OPENCODE_JSON = REPO_ROOT / ".opencode" / "opencode.json"
|
||||||
CHECK_PERM_SCRIPT = REPO_ROOT / ".opencode" / "scripts" / "check-permissions.py"
|
CHECK_PERM_SCRIPT = REPO_ROOT / ".opencode" / "scripts" / "check-permissions.py"
|
||||||
|
ENV_EXAMPLE = REPO_ROOT / ".env.example"
|
||||||
|
|
||||||
|
|
||||||
def _load_config() -> dict:
|
def _load_config() -> dict:
|
||||||
|
|
@ -26,6 +27,33 @@ def _load_config() -> dict:
|
||||||
return json.load(f)
|
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 ───────────────────────────────────────────────────────
|
# ── global deny rules ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue