From 767d56028c195d2acb3cfd1b73146fed6c771ffe Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 01:48:02 +0000 Subject: [PATCH 1/2] fix(oracle): make CodeQL run the dispose query + auto-pick a build target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first real oracle run (DapperLib/Dapper, run 27659607294) exposed two harness gaps that made BOTH oracles silently contribute nothing — the same way the first mine exposed two extractor false positives. - CodeQL: request `queries: security-and-quality`. `cs/local-not-disposed` and the other dispose/leak queries are *quality* queries, absent from the default code-scanning (security) suite. CodeQL reported 0 leaks because the query never ran (a false zero), not because the code was clean. - Infer# build: `dotnet build target` (the repo root) hit MSB1050 on Dapper (>1 solution/project present), so the build failed and Infer# was skipped. Now pick a target: explicit `build` input wins; else a lone *.sln; else the dir (still continue-on-error -> partial report). - docs/notes/oracle.md: record both (the security-and-quality requirement and the lone-.sln autodetect). No comparator code change. oracle.yml valid YAML; oracle selftest 12/12; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED --- .github/workflows/oracle.yml | 23 ++++++++++++++++++++--- docs/notes/oracle.md | 13 +++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml index 3a6a81dd..9f16ba92 100644 --- a/.github/workflows/oracle.yml +++ b/.github/workflows/oracle.yml @@ -83,8 +83,10 @@ jobs: scripts/own-check.sh --format human -- "$scan" > own.txt 2> own-extract.log echo "own-check rc=$? ; $(wc -l < own.txt) finding line(s)" - # CodeQL — database from source (no build), default queries; we filter to - # the dispose/leak family in the comparator. + # CodeQL — database from source (no build). The dispose/leak queries + # (cs/local-not-disposed & friends) are *quality* queries, absent from the + # default code-scanning (security) suite — so request security-and-quality, + # else CodeQL silently contributes zero. Comparator filters to the leak family. - name: CodeQL init uses: github/codeql-action/init@v3 continue-on-error: true @@ -92,6 +94,7 @@ jobs: languages: csharp build-mode: none source-root: target + queries: security-and-quality - name: CodeQL analyze uses: github/codeql-action/analyze@v3 continue-on-error: true @@ -101,12 +104,26 @@ jobs: upload: false # Infer# — needs compiled binaries; build the target into one output dir. + # `dotnet build ` errors (MSB1050) when a repo root holds more than one + # project/solution, so choose a target: explicit `build` input wins; else a + # lone *.sln; else the dir (may fail -> continue-on-error -> partial report). - name: Build the target (for Infer#) env: BUILD: ${{ inputs.build }} continue-on-error: true run: | - tgt="target"; [[ -n "$BUILD" ]] && tgt="target/$BUILD" + if [[ -n "$BUILD" ]]; then + tgt="target/$BUILD" + else + mapfile -t slns < <(find target -maxdepth 2 -name '*.sln' | sort) + if [[ ${#slns[@]} -eq 1 ]]; then + tgt="${slns[0]}" + else + tgt="target" + echo "note: found ${#slns[@]} .sln under target; pass the 'build' input to disambiguate" + fi + fi + echo "Infer# build target: $tgt" if dotnet build "$tgt" -c Release -o _bin -v quiet; then echo "BUILD_OK=1" >> "$GITHUB_ENV" else diff --git a/docs/notes/oracle.md b/docs/notes/oracle.md index e892c3da..36373ff4 100644 --- a/docs/notes/oracle.md +++ b/docs/notes/oracle.md @@ -36,7 +36,9 @@ Two classes sit **outside** the three-way diff and are reported separately: CodeQL constructs a database (here via `build-mode: none`, from source), Infer# analyses compiled `.dll`+`.pdb`. So the oracle run can fail where ours doesn't — that asymmetry is the point, and each oracle step is `continue-on-error` so a - build failure still yields a partial report. + build failure still yields a partial report. (For Infer#, the workflow builds a + lone `*.sln` automatically; a repo root with several needs the `build` input — + `dotnet build ` is ambiguous otherwise, MSB1050.) - **Path/line matching is deliberately loose.** Tools disagree on the exact line (allocation site vs declaration) and on path prefixes. The comparator matches on **basename + a line window** (`--line-tol`, default 3). Robust to prefixes; @@ -91,9 +93,12 @@ line up with two independent engines. - **No tool versions pinned in the report yet.** `microsoft/infersharpaction@v1.5` and `github/codeql-action@v3` float on tags; the report header names the tools but not exact analyser versions. A later pass can stamp them. -- **CodeQL runs the default suite, filtered in the comparator** (rather than a - single-query pack). Simpler and robust to suite/version drift; the filter keys - on the dispose/leak rule family. +- **CodeQL runs the `security-and-quality` suite, filtered in the comparator** + (rather than a single-query pack). This matters: the dispose/leak queries + (`cs/local-not-disposed` & friends) are *quality* queries, **absent from the + default code-scanning (security) suite** — without the suite, CodeQL silently + contributes zero. The filter keys on the dispose/leak rule family; robust to + version drift. - **One target, by hand.** Same discipline as mining: a deliberate spot-check, not a crawler. Be a good citizen (shallow, read-only). - **Agreement is necessary, not sufficient.** Two tools can share a blind spot. From 2afccab41e6e3fae60af4ca2c0f03c4359e0fca6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 01:55:24 +0000 Subject: [PATCH 2/2] fix(oracle): root-first .sln autodetect (address CodeRabbit #22) CodeRabbit (valid, Minor): `find -maxdepth 2` would miss a repo whose only solution sits deeper, forcing the dir fallback. Their suggested unlimited `find` over-corrects, though: a repo with a clean root solution plus nested sample .slns would then read as "multiple" and fall back unnecessarily. Root-first instead: a unique root-level *.sln wins; if none at root, a unique solution anywhere (this is the deep-lone-.sln case they flagged); else fall back to the dir + a note. More robust than either fixed depth. oracle.yml valid YAML; build-step bash parses. Docs note updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED --- .github/workflows/oracle.yml | 15 ++++++++++----- docs/notes/oracle.md | 7 ++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml index 9f16ba92..acf767e6 100644 --- a/.github/workflows/oracle.yml +++ b/.github/workflows/oracle.yml @@ -106,7 +106,7 @@ jobs: # Infer# — needs compiled binaries; build the target into one output dir. # `dotnet build ` errors (MSB1050) when a repo root holds more than one # project/solution, so choose a target: explicit `build` input wins; else a - # lone *.sln; else the dir (may fail -> continue-on-error -> partial report). + # lone solution (root-preferred); else the dir (continue-on-error -> partial). - name: Build the target (for Infer#) env: BUILD: ${{ inputs.build }} @@ -115,12 +115,17 @@ jobs: if [[ -n "$BUILD" ]]; then tgt="target/$BUILD" else - mapfile -t slns < <(find target -maxdepth 2 -name '*.sln' | sort) - if [[ ${#slns[@]} -eq 1 ]]; then - tgt="${slns[0]}" + # Prefer a unique solution at the repo root; else a unique solution + # anywhere (covers a lone deep .sln); else fall back to the dir + note. + mapfile -t root_slns < <(find target -maxdepth 1 -name '*.sln' | sort) + mapfile -t all_slns < <(find target -name '*.sln' | sort) + if [[ ${#root_slns[@]} -eq 1 ]]; then + tgt="${root_slns[0]}" + elif [[ ${#root_slns[@]} -eq 0 && ${#all_slns[@]} -eq 1 ]]; then + tgt="${all_slns[0]}" else tgt="target" - echo "note: found ${#slns[@]} .sln under target; pass the 'build' input to disambiguate" + echo "note: ${#root_slns[@]} root / ${#all_slns[@]} total .sln under target; pass the 'build' input to disambiguate" fi fi echo "Infer# build target: $tgt" diff --git a/docs/notes/oracle.md b/docs/notes/oracle.md index 36373ff4..27f8112e 100644 --- a/docs/notes/oracle.md +++ b/docs/notes/oracle.md @@ -36,9 +36,10 @@ Two classes sit **outside** the three-way diff and are reported separately: CodeQL constructs a database (here via `build-mode: none`, from source), Infer# analyses compiled `.dll`+`.pdb`. So the oracle run can fail where ours doesn't — that asymmetry is the point, and each oracle step is `continue-on-error` so a - build failure still yields a partial report. (For Infer#, the workflow builds a - lone `*.sln` automatically; a repo root with several needs the `build` input — - `dotnet build ` is ambiguous otherwise, MSB1050.) + build failure still yields a partial report. (For Infer#, the workflow + auto-builds a lone solution — a root-level `*.sln` preferred, else a unique one + anywhere; a repo with several needs the `build` input, since `dotnet build + ` is ambiguous otherwise, MSB1050.) - **Path/line matching is deliberately loose.** Tools disagree on the exact line (allocation site vs declaration) and on path prefixes. The comparator matches on **basename + a line window** (`--line-tol`, default 3). Robust to prefixes;