Migrate to IDF 5.5.3 candidate

Pin PlatformIO packages and toolchains, rebase protected SDK
overrides, and add WebSocket receive regression coverage. Document
isolated candidate validation, archive provenance, and remaining gates.
This commit is contained in:
2026-09-18 14:23:13 +02:00
parent cdc4d4a8df
commit 797d2681ac
32 changed files with 1394 additions and 123 deletions
+43 -4
View File
@@ -41,8 +41,8 @@ def source_path(entry, idf, project=ROOT):
AUXILIARY = {
"components/esp_http_server/src/httpd_main.c": "a16ef65069dda13889c67b922f25eb566573983d6c24f01c089a902d5fd26149",
"components/esp_http_server/src/httpd_txrx.c": "7659ad52c32f29b9a08208dc8b22d023edf274047835ed58107d82a47ccce00e",
"components/esp_http_server/src/httpd_main.c": "55fccf1ec01265dd9be45609c4d8eeb5d9f80da99fee23b2309a6b372c56e24f",
"components/esp_http_server/src/httpd_txrx.c": "f0978034ae0acc7e5f5c52fcb4aabc424afd403d433a417e04ff70319a7dd140",
}
FEATURES = ["MBEDTLS_SSL_PROTO_TLS1_2", "MBEDTLS_SSL_SRV_C",
"MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", "MBEDTLS_ECDH_C",
@@ -145,8 +145,8 @@ def generator_tests(idf, work):
expect_error(lambda: sdk.generate(fake, ROOT, binary), "SHA256 mismatch")
assert before == {p: (p.read_bytes(), p.stat().st_mtime_ns) for p in before}
shutil.copyfile(idf / TLS_ENTRY.source, last)
(fake / version).write_text((fake / version).read_text().replace("VERSION_PATCH 0", "VERSION_PATCH 1"))
expect_error(lambda: sdk.generate(fake, ROOT, failed), "5.5.0")
(fake / version).write_text((fake / version).read_text().replace("VERSION_PATCH 3", "VERSION_PATCH 1"))
expect_error(lambda: sdk.generate(fake, ROOT, failed), "5.5.3")
shutil.copyfile(idf / version, fake / version)
last.unlink()
expect_error(lambda: sdk.generate(fake, ROOT, failed), "No such file")
@@ -215,6 +215,44 @@ def extracted_tests(idf, binary, work):
"-fsanitize=undefined", "-fsanitize-undefined-trap-on-error"])
def websocket_tests(idf, binary, work):
entry = next(e for e in sdk.ENTRIES if e.name == "httpd_ws")
text = generated_path(binary, entry).read_text()
assert text.encode() == sdk.render_entry(entry, {"idf": idf, "project": ROOT})[1]
txrx = (idf / "components/esp_http_server/src/httpd_txrx.c").read_text()
assert hashlib.sha256(txrx.encode()).hexdigest() == AUXILIARY["components/esp_http_server/src/httpd_txrx.c"]
private = (idf / "components/esp_http_server/src/esp_httpd_priv.h").read_text()
options = re.search(r"typedef enum \{[^}]*\} httpd_recv_opt_t;", private)
assert options
functions = "".join(extract(txrx, n) for n in ("httpd_recv_pending", "httpd_recv_with_opt"))
functions += "".join(extract(text, n) for n in (
"httpd_ws_check_req", "httpd_ws_unmask_payload", "httpd_ws_recv_frame",
"httpd_ws_send_frame", "httpd_ws_get_frame_type"))
template = (HERE / "ws.c").read_text().replace("/* SDK_OPTIONS */", options.group())
source = template.replace("/* SDK_FUNCTIONS */", functions)
flags = ["-fsanitize=undefined", "-fsanitize-undefined-trap-on-error"]
compile_run("ws", source, work, flags)
# Independently enumerate all five sites, rather than trusting the edit registry.
sites = list(re.finditer(r"httpd_recv_with_opt\([^\n]+HTTPD_RECV_OPT_BLOCKING\) < \(int\)sizeof\(([^)]+)\)", functions))
assert [m[1] for m in sites] == ["second_byte", "length_bytes", "length_bytes", "aux->mask_key", "first_byte"]
for i, match in enumerate(sites):
removed = functions[:match.start()] + match[0].replace("(int)sizeof", "sizeof") + functions[match.end():]
c = work / f"ws_removed_cast_{i}.c"
c.write_text(template.replace("/* SDK_FUNCTIONS */", removed))
output = run(["cc", "-std=gnu11", "-Wall", "-Wextra", "-Werror", "-fsyntax-only", c], ok=False)
assert "sign-compare" in output, output
# Explicit unsigned conversion reproduces the vendor's implicit promotion
# without disabling sign-compare diagnostics: rejection must be behavioral.
mutant = functions[:match.start()] + "(size_t)" + match[0].replace("(int)sizeof", "sizeof") + functions[match.end():]
c = work / f"ws_mutant_{i}.c"
exe = work / f"ws_mutant_{i}"
c.write_text(template.replace("/* SDK_FUNCTIONS */", mutant))
run(["cc", "-std=gnu11", "-O2", "-Wall", "-Wextra", "-Werror", *flags, c, "-o", exe])
output = run([exe], ok=False)
assert "Assertion" in output or "assertion" in output, output
print("WS five removed casts rejected by strict compilation and five unsigned-comparison behavioral mutations rejected PASS")
def compile_run(name, source, work, flags=()):
c = work / (name + ".c"); exe = work / name
c.write_text("/* Extracted SDK sections retain their upstream Apache-2.0 license. */\n" + source)
@@ -410,6 +448,7 @@ def main():
work = Path(tmp)
binary = generator_tests(idf, work)
extracted_tests(idf, binary, work)
websocket_tests(idf, binary, work)
cmake_fixture_tests(idf, work)
extension_fixture_tests(idf, work)
if args.build_dir: build_registration(args.build_dir.resolve(), idf)