fix(sql): withhold the JSON parser's message from the probe's red result (Driver.Sql-009)
SqlDriverProbe surfaced 'Config JSON is invalid: ' + ex.Message, where SqlDriverBrowser.ParseDocument deliberately withholds the identical message because the malformed text may itself carry a connection string. The two read the same blob shape - the AdminUI Sql picker composes a document with a top-level connectionString literal - so a malformed paste reaches both. The probe now reports the failure class only, matching the browser.
This commit is contained in:
@@ -19,7 +19,10 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Sql;
|
||||
/// timeout, a cancellation — becomes a red <see cref="DriverProbeResult"/>, so the AdminUI has nothing to
|
||||
/// catch.</para>
|
||||
/// <para><b>The resolved connection string never reaches the result message.</b> A red result names the
|
||||
/// failure class, never the string — the same credential discipline the factory and the driver keep.</para>
|
||||
/// failure class, never the string — the same credential discipline the factory and the driver keep.
|
||||
/// That includes the JSON parser: a malformed config is reported as a class, with the parser's own
|
||||
/// message withheld exactly as <c>SqlDriverBrowser.ParseDocument</c> withholds it, because the malformed
|
||||
/// text may itself be a pasted connection string.</para>
|
||||
/// </summary>
|
||||
public sealed class SqlDriverProbe : IDriverProbe
|
||||
{
|
||||
@@ -80,7 +83,16 @@ public sealed class SqlDriverProbe : IDriverProbe
|
||||
}
|
||||
catch (Exception ex) when (ex is System.Text.Json.JsonException or ArgumentNullException)
|
||||
{
|
||||
return new DriverProbeResult(false, $"Config JSON is invalid: {ex.Message}", null);
|
||||
// The parser's message is WITHHELD, matching SqlDriverBrowser.ParseDocument. Nothing has been
|
||||
// extracted at this point, so there is no known secret to redact the message against — and the
|
||||
// blob both types read is the one the AdminUI Sql picker composes, which carries a top-level
|
||||
// `connectionString` literal. A malformed paste is therefore exactly the text that reaches here,
|
||||
// and System.Text.Json quotes the offending token and states the JSON path and byte position.
|
||||
return new DriverProbeResult(
|
||||
false,
|
||||
"Config JSON is not valid JSON. (The parser's message is withheld because the malformed "
|
||||
+ "text may carry a connection string.)",
|
||||
null);
|
||||
}
|
||||
|
||||
if (dto is null)
|
||||
|
||||
@@ -79,6 +79,38 @@ public sealed class SqlDriverProbeTests
|
||||
result.Message.ShouldNotBeNullOrWhiteSpace();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A malformed config is reported as a failure CLASS, never as the parser's own message — the same
|
||||
/// discipline <c>SqlDriverBrowser.ParseDocument</c> keeps, and for the same reason: the blob the two
|
||||
/// read is the one the AdminUI Sql picker composes, which carries a top-level <c>connectionString</c>
|
||||
/// literal, so a malformed paste is exactly the text that reaches here.
|
||||
/// <para><see cref="System.Text.Json"/>'s message quotes the offending token and states the JSON path
|
||||
/// and the byte position. None of it may leave the probe: at this point nothing has been extracted,
|
||||
/// so there is no known secret to redact against.</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Probe_malformedConfig_withholdsTheParserMessage()
|
||||
{
|
||||
using var fixture = new SqlitePollFixture();
|
||||
var probe = SqlDriverProbe.ForTest(fixture.Factory, new SqliteDialect());
|
||||
|
||||
// A pasted literal whose password carries an unquoted ';' — mis-quoted exactly the way an operator's
|
||||
// paste is, so the parse fails partway THROUGH the credential.
|
||||
const string malformed =
|
||||
"""{"provider":"SqlServer","connectionString":Password=Sup3r;SecretTail}""";
|
||||
|
||||
var result = await probe.ProbeAsync(malformed, TimeSpan.FromSeconds(5), CancellationToken.None);
|
||||
|
||||
result.Ok.ShouldBeFalse();
|
||||
result.Message.ShouldNotBeNull();
|
||||
result.Message!.ShouldNotContain("LineNumber");
|
||||
result.Message.ShouldNotContain("BytePositionInLine");
|
||||
result.Message.ShouldNotContain("Sup3r");
|
||||
result.Message.ShouldNotContain("SecretTail");
|
||||
// Still actionable: it names what is wrong and why the detail is missing.
|
||||
result.Message.ShouldContain("not valid JSON");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Probe_providerNumberSpelling_parses_soTestConnectMatchesDeploy()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user