Skip to content

Add audit/ — Own.NET Audit static-layer orchestrator + aggregation pipeline#100

Merged
PhysShell merged 3 commits into
mainfrom
claude/brave-gauss-elvquy
Jun 25, 2026
Merged

Add audit/ — Own.NET Audit static-layer orchestrator + aggregation pipeline#100
PhysShell merged 3 commits into
mainfrom
claude/brave-gauss-elvquy

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 24, 2026

Copy link
Copy Markdown
Owner

First deliverable of the Own.NET Audit plan (Plan.md, merged in #99): the
build-free static tier plus the full normalize → score → report
aggregation. Everything here runs and is tested on Linux CI with no target build
and no external tools — the target itself is audited on a local Windows machine,
never in CI.

What's here

Aggregation core (audit/aggregate/), each module with an embedded-fixture
--selftest in the oracle_compare style (48 checks total):

  • normalize.py — reads every tool's SARIF through the same parse_sarif
    as oracle_compare (reused, not duplicated), maps (tool, ruleId) → a Plan.md
    §2 category via static/taxonomy/categories.yml. The umbrella OWN001 code
    is split by its [resource: …] tag so subscription/timer leaks land in
    categories 2/3 instead of collapsing into IDisposable (cat. 1); OWN014 is
    labelled region-escape. DevExpress findings are baseline-suppressed — counted in
    coverage, never hidden. Unmapped rules surface as pending taxonomy, not dropped.
  • score.py — generalizes oracle_compare.compare() into cross-tool
    agreement (≥2 tools at basename + line-window → high confidence), category-driven
    P0–P3 severity, and a per-module pain heatmap ("where does it hurt most").
  • report.py — markdown health report + machine JSON, with a load-bearing
    coverage/honesty section (NO-TOOL categories, suppressed count, unmapped rules).

Static layer (audit/static/):

  • run_static.py orchestrator (build-free runners → aggregate → report), with
    a full end-to-end --selftest on embedded SARIF fixtures.
  • tools/owncheck.py (own-check.sh --format sarif, build-free; graceful
    when dotnet is absent), codeql.sh (build-mode=none, security-and-quality
    suite), and the build-required Windows runners roslyn_pack.ps1 / infersharp.sh
    (real skeletons, NO-TOOL exit when the tool is absent).
  • inject/ analyzer props+targets under MSBuild's recognized names, gated on
    /p:OwnAudit=true; taxonomy/categories.yml; config/profiles/desktop-wpf.yml.

Decoupling (Plan.md §7)

Imports nothing from the ownlang core. The only in-repo seam is
scripts/oracle_compare.parse_sarif (a pure SARIF reader, vendored on lift-out);
own-check is consumed only via its CLI. PyYAML is scoped to audit/
(requirements.txt) so the core test suite stays zero-dependency.

CI

A new audit-selftests job installs the audit-scoped PyYAML and runs the four
selftests (normalize + score + report + orchestrator). Tree-wide ruff already
covers audit/.

normalize selftest: 18/18 · score selftest: 9/9 · report selftest: 13/13 · run_static selftest: 8/8

Deferred (later phases)

HTML + merged-SARIF renderers; the runtime layer (FlaUI + ClrMD leak-harness,
duplicate-immutable detector); the AI-reviewer layer; feeding confirmed findings
back into the OwnLang corpus.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QDPpNT9Uh8RoTrKPvgcoRE


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added an Own.NET Audit orchestrator that runs build-free/build-required analyzers, aggregates SARIF, and generates ranked Markdown/JSON health reports.
    • Introduced a new desktop WPF audit profile and supporting local runners for owning-check, CodeQL, Roslyn analyzer packing, and Infer#.
    • Added build-time injection support to emit per-project SARIF and enable audit collection.
  • Documentation

    • Expanded audit documentation with architecture, profiles, and step-by-step run guidance.
  • Tests

    • Added CI-gated selftests covering normalization, scoring, coverage, and report rendering.

…d Phase 0–1)

