Fix constrained logging matrix builds

This commit is contained in:
mikecarper committed 2026-09-04 08:34:34 -07:00
1 parent 65a53285d9
commit 1e32abc41e
9 files changed
+324 -4

No files matched your search

+107
View File
@@ -0,0 +1,107 @@
#include <stdio.h>
#include <string.h>
#include "ed_25519.h"
typedef struct {
const char *seed;
const char *public_key;
const char *message;
const char *signature;
} rfc8032_vector;
static int hex_nibble(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
static int decode_hex(unsigned char *out, size_t out_len, const char *hex) {
size_t i;
if (strlen(hex) != out_len * 2) return 0;
for (i = 0; i < out_len; ++i) {
const int high = hex_nibble(hex[i * 2]);
const int low = hex_nibble(hex[i * 2 + 1]);
if (high < 0 || low < 0) return 0;
out[i] = (unsigned char)((high << 4) | low);
}
return 1;
}
static int run_vector(const rfc8032_vector *vector, int number) {
unsigned char seed[32];
unsigned char expected_public_key[32];
unsigned char expected_signature[64];
unsigned char public_key[32];
unsigned char private_key[64];
unsigned char signature[64];
unsigned char message[256];
const size_t message_len = strlen(vector->message) / 2;
if (message_len > sizeof(message) ||
!decode_hex(seed, sizeof(seed), vector->seed) ||
!decode_hex(expected_public_key, sizeof(expected_public_key), vector->public_key) ||
!decode_hex(message, message_len, vector->message) ||
!decode_hex(expected_signature, sizeof(expected_signature), vector->signature)) {
fprintf(stderr, "RFC 8032 vector %d is malformed\n", number);
return 0;
}
ed25519_create_keypair(public_key, private_key, seed);
if (memcmp(public_key, expected_public_key, sizeof(public_key)) != 0) {
fprintf(stderr, "RFC 8032 vector %d public key mismatch\n", number);
return 0;
}
ed25519_sign(signature, message, message_len, public_key, private_key);
if (memcmp(signature, expected_signature, sizeof(signature)) != 0) {
fprintf(stderr, "RFC 8032 vector %d signature mismatch\n", number);
return 0;
}
if (!ed25519_verify(signature, message, message_len, public_key)) {
fprintf(stderr, "RFC 8032 vector %d signature did not verify\n", number);
return 0;
}
signature[17] ^= 0x01;
if (ed25519_verify(signature, message, message_len, public_key)) {
fprintf(stderr, "RFC 8032 vector %d accepted a damaged signature\n", number);
return 0;
}
return 1;
}
int main(void) {
static const rfc8032_vector vectors[] = {
{
"9d61b19deffd5a60ba844af492ec2cc4"
"4449c5697b326919703bac031cae7f60",
"d75a980182b10ab7d54bfed3c964073a"
"0ee172f3daa62325af021a68f707511a",
"",
"e5564300c360ac729086e2cc806e828a"
"84877f1eb8e5d974d873e06522490155"
"5fb8821590a33bacc61e39701cf9b46b"
"d25bf5f0595bbe24655141438e7a100b"
},
{
"4ccd089b28ff96da9db6c346ec114e0f"
"5b8a319f35aba624da8cf6ed4fb8a6fb",
"3d4017c3e843895a92b70aa74d1b7ebc"
"9c982ccf2ec4968cc0cd55f12af4660c",
"72",
"92a009a9f0d4cab8720e820b5f642540"
"a2b27b5416503f8fb3762223ebdb69da"
"085ac1e43e15996e458f3613d0f11d8c"
"387b2eaeb4302aeeb00d291612bb0c00"
}
};
size_t i;
for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); ++i) {
if (!run_vector(&vectors[i], (int)i + 1)) return 1;
}
return 0;
}
+40
View File
@@ -500,10 +500,27 @@ for full_env in "${SUPPORTED_PIO_ENVS[@]}"; do
|| fail "$full_env Full Companion omitted USB folder seeding"
[[ "$PLATFORMIO_BUILD_FLAGS" == *"COMPANION_FEATURE_BLE_MOTA_SOURCE=1"* ]] \
|| fail "$full_env Full Companion omitted BLE folder seeding"
if ! pio_env_option_contains "$pio_env" build_src_filter "helpers/ota/*.cpp" \
&& [[ "$PLATFORMIO_BUILD_SRC_FILTER" != *"helpers/ota/*.cpp"* ]]; then
fail "$full_env Full Companion omitted the OTA C++ implementation"
fi
done
unset PLATFORMIO_BUILD_FLAGS PLATFORMIO_BUILD_UNFLAGS \
PLATFORMIO_BUILD_SRC_FILTER
# An environment that includes only the tiny OTA inflater still needs the C++
# protocol implementation when build.sh overlays LoRa OTA.
reduced_nrf_ota_env=RAK_3401_repeater_lora_ota_no_external_sensors
reduced_nrf_pio_env=$(get_pio_build_env "$reduced_nrf_ota_env")
PLATFORMIO_BUILD_SRC_FILTER=""
PLATFORMIO_EXTRA_SCRIPTS=""
apply_nrf52_lora_ota_build_recipe "$reduced_nrf_ota_env" "$reduced_nrf_pio_env"
if ! pio_env_option_contains "$reduced_nrf_pio_env" build_src_filter "helpers/ota/*.cpp" \
&& [[ "$PLATFORMIO_BUILD_SRC_FILTER" != *"helpers/ota/*.cpp"* ]]; then
fail "$reduced_nrf_ota_env omitted the OTA C++ implementation"
fi
unset PLATFORMIO_BUILD_SRC_FILTER PLATFORMIO_EXTRA_SCRIPTS
# The bounded AsyncTCP task stack belongs to every ESP32 Full profile, including
# expanded non-Companion builds, but must not leak into ordinary or nRF52
# recipes.
@@ -764,6 +781,29 @@ if declare -f run_logging_matrix_build_targets | grep -q 'Profile 2'; then
fail "logging matrix still labels a separate Profile 2"
fi
# Option 3 must not publish an oversized standard ESP32 image, but its expected
# portable-slot status is satisfied by the mandatory expanded FULL pass.
saved_supports_esp32_full_build=$(declare -f supports_esp32_full_build)
supports_esp32_full_build() { [ "$1" = esp32_portable_overflow ]; }
build_firmware() { return 42; }
saved_output_dir=$OUTPUT_DIR
OUTPUT_DIR=$version_test_dir
LOGGING_MATRIX_FAILURES=()
LOGGING_MATRIX_DEFERRED_TARGETS=()
DEFER_ESP32_PORTABLE_OVERFLOW_TO_FULL=1
FIRMWARE_FILENAME_INFIX=""
MQTT_BRIDGE_OVERRIDE="off"
if ! run_logged_build_targets esp32_portable_overflow >/dev/null; then
fail "portable ESP32 overflow made the logging pass fail"
fi
[ ${#LOGGING_MATRIX_FAILURES[@]} -eq 0 ] \
|| fail "portable ESP32 overflow remained a logging-matrix failure"
[ "${LOGGING_MATRIX_DEFERRED_TARGETS[*]}" = esp32_portable_overflow ] \
|| fail "portable ESP32 overflow was not deferred to FULL"
OUTPUT_DIR=$saved_output_dir
unset DEFER_ESP32_PORTABLE_OVERFLOW_TO_FULL
eval "$saved_supports_esp32_full_build"
calls=()
build_firmware() {
calls+=("$1:$BUILD_PROFILE_EFFECTIVE:$SKIP_DECLARED_REDUCTIONS:$FIRMWARE_OUTPUT_ENV_NAME")
+60
View File
@@ -0,0 +1,60 @@
import subprocess
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
ED25519 = ROOT / "lib" / "ed25519"
HARNESS = ROOT / "test" / "fixtures" / "ed25519_compact" / "test_ed25519_compact.c"
SOURCES = [
ED25519 / name
for name in (
"fe.c",
"ge.c",
"keypair.c",
"sc.c",
"sha512.c",
"sign.c",
"verify.c",
)
]
class Ed25519CompactTest(unittest.TestCase):
def test_stm32_builds_enable_compact_base_table(self):
platformio = (ROOT / "platformio.ini").read_text()
stm32_base = platformio.split("[stm32_base]", 1)[1].split("\n[", 1)[0]
self.assertIn("-D ED25519_COMPACT_BASE=1", stm32_base)
def test_standard_and_compact_paths_match_rfc8032(self):
with tempfile.TemporaryDirectory() as temp_dir:
for label, extra_flags in (
("standard", []),
("compact", ["-DED25519_COMPACT_BASE=1"]),
):
executable = Path(temp_dir) / label
subprocess.run(
[
"cc",
"-std=c99",
"-O2",
"-Wall",
"-Wextra",
"-Werror",
"-DED25519_NO_SEED=1",
*extra_flags,
f"-I{ED25519}",
str(HARNESS),
*(str(source) for source in SOURCES),
"-o",
str(executable),
],
check=True,
cwd=ROOT,
)
subprocess.run([str(executable)], check=True, cwd=ROOT)
if __name__ == "__main__":
unittest.main()
+8
View File
@@ -108,6 +108,14 @@ int main() {
companion = (ROOT / "examples/companion_radio/MyMesh.cpp").read_text()
formatter = (ROOT / "src/helpers/StorageLayout.cpp").read_text()
stm32_include = formatter.index("#elif defined(STM32_PLATFORM)")
stm32_include_end = formatter.index("#endif", stm32_include)
stm32_headers = formatter[stm32_include:stm32_include_end]
self.assertLess(
stm32_headers.index("#include <Arduino.h>"),
stm32_headers.index("#include <InternalFileSystem.h>"),
)
self.assertIn('#include "StorageLayout.h"', common)
self.assertIn(
"mesh::cli::handleStorageLayoutGet(config, *_board, reply, 160)",