Skip to content

Commit 73cafe1

Browse files
author
Ubuntu
committed
feat: add v0.8 workflow readiness gates
1 parent 3273e4e commit 73cafe1

12 files changed

Lines changed: 1184 additions & 50 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ Run the core workflow inside Claude Code:
5555
5656
omv findings init demo-traversal
5757
/omv-audit demo-traversal
58+
omv repro init demo-traversal
5859
/omv-repro demo-traversal
5960
omv findings validate demo-traversal
61+
omv findings doctor demo-traversal
6062
6163
/omv-report demo-traversal
64+
omv report artifacts demo-traversal
6265
```
6366

6467
<details>
@@ -98,9 +101,12 @@ Project-level setup writes `.omv/setup-scope.json` so `omv doctor` can resolve t
98101
-> candidate packages and code-reading entry points
99102
-> .omv/findings/<id>.yaml
100103
-> /omv-audit
104+
-> omv repro init <id>
101105
-> /omv-repro when observed_result still needs local confirmation
102106
-> omv findings validate <id>
107+
-> omv findings doctor <id>
103108
-> /omv-report
109+
-> omv report artifacts <id>
104110
-> advisory draft for VulDB, CVE, GHSA, OSV, or Markdown
105111
```
106112

README.zh-CN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ npx -p oh-my-vul omv doctor
5555
5656
omv findings init demo-traversal
5757
/omv-audit demo-traversal
58+
omv repro init demo-traversal
5859
/omv-repro demo-traversal
5960
omv findings validate demo-traversal
61+
omv findings doctor demo-traversal
6062
6163
/omv-report demo-traversal
64+
omv report artifacts demo-traversal
6265
```
6366

6467
<details>
@@ -98,9 +101,12 @@ omv version --json
98101
-> 候选项目和源码入口
99102
-> .omv/findings/<id>.yaml
100103
-> /omv-audit
104+
-> omv repro init <id>
101105
-> /omv-repro
102106
-> omv findings validate <id>
107+
-> omv findings doctor <id>
103108
-> /omv-report
109+
-> omv report artifacts <id>
104110
-> 提交前报告草稿
105111
```
106112

docs/examples/demo-finding-flow.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,241 @@ A submission-ready finding should have:
182182
- no unresolved blockers
183183

