novahiz 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/NOTICE.md CHANGED
@@ -43,6 +43,7 @@ Installed on demand with `npx skills add` (or an upstream tarball when git trans
43
43
  | `flutter-skills` | https://github.com/flutter/agent-plugins | BSD-3-Clause |
44
44
  | `dart-skills` | https://github.com/dart-lang/skills | BSD-3-Clause |
45
45
  | `expo-skills` | https://github.com/expo/skills | MIT |
46
+ | `impeccable` | https://github.com/pbakaus/impeccable | Apache-2.0 |
46
47
 
47
48
  ## opencode plugins (third-party)
48
49
 
package/README.md CHANGED
@@ -274,7 +274,7 @@ Novahiz auto-registers external MCP servers based on the prompt category:
274
274
  | cron | `scheduler-mcp` (local venv clone) | MIT | devops |
275
275
  | dart | `dart mcp-server` (Dart SDK) | BSD-3-Clause | code, debug, design-ui, flutter |
276
276
 
277
- Skill packs (installed from official repos, never vendored): `flutter/agent-plugins` (25 skills), `dart-lang/skills` (15 skills), `expo/skills` (17 skills, the `expo-*` group only; `eas-*` paid services excluded). See [docs/PROVIDERS.md](docs/PROVIDERS.md).
277
+ Skill packs (installed from official repos, never vendored): `flutter/agent-plugins` (25 skills), `dart-lang/skills` (15 skills), `expo/skills` (17 skills, the `expo-*` group only; `eas-*` paid services excluded), `pbakaus/impeccable` (1 skill, the upstream `impeccable` design skill). See [docs/PROVIDERS.md](docs/PROVIDERS.md).
278
278
 
279
279
  Upstream repositories and full provenance for MCP providers and opencode plugins: [docs/PROVIDERS.md](docs/PROVIDERS.md), [docs/HARNESSES.md](docs/HARNESSES.md), [NOTICE.md](NOTICE.md).
280
280
 
@@ -39,20 +39,21 @@
39
39
  "id": "cron",
40
40
  "label": "Cron Scheduler",
41
41
  "kind": "mcp",
42
- "command": ["C:/Users/hiz/.local/share/mcp-scheduler/.venv/Scripts/python.exe", "C:/Users/hiz/.local/share/mcp-scheduler/main.py"],
42
+ "command": ["python", "C:/path/to/scheduler-mcp/main.py"],
43
43
  "source": "https://github.com/PhialsBasement/scheduler-mcp",
44
44
  "license": "MIT",
45
45
  "categories": ["devops"],
46
- "purpose": "Local MIT scheduler clone at C:/Users/hiz/.local/share/mcp-scheduler (requirements pin mcp<2)."
46
+ "purpose": "MIT scheduler clone (requirements pin mcp<2); no npm package exists. Clone PhialsBasement/scheduler-mcp, install its requirements into a venv, then point `command` at that venv's python and your clone's main.py (setup in docs/PROVIDERS.md). Shipped disabled: enable it after the local setup."
47
47
  },
48
48
  {
49
49
  "id": "novahiz",
50
50
  "label": "novahiz",
51
51
  "kind": "mcp",
52
- "command": ["node", "C:/Users/hiz/.config/novahiz/mcp/novahiz-tools/index.mjs"],
52
+ "command": ["node", "~/.config/novahiz/mcp/novahiz-tools/index.mjs"],
53
53
  "source": "https://github.com/novahiz/novahiz",
54
54
  "license": "Apache-2.0",
55
- "categories": ["code", "planning"]
55
+ "categories": ["code", "planning"],
56
+ "purpose": "Novahiz stdio MCP (novahiz_providers, novahiz_deps, memory tools). The opencode plugin resolves this path from the home directory itself; edit the command for other harnesses."
56
57
  },
57
58
  {
58
59
  "id": "dart",
@@ -94,5 +95,15 @@
94
95
  "license": "MIT",
95
96
  "categories": ["code", "expo"],
96
97
  "purpose": "17 official Expo framework skills (expo-* group); the 7 eas-* paid-service skills are excluded. Installed to ~/.agents/skills; when git clone fails, fetch the tarball from codeload.github.com and copy the skill folders."
98
+ },
99
+ {
100
+ "id": "impeccable",
101
+ "label": "Impeccable design skill",
102
+ "kind": "skill",
103
+ "install": ["npx", "-y", "skills@1.7.0", "add", "pbakaus/impeccable", "--skill", "impeccable", "-g", "-a", "opencode", "-y"],
104
+ "source": "https://github.com/pbakaus/impeccable",
105
+ "license": "Apache-2.0",
106
+ "categories": ["design-ui"],
107
+ "purpose": "Upstream Impeccable skill (critique, audit and polish playbooks) required by gate rule R14. Installed to ~/.agents/skills; rerun the command to update."
97
108
  }
98
109
  ]
package/docs/CATALOG.md CHANGED
@@ -8,7 +8,7 @@ The catalog is the knowledge base of Novahiz. It defines what categories exist,
8
8
  catalog/
9
9
  ├── categories.json # 17 categories with keywords, skills, roadmaps
10
10
  ├── rules.json # 11 pre-edit rules (file class + content triggers)
11
- ├── providers.json # 10 external providers (7 MCP + 3 skill packs)
11
+ ├── providers.json # 11 external providers (7 MCP + 4 skill packs)
12
12
  └── overrides.json # Manual skill curation (power, stars, tags)