First deliverable of the Own.NET Audit plan: the build-free static tier plus the
full normalize -> score -> report aggregation, all testable on Linux CI with no
target build and no external tools.

Aggregation core (audit/aggregate/), each with embedded-fixture --selftest in the
oracle_compare style:
- normalize.py: reads every tool's SARIF through the SAME parse_sarif as
  oracle_compare (reused, not duplicated), maps (tool, ruleId) -> Plan.md §2
  category via static/taxonomy/categories.yml. Splits the umbrella OWN001 code by
  its [resource: ...] tag so subscription/timer leaks land in cat. 2/3 instead of
  collapsing into IDisposable (cat. 1); labels OWN014 as region-escape. DevExpress
  findings are baseline-suppressed — counted in coverage, never hidden. Unmapped
  rules surface as pending taxonomy, not dropped.
- score.py: generalizes oracle_compare.compare() into cross-tool agreement
  (>=2 tools at basename+line-window -> high confidence), category-driven P0-P3
  severity, and a per-module pain heatmap answering "where does it hurt most".
- report.py: markdown health report + machine JSON, with a load-bearing coverage
  section (NO-TOOL categories, suppressed count, unmapped rules).

Static layer (audit/static/):
- run_static.py orchestrator (build-free runners -> aggregate -> report), with a
  full end-to-end --selftest on embedded SARIF fixtures.
- tools/owncheck.py (own-check.sh --format sarif, build-free; graceful when dotnet
  is absent), codeql.sh (build-mode=none, security-and-quality suite), and the
  build-required Windows runners roslyn_pack.ps1 / infersharp.sh (real skeletons,
  NO-TOOL exit when the tool is absent).
- inject/ analyzer props+targets under MSBuild's recognized names, gated on
  /p:OwnAudit=true; taxonomy/categories.yml; config/profiles/desktop-wpf.yml.

Decoupling: imports nothing from the ownlang core; the only in-repo seam is
scripts/oracle_compare.parse_sarif (vendored on lift-out), own-check via CLI only.
PyYAML is scoped to audit/ (requirements.txt) so the core suite stays zero-dep; a
new CI job runs the four selftests (48 checks). The target itself is audited on a
local Windows machine, never in CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDPpNT9Uh8RoTrKPvgcoRE
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 52f30b65-046e-4c96-a544-251a96c17895

📥 Commits

Reviewing files that changed from the base of the PR and between 14ce635 and df08418.

📒 Files selected for processing (2)
  • audit/static/tools/codeql.sh
  • audit/static/tools/infersharp.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • audit/static/tools/infersharp.sh
  • audit/static/tools/codeql.sh

📝 Walkthrough

Walkthrough

Adds an audit/ subtree for Own.NET that normalizes SARIF, scores findings by cross-tool agreement, renders Markdown/JSON reports, runs build-free and build-required analyzers, wires MSBuild injection, and adds CI selftests plus documentation.

Changes

Own.NET Audit Pipeline

Layer / File(s) Summary
Taxonomy, profile, and dependency config
audit/static/taxonomy/categories.yml, audit/config/profiles/desktop-wpf.yml, audit/requirements.txt
categories.yml maps analyzer ruleIds to categories with severities, suppression tokens, and coverage notes; desktop-wpf.yml defines tiered audit profile settings; requirements.txt adds PyYAML>=6.0.
SARIF normalization and finding model
audit/aggregate/normalize.py
Defines AuditFinding and Taxonomy, loads taxonomy data, categorizes rule IDs with resource-tag splitting and glob matching, applies suppression and coverage-note routing, and exposes normalization plus CLI and selftest entrypoints.
Cross-tool clustering and scoring
audit/aggregate/score.py
Defines Cluster, clusters findings by file and line tolerance, assigns category and severity from the most severe member, computes confidence and pain, serializes clusters, and exposes scoring CLI and selftests.
Markdown and JSON report rendering
audit/aggregate/report.py
Renders ranked Markdown and JSON reports from normalized findings and scoring output, adds coverage/honesty sections, and validates report content in selftests.
MSBuild analyzer injection for build-required tier
audit/static/inject/OwnAudit.Directory.Build.props, audit/static/inject/OwnAudit.Directory.Build.targets
MSBuild props and targets enable audit analyzer injection, set per-project SARIF output paths, and create the output directory before compilation.
Per-tool runners
audit/static/tools/owncheck.py, audit/static/tools/codeql.sh, audit/static/tools/infersharp.sh, audit/static/tools/roslyn_pack.ps1
Adds runners for own-check, CodeQL, Infer#, and Roslyn pack generation, each handling CLI arguments, tool availability, and standardized SARIF output paths.
Static audit orchestration
audit/static/run_static.py
Loads profiles, runs build-free and build-required audit tiers, collects SARIF inputs, aggregates findings into reports, and exposes CLI and selftest coverage for the full static pipeline.
CI selftests and audit documentation
.github/workflows/ci.yml, audit/README.md
Adds the CI job that runs audit selftests and expands the README with the audit architecture, usage, directory layout, tiers, commands, selftests, and status notes.

