wize-dev-kit 0.14.0 → 0.16.0

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.
Files changed (226) hide show
  1. package/ARCH.md +24 -77
  2. package/CHANGELOG.md +24 -0
  3. package/DECISIONS.md +1 -27
  4. package/README.md +7 -2
  5. package/ROSTER.md +3 -11
  6. package/adapters/README.md +7 -7
  7. package/adapters/antigravity/README.md +5 -5
  8. package/adapters/claude-code/README.md +1 -1
  9. package/adapters/codex/README.md +5 -5
  10. package/adapters/codex/adapter.yaml +1 -1
  11. package/adapters/codex/render.js +1 -1
  12. package/adapters/continue/README.md +5 -5
  13. package/adapters/cursor/README.md +2 -2
  14. package/adapters/generic/README.md +1 -1
  15. package/adapters/kimi-code/README.md +5 -5
  16. package/adapters/kimi-code/render.js +2 -2
  17. package/adapters/opencode/README.md +3 -3
  18. package/adapters/opencode/render.js +1 -27
  19. package/adapters/windsurf/README.md +3 -3
  20. package/package.json +1 -1
  21. package/schemas/agent.schema.json +2 -2
  22. package/schemas/workflow.schema.json +1 -1
  23. package/src/app-overlay/wize-app-release-channels/workflow.md +0 -2
  24. package/src/app-overlay/wize-app-scaffold/workflow.md +0 -2
  25. package/src/app-overlay/wize-app-store-listing/workflow.md +0 -2
  26. package/src/builder-skills/wize-create-agent/workflow.md +0 -2
  27. package/src/builder-skills/wize-create-skill/workflow.md +0 -2
  28. package/src/builder-skills/wize-create-workflow/workflow.md +0 -2
  29. package/src/core-skills/module.yaml +3 -0
  30. package/src/core-skills/wize-advanced-elicitation/skill.md +0 -2
  31. package/src/core-skills/wize-brainstorming/skill.md +0 -2
  32. package/src/core-skills/wize-eli5/skill.md +72 -0
  33. package/src/core-skills/wize-review-adversarial/skill.md +0 -3
  34. package/src/core-skills/wize-shard-doc/skill.md +0 -2
  35. package/src/method-skills/1-analysis/wize-agent-analyst/agent.yaml +0 -3
  36. package/src/method-skills/1-analysis/wize-document-project/workflow.md +20 -213
  37. package/src/method-skills/1-analysis/wize-prfaq/workflow.md +11 -152
  38. package/src/method-skills/1-analysis/wize-product-brief/workflow.md +19 -92
  39. package/src/method-skills/1-analysis/wize-research/workflow.md +12 -39
  40. package/src/method-skills/1-analysis/wize-trigger-map/workflow.md +16 -82
  41. package/src/method-skills/2-plan-workflows/wize-create-prd/workflow.md +23 -135
  42. package/src/method-skills/2-plan-workflows/wize-ux-design/workflow.md +28 -134
  43. package/src/method-skills/2-plan-workflows/wize-ux-scenarios/workflow.md +15 -93
  44. package/src/method-skills/2-plan-workflows/wize-validate-prd/workflow.md +12 -108
  45. package/src/method-skills/3-solutioning/wize-check-implementation-readiness/workflow.md +11 -103
  46. package/src/method-skills/3-solutioning/wize-create-architecture/workflow.md +48 -55
  47. package/src/method-skills/3-solutioning/wize-create-epics-and-stories/workflow.md +15 -154
  48. package/src/method-skills/3-solutioning/wize-design-system/workflow.md +22 -184
  49. package/src/method-skills/3-solutioning/wize-nfr-principles/workflow.md +17 -145
  50. package/src/method-skills/3-solutioning/wize-tech-vision/workflow.md +22 -130
  51. package/src/method-skills/4-implementation/wize-agent-dev/persona.md +0 -12
  52. package/src/method-skills/4-implementation/wize-code-review/workflow.md +12 -54
  53. package/src/method-skills/4-implementation/wize-create-story/workflow.md +10 -154
  54. package/src/method-skills/4-implementation/wize-dev-story/workflow.md +17 -185
  55. package/src/method-skills/4-implementation/wize-quick-dev/workflow.md +18 -136
  56. package/src/method-skills/4-implementation/wize-retrospective/workflow.md +10 -114
  57. package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +11 -78
  58. package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +11 -45
  59. package/src/method-skills/module.yaml +0 -28
  60. package/src/orchestrator-skills/module.yaml +1 -7
  61. package/src/orchestrator-skills/wize-help/skill.md +67 -227
  62. package/src/orchestrator-skills/wize-onboarding/workflow.md +14 -78
  63. package/src/orchestrator-skills/wize-orchestrator/agent.yaml +0 -2
  64. package/src/orchestrator-skills/wize-orchestrator/persona.md +3 -44
  65. package/src/orchestrator-skills/wize-party-mode/workflow.md +0 -2
  66. package/src/tea-skills/wize-tea-design/workflow.md +13 -107
  67. package/src/tea-skills/wize-tea-gate/workflow.md +25 -118
  68. package/src/tea-skills/wize-tea-nfr/workflow.md +14 -107
  69. package/src/tea-skills/wize-tea-review/workflow.md +13 -123
  70. package/src/tea-skills/wize-tea-risk/workflow.md +10 -113
  71. package/src/tea-skills/wize-tea-trace/workflow.md +12 -86
  72. package/src/web-overlay/wize-web-deploy/workflow.md +0 -2
  73. package/src/web-overlay/wize-web-scaffold/workflow.md +0 -2
  74. package/src/web-overlay/wize-web-seo-audit/workflow.md +0 -2
  75. package/tools/check-eli5-all-adapters.js +50 -0
  76. package/tools/installer/onboarding.js +20 -14
  77. package/tools/installer/render-shared.js +14 -158
  78. package/tools/installer/validators/run-all.js +2 -3
  79. package/tools/installer/wize-cli.js +70 -499
  80. package/AGENTS.md +0 -37
  81. package/README.es.md +0 -294
  82. package/README.pt-BR.md +0 -292
  83. package/docs/harnesses/antigravity.md +0 -20
  84. package/docs/harnesses/antigravity.pt-BR.md +0 -20
  85. package/docs/harnesses/claude-code.md +0 -23
  86. package/docs/harnesses/claude-code.pt-BR.md +0 -23
  87. package/docs/harnesses/codex.md +0 -21
  88. package/docs/harnesses/codex.pt-BR.md +0 -21
  89. package/docs/harnesses/continue.md +0 -21
  90. package/docs/harnesses/continue.pt-BR.md +0 -21
  91. package/docs/harnesses/cursor.md +0 -22
  92. package/docs/harnesses/cursor.pt-BR.md +0 -22
  93. package/docs/harnesses/generic.md +0 -20
  94. package/docs/harnesses/generic.pt-BR.md +0 -20
  95. package/docs/harnesses/kimi-code.md +0 -19
  96. package/docs/harnesses/kimi-code.pt-BR.md +0 -19
  97. package/docs/harnesses/opencode.md +0 -31
  98. package/docs/harnesses/opencode.pt-BR.md +0 -31
  99. package/docs/harnesses/windsurf.md +0 -22
  100. package/docs/harnesses/windsurf.pt-BR.md +0 -22
  101. package/src/core-skills/wize-customize/skill.md +0 -116
  102. package/src/core-skills/wize-editorial-review-prose/skill.md +0 -94
  103. package/src/core-skills/wize-editorial-review-structure/skill.md +0 -99
  104. package/src/core-skills/wize-grill/skill.md +0 -77
  105. package/src/core-skills/wize-index-docs/skill.md +0 -119
  106. package/src/core-skills/wize-pre-pr-check/skill.md +0 -134
  107. package/src/core-skills/wize-review-edge-case-hunter/skill.md +0 -115
  108. package/src/core-skills/wize-spec/assets/headless-schemas.md +0 -39
  109. package/src/core-skills/wize-spec/assets/spec-template.md +0 -40
  110. package/src/core-skills/wize-spec/customize.toml +0 -20
  111. package/src/core-skills/wize-spec/skill.md +0 -112
  112. package/src/method-skills/1-analysis/wize-document-project/documentation-requirements.csv +0 -12
  113. package/src/method-skills/1-analysis/wize-document-project/templates/api-contracts-template.md +0 -38
  114. package/src/method-skills/1-analysis/wize-document-project/templates/architecture-template.md +0 -54
  115. package/src/method-skills/1-analysis/wize-document-project/templates/component-inventory-template.md +0 -40
  116. package/src/method-skills/1-analysis/wize-document-project/templates/contribution-guide-template.md +0 -34
  117. package/src/method-skills/1-analysis/wize-document-project/templates/data-models-template.md +0 -36
  118. package/src/method-skills/1-analysis/wize-document-project/templates/deep-dive-template.md +0 -312
  119. package/src/method-skills/1-analysis/wize-document-project/templates/deployment-guide-template.md +0 -42
  120. package/src/method-skills/1-analysis/wize-document-project/templates/development-guide-template.md +0 -61
  121. package/src/method-skills/1-analysis/wize-document-project/templates/index-template.md +0 -185
  122. package/src/method-skills/1-analysis/wize-document-project/templates/project-overview-template.md +0 -110
  123. package/src/method-skills/1-analysis/wize-document-project/templates/project-scan-report-schema.json +0 -159
  124. package/src/method-skills/1-analysis/wize-document-project/templates/source-tree-template.md +0 -142
  125. package/src/method-skills/1-analysis/wize-domain-research/customize.toml +0 -14
  126. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-01-init.md +0 -49
  127. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-02-domain-analysis.md +0 -39
  128. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-03-competitive-landscape.md +0 -39
  129. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-04-regulatory-focus.md +0 -39
  130. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-05-technical-trends.md +0 -39
  131. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-06-research-synthesis.md +0 -43
  132. package/src/method-skills/1-analysis/wize-domain-research/research.template.md +0 -31
  133. package/src/method-skills/1-analysis/wize-domain-research/workflow.md +0 -58
  134. package/src/method-skills/1-analysis/wize-market-research/customize.toml +0 -14
  135. package/src/method-skills/1-analysis/wize-market-research/research.template.md +0 -31
  136. package/src/method-skills/1-analysis/wize-market-research/steps/step-01-init.md +0 -57
  137. package/src/method-skills/1-analysis/wize-market-research/steps/step-02-customer-behavior.md +0 -39
  138. package/src/method-skills/1-analysis/wize-market-research/steps/step-03-customer-pain-points.md +0 -37
  139. package/src/method-skills/1-analysis/wize-market-research/steps/step-04-customer-decisions.md +0 -39
  140. package/src/method-skills/1-analysis/wize-market-research/steps/step-05-competitive-analysis.md +0 -37
  141. package/src/method-skills/1-analysis/wize-market-research/steps/step-06-research-completion.md +0 -47
  142. package/src/method-skills/1-analysis/wize-market-research/workflow.md +0 -66
  143. package/src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md +0 -129
  144. package/src/method-skills/1-analysis/wize-technical-research/customize.toml +0 -14
  145. package/src/method-skills/1-analysis/wize-technical-research/research.template.md +0 -31
  146. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-01-init.md +0 -49
  147. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-02-technical-overview.md +0 -45
  148. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-03-integration-patterns.md +0 -39
  149. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-04-architectural-patterns.md +0 -39
  150. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-05-implementation-research.md +0 -42
  151. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-06-research-synthesis.md +0 -46
  152. package/src/method-skills/1-analysis/wize-technical-research/workflow.md +0 -60
  153. package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +0 -110
  154. package/src/method-skills/3-solutioning/wize-create-architecture/architecture-decision-template.md +0 -41
  155. package/src/method-skills/3-solutioning/wize-create-architecture/customize.toml +0 -20
  156. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01-init.md +0 -95
  157. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01b-continue.md +0 -32
  158. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-02-context.md +0 -126
  159. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-03-starter.md +0 -110
  160. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-04-decisions.md +0 -129
  161. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-05-patterns.md +0 -109
  162. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-06-structure.md +0 -97
  163. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-07-validation.md +0 -124
  164. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-08-complete.md +0 -59
  165. package/src/method-skills/3-solutioning/wize-project-context/workflow.md +0 -120
  166. package/src/method-skills/4-implementation/wize-changelog/workflow.md +0 -184
  167. package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +0 -117
  168. package/src/method-skills/4-implementation/wize-code-review/customize.toml +0 -21
  169. package/src/method-skills/4-implementation/wize-code-review/steps/step-01-gather-context.md +0 -64
  170. package/src/method-skills/4-implementation/wize-code-review/steps/step-02-review.md +0 -40
  171. package/src/method-skills/4-implementation/wize-code-review/steps/step-03-triage.md +0 -43
  172. package/src/method-skills/4-implementation/wize-code-review/steps/step-04-present.md +0 -100
  173. package/src/method-skills/4-implementation/wize-correct-course/workflow.md +0 -93
  174. package/src/method-skills/4-implementation/wize-investigate/workflow.md +0 -123
  175. package/src/method-skills/4-implementation/wize-release/workflow.md +0 -162
  176. package/src/orchestrator-skills/wize/skill.md +0 -164
  177. package/src/orchestrator-skills/wize-check/skill.md +0 -98
  178. package/src/security-overlay/_shared/allowlist.js +0 -154
  179. package/src/security-overlay/_shared/backlog.js +0 -169
  180. package/src/security-overlay/_shared/cli-runner.js +0 -87
  181. package/src/security-overlay/_shared/cvss.js +0 -108
  182. package/src/security-overlay/_shared/detect.js +0 -125
  183. package/src/security-overlay/_shared/install-script.js +0 -205
  184. package/src/security-overlay/_shared/invoke-phase.js +0 -86
  185. package/src/security-overlay/_shared/owasp.js +0 -56
  186. package/src/security-overlay/_shared/partial.js +0 -225
  187. package/src/security-overlay/_shared/preflight.js +0 -175
  188. package/src/security-overlay/_shared/scope-gate.js +0 -172
  189. package/src/security-overlay/_shared/scope-parser.js +0 -147
  190. package/src/security-overlay/agents/red-teamer/agent.yaml +0 -54
  191. package/src/security-overlay/agents/red-teamer/persona.md +0 -49
  192. package/src/security-overlay/data/common.txt +0 -115
  193. package/src/security-overlay/data/owasp-top10.json +0 -15
  194. package/src/security-overlay/data/tool-allowlist.json +0 -31
  195. package/src/security-overlay/skills/wize-sec-enumerate/scripts/run-enumerate.js +0 -180
  196. package/src/security-overlay/skills/wize-sec-enumerate/skill.md +0 -34
  197. package/src/security-overlay/skills/wize-sec-exploit/data/common.txt +0 -117
  198. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-ffuf.js +0 -147
  199. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nikto.js +0 -145
  200. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nuclei.js +0 -176
  201. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-sqlmap.js +0 -139
  202. package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +0 -184
  203. package/src/security-overlay/skills/wize-sec-pentest/skill.md +0 -54
  204. package/src/security-overlay/skills/wize-sec-recon/scripts/run-gitleaks.js +0 -139
  205. package/src/security-overlay/skills/wize-sec-recon/scripts/run-osv.js +0 -227
  206. package/src/security-overlay/skills/wize-sec-recon/scripts/run-recon.js +0 -162
  207. package/src/security-overlay/skills/wize-sec-recon/skill.md +0 -37
  208. package/src/security-overlay/skills/wize-sec-report/scripts/render-report.js +0 -1033
  209. package/src/security-overlay/skills/wize-sec-scope/scripts/generate-scope.js +0 -106
  210. package/src/security-overlay/skills/wize-sec-scope/skill.md +0 -52
  211. package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +0 -121
  212. package/tools/installer/baseline.js +0 -128
  213. package/tools/installer/commands/agent.js +0 -197
  214. package/tools/installer/commands/doctor.js +0 -319
  215. package/tools/installer/commands/document-project.js +0 -93
  216. package/tools/installer/commands/sync.js +0 -45
  217. package/tools/installer/commands/update.js +0 -172
  218. package/tools/installer/document-project/batch-scanner.js +0 -93
  219. package/tools/installer/document-project/classify.js +0 -170
  220. package/tools/installer/document-project/modes/deep-dive.js +0 -196
  221. package/tools/installer/document-project/modes/full-rescan.js +0 -15
  222. package/tools/installer/document-project/modes/initial-scan.js +0 -100
  223. package/tools/installer/document-project/modes/quick.js +0 -211
  224. package/tools/installer/document-project/render-index.js +0 -101
  225. package/tools/installer/document-project/state.js +0 -110
  226. package/tools/installer/version-check.js +0 -117
