Harden HTML export, repro script header, and CLI encryption - #586
Merged
Merged
Conversation
- HtmlExporter: map warning severity to a fixed CSS class name instead of writing the raw value into class attributes. A null severity no longer throws. - ReproScriptBuilder: split "*/" and "/*" and fold line breaks in every value written into the header comment, so a plan's database name cannot end it. - CliConnectionResolver: --trust-cert keeps encryption Mandatory, matching the direct-login path in ConnectionHelper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
The header line still named SQL Server Performance Monitor, the product this code was ported from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
- Header cases for overlapping delimiters and for VT, FF, NEL, U+2028 and U+2029. - HTML export cases for an attribute payload with no markup and for a warning on an operator. - Comments say why the USE line keeps line breaks in the name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
|
Reviewed. All three fixes are correct and narrowly scoped:
No repo-convention issues (no new warnings, no NoWarn, no version-file changes needed since PlanViewer.Ssms isn't touched, no TRY_CONVERT). Tests are well-targeted at the actual attack surface (crafted severities, hostile database names/sources with ScriptDom-verified single-batch output, encryption-mode parity assertions). Nothing further to flag. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
A private security report found three problems. This PR fixes all three. Each fix is small, and each has regression tests.
HTML export wrote severity into class attributes
HtmlExporterwrote each warning's severity, in lowercase, into twoclassattributes. The web app can export the analysis of a shared plan. That analysis is JSON from the person who shared the plan. A crafted severity closed the attribute and added a script element to the exported file.The exporter now maps severity to one of the three class names in its stylesheet:
critical,warningorinfo. Any other value getsinfo. The visible severity text was already HTML-encoded, and it still is. A null severity also threw an exception. Now it exports asinfo.The web app itself was not affected. It has no
MarkupString, so Blazor encodes every value that it shows.Repro script header took text from the plan
ReproScriptBuilderwrites the plan's database name into the block comment at the top of the script. Plan XML can be crafted. A database name that contained*/ended the comment early. The text after it became T-SQL, and it ran when someone executed the script.A new helper,
CommentSafe, now handles every value in the header. It puts a space inside each*/and each/*. T-SQL block comments nest, so a/*in a value opened a comment that swallowed the rest of the script. The helper also changes line breaks to spaces. So each value stays on one line, and it cannot putGOon a line of its own.The
USEstatement did not change. It already doubles]in the name, and that is the correct escape for a bracketed name. go-sqlcmd v1.9.0 and ODBC sqlcmd 15.0 do not split a batch at aGOline inside a bracketed name or inside anN'...'string. Neither does the batch parser of the SSMS 21 and 22 query editor, in normal or SQLCMD mode. A client that splits at everyGOline is out of scope, because the statement text itself can hold such a line.A second commit changes the header's first line from "generated by SQL Server Performance Monitor" to "generated by Performance Studio". That text came with the code when it was ported from Performance Monitor.
CLI
--trust-certmade encryption optionalCliConnectionResolverset encryption to Optional whenever--trust-certwas set. It builds the connection foranalyzeandquerystorewhen you use a stored credential or Windows authentication. The direct login path inConnectionHelperalready kept encryption Mandatory with--trust-cert.Now both paths keep encryption Mandatory.
--trust-certstill skips certificate validation, so a server with a self-signed certificate still connects. This PR does not add a CLI switch to make encryption optional.Which component(s) does this affect?
How was this tested?
ReproScriptBuilderSafetyTests: seven crafted database names and one crafted source. The names include overlapping delimiters and the other line breaks: VT, FF, NEL, U+2028 and U+2029. ScriptDom parses each script and finds one batch and noPRINT. The header ends at its own closing line and has no line that is onlyGO.HtmlExporterTests: the three known severities keep their classes. A crafted severity adds no script element and gets theinfoclass. So does a severity that adds an attribute with no markup, and a crafted severity on an operator's warning. A null severity exports asinfo.CliConnectionResolverTests: SQL and Windows authentication, each with and without--trust-cert. Encryption is Mandatory in all four cases.TrustServerCertificatefollows the flag, and encryption matchesConnectionHelper.TrustServerCertificate=true, each server connected, andsys.dm_exec_connectionsshowedencrypt_optionTRUE. Without trust, each connection failed the certificate check.Checklist
--no-incremental)dotnet test)🤖 Generated with Claude Code
https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR