Fix incremental sync discarding every certificate it retrieves - #65
Open
Pichatorn-A4K wants to merge 1 commit into
Open
Fix incremental sync discarding every certificate it retrieves#65Pichatorn-A4K wants to merge 1 commit into
Pichatorn-A4K wants to merge 1 commit into
Conversation
The guard in the incremental (non-full) branch of Synchronize() reads
if (orderCerts == null || orderCerts.Count > 0) { continue; }
so it continues for every order whose certificates were retrieved
successfully, and the blockingBuffer.Add loop below it is reachable only
when the list is empty - in which case it iterates nothing. An
incremental synchronization therefore adds zero certificates to the
buffer unconditionally, while still logging 'Sync complete with 0
certificates' and returning normally, so it is indistinguishable from a
healthy run with nothing to do.
The full-sync branch a few lines above has the correct 'Count == 0'.
Both guards were introduced in the same commit (ac791a7, 'Port sync CA
filter from DCOM gateway'), which suggests a copy-paste with one edit
missed rather than intent.
Note that the incremental-window fixes in Keyfactor#38, Keyfactor#40 and Keyfactor#41 all operate
inside this code path, which cannot emit anything until this predicate is
corrected.
This was referenced Sep 10, 2026
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.
The defect
In the incremental (non-full) branch of
Synchronize():The predicate
continues for every order whose certificates were retrieved, so theblockingBuffer.Addloop below is reachable only whenorderCertsis empty — in which case ititerates nothing. An incremental synchronization adds zero certificates to the buffer,
unconditionally.
It also does not look like a failure: the run logs
Sync complete with 0 certificatesand returnsnormally, which is indistinguishable from a healthy incremental sync with nothing to do. The
per-order API fan-out still happens, so the rate-limit cost is paid and the result is discarded.
The full-sync branch a few lines above has the correct comparison:
Provenance
Both guards were added in the same commit — ac791a7 "Port sync CA filter from DCOM gateway" (#7) —
one correct and one inverted, which reads as a copy-paste with one edit missed rather than intent.
The predicate has not been touched since.
Worth noting: the incremental-window changes in #38, #40 and #41 all operate inside this code
path, which cannot emit anything until this comparison is corrected.
How it was found
Reading the shipped
2.4.1net8.0release assembly (and confirming in2.4.2-rc.0, which iscode-identical here) while auditing the plugin before a customer engagement. In the IL the two
branches differ exactly as the source suggests: the full-sync branch proceeds when the count is
non-zero, the incremental branch reaches the emit block only when the count is
<= 0.Verification
Verified with a fake
CertCentralClientdrivingSynchronize()offline: with one issued order, thefull sync emits 1 certificate and the incremental sync emits 0 on
main, and both emit 1 with thischange. Reverting the one character makes that test fail again.
Those tests are not in this PR because the repository has no test project and adding one is a much
larger change than the fix. Happy to contribute the harness separately if it would be useful — it
needs a small seam, since the DigiCert client is constructed inline at eight call sites, which is
what makes
Synchronize()untestable today.We also have fixes for a handful of other findings from the same audit (unbounded 429 retry,
Errors[0]dereferences on response bodies that carry noerrorsarray, an unguardedIntermediates[0], a duplicatedViewCertificateOrderper order) and can raise them as separatePRs if you would like them.
🤖 Generated with Claude Code