Sequence Diagram(s)

sequenceDiagram
  participant Developer as Developer / CI
  participant RunStatic as run_static.py
  participant OwnCheck as owncheck.py
  participant CodeQL as codeql.sh
  participant FS as SARIF outputs
  participant Normalize as normalize.py
  participant Score as score.py
  participant Report as report.py

  Developer->>RunStatic: --target and profile
  RunStatic->>OwnCheck: build-free SARIF
  RunStatic->>CodeQL: build-free SARIF
  RunStatic->>FS: collect roslyn/ and infersharp.sarif
  RunStatic->>Normalize: normalize SARIF inputs
  Normalize-->>RunStatic: findings + coverage
  RunStatic->>Score: score findings
  Score-->>RunStatic: clusters + heatmap + totals
  RunStatic->>Report: render Markdown / JSON
  Report-->>RunStatic: report.md and report.json
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PhysShell/Own.NET#9: This audit work extracts [resource: ...] tags from finding messages, matching the earlier message-format change that adds resource tags in Finding.render().
  • PhysShell/Own.NET#42: The new audit/aggregate/normalize.py depends on scripts/oracle_compare.py SARIF ingestion behavior, which this PR updated for own-check --format sarif.
  • PhysShell/Own.NET#43: The audit normalizer reuses parse_sarif and norm_path from scripts/oracle_compare.py, making the shared SARIF parser changes directly relevant.

Poem

🐰 I hopped through SARIF in tidy rows,
Then scored the clusters as the audit grows.
A heatmap glows, the findings align,
With DevExpress whispers filtered fine.
Now reports are ready, crisp and bright —
A bunny-built audit, snug and right.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main addition: the new audit/ static-layer orchestrator and aggregation pipeline.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/brave-gauss-elvquy

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3a3029895

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread audit/static/tools/owncheck.py
Comment thread audit/static/inject/OwnAudit.Directory.Build.props Outdated
Comment thread audit/static/run_static.py Outdated
Comment thread audit/static/tools/infersharp.sh Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
audit/static/tools/owncheck.py (1)

55-60: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a timeout to the subprocess call.

own-check.sh runs a Roslyn fact extractor over the whole target tree; without a timeout, a hang stalls the runner (and CI) indefinitely. subprocess.TimeoutExpired should be caught and surfaced as an honest unavailable/partial result, consistent with the continue-on-error discipline in the module docstring.

♻️ Proposed change
-    proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
-    sarif_text = proc.stdout.strip()
+    try:
+        proc = subprocess.run(cmd, capture_output=True, text=True, check=False,
+                              timeout=900)
+    except subprocess.TimeoutExpired:
+        status["reason"] = "own-check timed out"
+        return status
+    sarif_text = proc.stdout.strip()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@audit/static/tools/owncheck.py` around lines 55 - 60, The subprocess
invocation in owncheck’s main flow lacks a timeout, so a hung own-check.sh can
block the runner indefinitely. Update the subprocess.run call in the own-check
logic to use a bounded timeout, and handle subprocess.TimeoutExpired by
returning an unavailable/partial status with a clear reason, consistent with the
module’s continue-on-error behavior. Keep the fix localized around the
subprocess.run and the existing status["reason"] / return status path so the
command still reports a graceful failure instead of hanging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@audit/aggregate/normalize.py`:
- Around line 339-342: The normalize selftest summary in the self-check block is
using the wrong total count, causing the printed pass/fail ratio to be off by
one. Update the hardcoded check count used by the summary near the selftest loop
so it matches the actual number of distinct checks validated in this section,
and keep the failure reporting in the same normalize selftest path consistent
with that corrected total.

