Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ jobs:
python scripts/metamorphic_facts.py --selftest
python scripts/benchmark.py --selftest

# Own.NET Audit (audit/) — the aggregation layer's selftests, the only thing the
# Linux CI gates for the audit (the target itself is analyzed on a local Windows
# machine, never in CI; see audit/README.md and Plan.md §3.2). PyYAML is scoped
# to audit/ here so the core test suite stays zero-dependency.
audit-selftests:
name: audit aggregation selftests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install audit deps (PyYAML, audit-scoped)
run: pip install -r audit/requirements.txt
- name: Own.NET Audit selftests (normalize + score + report + orchestrator)
run: |
python audit/aggregate/normalize.py --selftest
python audit/aggregate/score.py --selftest
python audit/aggregate/report.py --selftest
python audit/static/run_static.py --selftest

tests:
name: tests (py${{ matrix.python-version }})
runs-on: ubuntu-latest
Expand Down
118 changes: 118 additions & 0 deletions audit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Own.NET Audit

An audit **orchestrator** for a legacy .NET Framework 4.7.2 / WPF / DevExpress
desktop application. It runs a fleet of mature, ready-made analyzers over the
target, normalizes every tool's output to SARIF, scores findings by cross-tool
agreement, and produces a categorized **health report ranked by where it hurts
most** — the "anamnesis" of the codebase.

Full design: [`../Plan.md`](../Plan.md). This subtree is the first deliverable —
the **static layer** (build-free tier) plus the **aggregation pipeline**. The
runtime layer and the AI-reviewer layer are later phases.

## Principles (why this is an orchestrator, not a new analyzer)

- **No new heuristics.** We run existing tools; we do not invent regex detectors.
A category with no reliable tool is marked `NO-TOOL` and deferred to the runtime
layer — never faked. (Mirrors `own-check`'s honest-skip discipline.)
- **SARIF is the one normalized format.** Every tool's output is read through the
*same* `parse_sarif` the oracle uses, then mapped to a category.
- **Honest coverage.** Suppressed third-party (DevExpress) findings are counted,
not hidden. Unmapped rules are surfaced as pending taxonomy, not dropped.
Tiers that did not run are labelled, not silently treated as "clean".
- **Determinism.** A run over a fixed commit is a stable, diffable artifact.

## Decoupling

This subtree lifts out as a standalone project (Plan.md §7). It imports **nothing**
from the `ownlang` core. Its only in-repo seams are:

- `scripts/oracle_compare.parse_sarif` / `norm_path` — a pure SARIF reader, reused
(not duplicated) per Plan.md §3.4. Vendored on lift-out (Phase 4).
- `own-check` is consumed **only** via its CLI (`scripts/own-check.sh`).

The single third-party Python dependency is PyYAML (see `requirements.txt`),
scoped to this subtree so the zero-dependency core test suite stays untouched.

## Layout

```text
audit/
aggregate/
normalize.py # SARIF -> categorized findings; OWN001 [resource:] split; DevExpress suppress
score.py # cross-tool agreement + severity + "where it hurts most" heatmap
report.py # markdown + json renderers (health report)
static/
run_static.py # orchestrator: run build-free runners -> aggregate -> report
tools/
owncheck.py # build-free runner: own-check.sh --format sarif (needs dotnet)
codeql.sh # build-free runner: CodeQL build-mode=none, security-and-quality
roslyn_pack.ps1 # build-required runner (local Windows): NetAnalyzers/Roslynator/...
infersharp.sh # build-required runner: Infer# over built binaries
inject/ # OwnAudit.Directory.Build.props/.targets (analyzer injection, gated)
taxonomy/
categories.yml # rule-id -> category knowledge base (Plan.md §2/§3.4)
config/profiles/
desktop-wpf.yml # which packs / severity floor for the net472 WPF target
requirements.txt # PyYAML (audit-scoped)
```

## Tiers (Plan.md §3.2)

| Tier | Tools | Needs a successful build of the target? |
|---|---|---|
| **build-free** | own-check, CodeQL (`build-mode: none`) | no — works on a solution that does not compile |
| **build-required** | Roslyn analyzer packs, Infer# | yes |

The entire audit of the target runs on a **local Windows machine** (VS Build Tools
+ DevExpress 12.2). There is no CI run of the target — Own.NET's Linux CI only
gates the Python aggregation selftests (this subtree), exactly as it gates
`oracle_compare --selftest` today.

## Running it

```bash
# Build-free tier + report (own-check needs a .NET SDK on PATH; codeql if installed):
python audit/static/run_static.py \
--target /path/to/legacy/src \
--profile desktop-wpf \
--target-name acme/LegacyApp --commit "$(git -C /path/to/legacy rev-parse HEAD)" \
--out artifacts/own-audit
# -> artifacts/own-audit/report.md and report.json

# Build-required tier runs on the Windows machine; drop its SARIF into the same
# --out directory and re-run run_static.py to fold it into the report:
pwsh audit/static/tools/roslyn_pack.ps1 -Solution ..\target-audit\Target.sln \
-AnalyzerCache .\cache -Out artifacts\own-audit
```

The aggregation modules also run standalone:

```bash
python audit/aggregate/normalize.py --sarif own-check=own.sarif --sarif codeql=cq.sarif \
--json findings.json
python audit/aggregate/report.py --findings findings.json --format markdown
```

## Selftests

Every aggregation module carries embedded-fixture selftests (the
`oracle_compare --selftest` discipline). They need no external tools and gate on
Linux CI:

```bash
python audit/aggregate/normalize.py --selftest
python audit/aggregate/score.py --selftest
python audit/aggregate/report.py --selftest
python audit/static/run_static.py --selftest # full pipeline end-to-end on fixtures
```

## Status

- **Done (this slice):** static build-free runners, normalization + taxonomy
(incl. the OWN001 `[resource:]` split and OWN014 region-escape labelling),
DevExpress baseline-suppress, cross-tool agreement scoring, the pain heatmap,
markdown + json reports, the analyzer-injection props/targets, and selftests.
- **Deferred:** HTML + merged-SARIF renderers (more views over the same model);
the runtime layer (FlaUI + ClrMD leak-harness, duplicate-immutable detector);
the AI-reviewer layer; feeding confirmed findings back into the OwnLang corpus.
Loading
Loading