diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b07554f..f09f2651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,98 @@ All notable changes to OpenAnt are documented in this file. +## [2026-05-07] — Incremental scans + scan pipeline rewire + +### Changed + +- **`openant scan` rewired end-to-end.** The full pipeline is now + explicit and visible in `--help`: + `init → parse → app-context → enhance → analyze → verify → + build-output → dynamic-test → report`. A single run-mode decision + (full vs incremental) is resolved once — at `init` or at `scan` — + and recorded in a per-run `meta.json` whose status field + transitions `running → success | failed | interrupted`. Step verbs + (`parse`, `enhance`, …) read that file and inherit the mode, so a + standalone step after `init --incremental` filters correctly + without re-passing flags. Docker is preflighted before any work + begins, so a missing daemon is reported up front instead of after + a full pipeline run. +- **Dynamic testing is on by default.** The opt-in `--dynamic-test` + flag has been replaced by an opt-out `--skip-dynamic-test`. `scan` + now produces dynamic verification of findings out of the box; + callers without Docker should pass `--skip-dynamic-test`. + +### Added + +- **Incremental scans.** New `openant diff` subcommand and + `--diff-base`, `--pr`, and `--diff-scope` flags on `scan` and + `parse` scope the pipeline to changed files only. Go computes a + `diff_manifest.json` from the working tree (or a fetched PR head) + and threads it through every stage — parse → enhance → analyze → + report — so each phase only processes what changed. The diff range + surfaces in the CSV export, `_summary.json`, the standalone HTML + report, the report header, and the live scan banner. +- **Explicit run-mode flags on `init`, `scan`, and `parse`** — + `--full`, `--incremental`, `--diff-base `, `--pr `, and + `--diff-scope`. With a baseline present, an interactive TTY shows + a recap prompt (default Enter = full, the safer choice); non-TTY + callers without a flag get a loud error so CI scripts fail fast + instead of silently picking a mode. + +### Fixed + +- **Python call graph no longer drops `self.X()` calls.** The call- + graph builder fed function bodies straight into `ast.parse`, but + method bodies are stored with their original class indentation — + so `ast.parse` raised `IndentationError`, the regex fallback ran + without `self.X()` resolution, and every method-to-method call in + every Python codebase silently disappeared from the graph. On + dbt-core that meant 2,243 of 3,116 functions (72%) marked isolated + and a real scan returning zero findings. The fix dedents a + temporary copy before parsing and leaves the stored source byte- + correct so the disclosure renderer's offsets stay valid. +- **Disclosure code is byte-faithful to source.** The disclosure + renderer pulls the actual file slice from the repo instead of + rerunning an LLM rewrite, so every finding's `Vulnerable Code` + block matches the real source. +- **No more silent 401s.** `openant set-api-key` validates the key + on save and fails loudly on bad input. `openant scan` prints a + blocking warning and exits non-zero when zero API calls succeed, + so an all-401 run can no longer masquerade as a clean repo. +- **CWE tagging is systematic.** `pipeline_output.json` carries + non-null `cwe`, `cwe_id`, and `vulnerability_type` for every + finding. The Stage 1 prompt asks for them directly rather than + relying on the renderer LLM to infer them from prose. +- **Repo metadata reaches every report envelope.** Repo name, + commit SHA, and file count are threaded into `parse.report.json` + and `scan.report.json` instead of being lost between stages, + eliminating the `[NOT PROVIDED]` placeholders. +- **`Verified` column reflects the highest evidence tier.** + `dynamic` > `verified` > `static`, so dynamically reproduced + findings show as `dynamic` and the disclosure footer reads + "Confirmed via dynamic test" where applicable. +- **Call-graph-aware deduplication.** When two findings share a + sink/vector and the call graph records an edge between them, + they collapse into a single finding. +- **Dedup matches on CWE** instead of `attack_vector` text, so + small wording differences no longer split what's logically the + same finding. +- **Dynamic test Docker context is complete on the first try.** + `openant dynamic-test` pre-stages the vulnerable source file + into the Docker build context end-to-end through the dynamic- + test chain — first-try builds no longer fail because the source + isn't in context. +- **Concurrency-safe Docker resources.** Docker image and network + names get a UUID prefix so parallel dynamic-test workers can't + collide. +- **Agreement filter checks the final verdict** instead of the + intermediate `agree` flag, so high-confidence dynamic results + aren't dropped by a stale agreement signal. +- **Report prompts respect non-interactive runs.** Prompt output + goes to stderr (keeping stdout clean for piped JSON) and the + prompt is skipped entirely when there's no TTY, so CI/scripted + invocations no longer hang. + ## [2026-04-29] — Python parser dedent fix ### Fixed