Skip to content

fix: repair master after the 09-07 batch merge - #115

Open
Kartikey1306 wants to merge 6 commits into
embeddedos-org:masterfrom
Kartikey1306:fix/repair-master-after-batch-merge
Open

Kartikey1306 wants to merge 6 commits into
embeddedos-org:masterfrom
Kartikey1306:fix/repair-master-after-batch-merge

Conversation

@Kartikey1306

@Kartikey1306 Kartikey1306 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

For the merger (2026-09-17): master 682d005 fails CI — eBoot (34898627047): core/sha512.c uses a count member eos_sha512_ctx_t no longer has (6 sites) and core/ed25519_verify.c:303 redefines scalarbase, so every PR branched from it fails the six build-side checks — currently #109 (@Mohammed18-19, 34471772092). This PR's head passes CI — eBoot (34937012090), is 0 behind master, and nothing needs to land before it; it is the base of #116#122#123#125 and of #127/#129/#131/#133/#138, all green on top of it. Merging it takes master green and lets #109 go green on a rebase (merge result built and tested: 31/31).

Problem

eBoot master has not configured, compiled, linked or passed its tests since the 09-07 batch merge (twenty PRs in ninety minutes, each replayed onto a master its author never saw). Every CI — eBoot, eBoot Build & Test, CodeQL and nightly run on master is red, and because eos/.github/workflows/eos-simulation.yml and eos's nightly Upstream drift build eBoot at master, eos is red on those jobs too, regardless of what an eos PR contains.

Verified against run 34177770756 (CI — eBoot on b429354) and 34177770734 (eBoot Build & Test), and reproduced locally on master before every fix below.

What broke, and which merge broke it

Stage Symptom Cause Fix
configure add_executable cannot create target "eboot_test_fdt_loader" #84 registered it; #85, stacked on #84, re-added it at a different anchor when replayed onto a master that already had #84 (my duplicate-insert) first block removed — the same hunk as #111, blob 11f2f3f
compile 'eos_sha512_ctx_t' has no member named 'count' ×5 #55 restored a core/sha512.c from 02b7dac that predates the bitlen[2]/buffer_len context (#69/#93) pre-#55 file restored, blob-identical (d9aa57c)
compile redefinition of 'scalarbase' #94 and #105 each repaired the Ed25519 verifier and each added an identical static scalarbase(); both merged one copy removed
compile redefinition of 'k_low_order' / 'messages' in test_ed25519.c same pair, same reason #105's copy removed; #94's stays because it also carries k_non_canonical[]
link _eos_boot_log_append, _eos_secure_boot, _eos_secure_boot_lock_debug undefined #55's source-list "correction" dropped core/boot_log.c, core/secure_boot.c, core/fdt_loader.c (added by #72/#84 after #55 was written) CMakeLists.txt blob-identical to pre-#55 (f8fe6eb)
compile eos_boot_log_get_head undeclared in test_boot_log.c #55 replaced its declaration with a second copy of eos_boot_log_read(); #91 had already fixed the prototype #55 meant to fix header restored (964ebb8)

Three suites then compiled and failed, because two merged PRs disagree on behaviour:

Guards from #95 that later merges walked back, invisible until now because configure failed first (observed locally: pytest tests/ on master-with-the-C-fixes was 5 failed / 73 passed):

One more, found on this PR's first run (run 34591438682): test_imgpack.py::test_out_of_range_version_is_rejected[-1.0.0] passes on Python 3.13+ and fails on ubuntu-22.04's 3.10, because the older argparse negative-number matcher reads -1.0.0 as an unknown option and rejects it before imgpack.py's own range check runs. The test now passes --version=X, which every interpreter reads as a value; verified the tool's message is what the test then sees.

CI plumbing on the same red runs:

  • eosim-sanity.yml: the install-validate job is written in bash ($(...), || { ... }, a heredoc, /tmp) but ran under PowerShell on the Windows legs, where SITE_PACKAGES=$(...) is an unknown command — and where the || { exit 1 } guard in "Verify installation" parses as an unexecuted script block and could never fail. defaults.run.shell: bash on the job. (Run 34561593562.)
  • scorecard.yml: ossf/[email protected] pulls gcr.io/openssf/scorecard-action, and gcr.io now refuses with "This API method requires billing to be enabled". v2.4.3 pulls from ghcr.io; eos already pins it and its Scorecard job is green. (Run 34177770753.)

Test plan

Verified, macOS / clang:

cmake -DEBLDR_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release   → 0 errors, 0 warnings
ctest --timeout 120                                        → 100% tests passed, 31/31
cmake -DEBLDR_BUILD_TESTS=ON -DEBLDR_SANITIZE=ON (ASan+UBSan) → 31/31
pytest tests/                                              → 78 passed

Not verified here: the STM32F4 / Cortex-M4 cross build (no arm-none-eabi toolchain on this machine) and the fuzz harness build (no libFuzzer runtime). Both failed on master for the compile errors above, which are gone; CI on this PR is the check.

Relationship to open PRs

  • Remove duplicate FDT loader test target #111 (remove duplicate FDT loader target) — merged 2026-09-14 21:24Z as 682d005. The tests/CMakeLists.txt hunk here was byte-identical to it, so that half of this PR is now on master and drops out of this diff on merge. Verified rather than assumed: this branch merged onto 682d005 leaves exactly one test_fdt_loader registration, configures with 0 errors, builds, and passes ctest 31/31. Rebased onto 682d005 at 12:05 IST 2026-09-15 (head a276016e152d8e, six commits replayed with --onto, the CMake hunk dropped out as expected — one test_fdt_loader registration in the tree). Verified on the new head before the push: configure 0 errors, build OK, ctest 31/31, pytest 55 passed / 3 skipped. This corrects the previous "Not rebased" statement here: the hold was for the active merge window overnight; nothing has merged since 02:54 IST and the PR is the base of the stack, so it goes first and the dependents follow in the same window.
  • ci: fail test jobs when no tests are registered #112 (fail test jobs when no tests registered) — merged as 50c66af. Touches only workflow files this PR does not; no overlap.
  • ABI mismatch between tools/sign_image.py and core/image_verify.c #117 (sign_image.py / image_verify.c ABI) — merged as f22896d. No overlap with this PR.
  • Master at 682d005 still does not compile without this PR: core/sha512.c count (×6) and the scalarbase redefinition are unchanged by the three merges above.

Reported, not fixed here

core/keystore.c's compiled-in default_dev_key is described (in a #warning and in comments, including one in my own test_secure_boot_policy.c) as the RFC 8032 TEST 1 public key. It is not: it diverges from byte 21 on and does not decode to a point on the curve (verified by decoding y and checking x² against the curve equation). Nothing can ever verify against it, and since #104 that means firmware update refuses every image on a board without OTP. That is a defect in its own right, unrelated to the batch merge, and is why the tests here provision the key through simulated OTP rather than rely on the fallback. Separate PR to follow.

Review follow-ups (2026-09-14)