In `@audit/aggregate/report.py`:
- Around line 79-83: The high-confidence findings section in report generation
is truncating entries with high[:max_list] without signaling that more items
exist, which conflicts with the visible total in the header. Update the logic in
aggregate/report.py around the high-confidence list assembly in the report
builder so it mirrors the candidates overflow handling: keep the same slicing by
max_list, but append a “+N more” note when len(high) exceeds max_list. Use the
existing report formatting flow and the high/candidates list patterns in the
report output to locate and align the fix.

In `@audit/static/run_static.py`:
- Around line 195-236: The selftest in _selftest() hard-codes the total number
of checks as 8 even though there are 9 validation branches appending to fails,
so update the total to be derived from the actual number of checks (or otherwise
keep it in sync automatically) so the final summary printed by run_static
selftest matches the real count.

In `@audit/static/tools/infersharp.sh`:
- Around line 36-44: The fallback in infersharp.sh is invalid because
infersharpaction is a GitHub Action, not a CLI compatible with the infersharp
--sarif --results-dir invocation. Update the command check and execution flow
around the infersharp/infersharpaction handling so this script either requires
infersharp explicitly or branches into a separate action-based path instead of
calling infersharpaction as a shell command.

---

Nitpick comments:
In `@audit/static/tools/owncheck.py`:
- Around line 55-60: The subprocess invocation in owncheck’s main flow lacks a
timeout, so a hung own-check.sh can block the runner indefinitely. Update the
subprocess.run call in the own-check logic to use a bounded timeout, and handle
subprocess.TimeoutExpired by returning an unavailable/partial status with a
clear reason, consistent with the module’s continue-on-error behavior. Keep the
fix localized around the subprocess.run and the existing status["reason"] /
return status path so the command still reports a graceful failure instead of
hanging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ac3407d-bf2f-4b84-a24e-0213a2ed78e5

📥 Commits

Reviewing files that changed from the base of the PR and between e9a62bd and b3a3029.

📒 Files selected for processing (15)
  • .github/workflows/ci.yml
  • audit/README.md
  • audit/aggregate/normalize.py
  • audit/aggregate/report.py
  • audit/aggregate/score.py
  • audit/config/profiles/desktop-wpf.yml
  • audit/requirements.txt
  • audit/static/inject/OwnAudit.Directory.Build.props
  • audit/static/inject/OwnAudit.Directory.Build.targets
  • audit/static/run_static.py
  • audit/static/taxonomy/categories.yml
  • audit/static/tools/codeql.sh
  • audit/static/tools/infersharp.sh
  • audit/static/tools/owncheck.py
  • audit/static/tools/roslyn_pack.ps1

