Skip to content

v1.0.1: synchronous certificate pickup (Sectigo parity) - #20

Open
spbsoluble wants to merge 5 commits into
release-1.0from
hotfix/v1.0.1-sectigo-parity-pickup
Open

v1.0.1: synchronous certificate pickup (Sectigo parity)#20
spbsoluble wants to merge 5 commits into
release-1.0from
hotfix/v1.0.1-sectigo-parity-pickup

Conversation

@spbsoluble

@spbsoluble spbsoluble commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an in-call certificate pickup to enrollment. After an order is submitted, the plugin waits briefly for the certificate and returns it in the same enrollment request when it issues quickly — so DV and already-approved certs come back immediately instead of waiting for the next synchronization. Mirrors the legacy Sectigo connector's pickup behavior.

Behavior

  • Fast-issuing orders (DV / already approved) return the issued certificate in the same call.
  • Slower orders — including OV/EV, which CERTInext validates asynchronously (minutes to hours) — return pending and are imported by a later sync, unchanged from today.
  • Default wait is ~55s (5 polls, 10s apart, after a 5s initial delay), with a built-in ceiling so it can't run long enough to time out the enrollment.
  • Applies to new, reissue, and renew enrollments, in both build flavors (no-DCV 3.2.0 and DCV 3.3.0). On the DCV build it works alongside DCV without adding a second wait.

New settings

  • PickupRetries — number of poll attempts (default 5; set to 0 to disable the wait)
  • PickupDelay — seconds between polls (default 10)

Also included

Fixes a duplicate/orphaned-order bug: order and CSR submissions are no longer retried after a network timeout. A timeout can occur after the CA has already accepted the request, so the retry was being rejected as a duplicate — failing the enrollment and leaving an orphaned order behind. These now run once and reconcile on the next sync.

Testing

  • Both flavors build clean, 0 warnings (-p:DcvSupport=false and -p:DcvSupport=true).
  • Unit tests: DCV 199/199, no-DCV 176/176.

After submitting an order, Enroll() polls GetCertificate up to PickupRetries
times (default 5), PickupDelay seconds apart (default 10), after a 5s initial
delay, so a fast-issuing order returns the certificate in the same enrollment
call instead of waiting for the next sync. Mirrors the legacy Sectigo connector's
PickUpEnrolledCertificate (~55s max worker-thread occupancy by default). Applied
to the new, reissue, and renew paths; both build flavors. PickupRetries=0 disables.

Orders not issued within the window are returned pending and imported by a later
sync (unchanged). OV/EV are issued asynchronously by the CA and typically exhaust
the window; DV / already-approved orders return in-call.
@spbsoluble
spbsoluble force-pushed the hotfix/v1.0.1-sectigo-parity-pickup branch from d49e2aa to 3e3d581 Compare July 31, 2026 17:11
RequestFormat is received by Enroll() but was never logged, so logs could not
show what Command passes for CSR vs PFX enrollments. Add it to the enrollment-start
Information line for diagnostics. Behavior unchanged — the value is still not used
for any decision (the gateway treats every enrollment as a CSR-based request).
…k timeout

A network-level timeout on GenerateOrderSSL / SubmitCSR can occur after CERTInext
has already received and created the order. The inner HTTP retry re-sent the same
request body (same requestTxn), which CERTInext rejected as EMS-947 "Duplicate
requestTxn" — failing the enrollment while orphaning the created order.

ExecuteWithRetryAsync gains an `idempotent` flag; PlaceOrderAsync and SubmitCsrAsync
now submit once (idempotent:false). A transient submit failure and an EMS-947
duplicate are each logged as an explicit no-retry decision and surfaced with a
clear, conditional message (if an order was created it is imported by the next
sync). Idempotent read calls are unchanged and still retry.
…dance

Compliance follow-ups (both Low):
- Add DomainName as a non-sensitive correlation key to the PlaceOrder transient
  and EMS-947 warnings so an orphaned order can be tied to its enrollment under
  concurrency (requestTxn is deliberately NOT logged — it is part of the authKey
  preimage).
- SubmitCSR now carries the "may already have been received; do not resubmit"
  guidance in the thrown exception on a transient failure, for parity with
  PlaceOrderAsync (previously only in the log line).
…dit logging

Review-driven refinements to the v1.0.1 synchronous-pickup feature:

- Skip the pickup poll when the DCV path already owns the in-call issuance
  wait, so the two never stack and a cancelled/rejected order is not re-polled
  for the full window (fixes a regression that broke the terminal-order guard).
- Cap total in-call pickup wait at 180s regardless of how PickupRetries and
  PickupDelay are configured, so an aggressive combination can't exceed
  Command's enrollment timeout.
- Log a terminal FAILED at Error and REVOKED at Warning; trace each poll at
  Debug; distinguish "all polls errored" from "still pending" in the timeout
  summary; include OrderNumber in the CSR transient-failure warning; surface a
  pending result that has no order number to poll instead of skipping silently.
- Default pickup off in the unit-test fixtures and add targeted pickup tests
  (disabled / issued / terminal / budget-exhausted).

Both flavors build clean (0 warnings); DCV 199/199, no-DCV 176/176.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant