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
86 changes: 86 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1543,3 +1543,89 @@ jobs:
# use, and an injected-source region-escape. A drop below the floor is a regression.
run: python scripts/benchmark.py --min-recall 25

# Alpha gate A (issue #202): the single delightful command, proven end-to-end
# on a clean runner — install -> check -> findings. Packaging only, no
# analysis-behaviour change: OwnSharp.Cli bundles the *unmodified* extractor
# (ProjectReference; invoked as a child process, same shape own-check.sh
# already uses) and vendors the *unmodified* ownlang/ core, run by the
# machine's own Python. Both ubuntu AND windows matter here specifically
# (not just "more coverage") — a dotnet-tool shim is a native apphost on
# Windows and a shell script on Unix, so they exercise genuinely different
# process-launch mechanics; ubuntu-only would not prove the Windows path.
ownsharp-cli-smoke:
name: ownsharp CLI (gate A) — clean install -> check -> findings
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
defaults:
run:
# bash (git-bash on Windows runners) so one script works on both legs;
# the thing under test is the ownsharp/dotnet/python binaries, not the
# shell driving them.
shell: bash
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4
with:
dotnet-version: "8.0.x"
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- name: Put the dotnet global-tools shim dir on PATH
run: echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH"
# CI-only stand-in for "download the package from nuget.org" (not
# published there yet, see P-013's Non-goals) -- pack from the source
# this job already checked out. Deliberately OUTSIDE the timed window
# below: it is not part of the "install -> check" claim being proven.
- name: Pack OwnSharp.Cli (pulls in the extractor via ProjectReference)
run: dotnet pack frontend/roslyn/OwnSharp.Cli/OwnSharp.Cli.csproj -c Release -o "$RUNNER_TEMP/ownsharp-nupkg"
- name: A minimal leak, in a scratch dir OUTSIDE the repo
# Proves the tool needs nothing but itself + Python -- not the Own.NET
# checkout (a real end user obviously won't have this repo on disk).
run: |
mkdir -p "$RUNNER_TEMP/ownsharp-sample"
cat > "$RUNNER_TEMP/ownsharp-sample/Leak.cs" <<'EOF'
using System.IO;
public class Leaky
{
public void Run()
{
var s = new MemoryStream();
s.WriteByte(1);
}
}
EOF
- name: Start the clean-machine timer (install -> check -> findings)
run: echo "SMOKE_START=$(date +%s)" >> "$GITHUB_ENV"
- name: dotnet tool install --global (the one install the user runs)
run: dotnet tool install --global OwnSharp.Cli --version 0.1.0 --add-source "$RUNNER_TEMP/ownsharp-nupkg"
- name: ownsharp check finds the leak
run: |
set +e
out=$(ownsharp check "$RUNNER_TEMP/ownsharp-sample" --fail-on-finding 2>&1)
rc=$?
set -e
echo "$out"
[ "$rc" -eq 1 ] || { echo "FAIL: expected exit 1 (findings), got $rc"; exit 1; }
echo "$out" | grep -q "OWN001" || { echo "FAIL: expected OWN001 in the output"; exit 1; }
- name: Stop the timer -- report it, and gate on a generous regression ceiling
# A hard ceiling, not a precision claim: CI timing varies with runner
# load, so this is a regression guard (catch "it now takes 20 minutes"),
# not a rubber stamp of the "~3 minutes" marketing number itself.
run: |
elapsed=$(( $(date +%s) - SMOKE_START ))
echo "install -> check -> findings: ${elapsed}s"
[ "$elapsed" -lt 240 ] || { echo "FAIL: took ${elapsed}s (ceiling 240s) — see alpha-readiness.md gate A"; exit 1; }
- name: No Python found -> a fast, actionable failure (never an auto-download)
run: |
set +e
out=$(OWN_PYTHON=/definitely/does/not/exist/python3 ownsharp check "$RUNNER_TEMP/ownsharp-sample" 2>&1)
rc=$?
set -e
echo "$out"
[ "$rc" -eq 3 ] || { echo "FAIL: expected exit 3 (Python not found), got $rc"; exit 1; }
echo "$out" | grep -qi "OWN_PYTHON" || { echo "FAIL: expected the OWN_PYTHON-specific message"; exit 1; }
echo "$out" | grep -Eiq "winget|apt|brew|python.org" || { echo "FAIL: expected an actionable install hint"; exit 1; }

8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ scripts/own-check.sh --format human -- /path/to/your/csharp/repo
```

Needs Python 3.11+ and the .NET SDK on `PATH` — nothing to build, nothing to
`pip install` (there's no packaged CLI yet; see
[`docs/notes/alpha-readiness.md`](docs/notes/alpha-readiness.md) gate **A**).
`pip install`. A packaged single-command CLI (`ownsharp check`) also exists —
build-and-install-locally today, not yet published to nuget.org; see
[`frontend/roslyn/OwnSharp.Cli/README.md`](frontend/roslyn/OwnSharp.Cli/README.md)
and [`docs/notes/alpha-readiness.md`](docs/notes/alpha-readiness.md) gate **A**.

## One it actually found

Expand Down Expand Up @@ -918,6 +920,8 @@ ownlang/
test_spec.py # conformance: every spec/ rule fires on an example
test_ownir.py # the OwnIR bridge: C# facts -> core -> OWN001 at the C# site
frontend/roslyn/ # the C# extractor (Roslyn, CI-only) + .cs samples (P-001)
OwnSharp.Extractor/ # ownsharp-extract (dotnet tool): facts only
OwnSharp.Cli/ # ownsharp (dotnet tool, gate A): extractor + vendored core, one install
rust/ # the Rust core migration (P-022): own-ir + own-syntax so far,
# oracle-gated against this Python core — see rust/README.md
pyproject.toml # gate: ruff + mypy --strict (see below)
Expand Down
6 changes: 4 additions & 2 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ scripts/own-check.sh --format human -- /путь/к/вашему/csharp/репо
```

Нужны Python 3.11+ и .NET SDK в `PATH` — ничего собирать, ничего ставить через
`pip install` (упакованного CLI пока нет; см.
[`docs/notes/alpha-readiness.md`](docs/notes/alpha-readiness.md), gate **A**).
`pip install`. Есть и упакованный однокомандный CLI (`ownsharp check`) — сегодня
собирается и ставится локально, в nuget.org ещё не опубликован; см.
[`frontend/roslyn/OwnSharp.Cli/README.md`](frontend/roslyn/OwnSharp.Cli/README.md)
и [`docs/notes/alpha-readiness.md`](docs/notes/alpha-readiness.md), gate **A**.

## Один реальный баг, который он нашёл

Expand Down
21 changes: 12 additions & 9 deletions docs/notes/alpha-readiness.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The bar for "showable": a person can reproduce the wow in ~3 minutes

| | Item | Status (2026-06-27) | Gap to close |
|---|------|--------------------|--------------|
| **A** | `dotnet tool` one-command CLI | ◑ **partial** — the *extractor* is `PackAsTool` (`ownsharp-extract`, P-013); the core is Python. The delightful `ownsharp check MyApp.sln` single tool isn't packaged. | Wrap extractor+core into one `dotnet tool` (or a self-contained CLI) that takes a `.sln`/dir and prints findings. |
| **A** | `dotnet tool` one-command CLI | ◑ **mostly built** (issue #202) — `OwnSharp.Cli` wraps extractor+core into one `dotnet tool install` → `ownsharp check <path\|.sln>`, proven install→check→findings on a clean ubuntu/windows runner in CI (`ownsharp-cli-smoke`). See [`frontend/roslyn/OwnSharp.Cli/README.md`](../../frontend/roslyn/OwnSharp.Cli/README.md). | Not published to nuget.org yet — today it's build-and-install-from-source only. Publishing (+ a real version scheme beyond `0.1.0`) is the remaining step. |
| **B** | GitHub Action | ✅ **built** — `action.yml`: `path`/`severity`/`format` (`github` / `msbuild` / `human` / `sarif`), purple shield branding. Matches the "stupidly simple YAML" bar. | Publish to Marketplace; pin the 6-line usage in the README. |
| **C** | SARIF / PR annotations | ✅ **built** — SARIF 2.1.0 + GitHub annotations + reachability/evidence (P-015). | — |
| **D** | 5 core diagnostics | ✅ **built, well past** — OWN001/002/003, OWN014, DI001–005, POOL001–005, WPF001–005 (catalog). The comment's `SUB001/SUB002/TMR001/DISP001/DI001` all exist *semantically*; the `SUB/TMR/DISP` catalog rename is the deferred consolidation item, not new work. | (naming only) land the catalog rename with the OwnIR-v1/profile-label work. |
Expand All @@ -54,17 +54,19 @@ suppression → "why not Sonar/CodeQL"), every step of that path now exists.