13
13
  ```
14
14
 
@@ -41,7 +41,7 @@ These files live in `catalog/` and are part of the git repository:
41
41
  "providers": {
42
42
  "autoRegister": true,
43
43
  "autoInstall": false,
44
- "disabled": []
44
+ "disabled": ["cron"]
45
45
  },
46
46
  "ledger": {
47
47
  "enabled": true,
@@ -69,7 +69,7 @@ These files live in `catalog/` and are part of the git repository:
69
69
  | `classify.fallbackCategory` | `general` | Fallback when no category matches |
70
70
  | `providers.autoRegister` | `true` | Auto-register MCP providers |
71
71
  | `providers.autoInstall` | `false` | Auto-install provider dependencies |
72
- | `providers.disabled` | `[]` | Providers to skip |
72
+ | `providers.disabled` | `["cron"]` | Providers to skip (`cron` needs a local scheduler clone first) |
73
73
  | `ledger.enabled` | `true` | Enable the task ledger |
74
74
  | `ledger.review.edits` | `3` | Force review after N edits |
75
75
  | `ledger.review.todos` | `2` | Force review after N completed todos |
package/docs/PROVIDERS.md CHANGED
@@ -46,7 +46,7 @@ MCP servers, with provenance from `catalog/providers.json`:
46
46
  | `novahiz` | local (`mcp/novahiz-tools`) | [novahiz/novahiz](https://github.com/novahiz/novahiz) | Apache-2.0 | code, planning |
47
47
  | `dart` | `dart mcp-server` (Dart SDK) | [dart-lang/ai · dart_mcp_server](https://github.com/dart-lang/ai/tree/main/pkgs/dart_mcp_server) | BSD-3-Clause | code, debug, design-ui, flutter |
48
48
 
49
- `cron` runs `scheduler-mcp` (MIT) from a local clone at `C:/Users/hiz/.local/share/mcp-scheduler` with its own virtualenv. It replaced the former AGPL `mcp-cron` npm package; there is no npm install step for it.
49
+ `cron` runs `scheduler-mcp` (MIT) from a local clone with its own virtualenv. It replaced the former AGPL `mcp-cron` npm package; there is no npm install step for it. It ships disabled because the `command` has to point at your own clone: install the upstream requirements into a venv, set `command` to that venv's python plus your clone's `main.py`, then remove `cron` from `providers.disabled`.
50
50
 
51
51
  `dart` requires the Dart SDK on `PATH` (`requires: ["dart"]`). Without it the MCP entry still registers, but the server fails to start; disable it or install the SDK.
52
52
 
@@ -57,12 +57,13 @@ Skill and command packs:
57
57
  | `flutter-skills` | `npx skills add flutter/agent-plugins --skill '*' -g -a opencode -y` | [flutter/agent-plugins](https://github.com/flutter/agent-plugins) | BSD-3-Clause | code, design-ui, flutter |
58
58
  | `dart-skills` | `npx skills add dart-lang/skills --skill '*' -g -a opencode -y` | [dart-lang/skills](https://github.com/dart-lang/skills) | BSD-3-Clause | code, debug, flutter |
59
59
  | `expo-skills` | `npx skills add expo/skills --skill expo-overview ... -g -a opencode -y` | [expo/skills](https://github.com/expo/skills) | MIT | code, expo |
60
+ | `impeccable` | `npx skills add pbakaus/impeccable --skill impeccable -g -a opencode -y` | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) | Apache-2.0 | design-ui |
60
61
 
61
62
  Installed skills land under `~/.agents/skills` for OpenCode. They are referenced by install command, never vendored in this repository. `dart-lang/skills` is a subset of `flutter/agent-plugins` (same 15 Dart skills); both are listed for provenance.
62
63
 
63
64
  `expo-skills` names the 17 `expo-*` skills explicitly; the 7 `eas-*` skills (paid EAS services) are excluded. When `npx skills add` cannot reach the repo (git clone failures), fetch the tarball from `codeload.github.com` and copy the skill folders into `~/.agents/skills`, then run `Novahiz sync` — that fallback was used on this machine.
64
65
 
65
- Design and text skills ship as ordinary Novahiz skills under `skills/`, not as providers.
66
+ `impeccable` is the one design skill referenced as a provider: gate rule R14 requires it, and it installs from upstream under its own Apache-2.0 terms instead of being vendored. The other design and text skills ship as ordinary Novahiz skills under `skills/`, not as providers.
66
67
 
67
68
  ## Mapping
68
69
 
@@ -92,7 +93,7 @@ Control it in `novahiz.config.json`:
92
93
 
93
94
  - `autoRegister`: register missing MCP servers on startup.
94
95
  - `autoInstall`: run the official install commands during `node install/install.mjs`.
95
- - `disabled`: provider ids to skip.
96
+ - `disabled`: provider ids to skip. `cron` ships disabled by default; enable it after the local scheduler setup described above.
96
97
 
97
98
  Run the install commands on demand:
98
99
 
@@ -58,7 +58,7 @@ function defaultConfig(skillsDir) {
58
58
  providers: {
59
59
  autoRegister: true,
60
60
  autoInstall: false,
61
- disabled: []
61
+ disabled: ["cron"]
62
62
  }
63
63
  };
64
64
  }
@@ -314,8 +314,8 @@ async function main() {
314
314
  { pkg: "narsil-mcp", bin: "narsil-mcp", name: "narsil" },
315
315
  { pkg: "security-mcp", bin: "security-mcp", name: "security" },
316
316
  ];
317
- // `cron` has no npm package: the plugin registers it from catalog/providers.json
318
- // (scheduler-mcp local venv, see docs/PROVIDERS.md).
317
+ // `cron` has no npm package and ships disabled (local scheduler clone only);
318
+ // enable it after the local setup documented in docs/PROVIDERS.md.
319
319
 
320
320
  if (!dryRun) {
321
321
  note("\nInstalling MCP servers...");
@@ -418,8 +418,8 @@ async function main() {
418
418
  "timeout": 120000,
419
419
  "enabled": true
420
420
  },
421
- // `cron` is registered by the plugin from catalog/providers.json
422
- // (scheduler-mcp local venv); no npm install, no template entry.
421
+ // `cron` ships disabled by default: no template entry here, enable it
422
+ // after the local scheduler clone setup (docs/PROVIDERS.md).
423
423
  "playwright": {
424
424
  "type": "local",
425
425
  "command": ["npx", "@playwright/mcp@latest", "--browser=msedge"],
@@ -18,7 +18,7 @@
18
18
  "providers": {
19
19
  "autoRegister": true,
20
20
  "autoInstall": false,
21
- "disabled": []
21
+ "disabled": ["cron"]
22
22
  },
23
23
  "tokens": {
24
24
  "enabled": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "novahiz",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Enforce AI agent skills before every file edit: prompt classifier, skill catalog, and pre-edit gate.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -60,6 +60,7 @@
60
60
  "mcp",
61
61
  "skills",
62
62
  "docs",
63
+ "!docs/audit-2026-09-25.md",
63
64
  "README.md",
64
65
  "NOTICE.md",
65
66
  "novahiz.config.example.json",
package/src/spec.ts CHANGED
@@ -171,7 +171,7 @@ export const DEFAULT_CONFIG: NovahizConfig = {
171
171
  providers: {
172
172
  autoRegister: true,
173
173
  autoInstall: false,
174
- disabled: []
174
+ disabled: ["cron"]
175
175
  },
176
176
  ledger: {
177
177
  enabled: true,
@@ -1,275 +0,0 @@
1
- # Audit en profondeur du système Novahiz — 2026-09-25
2
-
3
- ## Méthode
4
-
5
- - Demande utilisateur : auditer en profondeur Novahiz, plugins un à un, serveurs MCP, tools, rules, catalogue.
6
- - 5 sous-agents reviewer en lecture seule, un par axe. Session IDs pour traçabilité :
7
- - Plugins : `ses_f285bcda6ffef7ox95YLcQxx0H`
8
- - MCP : `ses_f285b9f3fffe27HJYbhwpe3t1N`
9
- - Rules & gate : `ses_f285b6f8bffeWWcf0e5nSMCyBi`
10
- - Tools : `ses_f285b405bffe7MkZh0NAxD9Rbc`
11
- - Catalogue : `ses_f285b0a9cffe7J5YB25MiVtPZ8`
12
- - Périmètre : `C:\Users\hiz\.config\novahiz`, `C:\Users\hiz\.config\opencode`, `opencode.jsonc`, `dcp.jsonc`, `.config\.mcp\`, `~/.agents/skills`, `.config\.agents\skills`.
13
- - Audit seul : aucun correctif n'a été appliqué. Chaque finding cite un fichier et une ligne vérifiés par l'agent qui l'a produit.
14
- - Hors périmètre : comportement runtime du navigateur, contenu des sessions, audit de dépendances des paquets tiers installés.
15
-
16
- ## Vue d'ensemble
17
-
18
- | Axe | Findings | Répartition |
19
- |---|---|---|
20
- | 1. Plugins opencode | 24 | 3 HIGH, 5 MEDIUM, 6 LOW, 10 INFO |
21
- | 2. Serveurs MCP (7 résolus) | 31 listés (l'agent déclare 32, voir Inconnus) | 2 HIGH, 9 MEDIUM, 11 LOW, 9 INFO |
22
- | 3. Rules & gate | 29 | 3 CRITICAL, 6 MAJEUR (=HIGH), 9 MINEUR (=MEDIUM), 11 SUGGESTION |
23
- | 4. Tools (CLI, MCP tools, scripts) | 25 | 3 HIGH, 8 MEDIUM, 10 LOW, 4 INFO |
24
- | 5. Catalogue de skills | 22 | 2 HIGH, 4 MEDIUM, 10 LOW, 6 INFO |
25
- | **Total** | **131** | **3 CRITICAL, 16 HIGH, 35 MEDIUM, 37 LOW, 40 INFO/SUGGESTION** |
26
-
27
- Six findings sont présents sous deux angles différents (doublons inter-axes listés plus bas) : environ 125 uniques.
28
-
29
- Verdict global : **le gate, qui est le cœur du système, échoue en fail-open sur trois axes d'entrée** (classification du prompt, config éditable, index des skills). Les garde-fous existent et sont testés sur les chemins heureux, mais plusieurs chemins d'erreur contournent l'enforcement sans log visible.
30
-
31
- ## Top des blocages
32
-
33
- 1. **[CRITICAL]** `novahiz/src/gate.ts:280` — le tier est calculé sur le contenu édité et non sur le prompt : R6 et la roadmap sont sautées dès que l'édit est court, donc l'étape « plan » n'est presque jamais exigée mécaniquement.
34
- 2. **[CRITICAL]** `novahiz/src/commands/gate.ts:48` — `gate.enabled: false` ou `gate.tools: []` dans `novahiz.config.json` désactive tout l'enforcement sans aucune barrière ni log. Un kill-switch silencieux, éditable par la même session que le gate protège.
35
- 3. **[CRITICAL]** `novahiz/src/spec.ts:137` — l'index des skills est lu sous `**/build/**` : retirer un skill de `build/installed-skills.json` le rend `unmatchedRequired` et donc jamais exigé, sans warning.
36
- 4. **[HIGH]** `plugins/novahiz.ts:401` — un échec de `classify` vide les catégories et neutralise 6 des 11 règles à `promptCategories`, avec seulement un warning en log.
37
- 5. **[HIGH]** `plugins/novahiz.ts:486` — un sessionID vide ou invalide fait retourner le hook avant tout appel au gate : l'outil s'exécute sans contrôle.
38
- 6. **[HIGH]** `plugins/novahiz.ts:494` — `loaded.add` précède la vérification de session-load, et le nom de skill est joint puis resplitté par virgules : des skills inexistants passent pour chargés.
39
- 7. **[HIGH]** `scripts/capture-cli.mjs:69` — `--label` ou `--out` contenant `..` résout hors du dossier de sortie et déclenche un `rmSync` récursif avec `force: true`.
40
- 8. **[HIGH]** `package.json:52` — le `postinstall` exécute `install.mjs --yes` : 5 `npm i -g` non pinnés, écriture de `~/.config/opencode/opencode.jsonc` et `npm update`, sans consentement.
41
- 9. **[HIGH]** `src/exec.ts:53` — `SAFE_BOOTSTRAP_BINS` contient `cmd` et `bash` : un bootstrap `["cmd","/c",…]` dans `catalog/providers.json` fait sauter toute la barrière d'exécution, arguments non validés.
42
- 10. **[HIGH]** `mcp_scheduler/executor.py:119` — l'outil cron planifie des commandes shell persistantes (`cmd.exe /c`) hors du périmètre du gate. La DB est vide aujourd'hui : risque capacitaire.
43
- 11. **[HIGH]** `opencode.jsonc:17` — narsil indexe tout `.config` avec `--git --persist` : journaux et base du scheduler deviennent lisibles via `narsil_get_file` par tout appelant d'outil.
44
- 12. **[HIGH]** `build/installed-skills.json` — index à 84 skills sur 95 présents : 11 skills (eas-* ×7, supabase, supabase-postgres-best-practices, expo-migrate-module, expo-skill-eval) sont invisibles pour le gate et le ranking.
45
- 13. **[HIGH]** `opencode/skills-lock.json` — fichier vide (`{"version":1,"skills":{}}`), lu par aucun code : aucune détection de non-conformité des 95 skills.
46
-
47
- ## 1. Plugins opencode (24 findings)
48
-
49
- Deux plugins chargés : `plugins/novahiz.ts` (le gate, cœur critique) et `plugins/orca-opencode-status.js` (report d'état externe). Le chargement est automatique par scan `plugin/` et `plugins/` (non récursif) ; `opencode.jsonc` ne référence que les plugins npm `@mohak34/opencode-notifier` et `@tarquinen/opencode-dcp`.
50
-
51
- ### plugins/novahiz.ts (14 findings)
52
-
53
- | Sévérité | Finding | Fichier:ligne | Impact |
54
- |---|---|---|---|
55
- | HIGH | Échec de classification = fail-open sur tout le cœur du gate | plugins/novahiz.ts:401-404 | 6 des 11 règles neutralisées, éditions possibles sans skills pipeline |
56
- | HIGH | Bypass total si sessionID invalide | plugins/novahiz.ts:486-487 | Retour avant appel gate, outil exécuté sans contrôle |
57
- | HIGH | Skills comptés chargés sans vérification + injection par virgule | plugins/novahiz.ts:494-501 | Skills inexistants ou multiples passent pour chargés |
58
- | MEDIUM | Prompt passé en argv : injection d'options, fuite, troncature | plugins/novahiz.ts:400 | `--home` détourne le spec, prompt >32767 casse argv Windows, texte visible dans les processus |
59
- | MEDIUM | spawnSync bloque l'événementiel d'opencode | plugins/novahiz.ts:254-260 | Serveur gelé jusqu'à 10 s par appel sur chaque chemin chaud |
60
- | MEDIUM | Enregistrement de commandes MCP depuis un catalog git-oppable non signé | plugins/novahiz.ts:334-340 | Une compromission de `catalog/providers.json` devient exécution au démarrage |
61
- | LOW | TOCTOU et écritures d'état non atomiques | plugins/novahiz.ts:119-121 | État autodocs corrompu ou perdu |
62
- | LOW | Garde anti-traversal incomplète vers un autre lecteur | plugins/novahiz.ts:568-572 | Chemins absolus étrangers dans l'état `.novahiz` |
63
- | LOW | Compteur `sessions` mort et mal nommé | plugins/novahiz.ts:180 | Incrémenté à chaque édition, jamais lu |
64
- | INFO | Duplication à trois niveaux (src/, adapters/, nettoyage) | plugins/novahiz.ts:7-8 | Exposé à la dérive entre copies |
65
- | INFO | Détection de timeout par heuristique fragile | plugins/novahiz.ts:264 | Timeout remonté comme exit 1 générique sur Windows |
66
- | INFO | Effets de bord disque à chaque message | plugins/novahiz.ts:322 | 3 existsSync + création de project-memory au démarrage et par message |
67
- | INFO | Texte d'enforcement en dur dupliqué de la doc | plugins/novahiz.ts:459-462 | Évolution d'AGENTS.md sans mise à jour = system prompt mensonger |
68
- | INFO | Aucune injection shell (point conforme) | plugins/novahiz.ts:254 | spawn sans shell:true : CWE-78 non applicable |
69
-
70
- ### plugins/orca-opencode-status.js (10 findings)
71
-
72
- | Sévérité | Finding | Fichier:ligne | Impact |
73
- |---|---|---|---|
74
- | MEDIUM | Port non validé : le POST peut sortir de la boucle locale | orca-opencode-status.js:342 | Port contenant `@` redirige l'URL avec le header token vers un hôte distant |
75
- | MEDIUM | Un événement malformé tue l'abonnement pour tout le processus | orca-opencode-status.js:1089 | TypeError dans la boucle consume arrête tout report d'état jusqu'au redémarrage |
76
- | LOW | Aucun fichier d'état (correction de prémisse notifier-state) | orca-opencode-status.js:101-133 | État purement en mémoire, rien à recréer |
77
- | LOW | pendingAttentionByKey non borné avant dispose | orca-opencode-status.js:763 | Fuite mémoire jusqu'au dispose |
78
- | LOW | Logique de conversion v2→v1 tripliquée | orca-opencode-status.js:805-817 | Événement ajouté à un seul endroit disparaît silencieusement |
79
- | INFO | console.warn hors canal de log produit | orca-opencode-status.js:65 | Avertissements perdus du flux structuré |
80
- | INFO | IO synchrone sur l'événementiel | orca-opencode-status.js:33 | statSync/readFileSync empilés par événement |
81
- | INFO | Sortie de données de conversation vers un autre processus | orca-opencode-status.js:143 | Jusqu'à 4000 caractères de prompts/réponses vers Orca, secrets possibles |
82
- | INFO | Aucune commande exécutée (point conforme) | orca-opencode-status.js:356 | CWE-78 non applicable |
83
- | INFO | Bornes et timeouts conformes à leurs commentaires | orca-opencode-status.js:96 | Fail-open assumé documenté, non critique |
84
-
85
- ## 2. Serveurs MCP (31 findings listés)
86
-
87
- Sept serveurs résolus : novahiz (15 tools), context7 (2), narsil (~60 tools), cron/scheduler, dart (11), playwright (25), security (46). Les trois derniers points forts vérifiés : fail-closed du gate, validation Zod, HMAC constant-time.
88
-
89
- | Sévérité | Finding | Fichier:ligne | Impact |
90
- |---|---|---|---|
91
- | HIGH | Commandes shell arbitraires persistantes sans validation | mcp_scheduler/executor.py:119-131 | cron planifie `cmd.exe /c` hors gate (DB vide : risque capacitaire) |
92
- | HIGH | narsil indexe .config avec journaux et base de tâches | opencode.jsonc:17 | Logs et scheduler.db lisibles via narsil_get_file par tout appelant |
93
- | MEDIUM | Clé `env` rejetée silencieusement par le schéma McpLocalConfig | opencode.jsonc:24-27 | Config d'environnement de cron inopérante, artefacts dans le workspace |
94
- | MEDIUM | Échecs dart et playwright non journalisés | opencode.log:run 4410c095 | 55 et 30 échecs, zéro outil en session, aucune cause dans le log |
95
- | MEDIUM | Authentification security-mcp inactive | opencode.jsonc:30-35 | SECURITY_MCP_SHARED_SECRET absent : 46 tools (dont fortify auto-apply) utilisables sans auth |
96
- | MEDIUM | Journal d'audit des tools tracké par git | .mcp/audit/tool-calls.jsonl:1 | Inputs/outputs de tools exposés par l'historique git |
97
- | MEDIUM | Injection possible via commandes flottantes `npx -y pkg@latest` | catalog/providers.json:6 | Retrait d'une clé MCP = exécution auto d'un paquet non pinné au démarrage |
98
- | MEDIUM | Mises à jour automatiques de code DCP activées par défaut | dcp.jsonc:1 | Plugin en-process se recharge depuis npm et raw.githubusercontent sans revue |
99
- | MEDIUM | SSRF sur les tâches API du scheduler | mcp_scheduler/executor.py:168-203 | Toute URL acceptée (loopback, link-local), méthode et headers contrôlés |
100
- | MEDIUM | Disponibilité du gate : spawnSync node ETIMEDOUT récurrent | plugins/novahiz.ts:245 | 14 refus fail-closed sur les 23-24/09 (timeout 10 s dépassé) |
101
- | MEDIUM | mcp-audit-report.md périmé | opencode/mcp-audit-report.md:4 | 11 affirmations fausses sur une config antérieure au 24/09, posture GOOD usurpée |
102
- | LOW | root arbitraire dans les tools memory | novahiz/mcp/novahiz-tools/index.mjs:579 | memory_* créent/écrivent project-memory/ n'importe où (doublon axe tools) |
103
- | LOW | slotId non validé côté MCP | novahiz/mcp/novahiz-tools/index.mjs:590-593 | Format d'identifiant non contraint |
104
- | LOW | Versions context7 et security non pinnées | opencode/opencode.jsonc:12 | Shims npm user-remplaçables sans revue |
105
- | LOW | npx invoqué sans flag -y | opencode/opencode.jsonc:38 | Installation et exécution sans confirmation |
106
- | LOW | Timeout par défaut de 5000 ms sur context7 et cron | opencode/opencode.jsonc:10 | Démarrage lent = échec alors que le scheduler prévoit 300 s |
107
- | LOW | Dépendances flottantes du scheduler | mcp-scheduler/requirements.txt:1 | Réinstallation pip non reproductible |
108
- | LOW | Tokens OAuth résiduels en clair (expo, supabase) | ~/.local/share/opencode/mcp-auth.json:1 | Jetons de serveurs retirés encore lisibles sur disque |
109
- | LOW | Double source Playwright divergente | opencode/opencode.jsonc:36 | Global 0.0.81 vs npx 0.0.82 invoqué |
110
- | LOW | Schéma DCP chargé depuis raw.githubusercontent.com | opencode/dcp.jsonc:2 | Disponibilité et intégrité chez un tiers |
111
- | LOW | Profil navigateur persistant avec sessions vivantes | opencode/instructions.md:20 | browser_cookie_* lisent les jetons de session Edge |
112
- | LOW | Postinstall novahiz (doublon axe tools) | novahiz/package.json:52 | `install.mjs --yes` à l'installation npm |
113
- | INFO | Télémétrie OTel context7 active par défaut | context7 telemetry-config.js:1 | Métriques d'usage émises sans OTEL_SDK_DISABLED |
114
- | INFO | Clés d'embedding narsil non configurées | opencode/opencode.jsonc:15 | Recherche sémantique dégradée |
115
- | INFO | security-mcp en stdio pur | security-mcp/dist/mcp/server.js:1 | Surface réseau nulle (conforme) |
116
- | INFO | Shims npm orphelins de serveurs retirés | ~/AppData/Roaming/npm/obsidian-mcp.cmd:1 | supabase, chrome-devtools, obsidian, sequential-thinking, mcp-cron encore installés |
117
- | INFO | Deux racines .mcp, policies et reports absents | ~/.config/.mcp/audit/ | generate_policy et generate_compliance_report sans emplacement |
118
- | INFO | Panne réseau 24-25/09 rétablie | ~/.local/share/opencode/log/opencode.log:1 | ENOTFOUND opencode.ai avant rétablissement (HTTP 200 vérifié) |
119
- | INFO | Secrets uniquement en variables d'environnement | opencode/opencode.jsonc:171 | OPENROUTER_API_KEY hors fichiers trackés, filtrage enfants MCP non déterminé |
120
- | INFO | opencode.db 2343,7 Mo et opencode.log 56,7 Mo | ~/.local/share/opencode/opencode.db:1 | Hygiène du poste |
121
- | INFO | Garde-fous positifs vérifiés | novahiz/plugins/novahiz.ts:245 | Fail-closed, timeouts 10 s / 1 Mo, Zod, HMAC constant-time conformes |
122
-
123
- ## 3. Rules & gate (29 findings)
124
-
125
- Source de vérité : `~/.config/novahiz/catalog/rules.json` (11 règles, R1 et R2 référencées mais inexistantes dans ce fichier). Enforcement : `plugins/novahiz.ts` (hook `tool.execute.before`, throw) + `src/commands/gate.ts` (CLI).
126
-
127
- | Sévérité | Finding | Fichier:ligne | Impact |
128
- |---|---|---|---|
129
- | CRITICAL | Tier calculé sur le contenu édité et non sur le prompt | novahiz/src/gate.ts:280 | R6 et la roadmap sautées dès que l'édit est court |
130
- | CRITICAL | Config du gate éditable sans garde-fou | novahiz/src/commands/gate.ts:48 | `gate.enabled:false` désactive l'enforcement silencieusement |
131
- | CRITICAL | Index des skills sous `**/build/**` ignoré | novahiz/src/spec.ts:137 | Skill retiré de l'index = jamais exigé, sans warning |
132
- | MAJEUR | AGENTS.md pointe vers un rules.json mort | opencode/AGENTS.md:7 | Le gate lit `~/.config/novahiz/catalog/rules.json`, pas le fichier cité |
133
- | MAJEUR | Slash-commands écrivant vers le rules.json mort | opencode/commands/novahiz_new_rule.md:5 | novahiz_new_rule, novahiz_rule, novahiz_rule_audit sans effet sur le gate |
134
- | MAJEUR | R8-docs n'utilise que des chemins relatifs | novahiz/catalog/rules.json:51 | Tout chemin absolu vers novahiz-docs échappe à la règle (vérifié par exécution) |
135
- | MAJEUR | bash/shell sans cible détectée renvoie allow:true | novahiz/src/commands/gate.ts:105 | python -e, curl -o, git apply, patch, tar -x passent sans compétence exigée |
136
- | MAJEUR | Catégorie `test` n'exige aucune compétence | novahiz/catalog/rules.json:35 | R6 exclut `test`, roadmap testing sans étape kind:skill : requiredSkills vide |
137
- | MAJEUR | tsx/jsx/vue/svelte/astro hors R9, R13, R14 | novahiz/catalog/rules.json:98 | Classés `design` : ni code-review ni skills design sans prompt design-ui |
138
- | MINEUR | Échec du classifieur vide les catégories de session | opencode/plugins/novahiz.ts:400 | 7 règles à promptCategories inapplicables, log warning seulement (doublon axe plugins) |
139
- | MINEUR | contentExcludes regex invalide = fail-open silencieux | novahiz/src/gate.ts:306 | catch `continue` alors que le commentaire annonce fail-closed |
140
- | MINEUR | Règle avec `when` vide jamais applicable | novahiz/src/gate.ts:215 | Corruption partielle = règle morte, non remontée |
141
- | MINEUR | R9 déclenché sur tout fichier code | novahiz/catalog/rules.json:59 | novahiz-code-review exigé sur chaque édition de code, hors tâche de revue |
142
- | MINEUR | R11 plus large que sa description | novahiz/catalog/rules.json:78 | Tout prompt design-ui exige novahiz-wcag-audit |
143
- | MINEUR | Sensibilité à la casse divergente plugin vs CLI | novahiz/src/commands/gate.ts:60 | Outil en majuscules passe le filtre plugin, bloqué côté CLI |
144
- | MINEUR | mode warn/audit renvoie allow:false mais laisse passer | novahiz/src/commands/gate.ts:239 | JSON suggère un blocage inexistant (exit 0) |
145
- | MINEUR | Base SQLite indisponible bloque tout édit sans dégradation | novahiz/src/commands/gate.ts:135 | Seul NOVAHIZ_GATE=off y échappe |
146
- | MINEUR | Outils MCP hors GATE_TOOLS non gateés | opencode/plugins/novahiz.ts:236 | cron_add_command_task, playwright_*, security_* écrivent sans friction |
147
- | SUGGESTION | Sélecteur mort `promptCategories:["security"]` | novahiz/catalog/rules.json:70 | Id inexistant parmi les 17 catégories (doublon axe catalogue) |
148
- | SUGGESTION | `fileClasses:["design"]` et contentMatches/minChange inutilisés | novahiz/src/gate.ts:210 | Sélecteurs sans consommateur |
149
- | SUGGESTION | R4 trop large sur `**/*.spec.ts` | novahiz/catalog/rules.json:19 | Tests Jest/Vitest déclenchent à tort novahiz-browser |
150
- | SUGGESTION | novahiz-gate SKILL.md : étapes edit/verify/advisory fausses | opencode/skills/novahiz-gate/SKILL.md:35 | Affirmation non conforme au code |
151
- | SUGGESTION | novahiz-gate SKILL.md : référence de lignes périmée | opencode/skills/novahiz-gate/SKILL.md:37 | Repère 229-236 au lieu de 352-359 |
152
- | SUGGESTION | novahiz-gate SKILL.md : « sans message » faux | opencode/skills/novahiz-gate/SKILL.md:46 | Le CLI émet bien un warning |
153
- | SUGGESTION | docs/RULES.md ne liste que 9 règles sur 11 | novahiz/docs/RULES.md:34 | R7-assessment et R8-docs manquent |
154
- | SUGGESTION | docs/CATALOG.md defaultSkills obsolètes | novahiz/docs/CATALOG.md:26 | Anciens noms supabase au lieu de novahiz-supabase/novahiz-postgres |
155
- | SUGGESTION | docs/GATE.md classes de fichiers incorrectes | novahiz/docs/GATE.md:17 | tsx/json/sql décrits à tort, contraire à CLASS_BY_EXTENSION |
156
- | SUGGESTION | Tests nommant des règles supprimées | novahiz/tests/gate.test.ts:33 | 4 assertions passeraient aussi avec un gate vide |
157
-
158
- ## 4. Tools — CLI, MCP tools, scripts (25 findings)
159
-
160
- Inventaire : 22 commandes CLI, 15 tools MCP, 3 scripts bin/scripts, 10 scripts dans skills. 0 CRITICAL, 3 HIGH, 8 MEDIUM, 10 LOW, 4 INFO.
161
-
162
- | Sévérité | Finding | Fichier:ligne | Impact |
163
- |---|---|---|---|
164
- | HIGH | rmSync hors périmètre par traversal de chemin | scripts/capture-cli.mjs:69-71 | `--label`/`--out` avec `..` + `force:true` efface une arborescence arbitraire |
165
- | HIGH | postinstall sans consentement | package.json:52 | 5 npm i -g non pinnés + écriture d'opencode.jsonc + npm update |
166
- | HIGH | SAFE_BOOTSTRAP_BINS contient des shells | src/exec.ts:53-55 | `["cmd","/c",…]` dans providers.json saute toute la barrière |
167
- | MEDIUM | Gate CLI et gate MCP divergent | src/commands/gate.ts:141-198 | Le MCP saute traceCheck, recordEdit, enforcement_log |
168
- | MEDIUM | Binaire PATH exécuté à chaque ouverture de DB | src/db.ts:118-124 | `graft` via execFileSync hors de exec.ts, sans SAFE_TOKEN |
169
- | MEDIUM | Champ `file` non validé dans l'index memory | src/memory.ts:203-211 | Écriture hors project-memory/ via `..\..` dans index.json |
170
- | MEDIUM | Tools memory_* acceptent un root arbitraire | mcp/novahiz-tools/index.mjs:579 | Création/écriture n'importe où sur le disque (doublon axe MCP) |
171
- | MEDIUM | graft restore/export destructifs sans confirmation | src/commands/graft.ts:98-113 | Réécrit novahiz.sqlite sans --force ni sauvegarde |
172
- | MEDIUM | `task resume|current` annoncés mais non implémentés | src/commands/task.ts:66 | Actions listées valides, jamais traitées ; erreur gravée en référence de non-régression |
173
- | MEDIUM | Test novahiz_step n'exerce jamais l'écriture | tests/mcp.test.ts:191 | Assertion passe sur « aucune étape », régression invisible |
174
- | MEDIUM | npx -y sans pin pour skills tiers | catalog/providers.json:72 | Dernière version publiée exécutée sans hash |
175
- | LOW | confirm() interactif toujours `false` | src/commands/context.ts:81-85 | stdin sur TTY renvoie null : confirmation inexistante et non testée |
176
- | LOW | reviewTask n'isole pas les mutations par tâche | src/ledger.ts:531-539 | amendTodo/dropTodo sur les todos d'une autre tâche |
177
- | LOW | `kind` de todo non validé côté CLI | src/commands/task.ts:19 | Chaîne libre sans CHECK : todo verify validé sans preuve |
178
- | LOW | Entrées stdin non bornées | src/commands/context.ts:101-109 | readFileSync(0) sans limite vers JSON.parse |
179
- | LOW | Validation de session inégale CLI vs MCP | mcp/novahiz-tools/index.mjs:406 | Clés de table sans contrainte de longueur côté MCP |
180
- | LOW | Owner-globs sans garde ReDoS | src/ledger.ts:306-315 | globToRegExp sans isSafeRegexPattern |
181
- | LOW | `upgrade` exécute git pull sans contrôle | src/cli.ts:116 | Code auto-mis à jour avec hooks, sans --dry-run |
182
- | LOW | install/ écrit hors home sans garde | install/lib.mjs:39 | OPENCODE_CONFIG_DIR/XDG_CONFIG_HOME sans contrôle underHome |
183
- | LOW | chmod 0600 non appliqué sur Windows | src/db.ts:13-19 | novahiz.sqlite lisible par tout compte local |
184
- | LOW | openDb suit NOVAHIZ_DB sans garde | src/db.ts:10-11 | mkdirSync récursif à un chemin arbitraire |
185
- | INFO | README MCP : 10 tools annoncés pour 15 exposés | mcp/novahiz-tools/README.md:5 | memory_* manquants dans la doc |
186
- | INFO | doctor vérifie memory tools par source.includes | src/commands/doctor.ts:186 | Faux négatif silencieux au reformatage |
187
- | INFO | Test shell:true limité à src/ | tests/exec.test.ts:68 | mcp/, install/, scripts/ hors contrôle |
188
- | INFO | Redondances positives non documentées | src/commands/gate.ts:54 | Doublons CLI/MCP difficiles à maintenir |
189
-
190
- ## 5. Catalogue de skills (22 findings)
191
-
192
- 3 racines dans `skills.paths` : `opencode/skills` (41) + `~/.agents/skills` (53) + un skill (`impeccable`, R14) = 95. Aucun conflit de noms, `frontmatter.name == dossier` pour les 95.
193
-
194
- | Sévérité | Finding | Fichier:ligne | Impact |
195
- |---|---|---|---|
196
- | HIGH | Index Novahiz périmé : 84 sur 95 | novahiz/build/installed-skills.json:1 | 11 skills ignorés par gate et ranking |
197
- | HIGH | skills-lock.json vide, lu par personne | opencode/skills-lock.json:3 | Aucune détection de non-conformité |
198
- | MEDIUM | R10-security référence la catégorie "security" inexistante | novahiz/catalog/rules.json:66 | Seuls les prompts "audit" chargent novahiz-security |
199
- | MEDIUM | skills.paths indexe opencode/skills non indexé par Novahiz | opencode/opencode.jsonc:51 | Skill ajouté = invisible pour Novahiz sans resync manuel |
200
- | MEDIUM | skillRoots cible le sous-dossier impeccable | novahiz/novahiz.config.json:5 | Skills ajoutés dans .agents/skills ignorés par Novahiz |
201
- | MEDIUM | 55 skills sur 95 sans entrée dans overrides.json | novahiz/catalog/overrides.json:1 | Aucun boost de ranking, impeccable inclus alors que R14 l'exige |
202
- | LOW | README annonce 84 skills (×3 occurrences) | novahiz/README.md:5,55,245 | Doc en décalage avec l'arborescence |
203
- | LOW | Test d'hygiène asserte "84 skills" | novahiz/tests/plugin.hygiene.test.ts:91 | CI valide un chiffre obsolète, ne détecte pas la dérive |
204
- | LOW | Descriptions sans clause de routage "quand" | gate, memory, dart-collect-coverage (faute "packge"), expo-upgrade, expo-native-ui | Routage par description moins fiable |
205
- | LOW | Paquet yaml cassé : dist/compose/composer.js absent | opencode/node_modules/yaml/dist/index.js:3 | require('yaml') MODULE_NOT_FOUND depuis la racine OpenCode |
206
- | INFO | Aucun code ne synchronise novahiz/skills ↔ opencode/skills | novahiz/install/install.mjs:167 | Égalité actuelle par resync git manuel uniquement |
207
- | INFO | novahiz-postgres cite une reference inexistante | opencode/skills/novahiz-postgres/SKILL.md:93 | Référence morte documentée |
208
- | INFO | skill-authoring cite references/x.md (placeholder) | opencode/skills/skill-authoring/SKILL.md:67 | Exemple générique |
209
- | INFO | expo-overview cite references/native-ios.md absent | ~/.agents/skills/expo-overview/SKILL.md:77 | Résout seulement dans eas-app-stores |
210
- | INFO | Doublons sémantiques gate/novahiz-gate, memory/novahiz-memory, supabase/novahiz-supabase | opencode/skills/ | Chevauchement sans collision d'index |
211
- | INFO | Aucun parasite .bak/.old ni skill orphelin, 26 sous-dossiers agents/ sans SKILL.md = définitions de sous-agents | opencode/skills | Conforme |
212
-
213
- ## Doublons inter-axes
214
-
215
- 1. postinstall `package.json:52` (tools HIGH, MCP LOW)
216
- 2. memory_* root arbitraire `index.mjs:579` (tools MEDIUM, MCP LOW)
217
- 3. providers.json npx flottant (tools MEDIUM, MCP MEDIUM)
218
- 4. classify fail-open `novahiz.ts:401` (plugins HIGH, rules MINEUR)
219
- 5. catégorie "security" inexistante (catalogue MEDIUM, rules SUGGESTION)
220
- 6. spawnSync 10 s (plugins MEDIUM côté gel UI, MCP MEDIUM côté refus fail-closed) : angles différents, même cause racine
221
-
222
- ## Conformité doc ↔ code
223
-
224
- | Document | Affirme | Réalité |
225
- |---|---|---|
226
- | `opencode/AGENTS.md` | rules.json dans opencode/catalog | Fichier mort ; le gate lit `~/.config/novahiz/catalog/rules.json` |
227
- | `novahiz/docs/RULES.md` | 9 règles | 11 règles existent (R7, R8 absentes du tableau) |
228
- | `novahiz/docs/CATALOG.md` | defaultSkills supabase/* | Renommés novahiz-supabase/novahiz-postgres |
229
- | `novahiz/docs/GATE.md` | tsx=code, json=config, sql=data | Contraire à CLASS_BY_EXTENSION |
230
- | `opencode/skills/novahiz-gate/SKILL.md` | étapes edit/verify/advisory dans requiredSkills ; lignes 229-236 ; « sans message » | Faux sur les 3 points |
231
- | `opencode/mcp-audit-report.md` | posture GOOD | 11 affirmations fausses sur la config antérieure au 24/09 |
232
- | `novahiz/README.md` | 84 skills | 95 présents |
233
- | `mcp/novahiz-tools/README.md` | 10 tools | 15 exposés |
234
-
235
- ## Couverture tests — signaux faibles
236
-
237
- - `tests/mcp.test.ts:191` : test `novahiz_step` qui n'exerce jamais l'écriture (assertion sur « aucune étape »).
238
- - `src/commands/context.ts:81` : `confirm()` toujours false sur TTY, comportement non testable en l'état.
239
- - `tests/exec.test.ts:68` : parcours `shell:true` limité à `src/` (mcp, install, scripts hors garde-fou).
240
- - `tests/gate.test.ts:33` : assertions sur des règles supprimées, passeraient avec un gate vide.
241
- - `tests/plugin.hygiene.test.ts:91` : CI valide le chiffre « 84 skills ».
242
- - `scripts/capture-cli.mjs:42` : une erreur obtenue est gravée comme référence de non-régression (`task resume`).
243
-
244
- ## Recommandations priorisées
245
-
246
- Rien n'a été appliqué. Ordre de traitement proposé.
247
-
248
- **P0 — fail-open du gate (sécurité du système lui-même)**
249
- 1. gate.ts:280 : calculer le tier sur le prompt, pas sur le contenu.
250
- 2. commands/gate.ts:48 : rendre `gate.enabled`/`gate.tools` non désactivables sans changement externe tracé (ou au minimum logger fort).
251
- 3. spec.ts:137 : sortir l'index de `build/` ou le signer/valider à la lecture, avec warning si skill retiré.
252
- 4. plugins/novahiz.ts:401, 486, 494 : classifieur en échec = refus (fail-closed), sessionID invalide = refus, validation stricte des noms de skills.
253
- 5. exec.ts:53 : retirer cmd/bash de l'allowlist, valider les arguments bootstrap.
254
- 6. capture-cli.mjs:69 : résoudre puis vérifier que la cible reste sous le dossier de sortie avant rmSync.
255
-
256
- **P1 — surfaces d'exécution et d'index**
257
- 7. package.json:52 : supprimer ou rendre opt-in le postinstall.
258
- 8. executor.py:119 : valider/whitelist les commandes cron ; SSRF : restreindre les URL.
259
- 9. opencode.jsonc:17 : exclure logs/DB de l'index narsil.
260
- 10. opencode.jsonc:30 : activer SECURITY_MCP_SHARED_SECRET ou retirer les outils auto-apply.
261
- 11. opencode.jsonc:24 : passer `env` à `environment` si le schéma l'exige, ou corriger le schéma.
262
- 12. Rebuild de l'index : 84 → 95 ; remplir ou supprimer skills-lock.json ; corriger skillRoots.
263
-
264
- **P2 — dette, doc, cohérence**
265
- 13. Resynchroniser AGENTS.md, RULES.md, CATALOG.md, GATE.md, novahiz-gate/SKILL.md, mcp-audit-report.md, README (84 → 95).
266
- 14. R8 en chemins absolus normalisés ; catégorie `test` avec compétences ; .tsx/.jsx dans R9/R13/R14.
267
- 15. Dé-dupliquer le code du plugin (src/adapters/plugins) et documenter les redondances de sécurité.
268
- 16. Purger `mcp-auth.json`, shims npm orphelins, `.mcp/audit/tool-calls.jsonl` tracké.
269
-
270
- ## Inconnus et réserves
271
-
272
- - L'agent MCP a déclaré `TOTAL: 32` mais liste 31 lignes de findings (écart de comptage non résolu ; le total général de 131 suit les lignes listées).
273
- - Non évalué : comportement runtime réel des sessions Edge/Orca, contenu des conversations, CVE des dépendances installées (hors périmètre).
274
- - Les décomptes de sévérité par axe viennent des agents eux-mêmes, dont les barèmes diffèrent (CRITICAL/MAJEUR/MINEUR/SUGGESTION côté gate).
275
- - Aucun finding n'a été re-testé indépendamment après coup : les exécutions de preuve citées (R8 absolu, tests passants) sont celles des sous-agents.