Download src/data/load_secvuleval.py from Dhruv1000/tracegrpo: direct link, hf CLI and curl.
- Browser
- Download file 3.96 kB
-
https://huggingface.co/Dhruv1000/tracegrpo/resolve/main/src/data/load_secvuleval.py
- Command line
-
hf download hf://Dhruv1000/tracegrpo/src/data/load_secvuleval.py
-
curl -L -o load_secvuleval.py https://huggingface.co/Dhruv1000/tracegrpo/resolve/main/src/data/load_secvuleval.py
3.96 kB
| """Loads SecVulEval (HF: arag0rn/SecVulEval) and normalizes to the unified | |
| corpus schema (spec §3.2). | |
| SecVulEval ships statement-level `changed_statements` (line, code) pairs, | |
| but **its line numbers are relative to the original source FILE, not the | |
| extracted function body** (verified by inspection: a sample with an 80-line | |
| func_body had a changed_statements line number of 877). Silently trusting | |
| them would map every patch line to nothing inside func_vuln. We therefore | |
| recompute `patch_lines_vuln` ourselves via the same diff-based approach as | |
| PrimeVul (`src/data/diff_utils.py`), using `changed_statements` only to | |
| sanity-check CWE/pairing — not for line numbers. See DECISIONS.md | |
| "SecVulEval patch-line numbers were file-absolute, not function-relative". | |
| Pairing is via `fixed_func_idx`, which points from a vulnerable row's `idx` | |
| to its patched counterpart's `idx` in the same table. | |
| `commit_date` is not provided by this dataset directly; recovering it would | |
| require one GitHub API call per of its 6,050 distinct commits, which the | |
| unauthenticated API's 60 req/hour limit makes impractical in one session | |
| (~100+ hours). Left as None here, consistent with PrimeVul rows that didn't | |
| match Big-Vul; see DECISIONS.md. Revisit with a GitHub token if the | |
| chronological split's date coverage needs improving. | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| from pathlib import Path | |
| import pandas as pd | |
| from src.data.diff_utils import diff_and_patch_lines | |
| PARQUET_PATH = Path("data/raw/SecVulEval/secvuleval.parquet") | |
| def _func_hash(text: str) -> str: | |
| return hashlib.sha256(text.encode("utf-8", errors="replace")).hexdigest()[:16] | |
| def _first_or_none(arr) -> str | None: | |
| try: | |
| return arr[0] if arr is not None and len(arr) > 0 else None | |
| except TypeError: | |
| return None | |
| def normalize_secvuleval(path: Path = PARQUET_PATH) -> tuple[list[dict], dict]: | |
| df = pd.read_parquet(path) | |
| by_idx = {int(row.idx): row for row in df.itertuples()} | |
| rows: list[dict] = [] | |
| n_pairs = 0 | |
| seen_pairs: set[frozenset[int]] = set() | |
| for row in df.itertuples(): | |
| if not row.is_vulnerable: | |
| continue | |
| fixed_idx = row.fixed_func_idx | |
| if fixed_idx is None or pd.isna(fixed_idx): | |
| continue | |
| fixed_idx = int(fixed_idx) | |
| if fixed_idx not in by_idx: | |
| continue | |
| patch_row = by_idx[fixed_idx] | |
| pair_key = frozenset((int(row.idx), fixed_idx)) | |
| if pair_key in seen_pairs: | |
| continue | |
| seen_pairs.add(pair_key) | |
| n_pairs += 1 | |
| cve = _first_or_none(row.cve_list) | |
| cwe = _first_or_none(row.cwe_list) | |
| pair_id = f"secvuleval:{row.commit_id}:{row.idx}" | |
| diff_text, patch_lines_vuln = diff_and_patch_lines(row.func_body, patch_row.func_body) | |
| # sample_id includes the row's own idx, not just a content hash: two | |
| # different pairs from the same commit can converge to an identical | |
| # func text (verified in PrimeVul; guarding against it here too). | |
| for target, func_text in ((1, row.func_body), (0, patch_row.func_body)): | |
| sample_id = f"secvuleval:{cve or 'NOCVE'}:{row.commit_id}:{row.idx}:{_func_hash(func_text)}" | |
| rows.append({ | |
| "sample_id": sample_id, | |
| "source": "secvuleval", | |
| "project": row.project, | |
| "cve": cve, | |
| "cwe": cwe, | |
| "commit_id": row.commit_id, | |
| "func_vuln": row.func_body, | |
| "func_patch": patch_row.func_body, | |
| "diff": diff_text, | |
| "patch_lines_vuln": patch_lines_vuln if target == 1 else [], | |
| "commit_date": None, | |
| "target": target, | |
| "pair_id": pair_id, | |
| }) | |
| stats = { | |
| "n_pairs": n_pairs, | |
| "n_rows": len(rows), | |
| "n_with_date": 0, | |
| "date_coverage": 0.0, | |
| } | |
| return rows, stats | |