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:
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile actual transport callbacks using the existing serial/store doubles."""
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
@@ -14,7 +17,40 @@ sys.path.insert(0, str(BASE))
|
||||
from run import HEADERS
|
||||
from serial_headers import SERIAL_HEADERS
|
||||
os.environ['CCACHE_DISABLE'] = '1'
|
||||
IDF = pathlib.Path(os.environ.get('IDF_PATH', str(pathlib.Path.home() / '.platformio/packages/framework-espidf')))
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--idf-path', type=pathlib.Path, default=pathlib.Path(os.environ.get(
|
||||
'IDF_PATH', str(pathlib.Path.home() / '.platformio/packages/framework-espidf'))))
|
||||
parser.add_argument('--build-dir', type=pathlib.Path,
|
||||
help='Require the actual generated WS compilation input and verify its bytes')
|
||||
parser.add_argument('--sanitize', action='store_true')
|
||||
args = parser.parse_args()
|
||||
IDF = args.idf_path.resolve()
|
||||
|
||||
|
||||
def generated_ws():
|
||||
spec = importlib.util.spec_from_file_location('performance_security_overrides', ROOT / 'tools/security_overrides.py')
|
||||
sdk = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = sdk
|
||||
spec.loader.exec_module(sdk)
|
||||
sdk.verify_version(IDF)
|
||||
entry = next(e for e in sdk.ENTRIES if e.name == 'httpd_ws')
|
||||
original, rendered = sdk.render_entry(entry, {'idf': IDF, 'project': ROOT})
|
||||
if args.build_dir:
|
||||
build = args.build_dir.resolve()
|
||||
expected = build / 'security_overrides/httpd_ws/httpd_ws.c'
|
||||
commands = json.loads((build / 'compile_commands.json').read_text())
|
||||
def input_path(command):
|
||||
return (pathlib.Path(command['directory']) / command['file']).resolve()
|
||||
matches = [c for c in commands if input_path(c) == expected]
|
||||
assert len(matches) == 1, ('missing/ambiguous generated WS compilation input', matches)
|
||||
assert not any(input_path(c) == original.resolve() for c in commands), 'vendor WS still compiled'
|
||||
command = matches[0].get('command') or ' '.join(matches[0]['arguments'])
|
||||
assert 'CMakeFiles/__idf_esp_http_server.dir/' in command, 'wrong WS owner'
|
||||
assert expected.read_bytes() == rendered, 'stale generated WS input'
|
||||
print('WS input: verified actual compilation input', expected)
|
||||
return expected.read_text()
|
||||
print('WS input: current hash-verified override render (not firmware build evidence)')
|
||||
return rendered.decode()
|
||||
|
||||
def function(source, name):
|
||||
match = re.search(r'^(?:static )?(?:esp_err_t|int|ssize_t) ' + name + r'\(.*?^\}', source, re.M | re.S)
|
||||
@@ -22,8 +58,8 @@ def function(source, name):
|
||||
return match.group() + '\n'
|
||||
|
||||
adapter = (ROOT / 'src/web_httpd_adapter.c').read_text()
|
||||
assert 'ESP_IDF_VERSION_VAL(5, 5, 0)' in adapter
|
||||
ws_source = (IDF / 'components/esp_http_server/src/httpd_ws.c').read_text()
|
||||
assert 'ESP_IDF_VERSION_VAL(5, 5, 3)' in adapter
|
||||
ws_source = generated_ws()
|
||||
ws = function(ws_source, 'httpd_ws_send_frame_async')
|
||||
main = (IDF / 'components/esp_http_server/src/httpd_main.c').read_text()
|
||||
assert main.index('/* Case0:') < main.index('httpd_process_ctrl_msg(hd);') < main.index('/* Case1:')
|
||||
@@ -53,6 +89,10 @@ with tempfile.TemporaryDirectory(prefix='web-performance-') as directory:
|
||||
(tmp / 'fixture.c').write_text(fixture)
|
||||
(tmp / 'binary.inc').write_text(function(adapter, 'web_httpd_aborted_send') + function(adapter, 'web_httpd_ws_send_binary'))
|
||||
(tmp / 'sdk_ws.inc').write_text(ws.replace('httpd_ws_send_frame_async(', 'sdk_ws_send_frame('))
|
||||
private = (IDF / 'components/esp_http_server/src/esp_httpd_priv.h').read_text()
|
||||
receive_options = re.search(r'typedef enum \{[^}]*\} httpd_recv_opt_t;', private)
|
||||
assert receive_options, 'Reaudit SDK receive option type'
|
||||
(tmp / 'sdk_recv_options.inc').write_text(receive_options.group())
|
||||
automatic = ''.join(function(ws_source, name) for name in
|
||||
('httpd_ws_check_req', 'httpd_ws_send_frame', 'httpd_ws_get_frame_type'))
|
||||
automatic = automatic.replace('httpd_ws_send_frame_async(', 'sdk_ws_send_frame(')
|
||||
@@ -65,10 +105,10 @@ with tempfile.TemporaryDirectory(prefix='web-performance-') as directory:
|
||||
(tmp / 'console.inc').write_text(
|
||||
'static const char *esp_err_to_name(esp_err_t e) { (void)e; return "error"; }\n'
|
||||
+ console[start:end])
|
||||
flags = ['-fsanitize=address,undefined', '-fno-omit-frame-pointer'] if '--sanitize' in sys.argv else []
|
||||
flags = ['-fsanitize=address,undefined', '-fno-omit-frame-pointer'] if args.sanitize else []
|
||||
subprocess.run(['cc', '-std=c11', '-Wall', '-Wextra', '-Werror', '-g', *flags,
|
||||
'-I'+str(tmp), '-I'+str(ROOT / 'src'), '-ffunction-sections', '-fdata-sections',
|
||||
'-Wl,--gc-sections', str(HERE / 'test.c'), str(ROOT / 'src/web_session_store.c'),
|
||||
str(ROOT / 'src/web_auth_parse.c'), '-o', str(tmp / 'test')], check=True, timeout=30)
|
||||
subprocess.run([str(tmp / 'test')], check=True, timeout=15)
|
||||
print('PASS installed IDF WS two-write / HTTPS forwarding / TLS partial-return contract guards')
|
||||
print('PASS generated IDF WS two-write / HTTPS forwarding / TLS partial-return contract guards')
|
||||
|
||||
@@ -61,9 +61,10 @@ static int host_shutdown(int fd, int how)
|
||||
#define HTTPD_WS_TYPE_PONG 10
|
||||
static uint8_t incoming_opcode;
|
||||
static unsigned automatic_reads;
|
||||
static int httpd_recv_with_opt(httpd_req_t *r, char *out, size_t n, bool peek)
|
||||
#include "sdk_recv_options.inc"
|
||||
static int httpd_recv_with_opt(httpd_req_t *r, char *out, size_t n, httpd_recv_opt_t opt)
|
||||
{
|
||||
(void)r; assert(n == 1 && !peek); *out = 0x80 | incoming_opcode;
|
||||
(void)r; assert(n == 1 && opt == HTTPD_RECV_OPT_BLOCKING); *out = 0x80 | incoming_opcode;
|
||||
++automatic_reads; return 1;
|
||||
}
|
||||
static esp_err_t sdk_control_recv(httpd_req_t *r, httpd_ws_frame_t *f, size_t n)
|
||||
|
||||
Reference in New Issue
Block a user