Comment thread audit/aggregate/normalize.py Outdated
Comment thread audit/aggregate/report.py
Comment thread audit/static/run_static.py
Comment thread audit/static/tools/infersharp.sh Outdated
Codex (4):
- OWN050 notes kept out of scored findings: own-check emits OWN050 ("cannot
  verify — unresolved") as a SARIF note, a non-verdict. The taxonomy now lists it
  under coverage_notes; normalize routes such rules to the coverage ledger
  (analysis-skipped count) instead of scoring them, so they no longer surface as
  phantom uncategorized P3 candidates.
- Roslyn ErrorLog now honors the runner's -Out: the injected props anchor the
  per-project SARIF at $(OwnAuditOutDir) (default unchanged), roslyn_pack.ps1
  passes /p:OwnAuditOutDir=<abs -Out>, and the targets MakeDir mirrors it.
- run_static picks up the Roslyn per-project SARIFs: it globs <out>/roslyn/*.sarif
  (the props write $(MSBuildProjectName).sarif under roslyn/) instead of a single
  fixed roslyn_pack.sarif, so analyzer-pack findings reach totals/coverage.
- infersharp.sh requires the infersharp CLI and drops the invalid infersharpaction
  fallback (that is a GitHub Action, not a CLI with this interface); aligns the
  invocation to Infer#'s documented infer-out/report.sarif output.

CodeRabbit (4 + 1 nitpick):
- report.py: high-confidence list now appends a "+N more" note past max_list,
  matching the candidates overflow — no silent truncation against the header count.
- owncheck.py: subprocess.run gains a 900s timeout; TimeoutExpired returns a
  graceful unavailable status (continue-on-error).
- selftest totals are now derived from a check() helper in all four modules
  (normalize/score/report/run_static), so the printed pass ratio can no longer
  drift from the real check count.
- infersharp.sh fallback removed (same as Codex item above).

Adds selftest coverage for the OWN050 routing and the roslyn/ pickup. All four
selftests green (19/11/15/11), ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDPpNT9Uh8RoTrKPvgcoRE

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
audit/static/tools/infersharp.sh (1)

25-31: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Guard --bin / --out against missing values.

If either flag is passed without a value, $2 is read under set -u, which aborts with a shell error instead of your intended usage exit path.

Suggested fix
 while [[ $# -gt 0 ]]; do
   case "$1" in
-    --bin) bin="$2"; shift 2 ;;
-    --out) out="$2"; shift 2 ;;
+    --bin)
+      [[ $# -ge 2 ]] || { echo "infersharp.sh: --bin requires a value" >&2; exit 2; }
+      bin="$2"; shift 2
+      ;;
+    --out)
+      [[ $# -ge 2 ]] || { echo "infersharp.sh: --out requires a value" >&2; exit 2; }
+      out="$2"; shift 2
+      ;;
     -h|--help) sed -n '2,18p' "$0"; exit 0 ;;
     *) echo "infersharp.sh: unknown arg $1" >&2; exit 2 ;;
   esac
 done
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@audit/static/tools/infersharp.sh` around lines 25 - 31, The argument parser
in infersharp.sh does not validate that --bin and --out are followed by values,
so reading $2 can fail under set -u before the script reaches the intended
usage/error path. Update the while/case handling in the main argument loop to
check that a value exists before assigning bin or out, and route missing-value
cases through the same usage/error exit path used by the script; use the
existing infersharp.sh option parsing block as the place to apply the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@audit/static/tools/infersharp.sh`:
- Around line 25-31: The argument parser in infersharp.sh does not validate that
--bin and --out are followed by values, so reading $2 can fail under set -u
before the script reaches the intended usage/error path. Update the while/case
handling in the main argument loop to check that a value exists before assigning
bin or out, and route missing-value cases through the same usage/error exit path
used by the script; use the existing infersharp.sh option parsing block as the
place to apply the fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 15e9cde6-d16c-47a1-9552-34d4c6299910

📥 Commits

Reviewing files that changed from the base of the PR and between b3a3029 and 14ce635.

📒 Files selected for processing (10)
  • audit/aggregate/normalize.py
  • audit/aggregate/report.py
  • audit/aggregate/score.py
  • audit/static/inject/OwnAudit.Directory.Build.props
  • audit/static/inject/OwnAudit.Directory.Build.targets
  • audit/static/run_static.py
  • audit/static/taxonomy/categories.yml
  • audit/static/tools/infersharp.sh
  • audit/static/tools/owncheck.py
  • audit/static/tools/roslyn_pack.ps1
🚧 Files skipped from review as they are similar to previous changes (6)
  • audit/static/inject/OwnAudit.Directory.Build.targets
  • audit/static/taxonomy/categories.yml
  • audit/static/inject/OwnAudit.Directory.Build.props
  • audit/static/tools/roslyn_pack.ps1
  • audit/aggregate/report.py
  • audit/aggregate/score.py

CodeRabbit (PR #100): infersharp.sh read $2 for --bin/--out without checking a
value was supplied, so under `set -u` a flag with no argument aborted with a raw
shell error instead of the intended usage exit. Added the `[[ $# -ge 2 ]]` guard
that own-check.sh already uses, and applied the same to codeql.sh (--target/
--out/--db) which had the identical pattern. Each missing value now exits 2 with
a clear message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDPpNT9Uh8RoTrKPvgcoRE

Copy link
Copy Markdown
Owner Author

@coderabbitai Good catch — fixed in df08418. Added the [[ $# -ge 2 ]] guard that scripts/own-check.sh already uses to infersharp.sh (--bin/--out), and applied the same to codeql.sh (--target/--out/--db) which had the identical pattern. A flag with no value now exits 2 with a clear message instead of aborting on set -u. Verified both with --bin/--target and no value.


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@PhysShell Thanks for the thorough fix — applying the same [[ $# -ge 2 ]] guard pattern consistently across all three scripts (infersharp.sh, codeql.sh, and the existing own-check.sh) keeps the argument-parsing contract uniform. The exit-2 path with a clear message is the right behavior when a flag is given without its value under set -u. Looks good!

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/PhysShell/Own.NET/issues/comments/4790923880","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/PhysShell/Own.NET/pull/100?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Path: .coderabbit.yaml\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro Plus\n> \n> **Run ID**: `52f30b65-046e-4c96-a544-251a96c17895`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between 14ce6357d568f3674a6c1f5bd2f8703c83b43741 and df08418cd48069841335e0938c36871e7c336ba2.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (2)</summary>\n> \n> * `audit/static/tools/codeql.sh`\n> * `audit/static/tools/infersharp.sh`\n> \n> </details>\n> \n> ```ascii\n>  _________________________________________\n> < Tensor cores warmed; bug cores chilled. >\n>  -----------------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds an `audit/` subtree for Own.NET that normalizes SARIF, scores findings by cross-tool agreement, renders Markdown/JSON reports, runs build-free and build-required analyzers, wires MSBuild injection, and adds CI selftests plus documentation.\n\n## Changes\n\n**Own.NET Audit Pipeline**\n\n|Layer / File(s)|Summary|\n|---|---|\n|**Taxonomy, profile, and dependency config** <br> `audit/static/taxonomy/categories.yml`, `audit/config/profiles/desktop-wpf.yml`, `audit/requirements.txt`|`categories.yml` maps analyzer ruleIds to categories with severities, suppression tokens, and coverage notes; `desktop-wpf.yml` defines tiered audit profile settings; `requirements.txt` adds `PyYAML>=6.0`.|\n|**SARIF normalization and finding model** <br> `audit/aggregate/normalize.py`|Defines `AuditFinding` and `Taxonomy`, loads taxonomy data, categorizes rule IDs with resource-tag splitting and glob matching, applies suppression and coverage-note routing, and exposes normalization plus CLI and selftest entrypoints.|\n|**Cross-tool clustering and scoring** <br> `audit/aggregate/score.py`|Defines `Cluster`, clusters findings by file and line tolerance, assigns category and severity from the most severe member, computes confidence and pain, serializes clusters, and exposes scoring CLI and selftests.|\n|**Markdown and JSON report rendering** <br> `audit/aggregate/report.py`|Renders ranked Markdown and JSON reports from normalized findings and scoring output, adds coverage/honesty sections, and validates report content in selftests.|\n|**MSBuild analyzer injection for build-required tier** <br> `audit/static/inject/OwnAudit.Directory.Build.props`, `audit/static/inject/OwnAudit.Directory.Build.targets`|MSBuild props and targets enable audit analyzer injection, set per-project SARIF output paths, and create the output directory before compilation.|\n|**Per-tool runners** <br> `audit/static/tools/owncheck.py`, `audit/static/tools/codeql.sh`, `audit/static/tools/infersharp.sh`, `audit/static/tools/roslyn_pack.ps1`|Adds runners for own-check, CodeQL, Infer#, and Roslyn pack generation, each handling CLI arguments, tool availability, and standardized SARIF output paths.|\n|**Static audit orchestration** <br> `audit/static/run_static.py`|Loads profiles, runs build-free and build-required audit tiers, collects SARIF inputs, aggregates findings into reports, and exposes CLI and selftest coverage for the full static pipeline.|\n|**CI selftests and audit documentation** <br> `.github/workflows/ci.yml`, `audit/README.md`|Adds the CI job that runs audit selftests and expands the README with the audit architecture, usage, directory layout, tiers, commands, selftests, and status notes.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant Developer as Developer / CI\n  participant RunStatic as run_static.py\n  participant OwnCheck as owncheck.py\n  participant CodeQL as codeql.sh\n  participant FS as SARIF outputs\n  participant Normalize as normalize.py\n  participant Score as score.py\n  participant Report as report.py\n\n  Developer->>RunStatic: --target and profile\n  RunStatic->>OwnCheck: build-free SARIF\n  RunStatic->>CodeQL: build-free SARIF\n  RunStatic->>FS: collect roslyn/ and infersharp.sarif\n  RunStatic->>Normalize: normalize SARIF inputs\n  Normalize-->>RunStatic: findings + coverage\n  RunStatic->>Score: score findings\n  Score-->>RunStatic: clusters + heatmap + totals\n  RunStatic->>Report: render Markdown / JSON\n  Report-->>RunStatic: report.md and report.json\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~60 minutes\n\n## Possibly related PRs\n\n- [PhysShell/Own.NET#9](https://github.com/PhysShell/Own.NET/pull/9): This audit work extracts `[resource: ...]` tags from finding messages, matching the earlier message-format change that adds resource tags in `Finding.render()`.\n- [PhysShell/Own.NET#13](https://github.com/PhysShell/Own.NET/pull/13): The audit taxonomy and coverage logic explicitly handle `OWN050` and related analysis-skip output, which aligns with the earlier unresolved-subscription diagnostic work.\n- [PhysShell/Own.NET#21](https://github.com/PhysShell/Own.NET/pull/21): `audit/aggregate/normalize.py` reuses `parse_sarif` and `norm_path` from `scripts/oracle_compare.py`, making that SARIF parser change directly relevant.\n\n## Poem\n\n> 🐰 I hopped through SARIF in tidy rows,  \n> Then scored the clusters as the audit grows.  \n> A heatmap glows, the findings align,  \n> With DevExpress whispers filtered fine.  \n> Now reports are ready, crisp and bright —  \n> A bunny-built audit, snug and right.\n\n</details>\n\n<!-- walkthrough_end -->\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4</summary>\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                       |\n| :------------------------: | :------- | :---------------------------------------------------------------------------------------------------------------- |\n|      Description Check     | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                       |\n|         Title check        | ✅ Passed | The title clearly describes the main change: adding the audit static-layer orchestrator and aggregation pipeline. |\n|     Linked Issues check    | ✅ Passed | Check skipped because no linked issues were found for this pull request.                                          |\n| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request.                                          |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `claude/brave-gauss-elvquy`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\n\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

@PhysShell PhysShell merged commit 6904a0a into main Jun 25, 2026
24 checks passed
PhysShell pushed a commit that referenced this pull request Jun 25, 2026
…) contract

CodeRabbit (PR #101):
- _coverage_section() now renders the analysis_skipped bucket (own-check OWN050
  coverage notes) alongside total/kept/suppressed. It was counted in coverage()
  and carried in the SARIF run properties since #100, but the human markdown/HTML
  report never showed it — so notes silently vanished from the honesty ledger.
  Added a note=True fixture to the report selftest and assertions that both the
  markdown and HTML coverage sections surface it, keeping SARIF/HTML aligned.
- Refreshed the run_static.aggregate() docstring to state it writes all four
  artifacts (report.md/json/sarif/html) and returns the four report_* paths.

report selftest 34/34, run_static 14/14, ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDPpNT9Uh8RoTrKPvgcoRE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants