From 2fb6f1de7814aa88c708393108bfadbe259c4d36 Mon Sep 17 00:00:00 2001 From: luckyabsoluter <80892490+luckyabsoluter@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:01:08 +0900 Subject: [PATCH 1/2] test: Add Debian 12/13 experiment suite for build Problem: - We needed a fair and repeatable way to compare build behavior across Debian 12 and Debian 13 Docker environments. - Previous checks mixed relative verdict logic and did not provide a clean per-image pass/fail matrix. - Experimental artifacts needed to be grouped in a dedicated location with local documentation and ignore rules. Actions: - Added an isolated experiment package under experiments/debian12-13. - Added Debian 12 and Debian 13 baseline Dockerfiles plus a Debian 13 remediated Dockerfile that pins a known-good toolchain workflow. - Implemented run-compare.sh to execute the same build workflow per image and report per-case PASS/FAIL with toolchain versions and exit codes. - Updated the experiment README to describe usage, optional flags, and matrix-style output. - Added a local .gitignore for experiment artifacts and made the script clean the experiment out/ directory before running. Result: - The repository now has a self-contained, fair comparison harness that reports Docker-specific build pass/fail outcomes. - Debian 13 remediation success can be verified as its own independent case without altering main project docs. - Experiment files, docs, and ignores are consolidated in one dedicated directory. --- experiments/debian12-13/.gitignore | 2 + experiments/debian12-13/Dockerfile.debian12 | 15 +++ experiments/debian12-13/Dockerfile.debian13 | 15 +++ .../Dockerfile.debian13-remediated | 19 +++ experiments/debian12-13/README.md | 43 +++++++ experiments/debian12-13/run-compare.sh | 109 ++++++++++++++++++ 6 files changed, 203 insertions(+) create mode 100644 experiments/debian12-13/.gitignore create mode 100644 experiments/debian12-13/Dockerfile.debian12 create mode 100644 experiments/debian12-13/Dockerfile.debian13 create mode 100644 experiments/debian12-13/Dockerfile.debian13-remediated create mode 100644 experiments/debian12-13/README.md create mode 100644 experiments/debian12-13/run-compare.sh diff --git a/experiments/debian12-13/.gitignore b/experiments/debian12-13/.gitignore new file mode 100644 index 0000000..d587e5f --- /dev/null +++ b/experiments/debian12-13/.gitignore @@ -0,0 +1,2 @@ +out/ +logs/ diff --git a/experiments/debian12-13/Dockerfile.debian12 b/experiments/debian12-13/Dockerfile.debian12 new file mode 100644 index 0000000..c17a282 --- /dev/null +++ b/experiments/debian12-13/Dockerfile.debian12 @@ -0,0 +1,15 @@ +FROM debian:bookworm-slim + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + make \ + gcc-arm-none-eabi \ + binutils-arm-none-eabi \ + libnewlib-arm-none-eabi \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /workspace + diff --git a/experiments/debian12-13/Dockerfile.debian13 b/experiments/debian12-13/Dockerfile.debian13 new file mode 100644 index 0000000..b32e475 --- /dev/null +++ b/experiments/debian12-13/Dockerfile.debian13 @@ -0,0 +1,15 @@ +FROM debian:13-slim + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + make \ + gcc-arm-none-eabi \ + binutils-arm-none-eabi \ + libnewlib-arm-none-eabi \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /workspace + diff --git a/experiments/debian12-13/Dockerfile.debian13-remediated b/experiments/debian12-13/Dockerfile.debian13-remediated new file mode 100644 index 0000000..aeca009 --- /dev/null +++ b/experiments/debian12-13/Dockerfile.debian13-remediated @@ -0,0 +1,19 @@ +FROM debian:13-slim + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + make \ + ca-certificates \ + && echo "deb http://deb.debian.org/debian bookworm main" > /etc/apt/sources.list.d/bookworm.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + gcc-arm-none-eabi=15:12.2.rel1-1 \ + binutils-arm-none-eabi=2.40-2+18+b1 \ + libnewlib-arm-none-eabi=3.3.0-1.3+deb12u1 \ + libnewlib-dev=3.3.0-1.3+deb12u1 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /workspace + diff --git a/experiments/debian12-13/README.md b/experiments/debian12-13/README.md new file mode 100644 index 0000000..c039c20 --- /dev/null +++ b/experiments/debian12-13/README.md @@ -0,0 +1,43 @@ +# Debian 12 vs 13 Experiment + +This experiment runs a fair, per-image comparison. + +- All images run the same build workflow: `make binaries` +- Output is reported as per-image `PASS/FAIL` +- `debian13-remediated` can be included as an extra case + +## Run + +```bash +./experiments/debian12-13/run-compare.sh +``` + +Optional modes: + +```bash +# Skip remediation path +RUN_REMEDIATION=0 ./experiments/debian12-13/run-compare.sh + +# Return non-zero if any image fails +FAIL_ON_ANY=1 ./experiments/debian12-13/run-compare.sh +``` + +## What it does + +1. Builds images: + - `experiments/debian12-13/Dockerfile.debian12` + - `experiments/debian12-13/Dockerfile.debian13` +2. Optionally builds remediation image: + - `experiments/debian12-13/Dockerfile.debian13-remediated` +3. Captures toolchain versions (`arm-none-eabi-gcc`, `arm-none-eabi-ld`) +4. Runs the same build command for each image: + - `make binaries BUILD=` +5. Uses isolated output dirs under this folder: + - `experiments/debian12-13/out/build-debian12` + - `experiments/debian12-13/out/build-debian13` + - `experiments/debian12-13/out/build-debian13-remediated` +6. Prints a result matrix with: + - case name + - `PASS/FAIL` + - exit code + - gcc/ld version lines diff --git a/experiments/debian12-13/run-compare.sh b/experiments/debian12-13/run-compare.sh new file mode 100644 index 0000000..03adc50 --- /dev/null +++ b/experiments/debian12-13/run-compare.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$ROOT_DIR" + +RUN_REMEDIATION="${RUN_REMEDIATION:-1}" +FAIL_ON_ANY="${FAIL_ON_ANY:-0}" + +declare -a NAMES +declare -a IMAGES +declare -a DOCKERFILES +declare -a OUTDIRS +declare -a GCC_LINES +declare -a LD_LINES +declare -a EXIT_CODES +declare -a RESULTS + +add_case() { + NAMES+=("$1") + IMAGES+=("$2") + DOCKERFILES+=("$3") + OUTDIRS+=("$4") +} + +add_case \ + "debian12" \ + "${IMAGE12:-airbreak-exp:debian12}" \ + "$SCRIPT_DIR/Dockerfile.debian12" \ + "experiments/debian12-13/out/build-debian12" + +add_case \ + "debian13" \ + "${IMAGE13:-airbreak-exp:debian13}" \ + "$SCRIPT_DIR/Dockerfile.debian13" \ + "experiments/debian12-13/out/build-debian13" + +if [[ "$RUN_REMEDIATION" == "1" ]]; then + add_case \ + "debian13-remediated" \ + "${IMAGE13_REMEDIATED:-airbreak-exp:debian13-remediated}" \ + "$SCRIPT_DIR/Dockerfile.debian13-remediated" \ + "experiments/debian12-13/out/build-debian13-remediated" +fi + +run_in_image() { + local image="$1" + shift + docker run --rm \ + --mount "type=bind,source=$ROOT_DIR,target=/workspace" \ + -w /workspace \ + "$image" \ + bash -lc "$*" +} + +echo "[0/4] Clean experiment output directory" +rm -rf "$SCRIPT_DIR/out" +mkdir -p "$SCRIPT_DIR/out" + +echo "[1/4] Build images" +for i in "${!NAMES[@]}"; do + echo " - ${NAMES[$i]} (${IMAGES[$i]})" + docker build -f "${DOCKERFILES[$i]}" -t "${IMAGES[$i]}" . +done + +echo "[2/4] Capture toolchain versions" +for i in "${!NAMES[@]}"; do + gcc_line="$(run_in_image "${IMAGES[$i]}" "arm-none-eabi-gcc --version | head -n 1")" + ld_line="$(run_in_image "${IMAGES[$i]}" "arm-none-eabi-ld --version | head -n 1")" + GCC_LINES+=("$gcc_line") + LD_LINES+=("$ld_line") + echo " - ${NAMES[$i]} gcc: $gcc_line" + echo " - ${NAMES[$i]} ld : $ld_line" +done + +echo "[3/4] Run same build workflow for each image (fair comparison)" +for i in "${!NAMES[@]}"; do + outdir="${OUTDIRS[$i]}" + set +e + run_in_image "${IMAGES[$i]}" "rm -rf $outdir; mkdir -p $outdir; make binaries BUILD=$outdir" + code=$? + set -e + EXIT_CODES+=("$code") + if [[ "$code" -eq 0 ]]; then + RESULTS+=("PASS") + echo " - ${NAMES[$i]}: PASS" + else + RESULTS+=("FAIL") + echo " - ${NAMES[$i]}: FAIL (exit=$code)" + fi +done + +echo "[4/4] Result matrix" +for i in "${!NAMES[@]}"; do + echo " - ${NAMES[$i]} | ${RESULTS[$i]} | exit=${EXIT_CODES[$i]}" + echo " gcc: ${GCC_LINES[$i]}" + echo " ld : ${LD_LINES[$i]}" +done + +if [[ "$FAIL_ON_ANY" == "1" ]]; then + for code in "${EXIT_CODES[@]}"; do + if [[ "$code" -ne 0 ]]; then + exit 1 + fi + done +fi + +exit 0 From 054afdf5274d029188226df295c46ea495494be5 Mon Sep 17 00:00:00 2001 From: luckyabsoluter <80892490+luckyabsoluter@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:14:11 +0900 Subject: [PATCH 2/2] test: Colorize per-image PASS/FAIL output in Debian compare script Problem: - The Debian image comparison output made PASS/FAIL states harder to scan quickly in terminal runs. - Case results were printed as plain text, which slowed visual review during repeated experiments. Actions: - Added terminal-aware ANSI coloring in experiments/debian12-13/run-compare.sh. - Rendered PASS in green and FAIL in red for per-case workflow output. - Applied the same coloring in the final result matrix while keeping plain output for non-TTY environments. Result: - Per-image outcomes are now immediately distinguishable in interactive runs. - Logs remain compatible with non-interactive environments without escape-code noise. --- experiments/debian12-13/run-compare.sh | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/experiments/debian12-13/run-compare.sh b/experiments/debian12-13/run-compare.sh index 03adc50..ece5f7a 100644 --- a/experiments/debian12-13/run-compare.sh +++ b/experiments/debian12-13/run-compare.sh @@ -8,6 +8,16 @@ cd "$ROOT_DIR" RUN_REMEDIATION="${RUN_REMEDIATION:-1}" FAIL_ON_ANY="${FAIL_ON_ANY:-0}" +if [[ -t 1 ]]; then + COLOR_PASS=$'\033[32m' + COLOR_FAIL=$'\033[31m' + COLOR_RESET=$'\033[0m' +else + COLOR_PASS="" + COLOR_FAIL="" + COLOR_RESET="" +fi + declare -a NAMES declare -a IMAGES declare -a DOCKERFILES @@ -84,18 +94,23 @@ for i in "${!NAMES[@]}"; do EXIT_CODES+=("$code") if [[ "$code" -eq 0 ]]; then RESULTS+=("PASS") - echo " - ${NAMES[$i]}: PASS" + echo " - ${NAMES[$i]}: ${COLOR_PASS}PASS${COLOR_RESET}" else RESULTS+=("FAIL") - echo " - ${NAMES[$i]}: FAIL (exit=$code)" + echo " - ${NAMES[$i]}: ${COLOR_FAIL}FAIL${COLOR_RESET} (exit=$code)" fi done echo "[4/4] Result matrix" for i in "${!NAMES[@]}"; do - echo " - ${NAMES[$i]} | ${RESULTS[$i]} | exit=${EXIT_CODES[$i]}" - echo " gcc: ${GCC_LINES[$i]}" - echo " ld : ${LD_LINES[$i]}" + if [[ "${RESULTS[$i]}" == "PASS" ]]; then + status_colored="${COLOR_PASS}${RESULTS[$i]}${COLOR_RESET}" + else + status_colored="${COLOR_FAIL}${RESULTS[$i]}${COLOR_RESET}" + fi + echo "- ${NAMES[$i]} | ${status_colored} | exit=${EXIT_CODES[$i]}" + echo " gcc: ${GCC_LINES[$i]}" + echo " ld : ${LD_LINES[$i]}" done if [[ "$FAIL_ON_ANY" == "1" ]]; then