[lts_03_2025] CI: migrate to Microsoft-hosted agents (retired ACR/self-hosted pools break all PRs) - #2747
Conversation
The C-canary pipeline on this branch cannot run at all. Every Linux job pulls its container from csdkcontainerregistry.azurecr.io via the csdk-containers endpoint, and runs on the sdk-c--* self-hosted pools. Both the registry and those pools were retired; main moved off them in #2701. On this branch the first job of the Setup stage therefore fails in "Initialize containers" with: Could not fetch access token for ACR. Please configure Managed Service Identity (MSI) for Azure Container Registry with the appropriate permissions. Setup gates everything, so all downstream stages are skipped and any PR targeting lts_03_2025 is red before a line is compiled. Observed on build 162517 (PR #2746), which failed 14s in. Bring the CI configuration to parity with main by taking main's version of the pipeline and the build/test scripts it drives. This corresponds to the eight pipeline commits made on main since this branch diverged: c59df07 Update CODEOWNERS and ubuntu-20.04 runner pool (deprecated) (#2677) 5f11fab Run Cleanup stage even if cancelled (#2682) c5d43cf Replace pipeline with Microsoft-hosted agents (#2701) 891fa30 Self-sufficient hosted-agent optimizations (#2718) 1317b57 Make AZURE_LOCATION a runtime parameter (#2717) 6473693 Replace Node.js check_submodules with PowerShell (#2721) fa6ad5d Disable NTLM in linux-setup-raspberry.sh (#2733) c86b2d6 Make CodeQL opt-in per job (#2743) Taken as an end state rather than eight cherry-picks: the intermediate commits conflict with each other in build_all/linux/run_tests.sh, and the only state that matters is the one main runs green today. Every file changed here is CI or test infrastructure. No product source, no submodule pointers, and no version change. Audited against this branch's tree before committing: - all build_all/, jenkins/, testtools/ and samples/ paths the pipeline invokes exist here - the cmake options it passes resolve the same way they do on main (enable_ipv6 is a c-utility option on both; -DpsX509IndividualEnrollments is a PowerShell parameter, not a cmake one) - the YAML parses: 4 stages, 30 jobs, no remaining azurecr.io reference Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 1 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Status note: build 162518 has been sitting in One thing already confirmed by this run, though: the stage graph now resolves to Please check the completed run before merging — as noted above, I could not build or test locally, and a genuine LTS-only failure is plausible given the ~14-month source gap. |
My previous commit took samples/dockerbuilds/myapp/CMakeLists.txt from main along with the pipeline files. That file is not CI infrastructure, and main's version links c_logging_v2: target_link_libraries(myapp ... aziotsharedutil c_logging_v2 parson ...) main can do that because its root CMakeLists.txt add_subdirectory()s deps/c-logging and installs the v2 target. This branch has no c-logging wiring in its root CMakeLists.txt at all, so libc_logging_v2 is never built or installed here and the cross-compile samples fail at link: ld: cannot find -lc_logging_v2 Observed on build 162518 in both Cross Compile (ARM) and Cross Compile (MIPS32). Restore this branch's line, which links parson and not c_logging_v2. Note both branches pin deps/c-logging at the same commit (504e7d47); the difference is purely that main wires it into the build and this branch does not. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
First full run completed — 30 jobs green, 6 failures, both root-caused and fixedBuild 162518 got the whole matrix running for the first time on this branch. 30 jobs passed, including every Linux job, all four valgrind/helgrind suites, the E2E jobs and OSX/Xcode. The ACR blocker is gone. Six jobs failed, from exactly two root causes. Both were my fault, not pre-existing breakage, and both are now fixed. 1. Cross Compile (ARM) and Cross Compile (MIPS32) —
|
✅ Fully green — build 162560 succeededAll 34 jobs passed, 37/37 GitHub checks green. Both fixes are confirmed by CI:
Everything that passed in the previous run still passes, including all valgrind/helgrind suites, the E2E jobs, OSX/Xcode, mbedTLS 2.16/2.28/3.x, WolfSSL, BearSSL and RIOT/DICE. No flakes, no reruns. This is the first green C-canary run on Recommended: merge this first, then rerun CI on #2746 (which is still red only because its branch predates this pipeline). |
There was a problem hiding this comment.
Pull request overview
This PR restores CI viability on lts_03_2025 by migrating the Azure DevOps pipeline off retired self-hosted pools/ACR images onto Microsoft-hosted agents, and updates the supporting build/test scripts (plus one sample build fix) so the hosted-agent lanes run successfully.
Changes:
- Replace container/self-hosted pool usage in
build/.vsts-ci.ymlwith Microsoft-hostedvmImagejobs, including new Requirements/Setup/Cleanup flow and artifact-based E2E env propagation. - Update Linux build/test automation for hosted agents (ccache integration, test sharding/parallelism changes, updated valgrind suppressions).
- Refresh cross-compile/docker toolchains (OpenSSL 3.0.15, curl 8.20.0, NTLM disabled) and fix a sample enum comparison for newer MSVC.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| build/.vsts-ci.yml | Migrates CI to Microsoft-hosted agents; adds Requirements/Setup/Cleanup orchestration and per-run test config artifacts. |
| build_all/linux/setup.sh | Adds ccache to Linux host dependencies for hosted-agent builds. |
| build_all/linux/build.sh | Enables ccache via CMAKE_*_COMPILER_LAUNCHER when available. |
| build_all/linux/run_tests.sh | Adds test-mode flags and tuned parallelism/sharding for hosted agents/valgrind tools. |
| testtools/scripts/linux-setup-raspberry.sh | New hosted-agent Raspberry Pi cross-toolchain bootstrap script (toolchain + OpenSSL/curl/util-linux). |
| samples/dockerbuilds/RaspberryPi/Dockerfile | Updates Raspberry Pi cross-build base/toolchain and bumps OpenSSL/curl, disables NTLM. |
| samples/dockerbuilds/ARM/Dockerfile | Updates ARM cross-build OpenSSL/curl and adds CMake policy compatibility settings. |
| samples/dockerbuilds/MIPS32/Dockerfile | Updates MIPS32 OpenSSL/curl, adds libatomic linkage notes and CMake find-package hardening. |
| jenkins/raspberrypi/Dockerfile | Updates Raspberry toolchain libs (OpenSSL/curl) and disables NTLM. |
| jenkins/raspberrypi/setup_pi_for_e2e_tests.sh | Updates curl install path/version and disables NTLM for device setup. |
| jenkins/raspberrypi/run_this_to_setup_a_pi_for_e2e_tests.sh | Same curl update as above for Raspberry Pi setup helper. |
| jenkins/osx_gcc_openssl.sh | Adds CMAKE_POLICY_VERSION_MINIMUM for newer CMake compatibility on hosted macOS. |
| jenkins/osx_xcode_native.sh | Adds CMAKE_POLICY_VERSION_MINIMUM for newer CMake compatibility on hosted macOS. |
| jenkins/linux_c_option_test.sh | Documents/avoids -Wmaybe-uninitialized due to GCC 12+ false positives on common patterns. |
| iothub_client/tests/global_valgrind_suppression.supp | Adds suppressions for helgrind/drd noise on newer Ubuntu/valgrind/glibc. |
| provisioning_client/tests/common_prov_e2e/prov_valgrind_suppression.supp | Broadens helgrind preload path matching and adds Ubuntu 24.04 suppression entries. |
| provisioning_client/samples/iothub_client_sample_hsm/iothub_client_sample_hsm.c | Fixes enum comparison so newer MSVC compiles warnings-as-errors. |
| build_all/docs/Doxyfile | Updates Doxygen project version number. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Copying main's build_all/docs/Doxyfile carried its PROJECT_NUMBER of 1.15.0 onto this branch, whose iothub_client_version.h is 1.14.0. That contradicts the stated scope of this change (no version bump) and made the generated docs disagree with the SDK version. The Doxyfile is not referenced by the pipeline, so it had no CI value here. Restored to 1.14.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Doxyfile reverted; one unrelated infrastructure failure in the new runPushed Build 162564 has one failure: Ubuntu 24.04 ARM64 (Cross-compile only), in the Not caused by this PR's latest change. The only delta between the fully green 162560 and this run is one line in Cause. This is inherited from Suggest a rerun of that job. If it should be hardened instead, the durable fix is to install the arm64 libs pinned to the image's installed |
Retry result: all 34 build/test jobs green; the ARM64 failure was transientBuild 162564 after retrying the failed job:
34/34 build and test jobs green. The one remaining red is a retry artifact, not a code or test failure
Attempt 1 of that job succeeded and deleted the group. The retry re-ran the whole set -e
az group delete --name $AZURE_RESOURCE_GROUP --yes --no-wait
No resources are leaked — the opposite: the group was already removed. This step is verbatim from State of this PRGreen on content, twice over:
The delta between the two commits is one line in Happy to either queue a fresh run so the current head shows a single clean green, or open the Cleanup idempotency fix against |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
build/.vsts-ci.yml:804
sudo apt-get install -y libwolfssl-dev || truesuppresses package-install failures, which can make this job fail later in less obvious ways (or accidentally stop exercising WolfSSL if the build scripts ever add a fallback). It’s better to fail fast if WolfSSL headers/libs can’t be installed.
set -e
sudo apt-get update -qq
sudo ./build_all/linux/setup.sh
# wolfSSL is not in Ubuntu main; install dev headers from universe.
sudo apt-get install -y libwolfssl-dev || true
build_all/linux/run_tests.sh:60
- When running plain tests with
--e2e, the--e2e-onlyflag is currently ignored (the script still runs unit tests + E2E), and--e2e --ut-onlyresults in running no tests. This can lead to incorrect or false-green executions if someone invokes the script with these flag combinations.
if $run_plain; then
if $run_e2e; then
if ! $ut_only; then
# Unit tests + E2E, no valgrind/helgrind/drd
# iothubclient_mqtt_dt_e2e is quarantined: see GitHub issue (twin PATCH never
Addressing the 2 suppressed comments from the latest reviewThe re-review of 1.
|
| Invocation | Runs |
|---|---|
--e2e --e2e-only |
UT + E2E — --e2e-only silently ignored |
--e2e --ut-only |
nothing |
--e2e-only |
nothing |
So there are three bad combinations, not one. In the plain branch --e2e-only is never consulted when --e2e is set, and --ut-only suppresses the only ctest call.
Not reachable from this pipeline. All six invocations resolve correctly:
RUN_TESTS_ARGS |
Runs |
|---|---|
--e2e |
plain UT + E2E |
--valgrind --ut-only |
valgrind UT |
--valgrind --e2e --e2e-only |
valgrind E2E |
--helgrind --ut-only |
helgrind UT |
--helgrind --e2e --e2e-only |
helgrind E2E |
--drd --e2e |
drd |
Verbatim from main, so same reasoning as the other inherited items — worth a proper argument-validation fix on main covering all three combinations.
2. build/.vsts-ci.yml:804 — libwolfssl-dev || true
Disagree that this can silently stop exercising wolfSSL. The build cannot succeed without it:
jenkins/linux_wolfssl.shconfigures with-Duse_wolfssl=ON -Duse_openssl=OFF.- With
use_wolfsslset, c-utility compilesadapters/tlsio_wolfssl.cunconditionally, which includeswolfssl/options.h,wolfssl/ssl.h,wolfssl/error-ssl.handwolfssl/wolfcrypt/types.h. - That script runs under
set -o errexit.
If the package were missing the compile would fail on the missing headers and the Build step would fail. The || true only tolerates a failure in the apt step; the real check is at compile time, and the WolfSSL job passed.
The valid part of the point is that failing at apt time gives a clearer error than failing later at a missing include. That is a readability improvement, not a correctness gap, and the line is verbatim from main.
No change made for either. Both are covered by the follow-up I offered against main.
Fetch the E2E helper module from master
Both call sites pulled Azure.Iot.Sdk.Test.psm1 from a personal feature
branch on iot-sdks-e2e-fx. That branch never had a pull request, is 43
commits behind master and 3 ahead, so CI depended on a stale dead end that
could vanish at any time. Point both at master.
All three commits unique to that branch are superseded on master:
- "install stable azure-iot CLI extension by default" -> master installs a
pinned extension version (0.30.0b2) via Install-AzureIotCliExtension,
which is strictly more reproducible than selecting whatever --allow-preview
resolves to.
- "use .pem for temp cert files" -> present on master.
- "--login on enrollment commands" -> that workaround existed because
--allow-preview drifted onto an untested extension build; pinning the
version removes the cause.
Verified master still satisfies this pipeline: New-AzureResourceGroupName,
New-AzIotTestEnvironment, New-AzIotCSDKE2ETestConfig and
Test-SubmoduleConsistency all exist, are exported, and accept every
parameter used here.
echo the home directory instead of executing it
A bare $HOME ran the home directory as a command, logging
"Is a directory" and returning 126. Harmless only because the step has no
set -e and $HOME was not the last command.
Make the raspberry toolchain setup idempotent
mkdir $WORK_ROOT failed on any re-run; mkdir -p and quoting fix that.
pushd /${WORK_ROOT}/... had a stray leading slash that produced a
double-slash path and would break outright if WORK_ROOT were relative.
Reject and correct the broken run_tests.sh flag combinations
Three invocations misbehaved silently:
--e2e-only ran nothing and exited 0 (false green)
--e2e --ut-only ran nothing and exited 0 (false green)
--e2e --e2e-only ignored --e2e-only and ran unit tests too
--e2e-only now requires --e2e, and the plain branch honours both flags.
Verified the six invocations this pipeline actually uses produce byte
identical ctest commands before and after.
Make resource group cleanup idempotent
az group delete exits 3 when the group is absent, and the step runs under
set -e. Retrying any job re-runs the Cleanup stage, so a build whose first
cleanup succeeded went red on retry with ResourceGroupNotFound. This was
observed on the previous run of this branch. Check for the group first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All 5 review comments fixed in
|
The Ubuntu 24.04 ARM64 job intermittently failed in
"Install aarch64 cross toolchain and arm64 dev libs" with apt exit 100:
libssl-dev:arm64 : Depends: libssl3t64:arm64 (= 3.0.13-0ubuntu3.12)
but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
libssl3t64, libcurl4t64 and zlib1g are Multi-Arch: same, so the arm64 copy
must be the exact version of the amd64 copy already on the runner image.
ports.ubuntu.com and archive.ubuntu.com are not always in sync; when they
drift apt rejects the whole transaction.
That the drift, not the tree, is the trigger is visible in the versions:
one failure demanded 3.0.13-0ubuntu3.15 and a later one 3.0.13-0ubuntu3.12,
with no change in between, and a plain retry of the first one passed.
Name both arches for the three Multi-Arch: same runtime libraries so apt can
settle on a version present in both archives, and allow downgrades so it can
move the amd64 copy back when ports is the side that lags.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ARM64 job hardened in
|
| Run | ARM64 result | Version apt demanded |
|---|---|---|
| 162564 attempt 1 | fail | libssl3t64:arm64 (= 3.0.13-0ubuntu3.15) |
| 162564 attempt 2 | pass | — (identical code) |
| 162575 | fail | libssl3t64:arm64 (= 3.0.13-0ubuntu3.12) |
Two different demanded versions with no change in between, and a plain retry passing, rules out this branch's contents. main passes the same job, which is why it was not caught earlier.
Cause. libssl3t64, libcurl4t64 and zlib1g are Multi-Arch: same, so the :arm64 copy must be the exact version of the :amd64 copy already on the runner image. ports.ubuntu.com and archive.ubuntu.com are not always in sync; when they drift, apt rejects the whole transaction with held broken packages. Whether a given run passes depends on which mirror snapshot the agent happens to hit.
Fix. Name both arches for those three runtime libraries so apt can settle on a version present in both archives, and pass --allow-downgrades so it can move the amd64 copy back when ports is the lagging side.
This is inherited from main and will keep biting there intermittently; same fix applies.
✅ Fully green — build 162584 succeeded37/37 checks, all 35 jobs succeeded on first attempt, no retries. Head Every previously failing job is now green, including the two that were failing for real reasons:
Notably All 5 review comments are addressed, plus the two robustness fixes needed to make the result reproducible rather than luck-of-the-agent. Ready to merge. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
build/.vsts-ci.yml:813
- The Host setup step installs libwolfssl-dev with
|| true, which can mask install failures and cause later CMake/configure failures that are harder to diagnose. Since the wolfSSL build relies on system headers (jenkins/linux_wolfssl.sh doesn’t build wolfSSL itself), fail fast by removing|| true(or explicitly check availability and error out).
set -e
sudo apt-get update -qq
sudo ./build_all/linux/setup.sh
# wolfSSL is not in Ubuntu main; install dev headers from universe.
sudo apt-get install -y libwolfssl-dev || true
build/.vsts-ci.yml:109
- There’s a stray
+at the end of this comment line (first job+). While harmless, it looks like an accidental artifact and reduces readability.
# stage rerun, or an agent-loss auto-retry). Publish only on the first job+
Latest review: no new inline comments; 2 suppressed itemsCopilot re-reviewed 1. 2. "Stray condition: and(always(), eq(variables['System.JobAttempt'], '1'), eq(variables['System.StageAttempt'], '1'))Both |
build/.horton-e2e.yml on this branch predates two changes that have since happened outside it, and cannot run as written: 1. It names the service connection 'GitHub OAuth - az-iot-builder-01'. That endpoint no longer exists in the azure-iot-sdks project; the GitHub connection is now 'azure-iot-sdk-python-github'. Resource resolution fails before any job starts. 2. It declares `jobs:` with jobs-gate-c.yaml directly, with no setup stage. That template is consumed from iot-sdks-e2e-fx@refs/heads/master, which is a moving ref, and it now begins with steps-load-test-config.yaml. That step does `download: current / artifact: test_config`, published by steps-create-azure-resources.yaml. With no setup stage nothing publishes that artifact, so every job fails on the download. Take main's version, which adds the setup and cleanup stages around the gate and uses the endpoint that exists. The file references only e2e-fx templates and no paths inside this repo, so it is branch agnostic; the SDK itself is cloned by the gate from Horton.Repo at Horton.Commit. Note this file alone does not make the gate run for this branch: the horton-c-gate pipeline's pull request trigger is filtered to +main, so PRs targeting lts_03_2025 are reported as skipped. That filter has to be widened separately for the gate to execute here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Why
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
build/.vsts-ci.yml:69
Setupis configured withdependsOn: [], socreate_azure_resourcescan run (and provision Azure resources) even if theRequirements/checksubmodulestage fails. This defeats the submodule-gating goal and can waste limited provisioning quota on known-bad runs.
- stage: Setup
dependsOn: [] # Run in parallel with Requirements to save ~3-5 min
Build 162609 green — 37/37, no retriesHead Latest review: 18/18 files, no new inline comments; 1 suppressed item
The accurate part is the quota point: on a failing-submodule run the resource group is provisioned and then torn down without being used. Verbatim from |
Trigger request widened to
|
| Pipeline | PR trigger branch filters |
|---|---|
| C-canary | +uhttp_upload, +public-preview-pnp, +public-preview, **+lts_\***, +main |
| horton-c-gate | +main |
Five integrate-into-repo-* pipelines use +master,+lts_* too, so the pattern is well established here.
Requested edit is now ["+main", "+lts_*"] instead of pinning one branch. Matches all 10 lts_ branches (lts_01_2021 … lts_08_2025-era, including lts_03_2025), so future LTS branches are covered without another pipeline edit. PR triggers match on the target branch, so topic branches like ci/lts_03_2025-hosted-agents are unaffected.
Two notes:
- This also gates PRs to LTS branches that are past end of support. Harmless — they rarely see PRs — but it is broader than strictly needed.
- The build-completion trigger is still
["+public-preview", "+main"], so the gate will not chain after C-canary on LTS branches post-merge. I left it alone; adding+lts_*there is a one-line change if you want that too, but it starts running live E2E on every LTS merge.
Still needs the pipeline-setting approval; the repo-side fix (affd1c5d3) is already in.
Trigger change not applied — horton-c-gate stays skippedThe pipeline-settings edit to widen horton-c-gate's PR trigger to Consequence: The repo-side half is still worth having and stays in: C-canary is unaffected: 37/37 green, all 35 jobs first attempt. |
The horton-c-gate pull request trigger was widened to +main,+lts_* so the gate applies to LTS branches. Branch filters are evaluated when a pull request event fires, so the already-reported skip on this PR does not re-evaluate on its own. Empty commit to raise a new event. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
horton-c-gate now runs here — and found a real gate bug, fixed in Azure/iot-sdks-e2e-fx#445Trigger is applied (definition 204 rev 26, PR filters The ported
Cause is in the gate, not this branch. The image is built in two phases:
The existing symlink guard in Fix: Azure/iot-sdks-e2e-fx#445 removes the stale forwarding headers before configuring. Safe both ways — an SDK that needs them regenerates them during the following This is a pre-existing gate limitation that only surfaced because the gate had never run against an LTS branch before. Nothing to change in this PR. Sequencing: the gate consumes e2e-fx templates from |
C-canary 162617: 34/35 green; one flake in
|
| Build | helgrind_e2e |
|---|---|
| 162560 | pass |
| 162564 | pass |
| 162584 | pass |
| 162609 | pass |
| 162617 | fail |
That test is known to be timing-sensitive under helgrind. It was quarantined in #2701 with the note that helgrind instrumentation makes IoTHubClient_Destroy() exceed the test's 30s deadline on the 4-vCPU hosted agents, then deliberately un-quarantined in #2718. So main carries the same exposure.
I have requested a retry of the failed job. If it should be made deterministic instead, the options are re-adding it to the helgrind exclusion list or raising that test's deadline — both decisions belong on main, since main un-quarantined it on purpose. Happy to open that PR.
Retrying only the failed helgrind E2E job could not succeed: the Cleanup stage runs on build completion with always(), so it had already deleted the resource group before the retry started. A full run re-executes Setup and provisions resources first. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The retry could not have passed — it ran after resources were deletedRetrying only the failed job was the wrong remedy, and the 17/18 result is an artifact of that, not new signal. The Confirming detail: the only test that passed on the retry was So the two attempts say different things:
Structural, inherited from Worth fixing properly on On the underlying flake
If it recurs on this run I will re-quarantine it under helgrind here, using #2701's own justification. Holding off for now rather than reducing coverage preemptively on a single data point. |
|
/azp run horton-c-gate |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Gate green. The earlier |
Problem
C-canarycannot run onlts_03_2025. Every Linux job pulls containers fromcsdkcontainerregistry.azurecr.iovia thecsdk-containersendpoint and targets the retiredsdk-c--*self-hosted pools.mainmoved off both in #2701.Setupfails inInitialize containers:Setupgates all stages, so every PR to this branch is red before anything compiles. Not transient.Change
Takes
main'sbuild/.vsts-ci.ymland the scripts it drives — the eight pipeline commits made onmainsince this branch diverged at5a48d3fd8:c59df07db5f11fab75c5d43cf83891fa30741317b572464736930afa6ad5d5ac86b2d6a5Applied as an end state, not eight cherry-picks: the intermediate commits conflict in
build_all/linux/run_tests.sh, and only the statemainruns green today matters.Plus one source fix required to build on hosted Windows agents —
ca8b9bf35(#2681), cherry-picked:resultis anIOTHUB_CLIENT_CONNECTION_STATUS;IOTHUB_CLIENT_CONFIRMATION_OKbelongs to a different enum. Newer MSVC rejects the mismatched comparison and this sample builds warnings-as-errors. Behaviour-preserving — both constants are0(verified by compiling the macro expansion).No submodule pointer changes, no version bump.
Verification
Build 162560: all 34 jobs green, 37/37 checks. First green C-canary run on this branch.
Locally verified before pushing: enum constants both
0; fixed sample compiles clean undergcc -Wall -Wextra. MSVC and the docker cross-compiles could not be run locally and were confirmed by CI.Note
lts_03_2025reaches maintenance end on 2026-10-07, so this restores the gate for the remaining ~6 weeks.#2746 cannot go green until this lands.