Repository navigation
add_servers reports every entry after a save fault, refuses a literal password on Linux, and never answers added for a save that wrote nothing (#4734) - #4787
Merged
Conversation
…Windows literal password, and a write that changes nothing (#4734) Adds the seam the tests need (the table operations behind an interface, the platform as a ParseRequest argument) with the old behavior still in place, so the new tests fail on this commit: a fault on entry 2 of 3 answers one error, a literal password is accepted off Windows, and a write that changed no rows is answered as added.
…password off Windows, and never answer added for a write that changed nothing (#4734) - A save that throws is caught per entry. That entry and every one after it are answered as the new not_saved status (counted under failed) without a probe, and the entries before it stay added in the results instead of being dropped behind one error. - ParseRequest refuses a literal SQL password or client secret when the platform is not Windows, where it cannot be encrypted, and names the env:/file: reference form. References pass everywhere. - The insert's row count is checked. When it wrote nothing, the row holding the server_id is read back: a different identity answers collides, the same identity answers duplicate, and no row answers not_saved.
…ver_id answers collides and leaves the first row alone (#4734)
erikdarlingdata
marked this pull request as ready for review
September 29, 2026 10:25
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.
Part of #4734 (items 3 and 4: add_servers results)
Why
Item 3.
add_serverssaves its entries one at a time, and one catch wrapped the whole loop. When entry N's save threw, the call answered a single error and dropped the list that recorded entries 1 to N-1 as added. Those servers were saved and being collected, but the caller was told the call failed, and a retry then reported them as duplicates. One trigger always reproduced it on Linux: a literal SQL password is encrypted with Windows DPAPI,ParseRequestdid not check the platform, and the throw came after the probe, in the middle of the batch.Item 4.
server_idis a 32-bit hash of the storage key, and the insert ends inON CONFLICT (server_id) DO NOTHING. Two different identities that hash to one id, or two concurrent adds of the same server, write nothing, and the tool still answeredaddedfor a server nothing would collect.What changes
All in
Darling/PerformanceMonitor.Darling.Service/Mcp/DarlingMcpServerAdminTools.cs, except the docs in the last item.try. On a fault that entry is reported asnot_savedwith the fault's message, and every remaining entry is reported asnot_savedwithout a probe (a probe waits out a connect timeout). Entries saved before the fault stayadded. Every entry gets a result, so the four counters still sum torequested. The outer catch stays for faults before any entry is attempted (reading the existing servers).not_saved, counted underfailed. The existing statuses did not fit:connection_failedis a probe failure,invalidis a structural one. Added toAddStatus,CounterOfStatusand both places in the tool description that list the statuses.LiteralSecretRefusal(secret, isWindows, isServicePrincipal).ParseRequestcalls it for SQL passwords and service-principal client secrets, so the entry isinvalidbefore any probe or write, with a message that names theenv:NAMEorfile:/run/secrets/<name>reference form (the form the README gives for every secret slot). References pass on every platform.ProtectPasswordForStoragekeeps its throw as the backstop for other callers.InsertServerAsyncnow returns the rows changed. On 0 the row holding theserver_idis read back (ServerByIdSql, the same five identity columns the duplicate gate reads) and the pureClassifyUnwrittenInsertanswers: a different storage key givescollides, the same key (compared case-folded, like the gate) givesduplicate, and no row givesnot_saved. It is neveradded.IServerDefinitions(the real one wraps the existing SQL),AddServersAsynchas an overload that takes it, andParseRequesthas an overload that names the platform. The public tool method and the existingAddServersAsync(NpgsqlDataSource, ...)signature are unchanged.add_serversparagraph inDarling/README.md: it now names thenot_savedandcollidesstatuses and the off-Windows rule, and it no longer says Entra auth isinvalid(ServicePrincipalandManagedIdentityare supported, Darling: non-interactive Entra auth (Service Principal + Managed Identity) for headless targets #3484; only the interactive Entra modes areinvalid).Test plan
Darling.Testsbuilds with 0 warnings, 0 errors.added, the census pin and the description pin). The second commit makes them pass.DarlingMcpServerAdminToolsSurfaceTests,DarlingMcpServerAdminToolsLivePostgresTests,AddServerVerbTests,DarlingConfigTests,PostgresTargetConfigTests,RegistrationCollisionTests,McpPayloadContractCensusTests: 215 tests, 0 failed, 1 skipped (the gated live test).McpToolsListBudgetTests,DocCommentHygieneTests,DarlingMcpInstructionsBudgetTests,LiveCleanupConversionRatchetTests,LivePostgresCollectionHygieneTests: 0 failed.Darling.Testssuite once, withoutDARLING_TEST_PG, after mergingorigin/dev: 17256 total, 0 failed, 1134 skipped (gated live tests), 1 not run.ParseRequestwith the platform named, and with the real platform (asserts the Windows or the non-Windows arm to match the machine); a write that changes nothing because a different identity holds the id (two real server names whose keys hash to one id, asserted in the test) answerscollidesand the rest of the batch continues; the same identity added concurrently answersduplicate; no row holding the id answersnot_saved.ParseRequestnow name the platform (isWindows: true), since they test what the probe config carries.DARLING_TEST_PG): not run here. It gains one test that adds an identity, adds a second identity with the sameserver_idagainst the real table, and checkscollidesand that the first row is untouched. CI's PostgreSQL job runs it.isWindows: falsetests cover the Linux answer on any machine.Worth a second look
not_savedis a new word on the wire. Callers that switch onstatussee it only in the fault and no-row cases; the counters and the sum rule are unchanged.OperationCanceledExceptionis not treated as a save fault; it still reaches the outer catch as before.--add-serversummary line still countsadded,skippedandfailedonly, so a collided entry is in the per-server lines but not in the totals line. That predates this change and is left alone.DO NOTHINGinsert and is not changed here.CHANGELOG
SECTION: Fixed
ENTRY:
add_serversreports every server in the batch when a later entry fails to save, and no longer says "added" for a save that wrote nothing ([Darling MCP: mute_analysis_finding picks the first partial match, create_mute_rule duplicates on retry, add_servers misreports, store growth hides gaps #4734]) -add_serversnow reports every server in the batch when a later entry fails to save, instead of reporting the whole call as failed after it had already added the earlier ones: the failed entry and the ones after it come back as the new statusnot_saved(counted as failed) and the earlier ones stayadded. It rejects a literal SQL password or service principal client secret on Linux, where it cannot be encrypted, and points at theenv:orfile:reference form. When the save wrote nothing because another server holds the same id, it answerscollides(orduplicatefor a concurrent add of the same server) instead of "added".REF:
[Darling MCP: mute_analysis_finding picks the first partial match, create_mute_rule duplicates on retry, add_servers misreports, store growth hides gaps #4734]: Darling MCP: mute_analysis_finding picks the first partial match, create_mute_rule duplicates on retry, add_servers misreports, store growth hides gaps #4734