Skip to content

Commit 7b6f5c8

Browse files
committed
docs: open-source polish — CoC, public OpenSpec specs, clearer README
Publish accepted openspec/specs for contributors while keeping openspec/changes local. Add Contributor Covenant CoC with security-research norms, fix root-only /SPEC.md gitignore on case-insensitive filesystems, and surface install/docs links plus an Unreleased 0.10 note on the README front door.
1 parent e6b345c commit 7b6f5c8

35 files changed

Lines changed: 2085 additions & 6 deletions

File tree

.gitignore

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
# Project-scoped Codex installs created by `omv setup --scope project`
55
.codex/
66

7-
# Local assistant/OpenSpec scaffolding and nested worktrees
7+
# Local assistant scaffolding and nested worktrees
88
.agents/
99
.claude/
1010
.github/prompts/
1111
.github/skills/
12-
openspec/
13-
SPEC.md
1412
oh-my-codex/
1513
oh-my-claudecode/
1614

15+
# OpenSpec: publish accepted specs; keep in-progress change drafts local
16+
openspec/changes/
17+
# Root historical vision draft only (do not match openspec/**/spec.md on case-insensitive FS)
18+
/SPEC.md
19+
1720
# TypeScript build output
1821
dist/
1922
node_modules/

CODE_OF_CONDUCT.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
We as members, contributors, and leaders pledge to make participation in our
6+
community a harassment-free experience for everyone, regardless of age, body
7+
size, visible or invisible disability, ethnicity, sex characteristics, gender
8+
identity and expression, level of experience, education, socio-economic status,
9+
nationality, personal appearance, race, caste, color, religion, or sexual
10+
identity and orientation.
11+
12+
We pledge to act and interact in ways that contribute to an open, welcoming,
13+
diverse, inclusive, and healthy community.
14+
15+
## Our Standards
16+
17+
Examples of behavior that contributes to a positive environment for our
18+
community include:
19+
20+
* Demonstrating empathy and kindness toward other people
21+
* Being respectful of differing opinions, viewpoints, and experiences
22+
* Giving and gracefully accepting constructive feedback
23+
* Accepting responsibility and apologizing to those affected by our mistakes,
24+
and learning from the experience
25+
* Focusing on what is best not just for us as individuals, but for the overall
26+
community
27+
28+
Examples of unacceptable behavior include:
29+
30+
* The use of sexualized language or imagery, and sexual attention or advances of
31+
any kind
32+
* Trolling, insulting or derogatory comments, and personal or political attacks
33+
* Public or private harassment
34+
* Publishing others' private information, such as a physical or email address,
35+
without their explicit permission
36+
* Other conduct which could reasonably be considered inappropriate in a
37+
professional setting
38+
39+
## Security Research Norms
40+
41+
This project is for **passive vulnerability research** and responsible disclosure
42+
preparation. Community participation also means:
43+
44+
* Do not share live exploit traffic against third-party systems
45+
* Do not post real private finding evidence, credentials, or unreleased
46+
vulnerability details in issues or pull requests
47+
* Prefer sanitized fixtures and public, already-disclosed examples in demos
48+
49+
## Enforcement Responsibilities
50+
51+
Project maintainers are responsible for clarifying and enforcing our standards of
52+
acceptable behavior and will take appropriate and fair corrective action in
53+
response to any behavior that they deem inappropriate, threatening, offensive,
54+
or harmful.
55+
56+
## Scope
57+
58+
This Code of Conduct applies within all community spaces, and also applies when
59+
an individual is officially representing the community in public spaces.
60+
61+
## Enforcement
62+
63+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
64+
reported to the project maintainers through the contact options listed in
65+
[SECURITY.md](SECURITY.md). All complaints will be reviewed and investigated
66+
promptly and fairly.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the
71+
[Contributor Covenant](https://www.contributor-covenant.org), version 2.1,
72+
available at
73+
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
Thanks for helping improve `oh-my-vul`. This project is a Claude Code skill collection, so the most important contribution quality is reproducibility: installed skills, `.skill` archives, and source checkout behavior should all match.
44

5+
By participating, you agree to the [Code of Conduct](CODE_OF_CONDUCT.md).
6+
7+
**Do not commit** local research state (`.omv/`), secrets, live target data, or unreleased vulnerability details. Use sanitized fixtures in issues and pull requests.
8+
9+
Accepted behavior specs live under [`openspec/specs/`](openspec/specs/). In-progress OpenSpec change drafts stay local (`openspec/changes/` is gitignored).
10+
511
## Development Setup
612

713
```sh

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,24 @@ Evidence-first vulnerability research skills for Claude Code.
66
[![npm](https://img.shields.io/npm/v/oh-my-vul)](https://www.npmjs.com/package/oh-my-vul)
77
[![license: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
88

9-
`oh-my-vul` helps you find open-source audit targets, keep evidence in local YAML files, review source -> sink -> guard claims, and draft VulDB/CVE/GHSA/OSV reports from confirmed findings.
9+
`oh-my-vul` is a local-first workbench for passive CVE-style research:
1010

11-
It is built for passive research and local verification. Do not use it to attack live third-party services or invent findings from weak evidence.
11+
1. **Find** audit targets (`/omv-find`)
12+
2. **Prove** source → sink → guard with Evidence.v1 (`/omv-audit`, `/omv-repro`)
13+
3. **Gate** readiness (`omv review --strict`)
14+
4. **Report** VulDB / GHSA / OSV drafts (`/omv-report`)
15+
16+
It does **not** attack live third-party services. Keep real findings under private `.omv/` state; never invent proof from weak evidence.
17+
18+
| | |
19+
|---|---|
20+
| Install | `npx oh-my-vul setup` then `omv doctor` |
21+
| Docs (zh) | [README.zh-CN.md](README.zh-CN.md) |
22+
| Contribute | [CONTRIBUTING.md](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md) |
23+
| Security | [SECURITY.md](SECURITY.md) |
24+
| Specs | [`openspec/specs/`](openspec/specs/) (accepted behavior) |
25+
26+
> **Version note:** npm package is currently **0.9.x**. Campaign / PatternPack / provenance work in this branch is **Unreleased** toward 0.10 — see [CHANGELOG.md](CHANGELOG.md).
1227
1328
## Install
1429

README.zh-CN.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020

2121
> **定位:** `oh-my-vul` 用来辅助研究员发现值得审计的开源项目,整理 **source -> sink -> guard** 证据链,并把已确认的问题转成适合提交给 **VulDB****CVE****GHSA****OSV** 或 Markdown advisory 的报告草稿。
2222
>
23-
> **安全边界:** 本项目只面向*被动研究**本地验证*。它不是批量扫描器,也不是线上攻击工具。
23+
> **安全边界:** 本项目只面向*被动研究**本地验证*。它不是批量扫描器,也不是线上攻击工具。真实 finding 放在私有 `.omv/` 中,不要提交到 Git。
24+
>
25+
> **版本说明:** npm 当前为 **0.9.x**;Campaign / PatternPack / provenance 等能力在 CHANGELOG 中记为 **Unreleased(面向 0.10)**
26+
>
27+
> **社区:** [贡献指南](CONTRIBUTING.md) · [行为准则](CODE_OF_CONDUCT.md) · [安全政策](SECURITY.md) · [行为规格](openspec/specs/)
2428
2529
---
2630

openspec/config.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
schema: spec-driven
2+
3+
context: |
4+
Project: oh-my-vul — a modular collection of LLM-friendly vulnerability research skills for Claude Code.
5+
6+
Tech stack:
7+
- TypeScript CLI (src/cli/) built with tsc; entry point dist/cli/omv.js
8+
- Python scripts (shared/scripts/, skills/*/scripts/) using stdlib only — no third-party deps
9+
- Skill definitions: Markdown files (SKILL.md) with YAML frontmatter, installed to ~/.claude/skills/
10+
- Contracts: YAML schemas (contracts/*.yaml) defining typed handoff objects between skills
11+
12+
Distribution: npm package `oh-my-vul`, installed via `npx oh-my-vul setup`
13+
Skills installed to: ~/.claude/skills/ (user scope) or ./.claude/skills/ (project scope)
14+
15+
Domain: passive CVE/VulDB security research — find open-source packages with potential vulnerabilities,
16+
build source→sink→guard evidence chains, generate advisory reports. No live exploitation.
17+
18+
Key conventions:
19+
- Skill files are concise; ecosystem-specific detail lives in references/ subdirectories
20+
- Scripts use only Python stdlib (no pip install required in skill sessions)
21+
- Contracts define the typed boundary between omv-find (output) and omv-report (input)
22+
- Evidence.v1 is the canonical finding schema: candidate → confirmed → blocked statuses
23+
- Validate with: python3 scripts/validate_skill.py; release with: python3 scripts/release_check.py
24+
25+
Active skills: omv, omv-find, omv-audit, omv-repro, omv-report, omv-radar, omv-dedup,
26+
omv-disclose, and omv-critic.
27+
28+
rules:
29+
proposal:
30+
- Keep proposals under 400 words
31+
- Always include a Non-goals section
32+
- Specify whether changes touch CLI (TypeScript), skills (Markdown), scripts (Python), or contracts (YAML)
33+
tasks:
34+
- Group tasks by file/component (one group per file changed)
35+
- Include a validation task (validate_skill.py or typecheck) and a reinstall task (omv setup --force) in every change that touches skills or CLI
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# campaign-workflow Specification
2+
3+
## Purpose
4+
TBD - created by archiving change add-campaign-workflow. Update Purpose after archive.
5+
## Requirements
6+
### Requirement: Campaigns have a validated local contract
7+
The system SHALL represent a research campaign as a closed-schema `Campaign.v1` YAML object under `.omv/campaigns/<id>.yaml` with a paired Markdown runbook at `.omv/campaigns/<id>.md`, and SHALL reject malformed, calendar-invalid, non-normalized, semantically inconsistent, or undeclared fields before returning or using the object.
8+
9+
#### Scenario: Valid Campaign object
10+
- **WHEN** a campaign contains schema version 1, a safe id, target name, supported enum values, at least one normalized vulnerability class, and matching lanes
11+
- **THEN** campaign validation succeeds and returns the typed normalized object
12+
13+
#### Scenario: Invalid Campaign object
14+
- **WHEN** a campaign YAML file is malformed or omits a required value
15+
- **THEN** campaign validation fails with the artifact path and actionable field errors
16+
17+
#### Scenario: Noncanonical or undeclared Campaign data
18+
- **WHEN** a campaign contains uppercase unknown markers, whitespace-padded normalized text, an invented title, missing baseline safety boundaries, an impossible calendar timestamp, or an undeclared root, nested, or lane field
19+
- **THEN** campaign validation fails before list, show, or seed returns the object
20+
21+
### Requirement: Campaign initialization is deterministic and conservative
22+
The system SHALL require a non-empty target and at least one vulnerability class; normalize text, ids, and vulnerability-class slugs; deduplicate classes while preserving first-seen order; and create one generic lane and deterministic finding id per class. Omitted optional values SHALL default to `mode: passive`, `goal.output: research-notes`, `budget.depth: standard`, `status: active`, `profile: generic`, and `unknown` for target version, source, ecosystem, and local reproduction.
23+
24+
#### Scenario: Initialize with required flags
25+
- **WHEN** the user initializes a campaign with a target and a comma-separated vulnerability-class list
26+
- **THEN** the CLI writes one YAML source of truth and one Markdown runbook with deterministic lanes and finding ids
27+
28+
#### Scenario: Normalize duplicate classes
29+
- **WHEN** vulnerability classes differ only by whitespace, case, or slug punctuation
30+
- **THEN** initialization preserves first-seen order and creates exactly one lane for each normalized class
31+
32+
#### Scenario: Safe public defaults
33+
- **WHEN** the user initializes target `Acme` with vulnerability classes `XSS, xss` and omits every optional value
34+
- **THEN** the Campaign contains one `xss` lane and every documented safe default
35+
36+
#### Scenario: Unknown version is omitted from derived id
37+
- **WHEN** target `Acme` has an omitted or explicit `unknown` version and no explicit id
38+
- **THEN** the derived campaign id is `acme` rather than `acme-unknown`
39+
40+
#### Scenario: Unsafe explicit id
41+
- **WHEN** an explicit campaign id contains unsafe filename characters
42+
- **THEN** initialization fails before either Campaign artifact is written
43+
44+
#### Scenario: Existing campaign is protected
45+
- **WHEN** either campaign artifact already exists and initialization does not include `--force`
46+
- **THEN** the CLI fails without overwriting either artifact
47+
48+
#### Scenario: Concurrent initialization is serialized
49+
- **WHEN** two no-force initializers race to create the same Campaign id
50+
- **THEN** exactly one commits the YAML/runbook pair and the other fails without overwriting it
51+
52+
#### Scenario: Dangling or external symlink is not followed
53+
- **WHEN** a Campaign destination is a symlink, including a dangling symlink or a symlink to an external file
54+
- **THEN** no-force initialization treats it as a collision and force replacement replaces only the directory entry without modifying the symlink target
55+
56+
#### Scenario: Explicit overwrite
57+
- **WHEN** the user repeats initialization with `--force`
58+
- **THEN** the CLI replaces both campaign artifacts from the newly normalized Campaign object
59+
60+
#### Scenario: Pair replacement rolls back on failure
61+
- **WHEN** staging or committing either Campaign artifact fails
62+
- **THEN** initialization leaves no partial new pair and restores any force-replaced artifact entries
63+
64+
#### Scenario: Activity failure is non-fatal
65+
- **WHEN** the YAML/runbook pair commits but workspace activity cannot be appended
66+
- **THEN** initialization succeeds with a warning that names the activity error
67+
68+
### Requirement: Campaign initialization supports safe interactive and non-interactive modes
69+
The system SHALL obtain missing required initialization values through an injectable prompt adapter only in an interactive terminal, and SHALL never prompt when `--no-interactive` or `--json` is present.
70+
71+
#### Scenario: Interactive required values
72+
- **WHEN** an interactive user initializes without a target or vulnerability classes
73+
- **THEN** the prompt adapter supplies the missing required values before normalization and persistence
74+
75+
#### Scenario: JSON is non-interactive
76+
- **WHEN** initialization includes `--json` but omits a required value
77+
- **THEN** the CLI returns an error without invoking the prompt adapter or writing an artifact
78+
79+
#### Scenario: Successful JSON initialization
80+
- **WHEN** initialization supplies a target and vulnerability classes with `--json` but without `--no-interactive`
81+
- **THEN** the CLI never invokes the prompt adapter, writes the YAML/runbook pair, and emits exactly one JSON document
82+
83+
#### Scenario: Non-TTY input is non-interactive
84+
- **WHEN** required values are missing and the command streams are not interactive terminals
85+
- **THEN** the CLI fails with the missing fields instead of waiting for input
86+
87+
### Requirement: Campaigns can be listed and shown without a workspace index
88+
The system SHALL scan `.omv/campaigns/*.yaml` directly for list and show operations, sort campaign summaries by id, and SHALL NOT add Campaign records to `WorkspaceIndex`.
89+
90+
#### Scenario: List campaigns
91+
- **WHEN** multiple valid campaign YAML files exist
92+
- **THEN** `omv campaign list` returns sorted summaries containing ids, targets, statuses, lane counts, and next actions
93+
94+
#### Scenario: Duplicate Campaign source pair
95+
- **WHEN** both `<id>.yaml` and `<id>.yml` exist for the same Campaign id
96+
- **THEN** list and show fail with an actionable duplicate-source error instead of returning inconsistent identities
97+
98+
#### Scenario: List missing campaign directory
99+
- **WHEN** `.omv/campaigns/` does not exist
100+
- **THEN** campaign listing returns an empty result without requiring an index rebuild
101+
102+
#### Scenario: Show campaign as JSON
103+
- **WHEN** the user runs `omv campaign show <id> --json`
104+
- **THEN** stdout is one JSON document containing the parsed Campaign object and its artifact paths
105+
106+
#### Scenario: Unknown ecosystem has an actionable prerequisite
107+
- **WHEN** init, list, show, or runbook rendering handles a Campaign whose target ecosystem is `unknown`
108+
- **THEN** its next action tells the user to set a supported ecosystem before running seed
109+
110+
### Requirement: Campaign command aliases preserve canonical behavior
111+
The system SHALL make `omv first [flags]` an alias of `omv campaign init`, and SHALL map `omv first init|list|show|seed` to the corresponding canonical campaign subcommands while `omv campaign` defaults to `list`.
112+
113+
#### Scenario: First without subcommand
114+
- **WHEN** the user runs `omv first --target acme --vuln xss --no-interactive`
115+
- **THEN** the same Campaign artifacts and result are produced as by the canonical `campaign init` command
116+
117+
#### Scenario: Canonical command without subcommand
118+
- **WHEN** the user runs `omv campaign`
119+
- **THEN** the CLI performs the campaign list operation
120+
121+
### Requirement: Campaign seeding creates hypotheses only
122+
The system SHALL validate the complete Campaign before writes, require a known Evidence-compatible ecosystem, create at most one valid candidate `Evidence.v1` file per lane, never overwrite an existing `.yaml` or `.yml` finding, and MUST NOT create ThreatMap, reproduction, verification, audit, proof-of-concept, or report artifacts. Seed SHALL have no force mode.
123+
124+
#### Scenario: Seed campaign lanes
125+
- **WHEN** a valid campaign with a known Evidence-compatible ecosystem has unseeded lanes
126+
- **THEN** `omv campaign seed <id>` creates candidate findings containing only target identity, ecosystem, vulnerability class, and explicit unknown evidence fields
127+
128+
#### Scenario: Existing YAML or YML finding is skipped
129+
- **WHEN** a lane's `.yaml` or `.yml` finding path already exists
130+
- **THEN** seeding preserves the existing file byte-for-byte and reports the lane as skipped
131+
132+
#### Scenario: Unknown ecosystem blocks seeding
133+
- **WHEN** a campaign target ecosystem is `unknown`
134+
- **THEN** seeding fails before creating any finding and asks for an explicit supported ecosystem
135+
136+
#### Scenario: Seed output has no Campaign coupling or proof artifacts
137+
- **WHEN** seeding completes
138+
- **THEN** created Evidence files contain the deterministically mapped `researcher_goal` and no `campaign_id`, tested version remains unknown, proof fields remain unknown, and no other lane artifact path exists
139+
140+
#### Scenario: Partial seed failure is structured and retryable
141+
- **WHEN** one lane encounters an I/O error after other lanes were created or skipped
142+
- **THEN** the result reports created, skipped, and failed ids with messages, and rerunning remains idempotent
143+
144+
### Requirement: Campaign profiles remain data-driven
145+
Every generated `Campaign.v1` SHALL use `profile: generic` and derive lanes solely from normalized user input. The CLI MUST NOT branch on target names.
146+
147+
#### Scenario: Named target receives no built-in content
148+
- **WHEN** a user initializes a Zimbra campaign with only the `xss` vulnerability class
149+
- **THEN** the Campaign contains only the generic `xss` lane and no built-in Zimbra attack-surface claims
150+

0 commit comments

Comments
 (0)