Repository navigation
fix: deflake //rs/boundary_node/ic_boundary:ic_boundary_test - #11899
Merged
Merged
Conversation
core::test::test_startup waits up to 240 s for ic-boundary to obtain a certificate from Pebble over ACME TLS-ALPN-01. rustls-acme polls the authorization 1 s after triggering the challenge and, when it is still pending, POSTs the challenge again. Pebble validates after a random 0-4 s delay and rejects that second POST (the challenge is processing), so rustls-acme abandons the order and retries with exponential backoff. Only luck (a fast validation or Pebble reusing a valid authorization in 51% of new orders) gets a certificate within the 8 orders that fit in 240 s. Set PEBBLE_VA_NOSLEEP=1 so Pebble validates the challenge right away and the first order succeeds. The TLS-ALPN-01 validation still runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The narrow test-only change addresses the identified timing issue without changing production behavior or bypassing validation.
No open issues 🎉
What changed in this PR
Reduces startup-test flakiness by disabling Pebble’s random validation delays, addressing the timing issue left unresolved by #9197.
Changes:
- Sets
PEBBLE_VA_NOSLEEP=1while preserving real ACME challenge validation. - Documents why immediate validation is needed.
| File | Description |
|---|---|
| rs/boundary_node/ic_boundary/BUILD.bazel | Disables random Pebble validation delays in the test environment. |
Review effort: Balanced
|
✅ No security or compliance issues detected. Reviewed everything up to 666f76f. Security OverviewDetected Code Changes
|
blind-oracle
approved these changes
Oct 20, 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.
Root cause
core::test::test_startupstarts Pebble (Let's Encrypt's ACME test server) and then ic-boundary with an ACME TLS-ALPN-01 certificate resolver. It then pollshttps://127.0.0.1:5001/healthfor up to 240 s, until ic-boundary serves the certificate it got from Pebble. Both flaky runs of the last week (merge queue on 2026-10-15, #11881 on 2026-10-19) failed their first attempt withUnable to query ic-boundary: timed out. The Pebble log interleaved in the test log shows ic-boundary abandoning 8 ACME orders in a row.ic-boundary only gets its certificate by luck:
rustls-acme 0.15.4 (used through ic-bn-lib's
AcmeAlpn) POSTs the challenge, waits 1 s and polls the authorization. If it is stillpending, it POSTs the challenge again (state.rs, unchanged on upstreammain).By default, Pebble's validation authority runs 3 validations per challenge, each after a random 0-4 s sleep (
rand.Intn(5)). Meanwhile the challenge isprocessing, so Pebble answers the second POST with400 malformed: Cannot update challenge with status processing, only status pending.rustls-acme treats the 400 as an order error. It abandons the order and starts a new one after an exponential backoff of 1, 2, 4, 8, … s.
An order succeeds only in two cases:
PEBBLE_AUTHZREUSEdefaults to 50, applied asrand.Intn(100) > 50).Abandoned authorizations become valid because rustls-acme leaves the challenge certificate in its single challenge slot when an order errors. When the next order replaces it before Pebble's delayed validation runs, that validation fails. This causes the
authz ... set INVALIDlines in the logs, which fix: deflake //rs/boundary_node/ic_boundary:ic_boundary_test #9197 took for the cause.With the backoff, 240 s fits 8 orders, starting about 0, 2, 6, 12, 21, 38, 71 and 137 s in; a 9th would start at about 267 s. #9197 raised the budget from 120 s to 240 s, which only added the 8th order.
Evidence:
test_startupfailed in all of them.core::test::test_startupwith Pebble's settings varied through--test_env:PEBBLE_AUTHZREUSE=0PEBBLE_VA_NOSLEEP=1+PEBBLE_AUTHZREUSE=0PEBBLE_VA_NOSLEEP=1Fix
Set
PEBBLE_VA_NOSLEEP=1in the test's environment. ic-bn-lib spawns Pebble as a child process, so Pebble inherits it and validates the challenge right away. rustls-acme's first poll then finds the authorization valid. Pebble still performs the real TLS-ALPN-01 validation against ic-boundary's resolver (unlikePEBBLE_VA_ALWAYS_VALID), so the test keeps covering it.One source of randomness remains. ic-bn-lib makes Pebble reject 1% of nonces, and rustls-acme doesn't retry a
badNonce, so an order of 9 signed requests still fails about 9% of the time. The next order starts 1 s later.Verification on this branch:
bazel test --runs_per_test=3 --jobs=3: 3/3 passed, about 4 s each.--runs_per_test=50of the whole target: 50/50 passed, at most 7.5 s; the certificate arrived after a median of 3 s and at most 7 s.Disabling random VA sleepsline and noSleeping forlines.Not addressed here
listen tcp 127.0.0.1:34000: bind: address already in use. ic-bn-lib's Pebble helper hard-codes ports 34000, 38053 and 38055, all inside Linux's ephemeral port range (32768-60999). Fixing it needs an ic-bn-lib change: ports below 32768, or retrying startup.badNonce. Let's Encrypt's Boulder rejects such a repeated challenge POST withAuthorization is already being validatedwhen itsSetAuthzProcessingfeature is enabled. Whether Let's Encrypt runs with that enabled in production is unknown.This PR was created following the steps in
.claude/skills/fix-flaky-tests/SKILL.md.🤖 Generated with Claude Code