## Honest verdict

**The engine is past alpha on *capability* (D/E strong, B/C built). F/G and the
front door have since closed too — the remaining packaging gap is narrower:**
**The engine is past alpha on *capability* (D/E strong, B/C built). F/G, the
front door, and now A have all closed too — what's left is publishing, not
building:**

1. a single `ownsharp check MyApp.sln` tool (**A**) — still open;
1. ~~a single `ownsharp check MyApp.sln` tool (**A**)~~**built**, not yet published to nuget.org;
2. ~~a wedge landing README + copy-paste quickstart (front door)~~ — **done**;
3. ~~three packaged case studies from finds we already have (**F**)~~ — **done**;
4. ~~one consolidated suppression / false-positive page (**G**)~~ — **done**.

None of those is research; all are the difference between "interesting PoC" and
"people install it." **A** is now the one item standing between here and the
day 1–30 milestone.
"people install it." Publishing `OwnSharp.Cli` to nuget.org is now the one item
standing between here and the day 1–30 milestone being *literally* copy-paste
for a stranger.

## The 20% rule (other stacks)

Expand All @@ -85,9 +87,10 @@ until the .NET alpha above is delicious. Do not let the spike exceed 20%.

## 90-day shape (sequencing, not a schedule)

- **Days 1–30 — make the .NET alpha tasty:** close A (B/C/D/E/F/G and the README
front door already done). Suppression UX + bad/ok corpus polish continue as
bug-driven follow-ups, not a blocking gate.
- **Days 1–30 — make the .NET alpha tasty:** publish `OwnSharp.Cli` to
nuget.org (A/B/C/D/E/F/G and the README front door are all otherwise done).
Suppression UX + bad/ok corpus polish continue as bug-driven follow-ups, not
a blocking gate.
- **Days 31–60 — real-world proof:** run over 20–50 OSS .NET/WPF/Avalonia/WinForms
repos; table of findings / confirmed / FP / unsupported; 2 case studies; compare
with CodeQL / NetAnalyzers / Infer# where possible (the oracle, `docs/notes/oracle.md`).
Expand Down
11 changes: 11 additions & 0 deletions docs/proposals/P-013-distribution-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ and defer the native analyzer until (if ever) the core itself moves to .NET.
(`dotnet tool install --global OwnSharp.Extractor` → `ownsharp-extract`).
Honest caveat: the tool is only the C# *extractor*; the verdict is still the
Python core. The script/Action are the complete product.
- **`OwnSharp.Cli`** (alpha gate A, issue #202) — the single-install answer to
that caveat: `dotnet tool install --global OwnSharp.Cli` → `ownsharp check
<path|.sln>` wraps both stages in one tool. It bundles the *unmodified*
extractor (`ProjectReference`, invoked as a child process) and vendors the
*unmodified* `ownlang/` core (run on the machine's own Python, resolved via
`OWN_PYTHON`/`py -3`/`python3`, `>=3.11`, fail-fast otherwise — never an
auto-download). See [`frontend/roslyn/OwnSharp.Cli/README.md`](../../frontend/roslyn/OwnSharp.Cli/README.md)
for the packaging shape and the rejected alternatives on record in the issue.
Not yet published to nuget.org (Non-goals below, unchanged) —
build-and-install from source until then; `own-check.sh`/`.ps1`/`action.yml`
are untouched and remain the supported surfaces alongside it.

## Not the same as P-011

Expand Down
Loading
Loading