Rebased onto the governance commit and the review findings applied, each as its own commit:

  • tests/unit/test_fw_update_test_sigs.py runs tools/gen_fw_update_test_sigs.py and asserts its output equals the committed tests/vectors/fw_update_test_sigs.h byte for byte (finding 3; approver's ask). Verified it fails on a one-byte edit of the header, with a unified diff naming the regenerate command. Comments above build_image() / build_container() name the coupling and the command.
  • docs/adr/ADR-020-install-path-verifies-signature-before-anti-rollback.md (+ docs/adr/README.md) records the ordering this PR settles: signature verification over the signed prefix precedes anti-rollback evaluation in eos_fw_update_finalize() (finding 1).
  • CHANGELOG entry for the repair.
  • test_imgpack.py: --version=X form (the 3.10 argparse difference).
  • The copy >> 61 term (finding 2) is fix(sha512): drop a carry term that is always zero #123, kept separate so core/sha512.c here stays blob d9aa57c.

One correction to the text above: "eleven registered suites had no list(APPEND …) and so no Valgrind run" overstated it — eleven were missing from EBLDR_UNIT_TESTS, but four of them were in the hand-written foreach and did run; seven (test_eos_sign_boot_path, test_fdt_loader, test_fw_decrypt, test_fw_update_sig, test_jump_app_bounds, test_qemu_arm64_timer, test_secure_boot_policy) had no Valgrind run at all. The CHANGELOG says it that way.

Verified on the current head: Release build clean, ctest 31/31, pytest tests/ 79 passed (78 + the new test), also with EOS_REQUIRE_SIGNING_TESTS=1.

Closing issue

Fixes #118

@codecov-commenter

codecov-commenter commented Sep 11, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 93.33333% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
tests/unit/test_fw_update_test_sigs.py 93.33% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@srpatcha srpatcha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — eBoot#115 "fix: repair master after the 09-07 batch merge"

head: 4d8696c author: Kartikey1306 ci: pass (25 checks green, 0 red; only Create GitHub Release skipped)

Verdict: This repairs a master that does not configure, does not compile, does not
link and has no passing test suite. I reproduced the broken baseline and the repaired one
independently: clean origin/master fails to build; this head configures, builds with no
errors and passes 31/31 under ctest --no-tests=error. Every blob-identity claim in the
PR body checks out against git rev-parse. This should land before the other four open
eBoot PRs
— three of them are blocked behind exactly the breakage it fixes.

Findings

# Severity File:line Finding Recommended fix
1 Medium tests/unit/test_fw_update.c:156-181, tests/unit/test_fw_transport.c A behavioural arbitration is being settled inside a repair PR, with no ADR and no design text backing it. #104 (verify signature at install, before anti-rollback) and #103 (anti-rollback counter check) were both merged and contradict each other; this PR picks #104's ordering and rewrites #103's fixtures to sign their images. The call is right and the reasoning in the body is sound — a counter is only trustworthy after the prefix binding it is authenticated. But the master design does not actually say so for the update path: §8.1 orders "Verify Manifest → Verify Image → Check Version Policy" for boot, while §15's update flow is "Download → Verify → Install" and never places the anti-rollback counter check at all. So the repo now has an ordering rule that exists only in a PR body. .ai/architect.md asks that structural decisions be recorded, and this is one. Nothing to change in the code. Record the decision: an ADR under the §38 series (the natural slot is ADR-011, eOTA firmware/update contract) stating that anti-rollback evaluation happens strictly after signature verification in the install path. I have appended an architecture proposal for §15.1 to .ai/autoreview/proposals/2026-09.md so the design stops being silent on it.
2 Low core/sha512.c (eos_sha512_update) ctx->bitlen[0] += (uint64_t)copy >> 61; is always zero. copy is clamped to 128 - ctx->buffer_len, so copy <= 128 and copy >> 61 == 0 on every iteration. The real 128-bit carry is already handled correctly by the old_low comparison two lines above. The line reads as overflow handling and does nothing, which is the kind of thing a future reader preserves because they assume it matters. Not a defect — the digest is correct, confirmed by KAT below. Delete the line, or replace it with a comment noting that copy is block-bounded so the low word alone cannot overflow within one iteration. Since this file is a byte-exact restoration of a previously-reviewed blob, it is fine to leave for a follow-up rather than perturb the restoration.
3 Low tests/vectors/fw_update_test_sigs.h:1-8, tools/gen_fw_update_test_sigs.py The committed vectors carry a "do not edit / regenerate with …" header, but nothing verifies that the committed bytes are what the committed script produces. If someone edits the header by hand, or changes a field inside the signed prefix in build_image() without regenerating, the failure surfaces as an opaque EOS_ERR_SIGNATURE in an unrelated-looking test rather than as "your vectors are stale". The suites do fail closed, which is the important half. Add a Python test that runs tools/gen_fw_update_test_sigs.py and asserts its stdout equals tests/vectors/fw_update_test_sigs.h. requirements.txt:4 already pins cryptography>=41.0, and tests/unit/test_eos_sign_payload_offset.py:34 already has the "ImportError must fail the job" idiom to copy.

Three findings, all minor, on a 21-file 522-line repair. That is the honest count — I went
looking for more and did not find it.

Verification performed for this review

Detached scratch worktrees under .ai/autoreview/state/verify/. The user's eBoot
checkout was not touched; nothing was committed to a tracked branch or pushed.

Check Result
cmake -B build/host -DEBLDR_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug on this head PASS
cmake --build build/host --parallel 4 on this head PASS — no errors
ctest --test-dir build/host --output-on-failure --no-tests=error PASS — 100%, 31/31, 11.04s
Same three steps on clean origin/master FAIL — configure aborts on the duplicate eboot_test_fdt_loader; with that removed, compile fails core/sha512.c ×5 + core/ed25519_verify.c:303. Confirms the stated baseline.
test_ed25519 specifically (covers the restored SHA-512) PASS, 10.40s — RFC 8032 vectors accepted, test_sha512_known_answers, test_sha512_streaming_matches_one_shot
Blob claim core/sha512.c = d9aa57c CONFIRMEDgit rev-parse FETCH_HEAD:core/sha512.cd9aa57ccc57dd28aad380693b0c579e4a2b100be
Blob claim CMakeLists.txt = f8fe6eb CONFIRMED
Blob claim include/eos_boot_log.h = 964ebb8 CONFIRMED
Provenance of d9aa57c (was it really pre-#55?) CONFIRMED — that blob was core/sha512.c at abd4dab (#93, 2026-09-03); effa9a2 (#55, 2026-09-07) replaced it
#111 hunk equivalence claim CONFIRMED — the deletion hunk is identical; the files differ because #115 also fills in EBLDR_UNIT_TESTS. The body says "hunk", which is the accurate word.
pytest tests/ ("78 passed") NOT RUNNo module named pytest on this host. Unverified.

On the SHA-512 "rewrite". core/sha512.c shows as 211+/111− and the first instinct is
that someone hand-wrote a hash primitive into the TCB, which .ai/security.md §Cryptography
would treat harshly. It is not: the file is byte-identical to the blob that was in the tree
from #93 until #55 overwrote it with a version predating the bitlen[2]/buffer_len
context. I read it anyway. Init constants are the FIPS 180-4 SHA-512 IVs; the 128-bit length
is accumulated correctly with the carry into bitlen[0]; final() handles the i > 112
case (no room for the 16-byte length) by transforming a padded block first, and the i == 112
boundary lands exactly right; buffer_len can never exceed 127 on entry to final(), so the
0x80 write cannot overrun buffer[128]; the context is zeroized on completion. Together
with the passing KAT, streaming-vs-one-shot equivalence test, and RFC 8032 vectors — which
would fail on any deviation, since Ed25519 derives its challenge scalar from this hash — the
restoration is sound.

Was anything weakened? No, and I checked specifically because the diff deletes 40 lines
from tests/unit/test_ed25519.c and one line each from test_tlv_auth.c and others.
master declared k_low_order[8][32] and messages[] twice (test_ed25519.c:106 and
:266), which is itself a compile error; the PR removes the first, unused copy and keeps the
one that sits with k_non_canonical[]. All fourteen TEST() cases survive and all fourteen
are still invoked from main() — including test_ed25519_low_order_keys_rejected,
test_ed25519_non_canonical_encodings_rejected and
test_ed25519_low_order_R_with_a_valid_key_is_not_a_forgery, the three that .ai/security.md's
"reject invalid and low-order public keys explicitly" rule depends on. The tests_run = <literal>
deletions are the opposite of a weakening: they replace a hand-maintained count with
tests_run++ inside the TEST() macro, so a suite can no longer silently report 6/6
while running four.

The change also tightens three things worth naming: ci.yml:253 adds fuzz-build to
CI Gate's needs (the gate previously did not wait for it); eosim-sanity.yml pins
shell: bash on a job whose Windows legs ran bash syntax under PowerShell, where the
|| { exit 1 } guard parsed as an unexecuted script block and could never fail; and
tests/CMakeLists.txt:226 restores foreach(TEST_NAME ${EBLDR_UNIT_TESTS}) with fourteen
missing list(APPEND ...) entries filled in, which puts eleven previously-uncovered suites
back under Valgrind. All three are fail-closed repairs of checks that could not fail.

On the test signing key. tools/gen_fw_update_test_sigs.py embeds the RFC 8032 §7.1
TEST 1 secret scalar. That is a published constant in a public IETF document, not a secret,
and the script says so. Only the public half and the resulting signatures reach
tests/vectors/fw_update_test_sigs.h. Per .ai/security.md's "test keys must be
structurally incapable of signing a release artifact": the script is invoked by nothing in
.github/workflows/release.yml, which builds and signs through a separate path, and its
output is a C header consumed only by tests/. No exposure.

Architecture conformance

Conforms. §21: eBoot is Tier 1 Foundation; every file touched is inside the owning repo.
§5.1 dependency direction is preserved and in one place restored — the CMakeLists.txt
change adds core/boot_log.c, core/secure_boot.c and core/fdt_loader.c back to
eboot_core, which is the correct tier for them under .ai/architect.md's target shape
(core/ = shared boot logic). No edge points up a tier; nothing outside eBoot is referenced.
§5.1's "eBoot keeps the trusted computing base minimal and auditable" is directly served:
before this PR the secure-boot implementation was not compiled into the core library at
all
, so eos_secure_boot, eos_secure_boot_lock_debug and eos_boot_log_append were
undefined symbols — a TCB that does not link is not auditable. §8.1's boot ordering is
unchanged. The include/eos_boot_log.h edit looks at first like a removed public function,
but master declared eos_boot_log_read() twice (:61 and :72) and never declared
eos_boot_log_get_head(), which core/boot_log.c:57 defines; the PR replaces the redundant
declaration with the missing one. No public API is lost, so brief item 8 is not engaged.

The pattern behind this PR

Worth recording beyond this review: git log -- core/sha512.c shows five separate
"restore the build / repair merge artifacts" commits between 2026-08-27 and 2026-09-11
(9fbfc91, 45519d7, ffda321, effa9a2, a8743dd). The proximate cause named here —
twenty PRs merged in ninety minutes, each replayed onto a master its author never saw —
is a merge-process defect, not a code defect, and no amount of repair PRs will stop it
recurring. A required status check on master plus a merge queue that rebases and re-runs
before landing would. That is outside this PR's scope and is carried into the run summary.

Proposed changes

Merge order (each of the next three is blocked until this lands):
  1. #115  (this PR)
  2. #111  -> its tests/CMakeLists.txt hunk becomes empty; close it or let it rebase to nothing
  3. #109  -> rebase; resolve test_jump_app_bounds.c:main() by DROPPING `tests_run = 3;`
  4. #112, #116, #117 -> rebase and get their first real CI

Follow-ups, none blocking:
  - delete the dead `copy >> 61` term in core/sha512.c
  - add a test regenerating tests/vectors/fw_update_test_sigs.h and diffing it
  - ADR-011 addendum: anti-rollback is evaluated after signature verification

Not checked

  • pytest tests/ — NOT RUN. pytest is not installed on this host, so the body's
    "78 passed" is unverified here, as is test_imgpack.py's --version=X argparse fix and
    the four new NO_TEST_MACRO classifications in test_suite_bookkeeping.py. The reasoning
    for the argparse change is correct on its face (3.10's negative-number matcher treats
    -1.0.0 as an unknown option), but I did not run it on 3.10 to confirm.
  • Cross-compile (STM32F4, Cortex-M4) and the fuzz harness build — not run locally. CI
    reports both green on this head and I am taking that at face value; I did not read the logs.
  • ASan/UBSan — not run. The body claims 31/31 under -DEBLDR_SANITIZE=ON; I built Debug
    without sanitizers. Unverified.
  • The #104 vs #103 negative control. The body says flipping one signature byte makes
    test_write_streams_tlv_then_finalize_rejects_below_floor fail with EOS_ERR_SIGNATURE.
    I did not reproduce that mutation, so the claim that these tests would catch a signature
    regression is inferred from reading build_image(), not observed.
  • The gcr.io billing explanation for the scorecard-action bump. The version change is
    benign either way, but I did not verify the stated cause.
  • I did not audit the other ~18 PRs from the 09-07 batch for damage this PR did not find.
    The claim "this is everything that broke" is the author's; my evidence only supports
    "everything that breaks configure, compile, link and ctest on the host is now fixed."

Automated architecture review of 4d8696cbecbd — scheduled, model claude-opus-5, checked against the EmbeddedOS Master Design v2.0. Advisory only: this reviewer never approves, requests changes, or merges. Reply here to discuss or push back — a wrong finding is a bug worth reporting.

srpatcha
srpatcha previously approved these changes Sep 14, 2026

@srpatcha srpatcha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this — it is a careful repair and the description made it easy to check. What I verified locally on your branch (gcc, Ninja, Debug): configure OK, build clean apart from the intentional #warning in keystore.c, ctest 31/31, the 31 valgrind_* targets 31/31, pytest 78/78. I also confirmed the three "blob-identical" claims by hash, reproduced the master configure failure and the sha512.c/ed25519_verify.c:303 compile failures on #111's branch, and confirmed tools/gen_fw_update_test_sigs.py regenerates tests/vectors/fw_update_test_sigs.h byte-for-byte.

One non-blocking note: tests/unit/test_fw_update.c:174-181 — since the C fixture and the Python generator each build the signed prefix independently, a future edit to either silently breaks the other with EOS_ERR_SIGNATURE. A short comment above build_image() naming the regenerate command would help.

For the maintainers: #116 is stacked on this branch, and #111 is a strict subset of the tests/CMakeLists.txt hunk here. Approving — this should land first.

Kartikey1306 added a commit to Kartikey1306/eBoot that referenced this pull request Sep 14, 2026
The changelog said eleven suites had no Valgrind run. Eleven were missing
from EBLDR_UNIT_TESTS, but four of those were named in the hand-written
foreach and did run; seven had no run at all. Say which.

ADR-020: its design-document citation now says where it comes from (the
architecture review of embeddedos-org#115), and the sentence about the two PRs' bases is
replaced with what the history shows -- embeddedos-org#103's commits predate embeddedos-org#104's merge,
and embeddedos-org#104 was written without embeddedos-org#103's check in place.
@Kartikey1306
Kartikey1306 force-pushed the fix/repair-master-after-batch-merge branch from 4d8696c to 976ab0c Compare September 14, 2026 19:42
@Kartikey1306

Kartikey1306 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the verification and the approval. Follow-ups are on the branch now, each as its own commit:

  • Finding 3 / your note on build_image(): tests/unit/test_fw_update_test_sigs.py regenerates the header with tools/gen_fw_update_test_sigs.py and compares bytes; it fails on a one-byte edit with a unified diff that names the regenerate command. Comments above build_image() and build_container() name the coupling.
  • Finding 1: docs/adr/ADR-020-install-path-verifies-signature-before-anti-rollback.md (+ docs/adr/README.md, the repo had no docs/adr/) records the ordering: signature over the signed prefix first, then anti-rollback, counter never consulted on a failed signature. Numbered 020 to sit after eos's 012–019; it extends ADR-011.
  • Finding 2: fix(sha512): drop a carry term that is always zero #123, kept out of here so core/sha512.c stays blob d9aa57c.
  • CHANGELOG entry added. One correction to my own description while doing it: eleven suites were missing from EBLDR_UNIT_TESTS, but four of those were in the hand-written foreach and did get Valgrind runs — seven had none. The changelog says it that way.

Current head: Release build clean, ctest 31/31, pytest 80 passed (also with EOS_REQUIRE_SIGNING_TESTS=1). (Corrected from 79: that figure was measured before a276016 added the second pin test. Re-run at a276016 with EOS_REQUIRE_SIGNING_TESTS=1: 80 passed.)

@srpatcha srpatcha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — eBoot#115 "fix: repair master after the 09-07 batch merge"

head: a276016 author: Kartikey1306 ci: pass (26 green, 0 red; only Create GitHub Release skipped)

Verdict: Follow-up review. All three findings from the previous report are answered —
two fixed on this branch, one moved to #123. The new commits are clean and I verified the
one that matters (the fixture pin) by breaking it on purpose. Two residuals, both Low, both
stated below rather than dropped. Nothing here blocks the merge.

Status of the previous findings (eBoot-115-4d8696cb.md)

# Prev. severity Status Evidence
1 Medium — install-path ordering settled with no ADR Resolved 049e2fe adds docs/adr/ADR-020-install-path-verifies-signature-before-anti-rollback.md and docs/adr/README.md. The recorded rule matches the code: core/fw_update.c:259 calls eos_image_verify_signature(), :270/:277 read and check the counter after it. The numbering claim checks out — eos/docs/adr/ holds exactly ADR-012…ADR-019, so 020 reuses nothing.
2 Low — dead copy >> 61 carry term in core/sha512.c Resolved elsewhere, correctly Deliberately excluded so core/sha512.c stays blob d9aa57c; carried as #123, which is open and in this review batch. Keeping a byte-exact restoration byte-exact was the right call.
3 Low — nothing checks the committed vectors against their generator Addressed, with a residual 8028bcc + a276016 add tests/unit/test_fw_update_test_sigs.py. See finding 1 below for the part that is still open.

Findings

# Severity File:line Finding Recommended fix
1 Low tools/gen_fw_update_test_sigs.py:25-27, tests/unit/test_fw_update.c:142, tests/unit/test_fw_transport.c:347 The pin test closes the hand-edited header hole, not the drifted prefix hole. test_committed_header_is_the_generator_output proves tests/vectors/fw_update_test_sigs.h == generator stdout, and I confirmed it fails on a one-byte edit. But the generator states outright that "the field values are copied from the tests" — the signed prefix is still built twice, in Python and in C. Change a field in build_image(), regenerate, and both halves agree with each other while disagreeing with the C test: the pin stays green and the failure is still the opaque EOS_ERR_SIGNATURE finding 3 was about. The new comments at both call sites are a real mitigation and may well be the proportionate answer for a test fixture; this is recorded so the remaining gap is on paper, not so it must be closed now. If it is worth closing later: have the C suite emit its prefix bytes under a test-only flag and assert the generator's signed_prefix() equals them, so the two copies are compared rather than described. Not worth a refactor on its own.
2 Low docs/adr/ADR-020-...md:4, CHANGELOG.md The ADR is status: Proposed. docs/adr/README.md defines Proposed as "not yet ratified … " and reserves "binding on new code" for Accepted, while the CHANGELOG entry says the ordering is "settled". The code is already merged and behaving this way, so the record is describing shipped behaviour with a status that says it is not yet binding. Nothing for the author to change unilaterally — ratification belongs to the deciders named in the header (Architecture Council, eBoot maintainers). Flag it for them so the ADR does not sit at Proposed indefinitely while the code it describes is in master.

Two findings, both Low, on 173 lines of genuinely new work. I went looking for a defect in
the new commits and did not find one.

Verification performed for this review

Detached worktree at .ai/autoreview/state/scratch/eBoot-115 off refs/pull/115/head. The
user's eBoot checkout (on fix/ed25519-low-order-keys) was not touched and is still clean;
nothing was committed or pushed.

Check Result
cmake -B build/host -DEBLDR_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release PASS
cmake --build build/host --parallel 4 PASS — no errors
ctest --test-dir build/host --output-on-failure --no-tests=error PASS — 31/31, 2.52s
pytest tests/ -q with EOS_REQUIRE_SIGNING_TESTS=1 PASS — 80 passed, 1.93s. (The PR comment says 79; that was measured before a276016 added the second pin test. The number is now 80.)
Negative control on the new pin test — flipped one hex byte in tests/vectors/fw_update_test_sigs.h FAILS as designedtest_committed_header_is_the_generator_output fails with the regenerate command and a unified diff. The header was restored; git diff --stat clean afterwards. This is the check the previous review listed as NOT RUN.
Is the pin test actually reachable in CI? YES.github/workflows/ci.yml:48 exports EOS_REQUIRE_SIGNING_TESTS=1 before :78 runs python3 -m pytest tests/, so a missing cryptography is a hard error there and a silent skip is not possible.
ADR-020 ordering claim vs. the code CONFIRMED — signature at core/fw_update.c:259, counter read at :270, eos_rollback_verify() at :277.
ADR numbering claim ("eos holds 012–019") CONFIRMEDeos/docs/adr/ contains ADR-012 … ADR-019 and nothing else.
CHANGELOG correction ("seven suites had no Valgrind run at all") CONFIRMED for the seventest_eos_sign_boot_path, test_fdt_loader, test_fw_decrypt, test_fw_update_sig, test_jump_app_bounds, test_qemu_arm64_timer, test_secure_boot_policy are all absent from the 20-name hand-written foreach at tests/CMakeLists.txt:226 in 221325c. Correcting one's own PR body downward is the right instinct.

On the rebase. 4d8696cb is not an ancestor of this head — the branch was rebased onto
master after #114 landed, so a raw 4d8696cb..a276016b diff also shows #114's governance
files (AGENTS.md, docs/wiki/*, linked-issue.yml, the PR template). Those are not this
PR's changes. The actual new work is CHANGELOG.md, docs/adr/ (2 files), the two build_*
comments, and tests/unit/test_fw_update_test_sigs.py — which is exactly what the author's
comment claims. No quiet additions rode in on the rebase.

Was anything weakened in the new commits? No. The diff is additive apart from the rebase:
no test disabled, no assertion removed, no lint loosened, no permission widened. The new
pytest module fails closed under EOS_REQUIRE_SIGNING_TESTS and only degrades to
importorskip on a developer machine, which is the same idiom
tests/unit/test_eos_sign_payload_offset.py:33 already established.

Architecture conformance

Conforms, unchanged from the previous review. §21: eBoot is Tier 1 Foundation and every
touched file is inside the owning repo. §5.1 dependency direction is untouched — the new
files are a markdown ADR, a changelog entry, two C comments and a test-only Python module;
none of them creates an edge of any kind, let alone one pointing up a tier. ADR-020 makes the
install-path ordering conform explicitly to the §8.1 principle (authenticate, then apply
version policy) that §15 leaves unstated for the update path — which is what the proposal
appended for §15.1 in proposals/2026-09.md asks the master design to say. §38's ADR series
is the right home for it.

Proposed changes

None blocking. Merge order from the previous review still stands:
  1. #115 (this PR)  — then #111, #109, #112, #116, #117 rebase onto it
Follow-ups, none blocking:
  - ratify ADR-020 (Proposed -> Accepted) or say why not
  - if ever worth it, compare the generator's signed prefix to the C suite's
    rather than documenting that they must match by hand

Not checked

  • Cross-compile (STM32F4, Cortex-M4), fuzz-harness build, CodeQL, cppcheck/clang-tidy —
    NOT RUN locally.
    CI reports all green on this head; I am taking that at face value and
    did not read the job logs.
  • ASan/UBSan — NOT RUN. I built Release without sanitizers. The body's -DEBLDR_SANITIZE=ON
    claim is unverified here.
  • Valgrind — NOT RUN. The restored EBLDR_UNIT_TESTS list is what puts the eleven suites
    back under Valgrind; I verified the list, by reading it and by confirming the seven named
    suites were absent from the old hand-written one. I did not execute the Valgrind tests, so
    "these eleven now get a Valgrind run" is Observed from CMake, not Verified by running it.
  • The rest of the 09-07 batch. Unchanged from last time: my evidence supports "everything
    that breaks configure, compile, link, ctest and pytest on the host is fixed", not the
    stronger "this is everything that broke".
  • ADR-020's account of why #103 and #104 disagreed (authorship dates, who saw what) is
    read from the ADR; I did not re-derive the commit chronology.

Automated architecture review of a276016bd3c3 — scheduled, model claude-opus-5, checked against the EmbeddedOS Master Design v2.0. Advisory only: this reviewer never approves, requests changes, or merges. Reply here to discuss or push back — a wrong finding is a bug worth reporting.

@Kartikey1306

Copy link
Copy Markdown
Contributor Author

Both findings accepted as recorded, and nothing pushed for them — deliberately, and here is why for each.

Finding 1 (the drifted-prefix hole). Agreed on the shape of the gap: the pin test proves fw_update_test_sigs.h equals the generator's output, and the generator builds the signed prefix a second time from field values copied out of the C tests. Change a field in build_image(), regenerate, and both halves agree with each other while the C suite still fails with an opaque EOS_ERR_SIGNATURE. Your proposed close — have the C suite emit its prefix bytes under a test-only flag and assert the generator's signed_prefix() equals them — is the right one, because it compares the two copies instead of describing them. I agree it is not worth a refactor on its own; it goes into the follow-up queue for this stack rather than into this PR.

Finding 2 (ADR-020 Proposed vs CHANGELOG "settled"). The mismatch is on my side of the line, not the deciders': the CHANGELOG word is mine. I have not pushed the one-word correction, because #116 and #122 are stacked on this branch and a push here re-stacks both and stales the review ranges stated in their bodies — the artefact-mismatch class this review set is already policing. The word gets fixed in whichever push next touches this branch, or in the squash. Ratification of ADR-020 itself is for the named deciders; flagged to them by this comment.

Corrected a stale number of mine. The earlier comment said pytest 79 passed; that was measured before a276016 added the second pin test. Re-run at a276016 with EOS_REQUIRE_SIGNING_TESTS=1: 80 passed. The comment is edited to say so, with the correction visible rather than silent.

Not re-run here, stated rather than omitted: Valgrind, ASan/UBSan, the cross-compile legs — same as your list; CI is green on this head and I have not read those logs either.

Twenty PRs were merged into master in ninety minutes on 09-07, each on the
base it was written against. Master has not configured, compiled, linked or
passed its tests since. Every nightly and every eos simulation run (which
builds eBoot master) has been red for the same reason.

Configure:
- tests/CMakeLists.txt registered eboot_test_fdt_loader twice. embeddedos-org#84 added it,
  and embeddedos-org#85 -- stacked on embeddedos-org#84 -- re-added it at a different anchor when it was
  replayed onto a master that already had embeddedos-org#84. Same hunk as embeddedos-org#111.

Compile (eboot_core):
- embeddedos-org#55 restored a core/sha512.c from 02b7dac that keeps its byte count in
  ctx->count; the eos_sha512_ctx_t master ships has bitlen[2]/buffer_len
  (embeddedos-org#69/embeddedos-org#93). Back to the pre-embeddedos-org#55 file, blob-identical (d9aa57c).
- embeddedos-org#55's source-list "correction" dropped core/boot_log.c, core/secure_boot.c
  and core/fdt_loader.c, which embeddedos-org#72/embeddedos-org#84 had added after embeddedos-org#55 was written.
  CMakeLists.txt is blob-identical to pre-embeddedos-org#55 again (f8fe6eb).
- embeddedos-org#55 replaced the eos_boot_log_get_head() declaration with a second copy of
  eos_boot_log_read(); embeddedos-org#91 had already fixed the prototype it meant to fix.
  Header restored (964ebb8).
- embeddedos-org#94 and embeddedos-org#105 each repaired the Ed25519 verifier and each added an identical
  static scalarbase(); both merged. One copy removed.
- The same pair each added k_low_order[]/messages[] to test_ed25519.c. The
  embeddedos-org#105 copy is removed; embeddedos-org#94's stays because it also carries k_non_canonical[].

Tests that stopped passing because two merged PRs disagree on behaviour:
- embeddedos-org#104 verifies the image signature at install unconditionally, before the
  anti-rollback check embeddedos-org#103 added, so embeddedos-org#103's unsigned images are refused as
  EOS_ERR_SIGNATURE before they can be refused as EOS_ERR_ANTI_ROLLBACK, and
  test_fw_transport's XMODEM install can no longer finalize. Both suites now
  stream genuinely signed images. eBoot has no Ed25519 signer in C, so
  tools/gen_fw_update_test_sigs.py signs the exact header prefixes those
  suites build under the RFC 8032 section 7.1 TEST 1 key and emits
  tests/vectors/fw_update_test_sigs.h; the suites serve that key from a
  simulated OTP slot 0. Negative control: one flipped signature byte fails
  test_write_streams_tlv_then_finalize_rejects_below_floor with
  EOS_ERR_SIGNATURE.
- embeddedos-org#103's step 5b reads the TLV counter through the HAL slot containing the
  image; test_secure_boot_policy (embeddedos-org#82) declared no slots, so eos_secure_boot()
  returned EOS_SBOOT_ERR_BAD_HEADER two steps before the one under test. The
  fixture now places its image in slot A.

Guards from embeddedos-org#95 that later merges walked back, never run until now because the
C configure step failed first:
- embeddedos-org#103 replayed the hand-written Valgrind foreach over the derived one.
  Restored foreach(TEST_NAME ${EBLDR_UNIT_TESTS}); eleven registered suites
  had no list(APPEND ...) and so no Valgrind run.
- Seven suites assign tests_run = <literal> and their TEST() does not count;
  four suites have no TEST() macro at all. Counted, and classified.
- embeddedos-org#101 added fuzz-build after embeddedos-org#90's gate; the gate did not wait for it.

CI plumbing:
- eosim-sanity.yml: the install-validate job is written in bash but ran under
  PowerShell on the Windows legs (no shell:), where SITE_PACKAGES=$(...) is an
  unknown command and `|| { exit 1 }` is an unexecuted script block.
- scorecard.yml: ossf/[email protected] pulls gcr.io, which now demands
  GCP billing. v2.4.3 pulls ghcr.io; eos already pins it and is green.

Verified locally (macOS, clang): Release build clean, 31/31 ctest; the same
under -DEBLDR_SANITIZE=ON (ASan+UBSan); 78/78 pytest.

Not fixed here, reported separately: core/keystore.c's compiled-in
default_dev_key is described as the RFC 8032 TEST 1 public key but differs
from byte 21 on and is not a point on the curve, so nothing can verify
against it on any board without OTP. With embeddedos-org#104 that makes firmware update
refuse every image on such boards.
… -1.0.0 as an option

test_out_of_range_version_is_rejected[-1.0.0] passed locally (Python 3.14)
and failed in CI (ubuntu-22.04, Python 3.10) with argparse's own
"expected one argument": the older negative-number matcher does not accept
-1.0.0, so the token was read as an unknown option and imgpack.py's range
check -- the thing under test -- never ran. The joined form is unambiguous
on every interpreter and the test now reaches the tool's message.
tests/vectors/fw_update_test_sigs.h is the output of
tools/gen_fw_update_test_sigs.py, committed because eBoot has no Ed25519
signer in C. Nothing checked that the two agree: a generator edit without a
regeneration leaves test_fw_update and test_fw_transport verifying against
stale signatures, failing with EOS_ERR_SIGNATURE and nothing to say why.

tests/unit/test_fw_update_test_sigs.py runs the generator with the test's
own interpreter and compares its stdout to the committed header byte for
byte, so a line-ending change counts too. It follows the same dependency
rule as test_eos_sign_payload_offset.py: with EOS_REQUIRE_SIGNING_TESTS set
(the CI workflow sets it before the pytest step) a missing cryptography
module fails the job instead of skipping. Negative control: one flipped hex
byte in the header fails the test with a unified diff naming the line.

build_image() and build_container() now carry a comment naming the
coupling: the signed prefix is assembled both there and in the generator,
and changing any field in it means changing the generator's copy and
regenerating the header.
…epair

embeddedos-org#103 and embeddedos-org#104 were both merged and disagree on whether the anti-rollback
counter or the signature is checked first in eos_fw_update_finalize(). The
master design orders boot as verify image, then version policy (section
8.1), but its update flow (section 15) never places the anti-rollback
check, so the order the install path uses existed only in a PR body.
ADR-020 records it: the signature over the signed header prefix is
verified first, the TLV counter is read only after the prefix that binds
it is authenticated, and an image that fails verification is refused as
EOS_ERR_SIGNATURE without its counter being consulted. docs/adr/README.md
is added in the shape of the eos repository's index; 020 avoids reusing
001 through 019.

CHANGELOG.md gains the Unreleased entries for the repair: the configure,
compile and link breakage after the 09-07 batch merge, the settled check
ordering with the suites streaming signed images, the re-derived Valgrind
list, fuzz-build in the CI gate, counted tests_run, the EoSim Windows legs
running under bash, and the Scorecard action on its ghcr.io-hosted release.
The changelog said eleven suites had no Valgrind run. Eleven were missing
from EBLDR_UNIT_TESTS, but four of those were named in the hand-written
foreach and did run; seven had no run at all. Say which.

ADR-020: its design-document citation now says where it comes from (the
architecture review of embeddedos-org#115), and the sentence about the two PRs' bases is
replaced with what the history shows -- embeddedos-org#103's commits predate embeddedos-org#104's merge,
and embeddedos-org#104 was written without embeddedos-org#103's check in place.
The regeneration test's failure path -- the unified diff under the
regenerate command -- ran only when the header was stale, so a green run
never executed it and the coverage report said so. The report is now a
helper the match asserts with, and a second test drives the helper with
two byte strings that differ in one byte and checks the command and both
sides of the changed line appear.
@Kartikey1306
Kartikey1306 force-pushed the fix/repair-master-after-batch-merge branch from a276016 to e152d8e Compare September 15, 2026 06:27
Kartikey1306 added a commit to Kartikey1306/eBoot that referenced this pull request Sep 15, 2026
…warded

Finding 1 from the review of 88cb92e. _forwarded_definitions() matched
add_compile_definitions(EBLDR_X) with the closing paren required to
follow the name, so of the three ordinary ways to forward a compile
definition it saw one. The reviewer showed the other two carrying a
name nothing reads straight past it:

    add_compile_definitions(EBLDR_DEAD_A=1)                      -> 4 passed
    target_compile_definitions(eboot_core PRIVATE EBLDR_DEAD_B)  -> 4 passed
    add_compile_definitions(EBLDR_DEAD_C)                        -> 1 failed

The =1 form is what someone writes when they want the macro to have a
value; target_compile_definitions is what they write when they want it
scoped to one library. Neither is exotic, and this guard exists only
for the future -- the tree forwards exactly one EBLDR_ name today and
it is read.

The collector now takes the whole argument list of add_ or
target_compile_definitions(...), every EBLDR_ token in it, with
anything after = stripped. Five shapes are pinned as collected,
including a multi-line call and a mixed list, and a second test appends
each shape to the real CMakeLists.txt text with a dead name and
requires the guard to fail on it -- which is exactly how a dead switch
would come back. All three of the reviewer's probes now fail the guard.

The secondary note is taken too: test_documented_options_exist checked
documented <= declared; the reverse direction is now asserted as well,
with EBLDR_BOARD exempted because the README covers it in prose above
the table rather than in it. Clean today, as the reviewer enumerated.

Negative control: with the old one-shape collector restored and the new
tests kept, 5 of 11 fail. At this head (restacked onto embeddedos-org#115's e152d8e,
itself on master 682d005): pytest tests/ 91 passed, ctest 31/31.
Kartikey1306 added a commit to Kartikey1306/eBoot that referenced this pull request Sep 15, 2026
…warded

Finding 1 from the review of 88cb92e. _forwarded_definitions() matched
add_compile_definitions(EBLDR_X) with the closing paren required to
follow the name, so of the three ordinary ways to forward a compile
definition it saw one. The reviewer showed the other two carrying a
name nothing reads straight past it:

    add_compile_definitions(EBLDR_DEAD_A=1)                      -> 4 passed
    target_compile_definitions(eboot_core PRIVATE EBLDR_DEAD_B)  -> 4 passed
    add_compile_definitions(EBLDR_DEAD_C)                        -> 1 failed

The =1 form is what someone writes when they want the macro to have a
value; target_compile_definitions is what they write when they want it
scoped to one library. Neither is exotic, and this guard exists only
for the future -- the tree forwards exactly one EBLDR_ name today and
it is read.

The collector now takes the whole argument list of add_ or
target_compile_definitions(...), every EBLDR_ token in it, with
anything after = stripped. Five shapes are pinned as collected,
including a multi-line call and a mixed list, and a second test appends
each shape to the real CMakeLists.txt text with a dead name and
requires the guard to fail on it -- which is exactly how a dead switch
would come back. All three of the reviewer's probes now fail the guard.

The secondary note is taken too: test_documented_options_exist checked
documented <= declared; the reverse direction is now asserted as well,
with EBLDR_BOARD exempted because the README covers it in prose above
the table rather than in it. Clean today, as the reviewer enumerated.

Negative control: with the old one-shape collector restored and the new
tests kept, 5 of 11 fail. At this head (restacked onto embeddedos-org#115's e152d8e,
itself on master 682d005): pytest tests/ 93 passed, ctest 31/31.

@srpatcha srpatcha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — eBoot#115 "fix: repair master after the 09-07 batch merge"

head: e152d8e author: Kartikey1306 ci: pass (26 green, 0 red; only Create GitHub Release skipped)

Verdict: Third look. This head is a pure rebase of the previously reviewed
a276016b onto the new master — no new commits, and the only content delta is the
tests/CMakeLists.txt hunk that dropped out because #111 landed, exactly as the last
review predicted. Both outstanding findings are Low and remain open by the author's
deliberate choice; one of the two stated reasons for deferring no longer holds. Build,
ctest and pytest re-verified green on this head. Nothing here blocks the merge.

Status of the previous findings (eBoot-115-a276016b.md)

# Prev. severity Status Evidence
1 Low — the pin test closes the hand-edited-header hole, not the drifted-prefix hole Untouched, accepted, deferred No change on the branch; tools/gen_fw_update_test_sigs.py:25-27 still states the field values are copied from the tests. The author accepted the analysis and the proposed close in the 2026-09-14T20:21Z comment and queued it as a follow-up rather than a change to this PR. Recorded as open, not dropped.
2 Low — ADR-020 is status: Proposed while CHANGELOG.md calls the ordering "settled" Untouched; the deferral reason is now stale docs/adr/ADR-020-…md:4 is still status: Proposed; CHANGELOG.md:17 still reads "Install-path verification order settled". See finding 1 below.

Findings

# Severity File:line Finding Recommended fix
1 Low CHANGELOG.md:17 The stated reason for not pushing the one-word correction has been overtaken by this head. The author's 2026-09-14T20:21Z comment says the fix is held back because "#116 and #122 are stacked on this branch and a push here re-stacks both and stales the review ranges stated in their bodies". That re-stack has now happened anyway: a276016b is no longer reachable, git merge-base pr/115 pr/116 and git merge-base pr/115 pr/122 both return e152d8ed, and both stacked PRs already carry new heads in this same review batch. The cost the deferral was avoiding has already been paid, so the word can ride the next push at zero additional cost. Still Low — this is a changelog adjective, and the underlying ADR ratification is the deciders' call, not the author's. In the next push to this branch (or in the squash), change "settled" to a word that matches docs/adr/README.md's definition of Proposed — e.g. "recorded" or "proposed". Leave status: alone; ratification belongs to the named deciders.

One finding, Low, on a rebase that introduced no new source. I re-read the new head's
delta specifically looking for anything that rode in on the rebase and found none — see
below.

Verification performed for this review

Detached worktree at .ai/autoreview/state/scratch/eBoot-115 off refs/pull/115/head.
The user's eBoot checkout (on fix/ed25519-low-order-keys) was not touched; nothing was
committed or pushed.

Check Result
cmake -B build/host -DEBLDR_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release PASS
cmake --build build/host --parallel 4 PASS — no errors
ctest --test-dir build/host --output-on-failure --no-tests=error PASS — 31/31, 2.49s
pytest tests/ -q with EOS_REQUIRE_SIGNING_TESTS=1 PASS — 82 passed, 2.07s. Up from 80 at the last review; the two extra are tests/unit/test_sign_image.py cases that arrived on the new base from #117, not from this branch.
Is this head a rebase or new work? REBASE, confirmed. origin/master..pr/115 lists the same six commit subjects in the same order as a276016b's range. Per-commit git patch-id --stable over both ranges differs on exactly one commit (b7d7cac35280b5).
What changed in that one commit CONFIRMED benign. Diffing (221325c..a276016b) against (682d005..e152d8ed) yields only the removal of the five-line eboot_test_fdt_loader deletion hunk in tests/CMakeLists.txt plus the resulting @@ line-number shifts and a blob-index line. #111 (682d005) removed the duplicate on master, so the hunk is now redundant. Totals move 191 → 186 deletions; insertions are unchanged at 702.
Duplicate target actually gone at this head CONFIRMEDgrep -c 'add_executable(eboot_test_fdt_loader' tests/CMakeLists.txt = 1. The configure failure the original PR fixed cannot recur from this file.
Did anything else ride in on the rebase? NO. The 25 files the PR touches are unchanged from the reviewed set apart from the hunk above. The a276016b..e152d8ed raw range additionally shows build.yml, nightly.yml, release.yml, weekly.yml, tools/sign_image.py and tests/unit/test_sign_image.py — those are #117 (f22896d) arriving on the new base, not this PR's changes.
Deferral-reason check for finding 1 CONFIRMED stalegit merge-base --is-ancestor e152d8ed pr/116 and … pr/122 both true.
Residual 1 still present CONFIRMEDtools/gen_fw_update_test_sigs.py unchanged on this head.
Residual 2 still present CONFIRMED — ADR-020 frontmatter status: Proposed; CHANGELOG.md:17 "settled".

Was anything weakened? No. There is no new source on this branch since the last
review, and the one hunk that disappeared disappeared because master already performs
the same removal. No test disabled, no assertion removed, no lint loosened, no permission
widened, and the test count went up (31 ctest unchanged, pytest 80 → 82).

On the author's self-corrections. Two numbers in the PR comments are now stale in the
harmless direction: "pytest 80 passed" was measured at a276016b and is 82 at this head.
That is the base moving, not a claim the author got wrong, and no action is needed. It is
noted only so the next reader does not treat the mismatch as a discrepancy.

Architecture conformance

Conforms; unchanged from the previous two reviews and re-checked rather than recalled.
§21: eBoot is Tier 1 Foundation and every touched file is inside the owning repo. §5.1
dependency direction is untouched — a rebase that removes a CMake deletion hunk creates no
edge of any kind. The core/ placement of boot_log.c, secure_boot.c and fdt_loader.c
restored by the original commit still matches .ai/architect.md's target shape for eBoot
(core/ = shared boot logic), and §5.1's "eBoot keeps the trusted computing base minimal
and auditable" is still served by having those objects actually link. §8.1's boot ordering
is unchanged. ADR-020 continues to record the install-path ordering that §15 leaves
unstated; the corresponding master-design gap is already filed as the 2026-09-13 proposal
"The update path does not say where anti-rollback is evaluated" in
.ai/autoreview/proposals/2026-09.md, so no new proposal is appended for this head.

Proposed changes

None blocking. Merge order from the previous reviews holds, with #111/#112/#117 now landed:
  1. #115 (this PR)  — #116 and #122 are stacked on it and rebase for free
Follow-ups, neither blocking:
  - CHANGELOG.md:17 "settled" -> "recorded"/"proposed" on the next push to this branch
  - ratify ADR-020 (Proposed -> Accepted) or say why not  [deciders, not the author]
  - if ever worth it, compare the generator's signed prefix against the C suite's bytes
    rather than documenting by hand that they must match

Not checked

  • Cross-compile (STM32F4, Cortex-M4), fuzz-harness build, CodeQL, cppcheck/clang-tidy —
    NOT RUN locally.
    CI reports all green on this head; taken at face value, job logs not read.
  • ASan/UBSan — NOT RUN. Built Release without sanitizers on this head.
  • Valgrind — NOT RUN. The restored EBLDR_UNIT_TESTS list is Observed from CMake, as in
    the previous review; not executed here.
  • Negative control on the pin test — NOT RE-RUN. It was executed and passed at
    a276016b; tests/unit/test_fw_update_test_sigs.py and the vectors are byte-identical at
    this head, so the earlier result carries, but I did not re-break the header this time.
  • The rest of the 09-07 batch. Unchanged: the evidence supports "everything that breaks
    configure, compile, link, ctest and pytest on the host is fixed", not "this is
    everything that broke".
  • CI on this exact head vs. the reported checks. I read checks.txt from the bundle; I
    did not re-query GitHub or open any job log.

Automated architecture review of e152d8edfce4 — scheduled, model claude-opus-5, checked against the EmbeddedOS Master Design v2.0. Advisory only: this reviewer never approves, requests changes, or merges. Reply here to discuss or push back — a wrong finding is a bug worth reporting.

Kartikey1306 added a commit to Kartikey1306/eBoot that referenced this pull request Sep 15, 2026
…warded

Finding 1 from the review of 88cb92e. _forwarded_definitions() matched
add_compile_definitions(EBLDR_X) with the closing paren required to
follow the name, so of the three ordinary ways to forward a compile
definition it saw one. The reviewer showed the other two carrying a
name nothing reads straight past it:

    add_compile_definitions(EBLDR_DEAD_A=1)                      -> 4 passed
    target_compile_definitions(eboot_core PRIVATE EBLDR_DEAD_B)  -> 4 passed
    add_compile_definitions(EBLDR_DEAD_C)                        -> 1 failed

The =1 form is what someone writes when they want the macro to have a
value; target_compile_definitions is what they write when they want it
scoped to one library. Neither is exotic, and this guard exists only
for the future -- the tree forwards exactly one EBLDR_ name today and
it is read.

The collector now takes the whole argument list of add_ or
target_compile_definitions(...), every EBLDR_ token in it, with
anything after = stripped. Five shapes are pinned as collected,
including a multi-line call and a mixed list, and a second test appends
each shape to the real CMakeLists.txt text with a dead name and
requires the guard to fail on it -- which is exactly how a dead switch
would come back. All three of the reviewer's probes now fail the guard.

The secondary note is taken too: test_documented_options_exist checked
documented <= declared; the reverse direction is now asserted as well,
with EBLDR_BOARD exempted because the README covers it in prose above
the table rather than in it. Clean today, as the reviewer enumerated.

Negative control: with the old one-shape collector restored and the new
tests kept, 5 of 11 fail. At this head (restacked onto embeddedos-org#115's e152d8e,
itself on master 682d005): pytest tests/ 93 passed, ctest 31/31.
@Kartikey1306

Copy link
Copy Markdown
Contributor Author

Answering the 06:41Z re-review at e152d8e. Pure rebase, no content change; the two carried Lows stand as accepted-and-deferred. On the third:

The deferral reason you quoted was stale, and you were right to say so. "#116 and #122 are stacked on this" was the reason on 09-14; the restack at 12:05 IST paid that cost anyway. The reason today is a different number: twelve open PRs now sit on e152d8e#116 #122 #123 #125 #127 #129 #131 #133 #135 #138 #139 #142 (checked by merge-base --is-ancestor at 12:50 IST), across four authors' stacks. A push to this branch for one changelog adjective restacks all twelve, stales twelve review ranges, and re-runs twelve CI matrices. So the word rides the squash-merge commit message, or the next push here that has a real reason — not this one. The adjective is wrong and I am not defending it; I am declining to spend twelve restacks on it.

ADR-020 ratification is the deciders' call, as you say; nothing from me there.

Body's "Relationship to open PRs" was updated at 12:05 IST to record the rebase and #111/#112/#117 with SHAs. Nothing pushed; nothing to re-approve.

@Kartikey1306

Copy link
Copy Markdown
Contributor Author

Status for the merger, 2026-09-17: green on all checks, rebased onto 682d005 (the #111/#112/#117 merges — the duplicate-target hunk dropped out as expected). It is the open repair for what still does not compile on master: core/sha512.c uses a count member eos_sha512_ctx_t no longer has (6 sites) and core/ed25519_verify.c:303 redefines scalarbase. Every PR based on master fails the six build-side checks — currently @Mohammed18-19's #109, whose merge result with this PR I built and tested (31/31; one trivial tests_run conflict, resolution in my comment there). This PR is also the base of the #116#122#123#125 stack and of #127/#129/#131/#133/#138, all green on top of it; merge order is this first. Ready when you are.

@Kartikey1306

Copy link
Copy Markdown
Contributor Author

@srpatcha — re-approval request, with the facts that make it a two-minute read rather than a re-review.

Your approval at 4d8696c (2026-09-14 05:16Z) was dismissed by follow-up pushes answering the automated review. The branch has not moved since e152d8e (2026-09-15 06:30Z).

The repair commit you approved got smaller, not different. Then a8743dd (20 files, +515/−190), now 35280b5 (20 files, +515/−185): the only change is five lines of tests/CMakeLists.txt the rebase dropped because #111 — merged to master on 09-14 — removed the same duplicate test_fdt_loader target this repair removed. Same 20 files, same additions; what remains is a strict subset of what you verified with gcc/Ninja/Debug.

What is new since your approval: 5 follow-up commits, +187/−1 across 7 files, each answering a finding from your automated review — 2b30fd7 (--version=X so argparse never reads -1.0.0 as an option), a95400f (fixture header pinned to its generator), e152d8e (exercise the stale-header report, not only the match), edfbaed/b01e9ce (ADR-020 for the install-path check ordering; the Valgrind gap stated exactly). Compare: 4d8696c...e152d8e — the automated review's final verdict on this head: "This head is a pure rebase of the previously reviewed" content.

What this unblocks: 12 open PRs are stacked on this head (#116, #122, #123, #125, #127, #129, #131, #133, #135, #138, #139, #142 — each drops to its own diff once this lands), plus Mohammed18-19's #109, whose only red is inherited from master.

Nothing further will be pushed to this branch. Merge order: this first.

@Mohammed18-19

Mohammed18-19 commented Sep 17, 2026 via email

Copy link
Copy Markdown
Contributor

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

master does not configure, compile, link or pass tests after the 09-07 batch merge

4 participants