184184
If any of these are missing, keep the finding out of the submission path.
185+
186+
## Copyable Example States
187+
188+
The snippets below use fake package names and paths. To try one locally:
189+
190+
```sh
191+
omv findings init demo-candidate --force
192+
# Replace .omv/findings/demo-candidate.yaml with one snippet, then:
193+
omv findings validate demo-candidate
194+
omv findings doctor demo-candidate
195+
```
196+
197+
### Candidate: Needs Local Reproduction
198+
199+
Expected shape: validation can pass, evidence score is partially complete, submission score remains low because local observation and version boundary are unresolved.
200+
201+
```yaml
202+
schema_version: "1"
203+
handoff_version: "1.0"
204+
status: candidate
205+
researcher_goal: VulDB
206+
package:
207+
ecosystem: npm
208+
registry_name: demo-widget-renderer
209+
repository_url: https://github.com/example/demo-widget-renderer
210+
vendor: example
211+
product: demo-widget-renderer
212+
versions:
213+
tested: "1.4.2"
214+
affected_range: unknown
215+
fixed: unknown
216+
vulnerability:
217+
class: path traversal
218+
cwe: CWE-22
219+
affected_component: lib/files.js
220+
affected_function: renderFile
221+
evidence:
222+
source: lib/server.js:18 req.query.template
223+
sink: lib/files.js:44 fs.readFileSync
224+
guard: missing path normalization before join
225+
reproducer: node repro.js ../package.json
226+
observed_result: unknown
227+
repro_artifacts: []
228+
cvss:
229+
vector: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
230+
score: 5.5
231+
severity: Medium
232+
impact:
233+
attack_vector: Local
234+
authentication_required: unknown
235+
user_interaction_required: unknown
236+
scope_changed: unknown
237+
confidentiality: High
238+
integrity: unknown
239+
availability: unknown
240+
dedup:
241+
nvd_searched: true
242+
ghsa_searched: true
243+
ecosystem_db_searched: true
244+
existing_cve: none
245+
notes: "searched NVD, GHSA, npm advisories"
246+
disclosure:
247+
vendor_contacted: false
248+
contact_date: unknown
249+
vendor_response: unknown
250+
planned_disclosure_date: unknown
251+
blockers: []
252+
verdict:
253+
exploitability: plausible
254+
confidence: medium
255+
reason: source and sink are connected, but local output has not been observed yet
256+
provenance:
257+
verification_date: "2026-05-08"
258+
researcher: demo
259+
unverified_fields:
260+
- versions.affected_range
261+
- versions.fixed
262+
- evidence.observed_result
263+
- disclosure.contact_date
264+
- disclosure.vendor_response
265+
- disclosure.planned_disclosure_date
266+
tool_versions: {}
267+
```
268+
269+
### Blocked: Default Guard Prevents Exploit
270+
271+
Expected shape: validation passes only as `blocked`, submission score is zero, and the next action is archive or return to audit if the conclusion changes.
272+
273+
```yaml
274+
schema_version: "1"
275+
handoff_version: "1.0"
276+
status: blocked
277+
researcher_goal: triage
278+
package:
279+
ecosystem: go
280+
registry_name: github.com/example/demo-webhook
281+
repository_url: https://github.com/example/demo-webhook
282+
vendor: example
283+
product: demo-webhook
284+
versions:
285+
tested: "0.8.0"
286+
affected_range: unknown
287+
fixed: unknown
288+
vulnerability:
289+
class: server-side request forgery
290+
cwe: CWE-918
291+
affected_component: internal/webhook/client.go
292+
affected_function: Send
293+
evidence:
294+
source: internal/webhook/handler.go:31 request URL
295+
sink: internal/webhook/client.go:87 http.Client.Do
296+
guard: internal/webhook/client.go:63 default allowlist blocks private IP ranges
297+
reproducer: none
298+
observed_result: unknown
299+
repro_artifacts: []
300+
cvss:
301+
vector: unknown
302+
score: unknown
303+
severity: unknown
304+
impact:
305+
attack_vector: Network
306+
authentication_required: unknown
307+
user_interaction_required: unknown
308+
scope_changed: unknown
309+
confidentiality: unknown
310+
integrity: unknown
311+
availability: unknown
312+
dedup:
313+
nvd_searched: true
314+
ghsa_searched: true
315+
ecosystem_db_searched: true
316+
existing_cve: none
317+
notes: "no matching advisory found"
318+
disclosure:
319+
vendor_contacted: false
320+
contact_date: unknown
321+
vendor_response: unknown
322+
planned_disclosure_date: unknown
323+
blockers:
324+
- default configuration blocks private network requests
325+
- no bypass found during source audit
326+
verdict:
327+
exploitability: blocked
328+
confidence: high
329+
reason: sink exists, but the default guard prevents the attacker-controlled URL from reaching private hosts
330+
provenance:
331+
verification_date: "2026-05-08"
332+
researcher: demo
333+
unverified_fields:
334+
- versions.affected_range
335+
- versions.fixed
336+
- evidence.reproducer
337+
- evidence.observed_result
338+
- cvss.vector
339+
- cvss.score
340+
- cvss.severity
341+
- impact.authentication_required
342+
- impact.user_interaction_required
343+
- impact.scope_changed
344+
- impact.confidentiality
345+
- impact.integrity
346+
- impact.availability
347+
- disclosure.contact_date
348+
- disclosure.vendor_response
349+
- disclosure.planned_disclosure_date
350+
tool_versions: {}
351+
```
352+
353+
### Confirmed: Ready For Report Drafting
354+
355+
Expected shape: validation passes as `confirmed`, submission score is above 75, and `omv report artifacts confirmed-demo` should pass after a non-empty report file exists under `.omv/reports/confirmed-demo/`.
356+
357+
```yaml
358+
schema_version: "1"
359+
handoff_version: "1.0"
360+
status: confirmed
361+
researcher_goal: VulDB
362+
package:
363+
ecosystem: python
364+
registry_name: demo-config-loader
365+
repository_url: https://github.com/example/demo-config-loader
366+
vendor: example
367+
product: demo-config-loader
368+
versions:
369+
tested: "2.1.0"
370+
affected_range: "up to and including 2.1.0"
371+
fixed: none
372+
vulnerability:
373+
class: YAML unsafe deserialization
374+
cwe: CWE-502
375+
affected_component: demo_config_loader/loader.py
376+
affected_function: load_config
377+
evidence:
378+
source: demo_config_loader/cli.py:22 user-supplied config path
379+
sink: demo_config_loader/loader.py:41 yaml.load
380+
guard: missing SafeLoader use before yaml.load
381+
reproducer: python repro.py payload.yml
382+
observed_result: local run printed marker DEMO_OWNED from the crafted YAML constructor
383+
repro_artifacts:
384+
- .omv/repro/confirmed-demo/commands.sh
385+
- .omv/repro/confirmed-demo/observed.txt
386+
cvss:
387+
vector: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
388+
score: 7.8
389+
severity: High
390+
impact:
391+
attack_vector: Local
392+
authentication_required: false
393+
user_interaction_required: true
394+
scope_changed: false
395+
confidentiality: High
396+
integrity: High
397+
availability: High
398+
dedup:
399+
nvd_searched: true
400+
ghsa_searched: true
401+
ecosystem_db_searched: true
402+
existing_cve: none
403+
notes: "searched NVD, GHSA, PyPI advisory database, and repository issues"
404+
disclosure:
405+
vendor_contacted: false
406+
contact_date: unknown
407+
vendor_response: unknown
408+
planned_disclosure_date: unknown
409+
blockers: []
410+
verdict:
411+
exploitability: proven
412+
confidence: high
413+
reason: local reproducer executed the unsafe YAML constructor on version 2.1.0
414+
provenance:
415+
verification_date: "2026-05-08"
416+
researcher: demo
417+
unverified_fields:
418+
- disclosure.contact_date
419+
- disclosure.vendor_response
420+
- disclosure.planned_disclosure_date
421+
tool_versions: {}
422+
```

docs/roadmap-0.8.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Make the CLI answer one question clearly:
1010
1111
## Planned Work
1212

13-
### 1. `omv repro init <id>`
13+
### 1. `omv repro init <id>` — implemented
1414

1515
Create a standard reproduction artifact directory:
1616

@@ -36,7 +36,7 @@ Acceptance criteria:
3636
- Adds suggested `evidence.repro_artifacts` paths to the finding or prints a patch users can apply.
3737
- Works for active findings only by default.
3838

39-
### 2. `omv findings doctor <id>`
39+
### 2. `omv findings doctor <id>` — implemented
4040

4141
Explain why a finding is not submission-ready:
4242

@@ -60,7 +60,7 @@ Acceptance criteria:
6060
- JSON mode is available for CI or future UI use.
6161
- It never suggests `/omv-report` unless the same finding would pass promotion and validation gates.
6262

63-
### 3. `omv report artifacts <id>`
63+
### 3. `omv report artifacts <id>` — implemented
6464

6565
Check report and reproduction material before archiving:
6666

@@ -80,7 +80,7 @@ Acceptance criteria:
8080
- `omv findings archive <id> --reason reported --strict` can reuse the same artifact checks.
8181
- Missing artifacts produce warnings for candidate findings and errors for strict confirmed archive.
8282

83-
### 4. Better Dashboard Detail
83+
### 4. Better Dashboard Detail — implemented
8484

8585
Improve `omv dashboard` without turning it into a full-screen app:
8686

@@ -95,7 +95,7 @@ Acceptance criteria:
9595
- The first screen tells users whether to audit, reproduce, report, or archive.
9696
- Long command truncation never hides the only actionable next step.
9797

98-
### 5. Documentation And Demo Assets
98+
### 5. Documentation And Demo Assets — implemented
9999

100100
Add sanitized examples:
101101

scripts/package_skill.sh

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,37 @@ done
3232

3333
(
3434
cd "$skill_dir"
35-
zip -qr "$out" "${entries[@]}" -x '*/__pycache__/*' '*.pyc' '*.pyo' '.git/*' '.claude/*'
35+
if command -v zip >/dev/null 2>&1; then
36+
zip -qr "$out" "${entries[@]}" -x '*/__pycache__/*' '*.pyc' '*.pyo' '.git/*' '.claude/*'
37+
else
38+
python3 - "$out" "${entries[@]}" <<'PY'
39+
import os
40+
import sys
41+
import zipfile
42+
43+
out = sys.argv[1]
44+
entries = sys.argv[2:]
45+
46+
def include(path: str) -> bool:
47+
parts = path.split(os.sep)
48+
if "__pycache__" in parts or ".git" in parts or ".claude" in parts:
49+
return False
50+
return not path.endswith((".pyc", ".pyo"))
51+
52+
with zipfile.ZipFile(out, "w", compression=zipfile.ZIP_DEFLATED) as archive:
53+
for entry in entries:
54+
if os.path.isfile(entry):
55+
if include(entry):
56+
archive.write(entry, entry)
57+
continue
58+
for root, dirs, files in os.walk(entry):
59+
dirs[:] = [name for name in dirs if include(os.path.join(root, name))]
60+
for name in files:
61+
path = os.path.join(root, name)
62+
if include(path):
63+
archive.write(path, path)
64+
PY
65+
fi
3666
)
3767

3868
python3 "$repo_root/scripts/validate_skill.py" "$skill_dir" --package "$out"

0 commit comments

Comments
 (0)