Files
Open_Ultra_SAST/.kiro/specs/real-world-vfc-slice/design.md
T
Marius CiepluchandClaude Opus 4.8 39a1873e5b docs: plain-English pass over the active specs
Ran the humanizer rules over 79 prose files in the active specs (brief,
design, requirements, research and narrative docs). Removed em dashes,
significance inflation, forced rule-of-three, bold-label list items and
filler. Skipped tasks.md checklists and the retired specs (harnessx-*,
openrouter-sast-harness, unseen-repo-evaluation).

Every number, path, command, hash and identifier was preserved: checked
each file against HEAD for drift in numbers, inline code and code fences,
zero drift across all 79 files.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-10-12 18:16:41 +02:00

377 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design Document
## Overview
**Purpose.** This feature gives OpenUltraSAST a labeled vuln-versus-fix slice from real OpenSSL, Firefox, and Chromium functions so engineers can evolve the harness against product code instead of only OWASP/Juliet.
**Users.** Maintainers grow and score the catalog. AppSec engineers read the honesty dashboard. CI proves the catalog loads and the slice command runs offline.
**Impact.** A new `vfc` slice is concatenated into the pair catalog. Overlay and inventory scores are reported side by side for that slice. The local 100% pair gate and the stage-1 smoke gate do not change.
### Goals
- Seed at least one reviewed isolated function pair each from OpenSSL, Firefox, and Chromium, with provenance.
- Score `vfc` as an honesty dashboard with overlay versus inventory figures.
- Harvest one function from public parent/fix blobs without cloning megarepos.
- Keep CI extra-free and offline; vfc Youden is not a merge condition.
### Non-Goals
- Cloning mozilla-central, gecko-dev, or Chromium.
- FixFox, Bugzilla scraping, or vendoring VFC dumps.
- CWE-121 buffer-size semantics, inter-file taint, or parser extra packaging.
- Changing inventory rules so the seed pairs become pair_correct.
- Making overlay or vfc Youden fail CI.
## Boundary Commitments
### This Spec Owns
- The `vfc` pair slice: catalog rows, vendored excerpts, provenance headers, recipes.
- Harvest procedure that extracts one function from public parent/fix snapshots.
- Dual overlay/inventory scoreboard fields for the vfc slice.
- CLI slice choice `vfc` and tests that the slice loads and runs.
- Dataset pointers for OpenSSL, Firefox/gecko-dev, and Chromium.
### Out of Boundary
- Overlay dispositions, taint, facts, FileIR (`propose-adjudicate-prove`).
- Tree-sitter extra packaging (`tree-sitter-overlay-extra`).
- Stage-1 `LANGUAGE_MANIFESTS` detection gate and local 100% pair gate fail condition.
- Pattern rule bodies; do not retune memcpy/eval to chase vfc Youden.
- Memory-safety / CWE-121 semantics (later spec may reuse these pairs).
### Allowed Dependencies
- Existing `PairCase` / `load_pair_catalog` / `evaluate_pair` / `result_payload`.
- Overlay pair path already used by `sast` (inventory fallback when unadjudicated).
- Stdlib HTTP client for harvest (maintainer-only, not CI).
- Public hosts: GitHub raw blobs, hg.mozilla.org / Phabricator raw diffs.
### Revalidation Triggers
- Changing `PairCase` required fields or catalog concatenation order.
- Failing CI on any slice other than `local`.
- Adding vfc names to `LANGUAGE_MANIFESTS`.
- Making harvest a network-using CI step.
- Importing parser wheels into harvest or pair eval.
## Architecture
### Existing Architecture Analysis
Pair eval materializes each side of a pair into an isolated temp tree and scans it. `local` and `github` use inventory (`quick_scan`). `sast` uses overlay, falling back to inventory when no promote/demote/coverage occurred. Catalog load already concatenates a second file. The pair gate prints every slice but fails only when `local` pair_pass_rate is below 100%.
### Architecture Pattern and Boundary Map
Selected: **concatenated honesty slice + dual scoreboard**. Same catalog schema. Overlay eval generalized from `sast` to `{sast, vfc}`. Inventory sidecar computed only for vfc.
```mermaid
flowchart TD
cli[ousast pairs slice vfc]
load[load_pair_catalog]
mainCat[pairs catalog]
sastCat[sast catalog]
vfcCat[vfc catalog]
eval[evaluate_pair]
overlay[overlay with inventory fallback]
inventory[inventory only]
board[result payload]
gate[pair_gate local only]
cli --> load
load --> mainCat
load --> sastCat
load --> vfcCat
load --> eval
eval --> overlay
eval --> inventory
overlay --> board
inventory --> board
load --> gate
```
**Key decisions**
- Primary `per_slice.vfc` metrics come from overlay-with-fallback (same as sast).
- `scorers.vfc.overlay` and `scorers.vfc.inventory` are explicit so operators can compare.
- Harvest never runs in pytest. Seed excerpts are committed.
- Dependency direction: recipes/excerpts → vfc catalog → pair loader → eval → CLI payload. Harvest writes excerpts; it does not import overlay.
### Technology Stack
| Layer | Choice / Version | Role in Feature | Notes |
|-------|------------------|-----------------|-------|
| CLI | existing `ousast pairs --slice` | Operator entry | Add `vfc` to choices |
| Catalog | TOML `[[pair]]` | Same schema as github/sast | New file, concatenated |
| Scoring | existing overlay + inventory | Dual scoreboard | No new taint engine |
| Harvest | Python stdlib urllib | Maintainer fetch | Not a core package dep |
| Tests | pytest extra-free | Offline existence + CLI | No network |
## File Structure Plan
```
benchmarks/pairs/
├── catalog.toml # unchanged rows; still the default path
├── datasets.toml # add OpenSSL, Firefox, Chromium pointers
├── README.md # document vfc slice
├── sast/catalog.toml # unchanged
└── vfc/
├── catalog.toml # slice = vfc rows
├── recipes.toml # harvest inputs for seed and later pairs
├── harvest.py # extract one function from parent/fix URLs
├── openssl-cve-2014-0160/
│ ├── vuln.c
│ └── fixed.c
├── firefox-cve-2020-15667/
│ ├── vuln.c
│ └── fixed.c
└── chromium-cve-2019-5786/
├── vuln.cc
└── fixed.cc
```
### Modified Files
- `src/openultrasast/pairs.py`: concatenate vfc catalog; overlay path for `vfc`; `scorers` on the eval result; `DEFAULT_VFC_CATALOG`.
- `src/openultrasast/cli.py`: `--slice` choice `vfc`.
- `src/openultrasast/pair_gate.py`: comment that vfc is honesty-only; fail condition stays local.
- `tests/test_pair_corpus.py`: vfc load, provenance, CLI, not in `LANGUAGE_MANIFESTS`, pair_gate still passes.
- `benchmarks/pairs/datasets.toml`: project pointers.
- `benchmarks/pairs/README.md`: slice list and harvest pointer.
## System Flows
```mermaid
sequenceDiagram
participant Op as Operator
participant CLI as pairs command
participant Cat as vfc catalog
participant Eval as pair eval
participant Inv as inventory scan
participant Ov as overlay adjudicate
Op->>CLI: pairs slice vfc
CLI->>Cat: load concatenated catalogs
Cat->>Eval: each vfc pair
Eval->>Inv: vuln tree and fix tree
Eval->>Ov: same trees
Ov-->>Eval: promote or fallback
Inv-->>Eval: inventory sidecar
Eval-->>CLI: outcomes plus scorers
CLI-->>Op: JSON or text scoreboard
```
Harvest (maintainer, not CI): recipe → fetch parent blob and fix blob → extract named function → write provenance header → write vuln/fixed files. Catalog rows stay hand-reviewed.
## Requirements Traceability
| Requirement | Summary | Components | Interfaces | Flows |
|-------------|---------|------------|------------|-------|
| 1.1, 1.2, 1.3 | vfc slice with three projects | VfcCatalog | catalog load | pairs command |
| 1.4 | reject advisory-only | HarvestTool, VfcCatalog | recipe validation | harvest |
| 2.1–2.4 | provenance and same relpath | ProvenanceHeader, VfcCatalog | catalog fields + file header | harvest |
| 3.1–3.4 | honesty not merge gate | PairGatePolicy, DualScorer | pair_gate, payload | gate |
| 4.1–4.4 | overlay vs inventory | DualScorer | scorers map | pairs command |
| 5.1–5.5 | harvest without clones | HarvestTool | recipes + harvest script | harvest |
| 6.1–6.4 | isolated reviewed functions | VfcCatalog, SeedExcerpts | expected CWE/sink | pair eval |
| 7.1–7.4 | offline testability | VfcTestMatrix | pytest + CLI | extra-free CI |
## Components and Interfaces
| Component | Domain/Layer | Intent | Req Coverage | Key Dependencies | Contracts |
|-----------|--------------|--------|--------------|------------------|-----------|
| VfcCatalog | Catalog | Reviewed vfc rows | 1.1, 1.2, 1.3, 2.3, 6.4 | Pair loader P0 | State |
| ProvenanceHeader | Catalog | Auditable origin on disk | 2.1, 2.2, 2.4 | VfcCatalog P0 | State |
| HarvestTool | Maintainer | Extract one function from public blobs | 1.4, 5.1, 5.2, 5.3, 5.4 | urllib P1 | Batch |
| DualScorer | Eval | Overlay primary + inventory sidecar | 4.1, 4.2, 4.3, 4.4, 3.3 | overlay eval P0 | State |
| PairGatePolicy | Eval | Local-only fail | 3.1, 3.2, 3.4, 7.4 | pair_gate P0 | State |
| SeedExcerpts | Catalog | Three isolated functions | 1.2, 6.1, 6.2, 6.3 | VfcCatalog P0 | State |
| VfcTestMatrix | Tests | Offline load and CLI | 7.1, 7.2, 7.3, 5.5 | pytest P0 | State |
### Catalog
#### VfcCatalog
| Field | Detail |
|-------|--------|
| Intent | Concatenated `slice = "vfc"` rows with OpenSSL, Firefox, Chromium seeds |
| Requirements | 1.1, 1.2, 1.3, 2.3, 6.4 |
**Responsibilities & Constraints**
- Same `[[pair]]` / `[[pair.expected]]` schema as github/sast.
- `load_pair_catalog` appends `benchmarks/pairs/vfc/catalog.toml` when loading the default catalog.
- Names stay out of `LANGUAGE_MANIFESTS`.
- Runnable set stays small; recipes may list more than CI runs.
**Dependencies**
- Inbound: pair loader: concatenate file (P0)
- Outbound: evaluate_pair: cases (P0)
**Contracts**: State [x]
##### State Management
- `DEFAULT_VFC_CATALOG` next to `DEFAULT_SAST_CATALOG`.
- Missing vfc file: do not crash default load if we require the seed to exist; the seed is committed so the file is present. Tests assert it exists.
#### ProvenanceHeader
| Field | Detail |
|-------|--------|
| Intent | Human-readable origin on every vendored excerpt |
| Requirements | 2.1, 2.2, 2.4 |
**Responsibilities & Constraints**
- Header comments include repo, commit, parent, commit URL, CVE, license, function name.
- Catalog row repeats repo, commit, commit_url, cve, license.
- License must be stated (OpenSSL License, MPL-2.0, BSD-3-Clause for the seeds).
#### SeedExcerpts
| Field | Detail |
|-------|--------|
| Intent | Isolated functions, same relpath, reviewed labels |
| Requirements | 1.2, 6.1, 6.2, 6.3 |
Seed pairs (reviewed):
| Name | Project | CVE | Function | Expected class | Honesty note |
|------|---------|-----|----------|----------------|--------------|
| openssl-cve-2014-0160 | OpenSSL | CVE-2014-0160 | `tls1_process_heartbeat` | CWE-126 / memcpy | memcpy remains after fix → likely LEAK |
| firefox-cve-2020-15667 | Firefox libmar | CVE-2020-15667 | `mar_insert_item` | CWE-119 / memcpy | namelen signedness fix; memcpy remains → likely LEAK |
| chromium-cve-2019-5786 | Chromium Blink | CVE-2019-5786 | `FileReaderLoader::ArrayBufferResult` | CWE-416 UAF | no inventory sink → likely MISS |
Stubs (SSL types, MarItem, DOMArrayBuffer) are allowed only to keep the changed function intact.
### Eval
#### DualScorer
| Field | Detail |
|-------|--------|
| Intent | Overlay-with-fallback as primary vfc metrics; inventory sidecar |
| Requirements | 4.1, 4.2, 4.3, 4.4, 3.3 |
**Responsibilities & Constraints**
- `evaluate_pair` uses overlay when `slice in {"sast", "vfc"}`.
- Inventory-only evaluation of vfc cases fills `PairEvalResult.scorers["vfc"]["inventory"]`.
- Overlay metrics also appear as `scorers["vfc"]["overlay"]` (same numbers as `per_slice["vfc"]`).
- `result_payload` includes `scorers`.
- Do not use these figures as a gate.
**Contracts**: State [x]
```python
class PairEvalResult:
outcomes: tuple[PairOutcome, ...]
overall: PairCorpusMetrics
per_slice: dict[str, PairCorpusMetrics]
signals: tuple[dict[str, object], ...]
scorers: dict[str, dict[str, PairCorpusMetrics]]
```
##### Service Interface
- `evaluate_catalog(cases) -> PairEvalResult`
- Preconditions: each case has existing vuln and fixed files.
- Postconditions: if any case has `slice == "vfc"`, `scorers["vfc"]` has `overlay` and `inventory`.
- Invariants: pair_gate fail reasons mention only local.
#### PairGatePolicy
| Field | Detail |
|-------|--------|
| Intent | Keep merge fail on local 100% only |
| Requirements | 3.1, 3.2, 3.4, 7.4 |
`pair_gate` may still *evaluate* the full catalog for the printed dashboard. It must not add vfc pair_correct to `reasons`.
### Maintainer
#### HarvestTool
| Field | Detail |
|-------|--------|
| Intent | Fetch parent/fix blobs and extract one function |
| Requirements | 1.4, 5.1, 5.2, 5.3, 5.4 |
**Contracts**: Batch [x]
##### Batch / Job Contract
- Trigger: maintainer runs harvest with a recipe name. CI does not.
- Input: `recipes.toml` row: name, host, repo, parent, commit, path, function, cve, license, relpath.
- Validation: parent and commit required; reject recipes that have only an advisory URL.
- Output: vuln/fixed files with provenance headers. Catalog row is still a human edit.
- Idempotency: overwrite excerpts for that recipe name; do not fetch in tests.
Function extract: start at the named declarator, copy through balanced braces. Do not clone a repo; HTTP GET of a raw blob or a raw diff.
Hosts: `raw.githubusercontent.com`, Phabricator `?diff=1`. Not FixFox.
### Tests
#### VfcTestMatrix
| Field | Detail |
|-------|--------|
| Intent | Offline proof the corpus exists and the slice runs |
| Requirements | 7.1, 7.2, 7.3, 5.5 |
- Catalog load includes `vfc`; files exist; names include openssl, firefox, chromium.
- Provenance headers contain commit URL, CVE, license.
- `ousast pairs --slice vfc --json` exits 0; payload has those names and `scorers.vfc`.
- Pair gate still passes; vfc names not in `LANGUAGE_MANIFESTS`.
- Harvest extract is unit-tested on a local string, not the network.
- Do not assert 100% pair_correct or a Youden floor.
## Data Models
### Domain Model
- **Pair**: isolated vuln snapshot + fixed snapshot + expected CWE/sink + provenance.
- **Slice**: `vfc` honesty set. Not a gate.
- **Scorer**: `overlay` or `inventory`.
- **Recipe**: harvest input, not ground truth until reviewed into the catalog.
### Logical Data Model
Catalog row (existing fields plus required provenance for vfc):
- `name`, `slice = "vfc"`, `language`, `origin`, `license`, `repo`, `commit`, `parent`, `commit_url`, `cve`, `vuln`, `fixed`, `relpath`, `min_recall`, `fix_policy = "silent"`
- `[[pair.expected]]`: `cwe`, `class`, `path`, `rule_id`, `sink`, `evidence`
`scorers` payload:
```json
{
"scorers": {
"vfc": {
"overlay": { "pairs": 3, "pair_correct": 0, "youden": 0.0 },
"inventory": { "pairs": 3, "pair_correct": 0, "youden": 0.0 }
}
}
}
```
Exact counts are not a contract; presence of both objects is.
## Error Handling
- Missing vfc catalog file when loading the default catalog: fail tests (seed is required). Loading an explicit `--catalog` path does not auto-append vfc.
- Harvest HTTP failure: non-zero exit, no partial file without a provenance header.
- Advisory-only recipe: reject before fetch.
- Overlay parse_failed / language_unsupported: inventory fallback (existing sast behavior).
## Testing Strategy
- Unit: harvest brace-extract on a fixture string; catalog load sees three project names; provenance fields non-empty.
- Integration: `evaluate_catalog(select_slice(..., "vfc"))` returns three outcomes and both scorers; pair_gate still passed.
- CLI: `main(["pairs", "--slice", "vfc", "--json"])` == 0.
- Regression: `LANGUAGE_MANIFESTS` leak check includes vfc names; extra-free suite still green.
## Security Considerations
- Vendored excerpts are public historical vuln code with license headers. Do not vendor exploit PoCs (Chromium FileReader exploit HTML is out of scope; only the C++ function).
- Harvest talks only to listed public hosts. No Bugzilla credentials. No FixFox.
## Supporting References
Seed commit identifiers are recorded in `research.md` and must appear in the vendored headers at implementation time.