-
Notifications
You must be signed in to change notification settings - Fork 28
fix: bug-bash batch 2 — six small correctness/hygiene fixes #250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,11 +103,14 @@ private static (int ExitCode, string Output) RunSecurity(params string[] args) | |
| using var process = Process.Start(psi); | ||
| if (process == null) return (-1, string.Empty); | ||
|
|
||
| // Read both streams concurrently. Doing stderr synchronously while stdout is | ||
| // async can deadlock if stderr fills its pipe buffer before the process exits | ||
| // (reproduces on `security dump-keychain` with large keychains). | ||
| var stdoutTask = process.StandardOutput.ReadToEndAsync(); | ||
| var stderr = process.StandardError.ReadToEnd(); | ||
| var stderrTask = process.StandardError.ReadToEndAsync(); | ||
| process.WaitForExit(); | ||
| var stdout = stdoutTask.Result; | ||
| Task.WaitAll(stdoutTask, stderrTask); | ||
|
|
||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: Generated by Claude Code |
||
| return (process.ExitCode, stdout + stderr); | ||
| return (process.ExitCode, stdoutTask.Result + stderrTask.Result); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,20 @@ namespace PlanViewer.Core.Services; | |
| /// </summary> | ||
| public static class ReproScriptBuilder | ||
| { | ||
| /// <summary> | ||
| /// Valid T-SQL isolation level names (uppercase) that may appear in a SET TRANSACTION | ||
| /// ISOLATION LEVEL statement. Used to gate interpolation so arbitrary upstream strings | ||
| /// can't land in the generated script. | ||
| /// </summary> | ||
| private static readonly HashSet<string> IsolationLevels = new(StringComparer.Ordinal) | ||
| { | ||
| "READ UNCOMMITTED", | ||
| "READ COMMITTED", | ||
| "REPEATABLE READ", | ||
| "SNAPSHOT", | ||
| "SERIALIZABLE", | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whitelist is correct per T-SQL spec — these are exactly the five values No tests in Generated by Claude Code |
||
| }; | ||
|
|
||
| /// <summary> | ||
| /// Builds a complete reproduction script from available query data. | ||
| /// </summary> | ||
|
|
@@ -94,10 +108,11 @@ public static string BuildReproScript( | |
| sb.AppendLine("*/"); | ||
| sb.AppendLine(); | ||
|
|
||
| /* USE database (skip for Azure SQL DB — USE is invalid there) */ | ||
| /* USE database (skip for Azure SQL DB — USE is invalid there). | ||
| Double any ']' in the identifier so names like 'cool]stuff' still parse. */ | ||
| if (!string.IsNullOrEmpty(databaseName) && !isAzureSqlDb) | ||
| { | ||
| sb.AppendLine($"USE [{databaseName}];"); | ||
| sb.AppendLine($"USE [{databaseName.Replace("]", "]]")}];"); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Escape is correct for the bracket-quoted identifier form. If anywhere else in this builder emits the database name without Generated by Claude Code |
||
| sb.AppendLine(); | ||
| } | ||
|
|
||
|
|
@@ -116,7 +131,9 @@ public static string BuildReproScript( | |
|
|
||
| if (!string.IsNullOrEmpty(isolationLevel)) | ||
| { | ||
| sb.AppendLine($"SET TRANSACTION ISOLATION LEVEL {isolationLevel.ToUpperInvariant()};"); | ||
| var upper = isolationLevel.ToUpperInvariant(); | ||
| if (IsolationLevels.Contains(upper)) | ||
| sb.AppendLine($"SET TRANSACTION ISOLATION LEVEL {upper};"); | ||
| } | ||
| sb.AppendLine("SET NOCOUNT ON;"); | ||
| sb.AppendLine(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1832,6 +1832,7 @@ private static double ParseDouble(string? value) | |
| private static long ParseLong(string? value) | ||
| { | ||
| if (string.IsNullOrEmpty(value)) return 0; | ||
| return long.TryParse(value, out var result) ? result : 0; | ||
| return long.TryParse(value, System.Globalization.NumberStyles.Integer, | ||
| System.Globalization.CultureInfo.InvariantCulture, out var result) ? result : 0; | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good alignment with Generated by Claude Code |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pre-existing, not introduced here, but worth flagging while you're in this file:
LoadHistoryAsync(lines 191–239) catchesOperationCanceledExceptionbut the success path still touchesStatusText,HistoryDataGrid.ItemsSource,UpdateChart(), andPopulateLegendPanel()without checkingct.IsCancellationRequested. If the fetch returns normally in the tiny window betweenOnClosedfiring and theawaitresuming, those UI writes happen on a closed window. Consider act.ThrowIfCancellationRequested()after theawait(or before the UI writes) so the post-await path routes through theOperationCanceledExceptioncatch.Generated by Claude Code