@@ -1,225 +0,0 @@
1
- 'use strict';
2
-
3
- // partial.js — the contract between phase skills and the report render.
4
- //
5
- // All phase skills write their findings to <securityDir>/<phase>.md using
6
- // this helper. The format is a YAML frontmatter (zero-dep serialization)
7
- // followed by `## <heading>` sections in a stable order. The report
8
- // (wize-sec-report) consumes these parciais and produces the final MD/HTML.
9
- //
10
- // Reruns are idempotent: writePartial overwrites the file in place; sections
11
- // are rendered in the order provided by the caller.
12
-
13
- const fs = require('node:fs');
14
- const path = require('node:path');
15
-
16
- const PARTIALS_SUBDIR = '.wize/security';
17
-
18
- // --- serialization helpers (zero-dep) ------------------------------------
19
-
20
- // YAML-quote a string value (only when needed). Strings that look like
21
- // numbers or booleans are still rendered as plain scalars — but the parse
22
- // side uses a STRICT type-coercion only when the string came in as a
23
- // non-string. That keeps version="2.9" round-tripping as a string.
24
- function yamlScalar(value) {
25
- if (value === null || value === undefined) return 'null';
26
- if (typeof value === 'boolean') return String(value);
27
- if (typeof value === 'number') return String(value);
28
- if (typeof value === 'string') {
29
- // Quote when the string contains characters that YAML would mis-parse
30
- // OR when the string is empty / has leading/trailing whitespace.
31
- if (/[:#&*?|<>=!%@`\n]/.test(value) || value === '' || /^\s|\s$/.test(value)) {
32
- return JSON.stringify(value);
33
- }
34
- return value;
35
- }
36
- throw new Error(`yamlScalar: unsupported type ${typeof value}`);
37
- }
38
-
39
- // Build a nested YAML mapping under a fixed indent. Used for `tools:` and
40
- // any other { name: { ... } } structure. Depth is unbounded; objects are
41
- // rendered as nested mappings, scalars as flat `key: value` lines.
42
- function renderNestedMap(obj, indent) {
43
- const pad = ' '.repeat(indent);
44
- const inner = ' '.repeat(indent + 2);
45
- const out = [];
46
- for (const [k, v] of Object.entries(obj)) {
47
- if (v && typeof v === 'object' && !Array.isArray(v)) {
48
- out.push(`${pad}${k}:`);
49
- for (const [k2, v2] of Object.entries(v)) {
50
- if (v2 && typeof v2 === 'object' && !Array.isArray(v2)) {
51
- out.push(`${inner}${k2}:`);
52
- const inner2 = ' '.repeat(indent + 4);
53
- for (const [k3, v3] of Object.entries(v2)) {
54
- out.push(`${inner2}${k3}: ${yamlScalar(v3)}`);
55
- }
56
- } else {
57
- out.push(`${inner}${k2}: ${yamlScalar(v2)}`);
58
- }
59
- }
60
- } else {
61
- out.push(`${pad}${k}: ${yamlScalar(v)}`);
62
- }
63
- }
64
- return out.join('\n');
65
- }
66
-
67
- // Parse a flat YAML frontmatter into an object. We only accept the limited
68
- // shape the helper writes: flat `key: value` lines plus a `tools:` block
69
- // that may nest 2 levels deep (tool -> { key: value }). This is
70
- // intentionally not a general YAML parser.
71
- function parseFrontmatter(text) {
72
- const lines = text.split('\n');
73
- const out = {};
74
- let inTools = false;
75
- let tools = null;
76
- let toolKey = null;
77
- for (const raw of lines) {
78
- if (inTools) {
79
- if (raw.trim() === '') continue;
80
- // 2-space-indented top-level key under `tools:`.
81
- const toolKeyMatch = raw.match(/^ ([a-zA-Z_][a-zA-Z0-9_-]*):\s*$/);
82
- if (toolKeyMatch) {
83
- toolKey = toolKeyMatch[1];
84
- tools[toolKey] = {};
85
- continue;
86
- }
87
- // 4-space-indented mapping under the current tool.
88
- const valMatch = raw.match(/^ ([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*?)\s*$/);
89
- if (valMatch && toolKey) {
90
- tools[toolKey][valMatch[1]] = coerceScalar(valMatch[2]);
91
- continue;
92
- }
93
- // Anything else ends the tools block.
94
- if (/^\S/.test(raw)) {
95
- inTools = false;
96
- toolKey = null;
97
- // fall through to the top-level branch on the same line
98
- } else {
99
- continue;
100
- }
101
- }
102
- if (/^[a-zA-Z_][a-zA-Z0-9_-]*:(\s|$)/.test(raw)) {
103
- const m = raw.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*?)\s*$/);
104
- if (!m) continue;
105
- const [, k, vRaw] = m;
106
- const v = vRaw.replace(/^['"]|['"]$/g, '');
107
- if (k === 'tools') {
108
- inTools = true;
109
- tools = {};
110
- out.tools = tools;
111
- toolKey = null;
112
- continue;
113
- }
114
- out[k] = coerceScalar(v);
115
- }
116
- }
117
- return out;
118
- }
119
-
120
- function coerceScalar(v) {
121
- // Strings are kept as strings (so version="2.9" round-trips as a string,
122
- // not a number). Booleans and null are explicit.
123
- if (v === 'true') return true;
124
- if (v === 'false') return false;
125
- if (v === 'null') return null;
126
- // Inline JSON array: [a, b, c]
127
- if (/^\[.*\]$/.test(v)) {
128
- try { return JSON.parse(v); } catch (_) { /* fall through */ }
129
- }
130
- return v;
131
- }
132
-
133
- // --- public API ----------------------------------------------------------
134
-
135
- function defaultSecurityDir() {
136
- return path.join(process.cwd(), PARTIALS_SUBDIR);
137
- }
138
-
139
- // Refuse phase names that try to escape the securityDir.
140
- function assertSafePhase(phase) {
141
- if (typeof phase !== 'string' || !phase) {
142
- throw new Error('invalid phase: empty');
143
- }
144
- if (phase.includes('..') || phase.includes('/') || phase.includes('\\') || path.isAbsolute(phase)) {
145
- throw new Error(`partial phase-name-traversal: refused ${JSON.stringify(phase)}`);
146
- }
147
- }
148
-
149
- // writePartial({ securityDir?, phase, mode, scope, status, tools?, sections })
150
- // - sections: object of { heading: content } (preserves order via Object.keys).
151
- // - Returns the absolute path of the written file.
152
- function writePartial(opts) {
153
- if (!opts || typeof opts !== 'object') throw new Error('writePartial: opts required');
154
- const phase = opts.phase;
155
- assertSafePhase(phase);
156
- const sec = opts.securityDir || defaultSecurityDir();
157
- fs.mkdirSync(sec, { recursive: true });
158
-
159
- const scope = opts.scope || {};
160
- const scopeSha = (scope.frontmatter && scope.frontmatter.scope_sha256) || (opts.scopeSha256 || '');
161
-
162
- const fm = [];
163
- fm.push('---');
164
- fm.push(`phase: ${yamlScalar(phase)}`);
165
- fm.push(`generated_at: ${new Date().toISOString()}`);
166
- fm.push(`scope_sha256: ${yamlScalar(scopeSha)}`);
167
- fm.push(`mode: ${yamlScalar(opts.mode || 'passive')}`);
168
- fm.push(`partial_status: ${yamlScalar(opts.status || 'complete')}`);
169
- if (Array.isArray(opts.dependsOn) && opts.dependsOn.length) {
170
- const arr = '[' + opts.dependsOn.map(v => JSON.stringify(String(v))).join(', ') + ']';
171
- fm.push(`depends_on: ${arr}`);
172
- }
173
- if (opts.tools && Object.keys(opts.tools).length) {
174
- fm.push(renderNestedMap({ tools: opts.tools }, 0));
175
- }
176
- fm.push('---');
177
- fm.push('');
178
-
179
- const body = [];
180
- for (const [heading, content] of Object.entries(opts.sections || {})) {
181
- body.push(`## ${heading}`);
182
- body.push('');
183
- body.push(String(content == null ? '' : content).trimEnd());
184
- body.push('');
185
- }
186
-
187
- const file = path.join(sec, `${phase}.md`);
188
- fs.writeFileSync(file, fm.join('\n') + '\n' + body.join('\n'), 'utf8');
189
- return file;
190
- }
191
-
192
- // loadPartial({ securityDir?, phase }) -> { frontmatter, body } or null.
193
- function loadPartial(opts) {
194
- const phase = opts.phase;
195
- assertSafePhase(phase);
196
- const sec = opts.securityDir || defaultSecurityDir();
197
- const file = path.join(sec, `${phase}.md`);
198
- if (!fs.existsSync(file)) return null;
199
- const text = fs.readFileSync(file, 'utf8');
200
- const fmMatch = text.match(/^---\n([\s\S]*?)\n---\n/);
201
- if (!fmMatch) return null;
202
- const frontmatter = parseFrontmatter(fmMatch[1]);
203
- const body = text.slice(fmMatch[0].length);
204
- return { frontmatter, body };
205
- }
206
-
207
- // listPartials({ securityDir? }) -> array of phase names (sorted).
208
- function listPartials(opts = {}) {
209
- const sec = opts.securityDir || defaultSecurityDir();
210
- if (!fs.existsSync(sec)) return [];
211
- const out = [];
212
- for (const name of fs.readdirSync(sec)) {
213
- if (name.endsWith('.md') && !name.startsWith('.')) {
214
- out.push(name.replace(/\.md$/, ''));
215
- }
216
- }
217
- return out.sort();
218
- }
219
-
220
- module.exports = {
221
- writePartial,
222
- loadPartial,
223
- listPartials,
224
- PARTIALS_SUBDIR
225
- };
@@ -1,175 +0,0 @@
1
- 'use strict';
2
-
3
- // preflight.js — detects the host environment (OS/arch/package manager)
4
- // and which tools from data/tool-allowlist.json are installed.
5
- //
6
- // Test hook: when WIZE_SEC_PREFLIGHT_OS, WIZE_SEC_PREFLIGHT_PM, and
7
- // WIZE_SEC_PREFLIGHT_TOOLS (JSON) env vars are set, the real probes
8
- // are skipped and the values are returned directly. This lets tests
9
- // simulate Mac/Linux/Windows-WSL without actually running `which` etc.
10
-
11
- const fs = require('node:fs');
12
- const path = require('node:path');
13
- const os = require('node:os');
14
- const { execFileSync, spawnSync } = require('node:child_process');
15
-
16
- const ALLOWLIST_PATH = path.join(__dirname, '..', 'data', 'tool-allowlist.json');
17
-
18
- function readToolNames() {
19
- try {
20
- const data = JSON.parse(fs.readFileSync(ALLOWLIST_PATH, 'utf8'));
21
- // Skip _schema and any non-array fields.
22
- return Object.keys(data).filter(k => k !== '_schema' && Array.isArray(data[k]));
23
- } catch (_) {
24
- return [];
25
- }
26
- }
27
-
28
- function detectOS() {
29
- if (process.env.WIZE_SEC_PREFLIGHT_OS) return process.env.WIZE_SEC_PREFLIGHT_OS;
30
- const platform = os.platform();
31
- if (platform === 'linux') {
32
- // Detect WSL by reading /proc/version for "Microsoft" or "WSL".
33
- try {
34
- const v = fs.readFileSync('/proc/version', 'utf8');
35
- if (/microsoft|wsl/i.test(v)) return 'wsl';
36
- } catch (_) { /* not linux */ }
37
- return 'linux';
38
- }
39
- if (platform === 'darwin') return 'darwin';
40
- if (platform === 'win32') return 'win32';
41
- return 'linux';
42
- }
43
-
44
- function detectArch() {
45
- if (process.env.WIZE_SEC_PREFLIGHT_ARCH) return process.env.WIZE_SEC_PREFLIGHT_ARCH;
46
- return process.arch; // 'x64' | 'arm64' | 'ia32' etc.
47
- }
48
-
49
- function detectPackageManager(os) {
50
- if (process.env.WIZE_SEC_PREFLIGHT_PM) return process.env.WIZE_SEC_PREFLIGHT_PM;
51
- // Check for the most common PMs in order.
52
- const candidates = {
53
- linux: ['apt', 'dnf', 'pacman', 'zypper', 'apk'],
54
- wsl: ['apt', 'dnf', 'pacman'],
55
- darwin: ['brew'],
56
- win32: ['scoop', 'chocolatey']
57
- };
58
- const list = candidates[os] || [];
59
- for (const pm of list) {
60
- const cmds = { apt: 'apt', dnf: 'dnf', pacman: 'pacman', zypper: 'zypper', apk: 'apk', brew: 'brew', scoop: 'scoop', chocolatey: 'choco' }[pm];
61
- try {
62
- execFileSync(cmds, ['--version'], { stdio: 'ignore' });
63
- return pm;
64
- } catch (_) { /* not present */ }
65
- }
66
- return 'none';
67
- }
68
-
69
- function whichCommand(os) {
70
- // 'command -v' on POSIX, 'where' on Windows.
71
- if (os === 'win32') return 'where';
72
- return 'command';
73
- }
74
-
75
- function whichArg(os) {
76
- if (os === 'win32') return [];
77
- return ['-v'];
78
- }
79
-
80
- function probeWhich(name, os) {
81
- try {
82
- const r = spawnSync(whichCommand(os), [...whichArg(os), name], { encoding: 'utf8', timeout: 2000 });
83
- if (r.status === 0 && r.stdout) {
84
- return r.stdout.split('\n')[0].trim();
85
- }
86
- } catch (_) { /* not present */ }
87
- return null;
88
- }
89
-
90
- function probeVersion(binPath, os) {
91
- // Try common version flags. Each is a separate probe; failure is non-fatal.
92
- const flags = ['--version', '-version', '-V', 'version'];
93
- for (const f of flags) {
94
- try {
95
- const out = execFileSync(binPath, [f], { encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'] });
96
- const first = (out || '').split('\n')[0].trim();
97
- if (first) return first.slice(0, 120);
98
- } catch (_) { /* try next */ }
99
- }
100
- return null;
101
- }
102
-
103
- function detectTools(os) {
104
- const names = readToolNames();
105
- const tools = {};
106
- // Initialize all tools as missing.
107
- for (const n of names) tools[n] = { present: false };
108
- // Test hook: parse the JSON env var. The hook marks the listed tools as
109
- // present; everything else stays missing.
110
- if (process.env.WIZE_SEC_PREFLIGHT_TOOLS) {
111
- try {
112
- const m = JSON.parse(process.env.WIZE_SEC_PREFLIGHT_TOOLS);
113
- for (const [name, path] of Object.entries(m)) {
114
- if (!(name in tools)) tools[name] = { present: !!path, path: path || undefined, version: null };
115
- else {
116
- tools[name] = { present: !!path, path: path || undefined, version: null };
117
- }
118
- }
119
- } catch (_) { /* fall through to real detection */ }
120
- return tools;
121
- }
122
- // Real detection.
123
- for (const name of names) {
124
- const p = probeWhich(name, os);
125
- if (!p) {
126
- tools[name] = { present: false };
127
- } else {
128
- tools[name] = { present: true, path: p, version: probeVersion(p, os) };
129
- }
130
- }
131
- return tools;
132
- }
133
-
134
- function runPreflight(opts = {}) {
135
- const os_ = detectOS();
136
- const arch = detectArch();
137
- const pm = detectPackageManager(os_);
138
- const tools = detectTools(os_);
139
- const missing = Object.entries(tools).filter(([, v]) => !v.present).map(([k]) => k);
140
- return {
141
- os: os_,
142
- arch,
143
- packageManager: pm,
144
- tools,
145
- missing,
146
- node: process.version,
147
- nodePath: process.execPath
148
- };
149
- }
150
-
151
- function formatReport(p) {
152
- const present = Object.entries(p.tools).filter(([, v]) => v.present);
153
- const lines = [];
154
- lines.push(`OS: ${p.os} (${p.arch})`);
155
- lines.push(`Package manager: ${p.packageManager || 'none'}`);
156
- lines.push(`Node: ${p.node}`);
157
- lines.push('');
158
- lines.push(`Tools: ${present.length} present, ${p.missing.length} missing`);
159
- if (present.length) {
160
- lines.push(' present:');
161
- for (const [name, info] of present) {
162
- const v = info.version ? ` — ${info.version}` : '';
163
- lines.push(` ✓ ${name}${v}`);
164
- }
165
- }
166
- if (p.missing.length) {
167
- lines.push(' missing:');
168
- for (const name of p.missing) lines.push(` ✗ ${name}`);
169
- lines.push('');
170
- lines.push('Run the install script (see .wize/security/install-pentest-tools.sh) to add the missing tools.');
171
- }
172
- return lines.join('\n');
173
- }
174
-
175
- module.exports = { runPreflight, formatReport, readToolNames };
@@ -1,172 +0,0 @@
1
- 'use strict';
2
-
3
- // scope-gate.js — single point that decides whether an offensive tool may run
4
- // against a given target. ADR-001: this module is THE gate; skills must call
5
- // assertTargetInScope before any execFile.
6
- //
7
- // Refusals (returns false) are logged to .wize/security/.refusals.log with
8
- // ISO-8601 timestamp + target + reason. Scope validation errors (ScopeError)
9
- // propagate — they signal an invalid scope, not a refused action.
10
-
11
- const fs = require('node:fs');
12
- const path = require('node:path');
13
-
14
- const {
15
- parseScope,
16
- validateScope,
17
- ScopeError
18
- } = require('./scope-parser.js');
19
-
20
- const REFSUAL_LOG_FILENAME = '.refusals.log';
21
-
22
- // --- body parsing --------------------------------------------------------
23
-
24
- // Parse the body of a scope.md into a structured allowlist. We accept the
25
- // shape defined in ADR-002:
26
- //
27
- // ## allowlist
28
- // hosts:
29
- // - localhost
30
- // - 127.0.0.1
31
- // urls:
32
- // - https://staging.example.internal/api/
33
- // paths:
34
- // - /api
35
- //
36
- // Zero-dep: each list block is matched line-by-line under its `## allowlist`
37
- // heading until the next `##` heading or EOF. Empty / missing blocks yield
38
- // empty arrays (which makes EVERY target fail the allowlist — fail-closed).
39
- function parseAllowlist(body) {
40
- const out = { hosts: [], urls: [], paths: [] };
41
- const lines = String(body || '').split('\n');
42
- let section = null;
43
- let key = null;
44
- for (const line of lines) {
45
- const h = line.match(/^##\s+([a-zA-Z_][a-zA-Z0-9_-]*)/);
46
- if (h) {
47
- section = h[1] === 'allowlist' ? 'allowlist' : null;
48
- key = null;
49
- continue;
50
- }
51
- if (section !== 'allowlist') continue;
52
- const km = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*$/);
53
- if (km) {
54
- const k = km[1];
55
- if (k === 'hosts' || k === 'urls' || k === 'paths') key = k;
56
- else key = null;
57
- continue;
58
- }
59
- const lm = line.match(/^\s+-\s+(.+?)\s*$/);
60
- if (lm && key) {
61
- out[key].push(lm[1]);
62
- }
63
- }
64
- return out;
65
- }
66
-
67
- // --- matching ------------------------------------------------------------
68
-
69
- function matchHost(allowlist, host) {
70
- return allowlist.hosts.some(h => h === host);
71
- }
72
-
73
- function matchUrl(allowlist, url) {
74
- // Normalize by stripping trailing slashes so 'http://x/' and 'http://x'
75
- // match the same prefix.
76
- const norm = s => String(s || '').replace(/\/+$/, '');
77
- const target = norm(url);
78
- return allowlist.urls.some(prefix => target.startsWith(norm(prefix)));
79
- }
80
-
81
- function matchPath(allowlist, p) {
82
- // The path must equal or start with one of the allowlisted paths.
83
- return allowlist.paths.some(ap => p === ap || p.startsWith(ap.endsWith('/') ? ap : ap + '/'));
84
- }
85
-
86
- // --- public api ----------------------------------------------------------
87
-
88
- // loadScope(scopePath) — load + parse + validate. On error: log refusal
89
- // (best-effort) and rethrow. The caller (a skill) aborts on throw.
90
- function loadScope(scopePath) {
91
- if (!fs.existsSync(scopePath)) {
92
- // Cannot log refusal without a known scope directory; rely on caller.
93
- throw new ScopeError('MISSING_FILE', null,
94
- `scope.md ausente em ${scopePath} — crie e assine em .wize/security/scope.md antes de rodar o pipeline`);
95
- }
96
- const text = fs.readFileSync(scopePath, 'utf8');
97
- const scope = parseScope(text);
98
- validateScope(scope);
99
- return scope;
100
- }
101
-
102
- // assertTargetInScope(scope, target, { refusalsDir }) -> boolean.
103
- // On refusal, writes a line to <refusalsDir>/.refusals.log and returns false.
104
- // Throws ScopeError if `scope` itself is invalid (HASH_MISMATCH, etc.) —
105
- // callers should treat that as abort-the-pipeline.
106
- function assertTargetInScope(scope, target, opts = {}) {
107
- const refusalsDir = opts.refusalsDir || path.join(process.cwd(), '.wize', 'security');
108
-
109
- // Validate the scope up front so any tampering is surfaced loudly. We
110
- // also log the attempt before re-throwing — an invalid scope is itself
111
- // a refusal event that must appear in the audit trail.
112
- try {
113
- validateScope(scope);
114
- } catch (err) {
115
- if (err && err.code) {
116
- logRefusal(refusalsDir, target || {}, `${err.code}: ${String(err.message || '').slice(0, 200)}`);
117
- }
118
- throw err;
119
- }
120
-
121
- const allowlist = parseAllowlist(scope.body);
122
-
123
- // Evaluate each provided dimension of the target. A dimension is "in scope"
124
- // iff it matches an allowlist entry. If the caller provides multiple
125
- // dimensions (e.g. {host, url}), all of them must match.
126
- const checks = [];
127
- if (target.host) checks.push({ ok: matchHost(allowlist, target.host), why: 'host not in allowlist' });
128
- if (target.url) checks.push({ ok: matchUrl(allowlist, target.url), why: 'url not in allowlist' });
129
- if (target.path) checks.push({ ok: matchPath(allowlist, target.path), why: 'path not in allowlist' });
130
-
131
- if (checks.length === 0) {
132
- // Defensive: refusing a target we can't classify is the safe default.
133
- logRefusal(refusalsDir, target, 'no target dimension provided');
134
- return false;
135
- }
136
-
137
- const allIn = checks.every(c => c.ok);
138
- if (!allIn) {
139
- const reason = checks.filter(c => !c.ok).map(c => c.why).join('; ');
140
- logRefusal(refusalsDir, target, reason);
141
- return false;
142
- }
143
- return true;
144
- }
145
-
146
- // logRefusal(refusalsDir, target, reason) — append a YAML line to
147
- // .wize/security/.refusals.log. Best-effort: never throws (a logging failure
148
- // must not mask the refusal that caused it).
149
- function logRefusal(refusalsDir, target, reason) {
150
- try {
151
- fs.mkdirSync(refusalsDir, { recursive: true });
152
- const file = path.join(refusalsDir, REFSUAL_LOG_FILENAME);
153
- const entry = [
154
- '-',
155
- ` timestamp: ${new Date().toISOString()}`,
156
- ...Object.entries(target || {}).map(([k, v]) => ` ${k}: ${String(v).replace(/\n/g, ' ')}`),
157
- ` reason: ${String(reason || 'unspecified').replace(/\n/g, ' ')}`
158
- ].join('\n') + '\n';
159
- fs.appendFileSync(file, entry, 'utf8');
160
- } catch (_) {
161
- // Intentionally swallow — refusing to crash the caller is more important
162
- // than refusing to log. The gate decision (return false) is what matters.
163
- }
164
- }
165
-
166
- module.exports = {
167
- loadScope,
168
- assertTargetInScope,
169
- logRefusal,
170
- parseAllowlist,
171
- ScopeError
172
- };