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
4 changes: 4 additions & 0 deletions .github/workflows/check-pr-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
- reopened
- synchronize
- edited

# pull_request_target runs with the base repo's token — this job needs none of it.
permissions: {}

jobs:
check-branches:
runs-on: ubuntu-latest
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/check-version-bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ on:
pull_request:
branches: [main]

permissions:
contents: read

jobs:
check-version:
if: github.head_ref == 'dev'
runs-on: ubuntu-latest

steps:
- name: Checkout PR branch
uses: actions/checkout@v5
uses: actions/checkout@v7

- name: Get PR version
id: pr
Expand All @@ -26,7 +29,7 @@ jobs:
Write-Host "PR version: $version (from $path)"

- name: Checkout main
uses: actions/checkout@v5
uses: actions/checkout@v7
with:
ref: main
path: main-branch
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ on:
- 'src/PlanViewer.Ssms/**'
- 'src/PlanViewer.Ssms.Installer/**'

permissions:
contents: read

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7

- name: Setup .NET 10.0
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
cache: true
Expand Down
103 changes: 103 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: Claude Code Review

# Automatic review on every PR. Fork PRs are skipped on purpose - see the note
# at the bottom of this file.
on:
pull_request:
types: [opened, synchronize, ready_for_review]
paths-ignore:
- '**.md'
- 'LICENSE'
- '.gitattributes'
- '.gitignore'
- 'CITATION.cff'
- 'llms.txt'
- '.github/ISSUE_TEMPLATE/**'
- 'docs/**'
- 'screenshots/**'

permissions:
contents: read
pull-requests: write
id-token: write

# One review at a time per PR; a rapid second push cancels the in-flight run
# instead of paying for two reviews of the same branch.
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
review:
# Drafts aren't ready for review, and a fork PR gets no secrets (so
# CLAUDE_CODE_OAUTH_TOKEN would be empty) and a read-only token it could
# not post with. Skip rather than fail a contributor's PR with a red X.
if: |
github.event.pull_request.draft == false &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 1

- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}

Review this pull request. The PR branch is already checked out in
the working directory.

Performance Studio is a cross-platform Avalonia desktop app (plus a
CLI, a Blazor WASM viewer, and an SSMS extension) that analyzes SQL
Server execution plans. Prioritize, in this order:

1. Correctness and crashes - null/empty plan XML, malformed
showplan attributes, off-by-one in operator tree walking.
2. Untrusted input. Execution plan XML is untrusted (users open
.sqlplan files they were emailed). Any generated T-SQL must stay
inert: identifiers bracket-escaped with ']' doubled, values
emitted only as self-contained literals. Flag string
concatenation into SQL that isn't a SqlParameter.
3. Security, calibrated to the deployment. This runs on a
single-user personal machine and its MCP tools are read-only, so
loopback-bound, opt-in, or local-IPC issues are Low here. Reserve
High for remotely reachable vectors (missing Host/Origin checks,
DNS rebinding) or credential disclosure.
4. Repo conventions that CI does not catch:
- The build standard is zero warnings. Flag new warnings and any
new NoWarn that lacks a comment explaining it.
- src/Directory.Build.props <Version> is the single source of
truth, but PlanViewer.Ssms is a legacy non-SDK project: its
version must be bumped by hand in
source.extension.vsixmanifest AND Properties/AssemblyInfo.cs.
Flag a version bump that updates one and not the others.
- A PlanViewer.Core file the Blazor app needs must also be added
as a linked <Compile Include> in PlanViewer.Web.csproj - a
ProjectReference is deliberately not used.
- T-SQL uses TRY_CAST, never TRY_CONVERT.
5. Test coverage for the behavior actually changed.

Be specific and concrete. Skip praise, style nits already handled by
the compiler, and restating what the diff does. If the PR looks good,
say so briefly rather than inventing findings.

Use `gh pr comment` for top-level feedback.
Use `mcp__github_inline_comment__create_inline_comment` (with
`confirmed: true`) to flag specific lines.
Only post GitHub comments - do not return review text as a message.

claude_args: |
--max-turns 20
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"

# Fork PRs: GitHub withholds repository secrets from `pull_request` runs on
# forks and issues a read-only GITHUB_TOKEN, so this workflow cannot review
# them. The fix is NOT `pull_request_target` - that would hand a writable token
# and this repo's secrets to an agent running untrusted fork code. To review a
# fork PR, comment `@claude review this` on it (claude.yml), which runs in the
# base-repo context and checks the commenter's write permission first.
43 changes: 43 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Claude

# On-demand: mention @claude in an issue, a PR comment, or a review comment.
#
# Unlike claude-code-review.yml this DOES work on fork PRs: issue_comment and
# review-comment events run in the base-repo context, so secrets are available
# and the token can post. The action verifies the commenter has write access
# before doing anything, so an outside user cannot trigger it.
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]
issues:
types: [opened, assigned]

permissions:
contents: write
pull-requests: write
issues: write
id-token: write

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 1

- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
claude_args: |
--max-turns 20
8 changes: 4 additions & 4 deletions .github/workflows/deploy-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7

- name: Setup .NET 10.0
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x

Expand All @@ -50,10 +50,10 @@ jobs:
run: cp publish/wwwroot/index.html publish/wwwroot/404.html

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v5
with:
path: publish/wwwroot

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
6 changes: 3 additions & 3 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
outputs:
has_changes: ${{ steps.check.outputs.has_changes }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
ref: dev
fetch-depth: 0
Expand All @@ -38,12 +38,12 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
ref: dev

- name: Setup .NET 10.0
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7

- name: Get version
id: version
Expand Down Expand Up @@ -46,7 +46,7 @@ jobs:
gh release create "v${{ steps.version.outputs.VERSION }}" --title "v${{ steps.version.outputs.VERSION }}" --generate-notes --target main

- name: Setup .NET 10.0
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x

Expand Down Expand Up @@ -143,7 +143,7 @@ jobs:

- name: Upload Windows build for signing
id: upload-unsigned
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: App-unsigned
path: publish/win-x64/
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ authors:
website: "https://erikdarling.com"
repository-code: "https://github.com/erikdarlingdata/PerformanceStudio"
license: MIT
version: "1.2.0"
date-released: "2026-03-18"
version: "1.17.0"
date-released: "2026-07-25"
keywords:
- sql-server
- execution-plan
Expand Down
6 changes: 5 additions & 1 deletion server/PlanShare/PlanShare.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.9" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.10" />
<!-- Direct ref lifts the transitive SQLitePCLRaw above 2.1.11, which bundles a
SQLite vulnerable to CVE-2025-6965 (GHSA-2m69-gcr7-jv3q). Microsoft.Data.Sqlite
still floors at 2.1.11 — remove this once its floor reaches 2.1.12+. -->
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.12" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
Tests and server/ projects are outside src/ and are unaffected.
-->
<PropertyGroup>
<Version>1.16.0</Version>
<Version>1.17.0</Version>
<Authors>Erik Darling</Authors>
<Company>Darling Data LLC</Company>
<Product>Performance Studio</Product>
Expand Down
8 changes: 4 additions & 4 deletions src/PlanViewer.App/MainWindow.FileOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,19 @@ private void OnDragOver(object? sender, DragEventArgs e)
{
e.DragEffects = DragDropEffects.None;

if (e.Data.Contains(DataFormats.Files))
if (e.DataTransfer.Contains(DataFormat.File))
{
var files = e.Data.GetFiles();
var files = e.DataTransfer.TryGetFiles();
if (files != null && files.Any(f => IsSupportedFile(f.TryGetLocalPath())))
e.DragEffects = DragDropEffects.Copy;
}
}

private void OnDrop(object? sender, DragEventArgs e)
{
if (!e.Data.Contains(DataFormats.Files)) return;
if (!e.DataTransfer.Contains(DataFormat.File)) return;

var files = e.Data.GetFiles();
var files = e.DataTransfer.TryGetFiles();
if (files == null) return;

foreach (var file in files)
Expand Down
Loading
Loading