Add Phase 9 validation and advisory review

Record the finite dependency search, Wi-Fi maintenance blocker, and
pinned
icon provenance. Add bounded host orchestration and fixture coverage,
and
update release documentation with current evidence.
This commit is contained in:
2026-09-16 16:26:46 +02:00
parent 51f835c22f
commit cdc4d4a8df
31 changed files with 1748 additions and 45 deletions
+3 -1
View File
@@ -14,7 +14,7 @@ ESP32-S3 firmware for a secure, multi-transport RS-232 adapter. It operates one
## Development status ## Development status
Hardware characterization, serial/USB/Wi-Fi/HTTPS/SSH and local display/control are implemented and hardware-validated. **Phase 8 role-based users and administration is complete:** 8A8C were target-hardware validated and the user explicitly signed off tested firmware at **8D.22 (2026-09-13)**. See the [roadmap](docs/roadmap.md#phase-8--role-based-users-and-administrative-access--complete) and [acceptance evidence](docs/web_administration_acceptance.md). Very low internal/DMA lifetime minima remain a nonblocking headroom follow-up, not an approved reserve. **Phase 9 security hardening is in progress**: 9A crash/debug policy, 9B SSH admission/credential handling and 9C library cleanup/protocol policy have passed host/build checks. **9D maintenance and lifecycle is in progress:** an operator runbook, finite SSH parser/caller and IDF applicability reviews, and offline notice assembly tooling are available. Scoped corrections have parent host/build evidence; broader advisory coverage, release delivery/source/legal questions and whole-phase target gates remain open; **Phase 9 is not complete or production-ready**. The user will validate Phase 9 as a whole; no 9D device validation or license clearance is claimed. See [security hardening](docs/security_hardening.md) for scope, operational profiles, and validation gates. Hardware characterization, serial/USB/Wi-Fi/HTTPS/SSH and local display/control are implemented and hardware-validated. **Phase 8 role-based users and administration is complete:** 8A8C were target-hardware validated and the user explicitly signed off tested firmware at **8D.22 (2026-09-13)**. See the [roadmap](docs/roadmap.md#phase-8--role-based-users-and-administrative-access--complete) and [acceptance evidence](docs/web_administration_acceptance.md). Very low internal/DMA lifetime minima remain a nonblocking headroom follow-up, not an approved reserve. **Phase 9 security hardening is in progress**: 9A crash/debug policy, 9B SSH admission/credential handling and 9C library cleanup/protocol policy have passed host/build checks. **9D maintenance and lifecycle is in progress:** an operator runbook, finite SSH parser/caller and IDF applicability reviews, and offline notice assembly tooling are available. Scoped corrections have parent host/build evidence; the [finite dependency search](docs/dependency_advisory_coverage.md) is complete (all 22 IDF advisory entries across three pages plus named managed/browser channels), but fresh findings, explicit coverage gaps, release delivery/source/legal questions and whole-phase target gates remain open. **The PMF-capable SoftAP security blocker is not fixed**: the [update plan](docs/wifi_security_update_plan.md) requires a coherent vendor framework/source/header/binary ABI bundle and compatible tooling, not PMF/WPA3 weakening; **Phase 9 is not complete or production-ready**. The user will validate Phase 9 as a whole; no 9D device validation or license clearance is claimed. See [security hardening](docs/security_hardening.md) for scope, operational profiles, and validation gates.
Latest supplied parent integration: `pio run` **PASS**, **94,340 B linked RAM / 1,768,901 B flash** (+200 B flash); **seven focused suites PASS**. See [exact counts and evidence limits](docs/security_hardening.md#ordering-hostbuild-evidence--2026-09-16). Linked size and host passes are not target headroom or release acceptance. Latest supplied parent integration: `pio run` **PASS**, **94,340 B linked RAM / 1,768,901 B flash** (+200 B flash); **seven focused suites PASS**. See [exact counts and evidence limits](docs/security_hardening.md#ordering-hostbuild-evidence--2026-09-16). Linked size and host passes are not target headroom or release acceptance.
@@ -40,6 +40,8 @@ Keep UART0 ready for administrative recovery and native USB for network-independ
- [wolfSSL/wolfSSH advisory review](docs/wolf_security_review.md): implemented scoped mitigations, historical research and remaining target/maintenance gates. - [wolfSSL/wolfSSH advisory review](docs/wolf_security_review.md): implemented scoped mitigations, historical research and remaining target/maintenance gates.
- [Remaining SSH parser review](docs/ssh_parser_remaining_review.md): completed finite server-profile dispatch/caller review, corrections and explicit exclusions; not exhaustive parser safety. - [Remaining SSH parser review](docs/ssh_parser_remaining_review.md): completed finite server-profile dispatch/caller review, corrections and explicit exclusions; not exhaustive parser safety.
- [IDF applicability review](docs/idf_security_review.md): six named findings and a bounded advisory-index feature screen, not all-CVE clearance. - [IDF applicability review](docs/idf_security_review.md): six named findings and a bounded advisory-index feature screen, not all-CVE clearance.
- [Bounded Phase 9 host validation](docs/phase9_validation.md): [orchestrator](tools/validate_phase9.py), 23 default commands; build and OpenSSH interop are separate opt-ins.
- [Exact icon provenance](docs/icon_provenance.md): official 7.4.47 retained SVGs verified; manual bitmap derivation and distinct mockup Wi-Fi path remain unresolved.
- [Release notice packaging](docs/release_packaging.md): offline [notice tool](tools/release_notices.py), deterministic bounded assembly and separate recipient/source/legal gates. - [Release notice packaging](docs/release_packaging.md): offline [notice tool](tools/release_notices.py), deterministic bounded assembly and separate recipient/source/legal gates.
- [Command reference](docs/command_reference.md): UART0/admin-SSH administration, serial, broker, USB, Wi-Fi, mDNS, web, SSH, and diagnostic commands. - [Command reference](docs/command_reference.md): UART0/admin-SSH administration, serial, broker, USB, Wi-Fi, mDNS, web, SSH, and diagnostic commands.
+4 -2
View File
@@ -26,12 +26,14 @@ This is a semantic map, not a complete file inventory. Start here, then read the
- Latest supplied parent `pio run` PASS: **94,340 B linked RAM / 1,768,901 B flash (+200 B versus 1,768,701 B)**. Final parent **all seven suites PASS**: ordering `--interop` (8,028 checks / seven rejected mutations / 12 exact-256-KiB sessions, clean channel close and transport EOF), SDK overrides `--build-dir .pio/build/esp32-s3-devkitc-1-n16r8`, auth (135), protocol, strict crypto, notices (30), and parser (3,258 × two modes plus channel profiles; 11 + 18 + 2 rejected mutations). Interop used unsandboxed approval only for local AF_UNIX sockets; no remote network/device operation. Review's misplaced EOF guard is corrected in `SendChannelEof` before lookup/serialization/state mutation; follow-up verification found no scoped blocker. Not target/runtime-reserve evidence. - Latest supplied parent `pio run` PASS: **94,340 B linked RAM / 1,768,901 B flash (+200 B versus 1,768,701 B)**. Final parent **all seven suites PASS**: ordering `--interop` (8,028 checks / seven rejected mutations / 12 exact-256-KiB sessions, clean channel close and transport EOF), SDK overrides `--build-dir .pio/build/esp32-s3-devkitc-1-n16r8`, auth (135), protocol, strict crypto, notices (30), and parser (3,258 × two modes plus channel profiles; 11 + 18 + 2 rejected mutations). Interop used unsandboxed approval only for local AF_UNIX sockets; no remote network/device operation. Review's misplaced EOF guard is corrected in `SendChannelEof` before lookup/serialization/state mutation; follow-up verification found no scoped blocker. Not target/runtime-reserve evidence.
- Restricted **CVE-2025-14942** ordering correction implemented: `tools/wolfssh_order/delta.json` supplies exact executable edits to `internal.c`, `ssh.c` and `internal.h`; [README](../../tools/wolfssh_order/README.md) records PR793/819/840/855/921 prerequisite disposition, and `provenance.json` pins archived patch hashes/commit IDs. Existing X25519/P-256 KEX only; independent SELF/PEER bits, expected-message/auth gates and exactly-once queued NEWKEYS under WANT_WRITE. **EXT_INFO intentionally disabled, no `server-sig-algs`; `extInfoSent` stays zero.** No full upstream backport or dependency upgrade. CMake propagates the generated ABI header BEFORE PUBLIC plus PUBLIC forced include with stale-header rejection; joined `-include/path` flags preserve ordering/crypto guards through PlatformIO sorting/deduplication. - Restricted **CVE-2025-14942** ordering correction implemented: `tools/wolfssh_order/delta.json` supplies exact executable edits to `internal.c`, `ssh.c` and `internal.h`; [README](../../tools/wolfssh_order/README.md) records PR793/819/840/855/921 prerequisite disposition, and `provenance.json` pins archived patch hashes/commit IDs. Existing X25519/P-256 KEX only; independent SELF/PEER bits, expected-message/auth gates and exactly-once queued NEWKEYS under WANT_WRITE. **EXT_INFO intentionally disabled, no `server-sig-algs`; `extInfoSent` stays zero.** No full upstream backport or dependency upgrade. CMake propagates the generated ABI header BEFORE PUBLIC plus PUBLIC forced include with stale-header rejection; joined `-include/path` flags preserve ordering/crypto guards through PlatformIO sorting/deduplication.
- Ordering tests: [tests/wolfssh_order_contract](../../tests/wolfssh_order_contract/README.md), full generated C/real wolfCrypt, **8,028 checks / seven rejected mutations**; `pio_adapter.py` validates installed PlatformIO/SCons flags with a real Xtensa consumer. Initial interop failed a harness close race despite early PASS output; fixed harness awaits peer close and transport EOF and independently reaps the server via fd-passing proxy. Final agent `--interop --interop-repeat 3`: **36/36 sessions**, exact **256 KiB** each, **two or ten** key exchanges and clean client/server exits. [Remaining gates](../wolf_security_review.md#restricted-ordering-correction-and-remaining-gates): target cleanup during rekey, no-EXT_INFO client compatibility, resource/timing and whole-phase validation; no device operation or phase sign-off. - Ordering tests: [tests/wolfssh_order_contract](../../tests/wolfssh_order_contract/README.md), full generated C/real wolfCrypt, **8,028 checks / seven rejected mutations**; `pio_adapter.py` validates installed PlatformIO/SCons flags with a real Xtensa consumer. Initial interop failed a harness close race despite early PASS output; fixed harness awaits peer close and transport EOF and independently reaps the server via fd-passing proxy. Final agent `--interop --interop-repeat 3`: **36/36 sessions**, exact **256 KiB** each, **two or ten** key exchanges and clean client/server exits. [Remaining gates](../wolf_security_review.md#restricted-ordering-correction-and-remaining-gates): target cleanup during rekey, no-EXT_INFO client compatibility, resource/timing and whole-phase validation; no device operation or phase sign-off.
- [Finite dependency advisory snapshot](../dependency_advisory_coverage.md): all 22 IDF index entries across three pages plus named managed/browser channels accounted for; declared search complete, not exhaustive clearance. **PMF-capable SoftAP security blocker remains unfixed**; [Wi-Fi update plan](../wifi_security_update_plan.md) requires coherent vendor framework/toolchain/source/header/binary ABI bundles and override revalidation, not PMF/WPA3 weakening. Residual applicability questions and target gates remain.
- [Bounded Phase 9 runner](../../tools/validate_phase9.py), [usage/evidence](../phase9_validation.md), fixtures `tests/phase9_validation/run.py`: 23 default commands; build and OpenSSH interop are independent opt-ins. After the owning agent fixed the stale console-boundary anchor, final supplied parent `CCACHE_DISABLE=1 python3 -B tools/validate_phase9.py` **PASS 23/23** and orchestrator fixtures **PASS 10 tests**. No build/interop this turn; historical build/interop evidence above is separate, not phase acceptance.
- Policy/evidence/limits: [library review](../security_library_review.md), [Phase 9C](../security_hardening.md#9c-library-cleanup-and-protocol-policy). Source-contract tests must locate and verify actual generated compilation inputs, not assume original vendor paths. - Policy/evidence/limits: [library review](../security_library_review.md), [Phase 9C](../security_hardening.md#9c-library-cleanup-and-protocol-policy). Source-contract tests must locate and verify actual generated compilation inputs, not assume original vendor paths.
## Offline release notice assembly ## Offline release notice assembly
- [Procedure and release gates](../release_packaging.md), [tool](../../tools/release_notices.py), catalog `third_party/release-notices/inputs.json`, scope/TLSF provenance under `third_party/release-notices/`; tests: `tests/release_notices/run.py` (parent 30 PASS). 62 explicit hash/size-pinned inputs; no recursive collection, fetch, build, asset regeneration or device access; output must be fresh and outside input roots. - [Procedure and release gates](../release_packaging.md), [tool](../../tools/release_notices.py), catalog `third_party/release-notices/inputs.json`, scope/TLSF provenance under `third_party/release-notices/`; tests: `tests/release_notices/run.py` (supplied agent 36 fixture tests PASS). 75 explicit hash/size-pinned inputs; no recursive collection, fetch, build, asset regeneration or device access; output must be fresh and outside input roots.
- Supplied independent review: no actionable scoped parser/bundle defects; two actual 62-input bundles deterministic. Historical actual bundle: 64 files / 541,147 bytes, not remeasured here. The catalog does not pin these overview/review documents. Assembly is implemented; recipient delivery, corresponding source, legal/radio-blob basis, icon provenance and whole-phase target gates remain open. Do not equate a notice manifest with a source archive, complete SBOM or release clearance. - Supplied agent evidence: two actual 75-input bundles verified deterministic, each **77 files / 4,433,930 bytes**; no reassembly here. [Exact retained SVG provenance](../icon_provenance.md) resolves official 7.4.47 sources at `9e04201d4557e729822fb57f62a316c3dea1d4a8` (Google USB, Simran Wi-Fi); manual bitmap derivation and distinct mockup Wi-Fi path remain unresolved. The catalog pins `docs/icon_provenance.md`, not this code map or the edited overview docs; coordinate changes to pinned evidence, never silently repin. Recipient delivery, corresponding source, legal/radio-blob basis and whole-phase target gates remain open. A notice manifest is not a source archive, complete SBOM or release clearance.
## Secure randomness ## Secure randomness
+8
View File
@@ -2,6 +2,14 @@
Working memory, not an implementation timeline. Source is authoritative; begin with [code map](code-map.md), then [architecture](architecture.md) and [decisions](design-decisions.md). Working memory, not an implementation timeline. Source is authoritative; begin with [code map](code-map.md), then [architecture](architecture.md) and [decisions](design-decisions.md).
## Phase 9D continuation — broader snapshot / reproducible validation — 2026-09-16
- Initial Git clean. `docs/dependency_advisory_coverage.md` completes finite dated search of all22official IDF advisories/3pages plus specified managed/browser channels. **New current-profile blocker:** PMF-capable mixed WPA2/WPA3 SoftAP matches vendor management-frame memory-corruption path; installed7S3WiFi archives match original5.5. No exploit demonstrated. `docs/wifi_security_update_plan.md` verifies fix/release bundle differences and both callback uint8_t*→size_t* ABI changes. Verified reference IDF5.5.3 commit2c211b236707889e8400c4dc5644dd5c4ee071e0 contains fix; not deployment approval or automatic recommendation over newer releases. Do not C-only patch/swap one archive/disable PMF as guessed mitigation. Next coherent framework/toolchain/source/header/radio update evaluation with audited override rebase; PHY/coexistence/privateABI compatibility unresolved. Direct SDK AES-DMA/PSRAM applicability remains explicit review gap.
- `tools/validate_phase9.py` fixed23command host plan, optional --build/--interop, strict existing build inputs, timeouts/process cleanup, no installs/device commands/permanent log captures. New10fixture tests. Actual run revealed stale admin_console_boundary extraction ending at removed ssh_malloc; replaced with reviewed consume_external_close endpoint and eight unique ordered markers, all existing assertions retained.
- **Final parent default validation23/23PASS and orchestrator fixtures10PASS.** Default intentionally skips build/interop; no firmware rebuild or new device/interoperability claim this slice. Prior firmware94340RAM1768901flash remains historical. Additional boundary accounts/lifecycle/psram suites passed agent. Run full opt-ins only deliberately with prerequisites.
- Exact retained USB/WiFi SVGs verified byte-identical official@mdi/svg7.4.47 commit9e04201d4557e729822fb57f62a316c3dea1d4a8; archive source/license/metadata/tree hashes in third_party/material-design-icons/upstream-7.4.47 and docs/icon_provenance.md. USB Google/WiFi Simran; fullApache text present. Mockup WiFi differs and firmware bitmap manual derivation not mechanically proven. Notice catalog75inputs preserving oldinputs except editedscopeREADME pins,36testsPASS; two actual agent bundles77files4433930bytes deterministic. No assets regenerated.
- Globaldocs/code map reflect fresh blocker, finite review boundaries and final parent results. Remaining release/source/radiolegal/wolf packaging/bitmap preferred-source delivery questions not cleared. Whole-phase hardware still deferred; secureboot/encryptedNVS excluded. No upgrades/device operations/commits. Continue concrete WiFi correction evaluation, not repeat completed finite snapshots.
## Phase 9D continuation — deferred applicability / notice tooling — 2026-09-16 ## Phase 9D continuation — deferred applicability / notice tooling — 2026-09-16
- Initial Git clean. `tools/security_overrides.py` now requires exact ssh-userauth service, exact bounded CHANNEL_FAILURE recipient with existing fatal policy, and length-first exact names for all nine channel requests. Supported bodies and unknown-request ACK/consumption retained. No ordering/crypto/version changes. `docs/ssh_parser_remaining_review.md` closes finite PR899/902/918/919 and generic current signature caller trace: client key-skip functions remain unpatched but blocked by current server ordering; forwarding absent; no current short-digest/OID trigger found. Not exhaustive parser certification. - Initial Git clean. `tools/security_overrides.py` now requires exact ssh-userauth service, exact bounded CHANNEL_FAILURE recipient with existing fatal policy, and length-first exact names for all nine channel requests. Supported bodies and unknown-request ACK/consumption retained. No ordering/crypto/version changes. `docs/ssh_parser_remaining_review.md` closes finite PR899/902/918/919 and generic current signature caller trace: client key-skip functions remain unpatched but blocked by current server ordering; forwarding absent; no current short-digest/OID trigger found. Not exhaustive parser certification.
+189
View File
@@ -0,0 +1,189 @@
# Broader dependency advisory coverage
Review date: **2026-09-16**. Documentation-only, finite snapshot; **not security certification, upgrade approval, or Phase 9 sign-off**.
## Result and authority
**New actionable maintenance finding:** the installed IDF 5.5 Wi-Fi bundle predates the official 5.5.3 correction for management-frame memory corruption. The project's PMF-capable WPA2/WPA3 SoftAP supplies the relevant supported configuration. Prioritize a coherent vendor-bundle update/backport investigation; see the exact evidence and limitations below. This is a current-feature exposure candidate supported by the vendor's release/fix description, **not a demonstrated device exploit or independently audited binary implementation**.
No additional current-path security correction was established for `esp_tinyusb`, TinyUSB, mDNS, LED strip, or the two vendored browser packages in this finite search. That statement does not establish that these dependencies are vulnerability-free.
- [IDF security review](idf_security_review.md) remains authoritative for its detailed mbedTLS findings, DHCP-server/EMS/X.509 backports, WebSocket subprotocol exclusion, and first-page feature dispositions. This document completes the previously omitted **IDF advisory-index pages**, without repeating those audits or claiming a fresh override verification.
- [Wolf security review](wolf_security_review.md), [key-validation review](ssh_key_validation_review.md), and [remaining parser review](ssh_parser_remaining_review.md) retain their scopes and outstanding gates. Wolf advisories were not re-searched here.
- Only `docs/dependency_advisory_coverage.md` was created. No sources, pins, manifests, assets, generated outputs, configuration, builds, tests, or devices were changed/run. Existing build metadata was read, not regenerated; it does not establish executable freshness or device state.
## Baseline actually inspected
Managed manifests were read from installed component directories, not inferred from the application's semver constraints. The application requests `mdns: ^1.8.2`, but installed mDNS is **1.12.0**.
| Dependency | Installed/source identity | Current use |
| --- | --- | --- |
| ESP-IDF | Existing reviewed 5.5.0 baseline; additional original SDK sources and Wi-Fi archives inspected below | Wi-Fi AP/STA, lwIP, HTTPS; existing local security overrides remain part of effective inputs |
| `espressif/esp_tinyusb` | **2.2.1**, manifest commit `8e779566ef71d43928cbf7e125e8eb54bab3f542`, path `device/esp_tinyusb` | CDC device wrapper |
| `espressif/tinyusb` | **0.21.0~1**, manifest commit `7049c58a0e895acc92c6407574b05b5536eddfc8` | Espressif fork, not interchangeable with an unqualified upstream 0.21.0 claim |
| `espressif/mdns` | **1.12.0**, manifest commit `db06b19b7be729c163d346f62ec0eba01047b7f1` | STA hostname responder; no registered DNS-SD services or browser/query application calls |
| `espressif/led_strip` | **3.0.3**, manifest commit `7cd447361ca2f0a1c01aa3089e3031f6171b6c7e` | One WS2812, RMT, no DMA |
| `@xterm/xterm` | **5.5.0** per [asset provenance](../web_assets/SOURCES.md); local JS SHA-256 `1f991ac3b4b283ebf96e60ae23a00a52765dd3a2e46fa6fdda9f1aab032f7495` rechecked | Serial and admin browser terminals |
| `@xterm/addon-fit` | **0.10.0**; local JS SHA-256 `bdaefa370b1bfc42ee88d46fe6072400902a4d4b2d45cd93438dda9b23c97089` rechecked | Only loaded addon |
Browser version attribution is to the recorded exact-package provenance plus matching local hashes. No npm install, registry dependency resolution, asset download, decompression, or embedded-asset regeneration was performed. Generated compressed arrays were not independently re-hashed in this slice.
Local configuration evidence is `.pio/build/esp32-s3-devkitc-1-n16r8/config/sdkconfig.h`; compilation evidence is a filtered read of the existing compilation database. Source references under `components/` below are relative to `/home/mscholz/.platformio/packages/framework-espidf/`.
## Finite search ledger: URLs checked and stopping rules
The search ended at the following dated snapshot. Empty official repository advisories mean **no published advisories returned by that endpoint**, not no CVEs anywhere, no undisclosed defects, or a security guarantee. GitHub releases and component changelogs are different publication channels; an empty Releases list is not evidence that component versions stopped shipping.
### IDF advisory index: all snapshot pages
Fetched the official HTML index [page 1](https://github.com/espressif/esp-idf/security/advisories), [page 2](https://github.com/espressif/esp-idf/security/advisories?page=2), and [page 3](https://github.com/espressif/esp-idf/security/advisories?page=3): **10 + 10 + 2 = 22 entries**, oldest June 23, 2022, newest September 3, 2026. Page 3 is the terminal listed page. Full advisory descriptions were read from the official [repository advisory API](https://api.github.com/repos/espressif/esp-idf/security-advisories?per_page=100&page=1), not merely titles.
The [API page=2 request](https://api.github.com/repos/espressif/esp-idf/security-advisories?per_page=100&page=2) unexpectedly returned the same 22 entries with no Link header. **It was not treated as an empty-page proof or 22 additional advisories.** The HTML pagination and unique IDs establish the 22-entry snapshot boundary. No unbounded pagination or general web search followed.
### Other official advisory channels
Each URL below returned the stated number of public advisory records, with no next-page Link header:
| Official endpoint checked | Records | Disposition |
| --- | ---: | --- |
| [esp-usb](https://api.github.com/repos/espressif/esp-usb/security-advisories?per_page=100&page=1) | 3 | HID/UVC **host** issues; device CDC exclusion below |
| [hathach/tinyusb](https://api.github.com/repos/hathach/tinyusb/security-advisories?per_page=100&page=1) | 0 | No published records returned |
| [espressif/tinyusb](https://api.github.com/repos/espressif/tinyusb/security-advisories?per_page=100&page=1) | 0 | Fork checked separately |
| [esp-protocols](https://api.github.com/repos/espressif/esp-protocols/security-advisories?per_page=100&page=1) | 0 | mDNS release fixes screened separately |
| [idf-extra-components](https://api.github.com/repos/espressif/idf-extra-components/security-advisories?per_page=100&page=1) | 0 | LED changelog screened separately |
| [xterm.js](https://api.github.com/repos/xtermjs/xterm.js/security-advisories?per_page=100&page=1) | 0 | Browser release fixes screened separately |
### Release/changelog boundary
- **IDF:** [release API page 1](https://api.github.com/repos/espressif/esp-idf/releases?per_page=100&page=1) returned 100 records; [page 2](https://api.github.com/repos/espressif/esp-idf/releases?per_page=100&page=2) returned 64 and no additional 5.5 tags. Screened published stable **5.5.15.5.5** GitHub release bodies for explicit security, vulnerability, overflow, out-of-bounds, corruption, UAF and double-free descriptions; followed the relevant additional candidates below. This is not a line-by-line audit of every bugfix or another IDF branch. [5.5.4 body](https://api.github.com/repos/espressif/esp-idf/releases/tags/v5.5.4) mainly describes a NimBLE regression. The linked full [5.5.4](https://release-notes.espressif.tools/release/5.5.4) and [5.5.5](https://release-notes.espressif.tools/release/5.5.5) release databases returned **no textual content** through the fetch tool: their database-only contents are an explicit coverage gap, not reviewed pages.
- **esp-usb:** [Releases API](https://api.github.com/repos/espressif/esp-usb/releases?per_page=100&page=1) returned zero. Read the official [component changelog](https://raw.githubusercontent.com/espressif/esp-usb/master/device/esp_tinyusb/CHANGELOG.md) through **2.3.0**, and [current manifest](https://api.github.com/repos/espressif/esp-usb/contents/device/esp_tinyusb/idf_component.yml), also 2.3.0. This establishes a changelog ceiling, not proof of registry publication or compatibility.
- **TinyUSB:** [upstream Releases API](https://api.github.com/repos/hathach/tinyusb/releases?per_page=100&page=1) returned 18 records, newest **0.21.0**, whose full release notes were read. [Fork Releases API](https://api.github.com/repos/espressif/tinyusb/releases?per_page=100&page=1) returned zero. [Installed fork commit API](https://api.github.com/repos/espressif/tinyusb/commits/7049c58a0e895acc92c6407574b05b5536eddfc8) identifies the merge “Necessary fixes for TinyUSB 0.21.” No later published upstream release was present. Two legacy-path requests, [upstream](https://raw.githubusercontent.com/hathach/tinyusb/master/docs/info/changelog.rst) and [fork](https://raw.githubusercontent.com/espressif/tinyusb/master/docs/info/changelog.rst), returned 404; [docs listing](https://api.github.com/repos/hathach/tinyusb/contents/docs) then [changelog directory](https://api.github.com/repos/hathach/tinyusb/contents/docs/changelog) resolved the moved layout and confirmed 0.21.0 as its highest listed version. Unreleased commits/PRs were not exhaustively searched.
- **mDNS:** [esp-protocols release page 1](https://api.github.com/repos/espressif/esp-protocols/releases?per_page=100&page=1) returned 100 records and [page 2](https://api.github.com/repos/espressif/esp-protocols/releases?per_page=100&page=2) 37. Post-pin mDNS releases in that finite list are **1.13.0 (September 14)** and **1.13.1 (September 15)**. Their notes and both production-source fix patches were inspected; other monorepo components are outside this slice.
- **LED:** [Releases API](https://api.github.com/repos/espressif/idf-extra-components/releases?per_page=100&page=1) returned zero. Official [LED changelog](https://raw.githubusercontent.com/espressif/idf-extra-components/master/led_strip/CHANGELOG.md) ends at **3.0.3**, matching installed version.
- **xterm:** [Releases API](https://api.github.com/repos/xtermjs/xterm.js/releases?per_page=100&page=1) returned 89 records with no pagination. Read **5.5.0** baseline and **6.0.0 (December 22, 2025)** post-pin release notes. 5.5.0 explicitly lists addon-fit 0.10.0 as compatible. Screened 6.0.0's security-relevant addon fixes and actual integration below; did not mistake npm development/demo dependency updates for packages served by this firmware.
This completes the **declared finite search**, not every possible vendor/CVE channel. NVD, OSV, npm's global advisory database, private advisories, all historical SDK subdependency advisories, every unreleased commit, and all non-security-labelled release regressions were not exhaustively searched. The failed full-release-database fetches remain visible above.
## IDF pages 23: all twelve previously omitted entries
All linked advisory bodies below were included in the fetched official API response. “Not-current-path” does not mean the underlying library is patched.
| Advisory / CVE | Required feature and snapshot disposition |
| --- | --- |
| [GHSA-9j5x-rf36-54x9](https://github.com/espressif/esp-idf/security/advisories/GHSA-9j5x-rf36-54x9), CVE-2026-25508 | BLE provisioning ATT prepared-write length accumulation. **Not-current-path:** Bluetooth/provisioning absent. |
| [GHSA-m2h2-683f-9mw7](https://github.com/espressif/esp-idf/security/advisories/GHSA-m2h2-683f-9mw7), CVE-2026-25532 | WPS enrollee fragment underflow requires initiating WPS PBC/PIN pairing. **Not-current-path:** no application `esp_wifi_wps_*` calls; no enabled WPS setting in the inspected generated header. Ordinary PSK/SAE association is not WPS. |
| [GHSA-hmjj-rjvv-w8pq](https://github.com/espressif/esp-idf/security/advisories/GHSA-hmjj-rjvv-w8pq), CVE-2025-68473 | Bluedroid Classic SDP UUID-array overflow. **Not-current-path:** Bluetooth absent. |
| [GHSA-43gh-7r4f-qp57](https://github.com/espressif/esp-idf/security/advisories/GHSA-43gh-7r4f-qp57), CVE-2025-68474 | Bluedroid Classic AVRCP vendor-command allocation/write. **Not-current-path:** Bluetooth absent. |
| [GHSA-vcw6-jc3p-4gj8](https://github.com/espressif/esp-idf/security/advisories/GHSA-vcw6-jc3p-4gj8), CVE-2025-65092 | ESP32-P4 hardware JPEG header parser. **Not-current-path:** ESP32-S3, no JPEG driver compilation inputs. |
| [GHSA-qhf9-vr2h-jh96](https://github.com/espressif/esp-idf/security/advisories/GHSA-qhf9-vr2h-jh96), CVE-2025-66409 | Bluedroid Classic AVRCP vendor-command read. **Not-current-path:** Bluetooth absent. |
| [GHSA-8mg7-9qpg-p92v](https://github.com/espressif/esp-idf/security/advisories/GHSA-8mg7-9qpg-p92v), CVE-2025-64342 | Original ESP32 Bluetooth controller invalid access address. **Not-current-path:** S3 explicitly outside affected chip family; Bluetooth also absent. |
| [GHSA-9w88-r2vm-qfc4](https://github.com/espressif/esp-idf/security/advisories/GHSA-9w88-r2vm-qfc4), CVE-2025-55297 | BluFi example credential/DH buffers. **Not-current-path:** no BluFi integration, no Bluetooth host. Not a generic flaw in this project's Wi-Fi password handling. |
| [GHSA-hqhh-cp47-fv5g](https://github.com/espressif/esp-idf/security/advisories/GHSA-hqhh-cp47-fv5g), CVE-2025-52471 | ESP-NOW receive underflow. **Not-current-path:** no application ESP-NOW initialization or receive callback. Does not prove opaque Wi-Fi archives are globally fixed. |
| [GHSA-wm57-466g-mhrr](https://github.com/espressif/esp-idf/security/advisories/GHSA-wm57-466g-mhrr), CVE-2024-53845 | ESPTouch v2 constant AES-CBC IV. **Not-current-path:** no SmartConfig/ESPTouch provisioning calls; PSK/SAE manager is separate. |
| [GHSA-22x6-3756-pfp8](https://github.com/espressif/esp-idf/security/advisories/GHSA-22x6-3756-pfp8), CVE-2024-28183 | Physical flash TOCTOU against anti-rollback. **Excluded/not configured:** no enabled `CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK`; physical firmware replacement is outside current review model. No claim of secure boot or rollback protection. |
| [GHSA-7f7f-jj2q-28wm](https://github.com/espressif/esp-idf/security/advisories/GHSA-7f7f-jj2q-28wm), CVE-2022-24893 | BLE Mesh provisioning `SegN` bounds. **Not-current-path:** Bluetooth/Mesh absent. |
Rechecked local evidence: target `esp32s3`/Xtensa; no enabled `CONFIG_BT_ENABLED`; compilation-entry counts `/bt/host/`, `esp_driver_jpeg`, `/esp_tee/` each zero. Targeted application searches for WPS, ESP-NOW, SmartConfig, BluFi and protocomm found no integration. These exclusions do not depend on later release tables implicitly excluding 5.5.0. Revisit before enabling these features.
Together with the ten entries already dispositioned in [the IDF review](idf_security_review.md#bounded-idf-advisory-index-snapshot-disabledunused-features), this accounts for all **22 unique IDs** in the dated official index.
## New release-note finding: Wi-Fi management-frame corruption
**Priority: prompt coherent vendor correction review for PMF-capable SoftAP operation. Not fixed by existing DHCP/mbedTLS overrides.** Reported to the parent during this review.
Official [IDF 5.5.3 release](https://github.com/espressif/esp-idf/releases/tag/v5.5.3) says “Fixed memory corruption issue by ensuring management frames are only encrypted when they are robust management frames,” referencing **`a3927641`**. Fetched [patch](https://github.com/espressif/esp-idf/commit/a3927641.patch) and [commit API](https://api.github.com/repos/espressif/esp-idf/commits/a3927641): merge commit **`a3927641bfd0aedfaab3514cba3d7fb01378ce4d`**, contained patch commit **`caf4cad3b422be5c2f93afeff4cd07796a262b46`**. The different patch-header ID is the contained commit, not an invented match to the merge hash.
The patch description states that when the supplicant sends an authentication response for an already-connected station with installed keys, unconditional management-packet encryption based on `bss->pmf_enable` assumed extra encryption-header space that was not present. It also mentions incorrect allocation due to RSN IE length mismatch; that second trigger was not independently established for the project's short configured IE set.
### Current application prerequisites and original interface
`src/wifi_manager.c:315331`, `configure_ap()`:
```c
wifi_config.ap.authmode = WIFI_AUTH_WPA2_WPA3_PSK;
wifi_config.ap.max_connection = 4U;
wifi_config.ap.pmf_cfg.capable = true;
wifi_config.ap.pmf_cfg.required = false;
wifi_config.ap.sae_pwe_h2e = WPA3_SAE_PWE_BOTH;
esp_err_t error = esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
```
`required=false` does **not** disable negotiated PMF. AP/APSTA is a supported runtime policy (`wifi_manager.c:382,646`), not an unused SDK feature; generated `CONFIG_ESP_WIFI_SOFTAP_SUPPORT=1` and WPA3 SAE support are enabled. Exposure is conditional on AP operation and the vendor-described station/key/PMF state. No claim is made that an arbitrary unassociated peer can exploit it.
Original configured compilation input `components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c:146155` still contains:
```c
uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len)
{
/* ... existing hostapd checks ... */
*ie_len = hapd->wpa_auth->wpa_ie_len;
return hapd->wpa_auth->wpa_ie;
}
```
`esp_wifi_driver.h:133` has the matching `uint8_t *len` callback signature; `esp_wpa_main.c:489496` registers it under `CONFIG_ESP_WIFI_SOFTAP_SUPPORT`. This is an interface/provenance marker for the old bundle, **not the source location of the opaque management-encryption defect**.
### Exact binary-bundle provenance
The official fix changes **both** callback signatures to `size_t *` and replaces `components/esp_wifi/lib` with **`a4e903fe43bf09a95022f9802db43d39740ccc0b`**. A C-only signature edit is not an adequate or ABI-safe implementation of this correction.
A local `git rev-parse` in the packaged Wi-Fi submodule failed because its Git metadata is not usable. Instead, calculated Git blob SHA-1 values directly from all seven installed `esp32s3/*.a` files and compared them with official content metadata:
- [IDF v5.5 submodule pointer](https://api.github.com/repos/espressif/esp-idf/contents/components/esp_wifi/lib?ref=v5.5): **`8a1b7bbc00e895d040c5c9a6fb9d1db2bbfc7958`**.
- [Baseline ESP32-S3 archive listing](https://api.github.com/repos/espressif/esp32-wifi-lib/contents/esp32s3?ref=8a1b7bbc00e895d040c5c9a6fb9d1db2bbfc7958): **all seven local blob IDs match** (`core`, `espnow`, `mesh`, `net80211`, `pp`, `smartconfig`, `wapi`).
- [Corrected bundle listing](https://api.github.com/repos/espressif/esp32-wifi-lib/contents/esp32s3?ref=a4e903fe43bf09a95022f9802db43d39740ccc0b): all seven differ from installed.
- Installed `libnet80211.a`: Git blob `6ee20bec142638dc0a442b9642de9fa62db6ddd0`, SHA-256 **`dcb524dda8563976cf1a97d4398c7b06cf024b7ef9a5f07788e84c88792d8071`**; corrected bundle's Git blob is `8ce8a2a6a9a753e31508bd609bf0a0d1d44c332f`.
This confirms the installed stock-baseline bundle, not a hidden same-version binary replacement carrying the published fix. It does not independently reverse-engineer the affected routine or establish a reliable remote attack.
**Parent action:** investigate a maintained IDF/vendor bundle carrying the complete correction, with matching supplicant ABI and all existing source-pinned overrides rebased and revalidated. Do not replace one archive or change only the callback type. Preserve USB/UART0 recovery and broker isolation. Target regression should cover PMF-capable WPA2/WPA3 SoftAP association, repeated authentication/reassociation with keys already installed, APSTA transitions and loaded service recovery. These tests were **not performed**. No blind recommendation to weaken PMF or disable recovery AP policy is made.
## Additional IDF release candidates screened
These are supplemental to, not replacements for, the existing detailed IDF review.
| Release candidate / fetched evidence | Actual-use disposition |
| --- | --- |
| 5.5.1 DHCP **client** option/HW-ID length, [bcd56c74 patch](https://github.com/espressif/esp-idf/commit/bcd56c74.patch), contained commit `1ad41e589ff7296c484ba64f206f2278a09dab37` | Original `lwip_default_hooks.c:262269,293300` retains old checks; generated option length **68**, vendor class ID disabled. Client path is used, but current hostname is fixed `CONFIG_LWIP_LOCAL_HOSTNAME="espressif"` and no application `esp_netif_set_hostname()` call exists. Inspected `dhcp_select()`/`dhcp_discover()` build bounded fixed options, short hostname and six-byte MAC, leaving space in 68 bytes; no current long-option trigger established. mDNS suffix is **not** the DHCP hostname. Revisit/backport before longer hostnames or extra options. Distinct from already fixed DHCP **server** CVE-2026-45160. |
| 5.5.2 `esp_timer_dump()` overflow, [a511f3be patch](https://github.com/espressif/esp-idf/commit/a511f3be.patch), contained commit `ec71bd189f6ef42aff2daa99f35d98611bb9faa3` | Original `esp_timer.c:613,616` retains old line-size constants 90/46 (fix 103/47) and profiling branch's incorrect size addition. No application dump call; timer profiling absent. **Not-current application path**, not a globally patched timer library or a ban on ordinary timers. |
| 5.5.3 HTTP **client** Digest OOB read, [6d0a7a01 patch](https://github.com/espressif/esp-idf/commit/6d0a7a01.patch), contained commit `bbcc13be8b38283547883bfee4920331bea80cd1` | Original `esp_http_client/lib/http_auth.c:131132` uses fixed-length `memcmp` on server algorithm string; no application HTTP-client/Digest consumer. **Not-current-path**; the HTTPS server's cookie login is not this function. |
| 5.5.3 AES DMA/PSRAM cache ordering, [3f10cdab patch](https://github.com/espressif/esp-idf/commit/3f10cdab.patch), contained commits `525ef3a2eab239e30cd4cc62f6d23b61743fe4c1`, `0742f3fce3a1779c63ec286342f6d9799e12822f` | Original `esp_aes_dma_core.c:11211128` invalidates after DMA; file is a configured compilation input. S3 has `SOC_PSRAM_DMA_CAPABLE=1`, so **target name alone does not exclude it**. Generated `CONFIG_MBEDTLS_HARDWARE_AES` absent; `esp_config.h:150153` therefore undefines `MBEDTLS_AES_ALT`, and no application `esp_aes_*` call was found. No current application mbedTLS hardware-AES path established. Direct SDK/opaque-radio consumers and their destination buffers were not exhaustively traced: retain this as a **residual SDK applicability question**, not global exclusion or a verified current HTTPS corruption finding. |
| Bluetooth, provisioning, JPEG, TREL/OpenThread, other-chip secure-boot/flash-encryption release fixes | Bluetooth/JPEG/provisioning exclusions above apply; project is not an OpenThread/TREL application. Physical security and other-chip configuration changes do not establish an S3 network attack. These release categories were screened, not their entire implementations audited. |
## Managed USB applicability
Published esp-usb records are [GHSA-gp8r-qjfr-gqfv](https://github.com/espressif/esp-usb/security/advisories/GHSA-gp8r-qjfr-gqfv) (HID host close double-free race), [GHSA-2pm2-62mr-c9x7](https://github.com/espressif/esp-usb/security/advisories/GHSA-2pm2-62mr-c9x7) (HID host descriptor UAF), and [GHSA-g65h-9ggq-9827](https://github.com/espressif/esp-usb/security/advisories/GHSA-g65h-9ggq-9827) (UVC host descriptor-printing stack overflow). Official affected components are `usb_host_hid` through 1.0.4 and `usb_host_uvc` through 2.3.1, **not similarly numbered esp_tinyusb releases**.
`src/usb_cdc_transport.c:763781` calls `TINYUSB_DEFAULT_CONFIG(device_event_callback)`, `tinyusb_driver_install(&usb_config)`, and `tinyusb_cdcacm_init(&cdc_config)` for `TINYUSB_CDC_ACM_0`, using the S3 internal full-speed PHY. Generated settings enable one CDC, 1,024-byte RX/TX buffers, 512-byte CDC endpoint buffer, no HID/MIDI/vendor instances, no DFU/network class. `esp_tinyusb/include/tusb_config.h:88` enables device mode and maps class counts at lines 192201. Filtered compilation database contains **zero** HID-host, UVC-host, or TinyUSB `src/host` entries. Thus all three published host advisories are **not-current-path**, without relying on “USB requires physical access” as an exclusion.
Post-pin wrapper changelog 2.3.0 describes MTP, IDF6 MSC compatibility and power-management/light-sleep integration, not a newly identified CDC memory-safety fix. MSC/MTP is not used; `CONFIG_PM_ENABLE` absent. Upstream TinyUSB's newest published 0.21.0 notes include EP0 OUT copy clamping, HID descriptor bounds and MSC callback-size caps. These are baseline-release fixes rather than evidence that a later release must be backported. Spot-check: installed `src/device/usbd.c:881,920` limits `data_len` to `wLength` and clamps transferred bytes to remaining control data. SHA-256 **`38de54351d81878e6543f2b022d0c39f45d28c8f0888491796398dec45e727be`**. This is not a complete USB control-request audit or proof every upstream fix is in the fork.
## mDNS post-pin fixes
mDNS is network-reachable when STA discovery starts: `src/wifi_manager.c:117` calls the application service, whose `src/mdns_service.c:154160` calls `mdns_init()`, `mdns_hostname_set()` and `mdns_instance_name_set()`. It is **not globally disabled**. The generated profile enables only predefined STA, maximum one interface/service, and has no `CONFIG_MDNS_ENABLE_BROWSE`. No application `mdns_service_add*`, `mdns_query_*` or `mdns_browse_*` calls were found.
1. **1.13.0 duplicate DNS-SD question expansion:** fetched [c56c725dd5e77c83c1a0683fce6dd3521e05cea2](https://github.com/espressif/esp-protocols/commit/c56c725d.patch). Upstream test explicitly calls repeated `_services._dns-sd._udp.local` PTR questions “heap amplification”: each expands the registered service list. Installed `mdns_receive.c:711716` lacks the new `if (parsed_packet->discovery) continue;` guard and allocates inside `while (a)` after `a = mdns_priv_get_services()`. **Primitive unpatched, no current amplification trigger:** no services registered; `mdns_responder.c:3845` zeroes the server and `:102104` returns its initially empty service list. A hostname/instance label is not a service registration, and `MAX_SERVICES=1` is a capacity, not one active service. Reassess before advertising `_https`, `_ssh`, or any DNS-SD service; the guard is a sensible narrow defense-in-depth candidate, not a demonstrated current responder DoS fix.
2. **1.13.1 staged-IP NUL termination:** fetched [b370a9abc29390b4adc612d251cc2dbbb325ff6f](https://github.com/espressif/esp-protocols/commit/b370a9ab.patch). Adds `new_staged_ip->hostname[MDNS_NAME_BUF_LEN - 1] = '\0';`; commit describes a GCC truncation warning. The installed receiver does **not** contain `rx_staged_ip_add()`; browsing is also disabled. Do not assert an installed unterminated-buffer vulnerability simply from version ordering or the release-note title. No current-path defect established.
Installed receiver SHA-256: **`9ada93eb2f89080a28bf2a849871e054032f06889c40397555de527af0e3d7bd`**. Earlier mDNS release notes mention parser/browse hardening, but this slice did not re-audit every pre-pin fix or equate the absence of a GHSA with a safe parser.
## LED strip and offline browser assets
**LED:** `src/status_led.c:1536` fixes `max_leds=1`, WS2812/GRB, RMT, `with_dma=false`; `:7277` sets pixel index zero then refreshes. No peer-controlled strip allocation or index is supplied. No later release/security correction was identified in the declared official channels; no blanket driver safety claim.
**Browser integration:** `src/web_ui.c:15071519` creates a terminal with `allowProposedApi:false`, loads only `FitAddon`, and `:15521554` does the same for admin. `:1531` feeds received bytes to `target.write(new Uint8Array(data), ...)`. Serial-device output is not automatically trustworthy just because a browser session authenticated; escape-sequence rendering remains a real boundary.
Post-pin 6.0.0 candidate dispositions:
- [PR5020 patch](https://github.com/xtermjs/xterm.js/pull/5020.patch), “Escape Unsafe HTML Characters in addon-serialize,” changes **addon-serialize HTML output**, not the core terminal renderer. That addon and `serializeAsHTML()` integration are absent. **Not-current-path**, not an assertion that all xterm 5.5 HTML rendering was repaired.
- [PR5355 patch](https://github.com/xtermjs/xterm.js/pull/5355.patch), “Add note about reverse tabnapping,” is **documentation-only in addon-web-links typings**, warning about iframe/custom-handler behavior. The addon is not loaded. Do not report this as a core security fix missing from 5.5.0.
- Core OSC 8 links exist even without addon-web-links. Checked [5.5.0 upstream provider](https://raw.githubusercontent.com/xtermjs/xterm.js/5.5.0/src/browser/OscLinkProvider.ts) and targeted matching snippets in hash-verified local JS: absent `allowNonHttpProtocols`, protocols are limited to `http:`/`https:`; default activation confirms navigation and sets `newWindow.opener=null` before assigning location. Application supplies no custom `linkHandler`. This rebuts an automatic arbitrary-protocol/tabnapping finding from these release notes, not all phishing/social-engineering risks or browser implementation issues.
- Other release-note changes include OSC parsing/correctness, readonly behavior for disabled input, selection/renderer fixes, and new clipboard/progress functionality. Only fit is installed; search, image, serialize, web-links, ligatures, clipboard and WebGL addons are not supplied. Build/demo updates to Express, ws, webpack, axios, etc. are not automatically firmware/browser runtime dependencies. No additional current security trigger was established from that release-note screen.
A future xterm upgrade would need deliberate addon compatibility, offline asset provenance/regeneration and browser regression review; no asset or version change is authorized by this document.
## Validation and handoff limits
Performed: official bounded advisory/release fetches; all 22 IDF index-entry accounting; targeted source/config/caller and configured-input inspection; managed manifest checks; two local web-asset hash checks; seven Wi-Fi archive Git-blob comparisons; source snippet/hash capture. Final checks passed for document whitespace/final newline, six local links, dated scope, and twelve additional IDF plus three USB advisory IDs. Document-scoped `git diff --check` also passed (the new untracked file was explicitly checked by Python). Final Git status showed concurrent changes in release-notice/validation/icon-provenance files outside this ownership scope; none were edited or reverted here. No firmware build, host regression execution, browser test, USB transaction, radio packet test, fault injection, upload, monitor, erase, or target resource measurement was performed.
**Parent summary:** carry forward the Wi-Fi bundle correction investigation and the residual direct-SDK AES-DMA applicability question. Do not describe either as implemented, or the AES question as an established current-path vulnerability. Preserve prior detailed wolf/IDF review authority and all existing mitigations. The omitted official IDF index pages and named managed/browser publication channels now have a finite dated coverage record; full release-database contents, unpublished issues, opaque implementation analysis and hardware acceptance remain outside the completed evidence. Re-run a bounded publication check before release or when dependencies, enabled features, callers, or trust boundaries change.
+5 -5
View File
@@ -4,7 +4,7 @@
**Missing generated modification/date notices: resolved; current count is eight C sources plus one header.** `tools/security_overrides.py` prepends the baseline project modification notice dated **2026-09-15**, identifying the editable generator and warning against editing derived copies. The wolfSSH `internal.c`, added `ssh.c` and generated `wolfssh/internal.h` also receive a prominent **2026-09-16** ordering-profile/provenance notice. Exact original hashes and exact-once edits remain required; upstream notices are retained. The header is a PUBLIC forced build input, not a ninth C source. Both new mbedTLS copies retain their original Mbed TLS Contributors copyright and **`Apache-2.0 OR GPL-2.0-or-later`** SPDX header; the Apache-2.0 selection in this inventory is unchanged. This resolves the narrow notice-generation finding, **not release packaging or license clearance**. **Missing generated modification/date notices: resolved; current count is eight C sources plus one header.** `tools/security_overrides.py` prepends the baseline project modification notice dated **2026-09-15**, identifying the editable generator and warning against editing derived copies. The wolfSSH `internal.c`, added `ssh.c` and generated `wolfssh/internal.h` also receive a prominent **2026-09-16** ordering-profile/provenance notice. Exact original hashes and exact-once edits remain required; upstream notices are retained. The header is a PUBLIC forced build input, not a ninth C source. Both new mbedTLS copies retain their original Mbed TLS Contributors copyright and **`Apache-2.0 OR GPL-2.0-or-later`** SPDX header; the Apache-2.0 selection in this inventory is unchanged. This resolves the narrow notice-generation finding, **not release packaging or license clearance**.
Offline notice assembly tooling is implemented; actual firmware/device/browser delivery, radio-blob corresponding-source/exception questions, preferred-source packaging, wolfSSH license-package discrepancy, exact icon provenance and release-specific runtime/bootloader review remain open. [Offline notice assembly](release_packaging.md) is implemented by [tools/release_notices.py](../tools/release_notices.py): 62 mandatory hash/size-pinned inputs, deterministic bounded outputs, fail-closed preflight and no overwrite/fetch/build/device access. Parent notices suite: 30 PASS. Supplied independent review found no actionable scoped parser/bundle defects and verified two actual 62-input bundles were deterministic. The previously measured actual bundle was 64 files / 541,147 bytes; that is snapshot evidence, not a newly measured bundle size or legal clearance. Include `cmake/wolf_crypto_policy.{cmake,h}` and the ordering inputs described below with the reproducible build/source package. No upgrades, asset regeneration or device operations were performed for this update. Offline notice assembly tooling is implemented; actual firmware/device/browser delivery, radio-blob corresponding-source/exception questions, preferred-source packaging, wolfSSH license-package discrepancy, manual bitmap/mockup provenance limits and release-specific runtime/bootloader review remain open; [exact retained SVG provenance](icon_provenance.md) is resolved. [Offline notice assembly](release_packaging.md) is implemented by [tools/release_notices.py](../tools/release_notices.py): 75 mandatory hash/size-pinned inputs, deterministic bounded outputs, fail-closed preflight and no overwrite/fetch/build/device access. Supplied agent evidence: **36 notice fixture tests PASS; two actual bundles verified deterministic, each 77 files / 4,433,930 bytes**. This includes retained SVGs and [exact icon provenance](icon_provenance.md), not corresponding-source delivery or legal clearance. These are agent measurements, not a parent rebuild or reassembly in this documentation turn. Include `cmake/wolf_crypto_policy.{cmake,h}` and the ordering inputs described below with the reproducible build/source package. No upgrades, asset regeneration or device operations were performed for this update.
## Historical inventory baseline — 2026-09-15 ## Historical inventory baseline — 2026-09-15
@@ -82,10 +82,10 @@ The installed license-path inventory also found OpenThread, NimBLE/Bluetooth, mi
| --- | --- | --- | | --- | --- | --- |
| `@xterm/xterm` | **5.5.0**; `web_assets/xterm.js`, `xterm.css`, `xterm.LICENSE`; [SOURCES.md](../web_assets/SOURCES.md) provides exact npm URLs/hashes | `MIT`. Full notice retained in repository; CSS also retains a notice. Minified JS has no `copyright`, `permission is hereby`, or `license` marker. | | `@xterm/xterm` | **5.5.0**; `web_assets/xterm.js`, `xterm.css`, `xterm.LICENSE`; [SOURCES.md](../web_assets/SOURCES.md) provides exact npm URLs/hashes | `MIT`. Full notice retained in repository; CSS also retains a notice. Minified JS has no `copyright`, `permission is hereby`, or `license` marker. |
| `@xterm/addon-fit` | **0.10.0**; `web_assets/addon-fit.js`, `addon-fit.LICENSE`; same provenance document | `MIT`. Full notice retained in repository; minified JS lacks those notice markers. | | `@xterm/addon-fit` | **0.10.0**; `web_assets/addon-fit.js`, `addon-fit.LICENSE`; same provenance document | `MIT`. Full notice retained in repository; minified JS lacks those notice markers. |
| Pictogrammers Material Design Icons | **7.4.47 according to `src/local_status_ui.c`**; `third_party/material-design-icons/usb.svg`, `wifi-strength-4.svg`, `LICENSE` | Source comments identify hand-rasterized USB and adapted Wi-Fi masks as Apache-2.0 icon derivatives. Retained license is **“Pictogrammers Free License” summary**, referring icons to Apache-2.0 or their respective licenses, code to MIT. **Not the full Apache-2.0 text or a per-icon origin record.** Version/individual-icon licensing is not independently authenticated by a local package manifest. | | Pictogrammers Material Design Icons | Official **7.4.47**, immutable commit `9e04201d4557e729822fb57f62a316c3dea1d4a8`; [exact evidence](icon_provenance.md) | Retained SVGs are byte-identical to upstream; metadata credits **Google (USB)** and **Simran (Wi-Fi)**. Apache-2.0 package evidence, full license text and a pinned-tree check finding no NOTICE are retained. Manual firmware bitmap derivation and the distinct Wi-Fi mockup path remain unresolved; source identity is not complete derivative or release clearance. |
| Project logo | `web_assets/logo.png`, derived from `images/logo.png` per SOURCES.md | Project-owned according to provenance document; no independent third-party license assigned. Generator's MIT banner must not be treated as proof that the logo was separately relicensed MIT. | | Project logo | `web_assets/logo.png`, derived from `images/logo.png` per SOURCES.md | Project-owned according to provenance document; no independent third-party license assigned. Generator's MIT banner must not be treated as proof that the logo was separately relicensed MIT. |
`git ls-files '*LICENSE*' '*COPYING*' '*NOTICE*'` found **4 tracked license files**: root GPLv3, two web MIT texts, and the icon summary. Existing `third_party/` licensing is therefore **not sufficient as a complete release notice bundle**. It also does not supply the missing full Apache text for the icon derivatives. Historical 2026-09-15 `git ls-files '*LICENSE*' '*COPYING*' '*NOTICE*'` found **4 tracked license files**: root GPLv3, two web MIT texts, and the icon summary. That historical count predates the retained upstream icon evidence and full Apache text now included in the 75-input catalog. Neither repository retention nor assembly proves recipient delivery or release compliance.
`web_assets/generate_embedded_assets.py` embeds three gzip files and the logo, **not either MIT license file**. Its generated-source banner points back to provenance/licenses; it is not the upstream MIT notice itself. This proves the embedding path does not carry the separate notice texts, not that every possible product-delivery channel lacks notices. Coordinate a release notice bundle and a way for recipients of the browser assets to obtain the notices (for example a bundled/served third-party license resource); verify the actual delivery path. Do not assume repository-only notices accompany a standalone firmware/device or a downloaded JS response. No assets or web endpoints were changed in this audit. `web_assets/generate_embedded_assets.py` embeds three gzip files and the logo, **not either MIT license file**. Its generated-source banner points back to provenance/licenses; it is not the upstream MIT notice itself. This proves the embedding path does not carry the separate notice texts, not that every possible product-delivery channel lacks notices. Coordinate a release notice bundle and a way for recipients of the browser assets to obtain the notices (for example a bundled/served third-party license resource); verify the actual delivery path. Do not assume repository-only notices accompany a standalone firmware/device or a downloaded JS response. No assets or web endpoints were changed in this audit.
@@ -139,8 +139,8 @@ Notice assembly is implemented; the remaining release actions below have not bee
| Priority | Action / completion evidence | | Priority | Action / completion evidence |
| --- | --- | | --- | --- |
| Release blocker to resolve | Document a defensible corresponding-source/exception basis for the **selected radio blobs** and other source-unavailable linked content. This is an unresolved question, not a legal verdict. | | Release blocker to resolve | Document a defensible corresponding-source/exception basis for the **selected radio blobs** and other source-unavailable linked content. This is an unresolved question, not a legal verdict. |
| Assembly tooling implemented; delivery pending | [Offline tool and procedure](release_packaging.md) assemble 62 pinned inputs, retaining GPL/Apache/MIT/BSD texts, mixed SDK/toolchain Newlib and argtable3 notices, GCC exception and a scoped full TLSF rendering. Parent fixture suite: 30 PASS; two actual bundles independently verified deterministic. Validate final firmware/device/browser recipient delivery; assembly is not corresponding-source delivery or legal clearance. | | Assembly tooling implemented; delivery pending | [Offline tool and procedure](release_packaging.md) assemble 75 pinned inputs, retaining GPL/Apache/MIT/BSD texts, mixed SDK/toolchain Newlib and argtable3 notices, GCC exception and a scoped full TLSF rendering. Supplied agent fixture suite: 36 PASS; two actual bundles independently verified deterministic, each 77 files / 4,433,930 bytes. Validate final firmware/device/browser recipient delivery; assembly is not corresponding-source delivery or legal clearance. |
| Before distributing icon derivatives | Full Apache-2.0 text is supplied in the scoped bundle via SDK LICENSE; still confirm exact two-icon provenance/licensing at 7.4.47; retain upstream attribution and any applicable NOTICE. Existing source comments already identify adaptations. Do not invent an absent upstream NOTICE or copy unrelated icon licenses. | | Before distributing icon derivatives | [Exact retained SVG provenance](icon_provenance.md) is resolved at official 7.4.47; full Apache-2.0 text and attribution are retained, with no NOTICE found in the pinned distribution. Preserve manual bitmap preferred sources and resolve the distinct mockup Wi-Fi path/derivation limits. Recipient delivery remains open; do not invent a NOTICE or rasterizer. |
| Resolved in generator; retain in distribution | Prominent modification notices cover **eight C sources plus one header** (baseline **2026-09-15**, wolfSSH ordering **2026-09-16**), with original notices retained. Release packaging must still include them, archived patches/provenance, consolidated delta and reproducible build inputs. | | Resolved in generator; retain in distribution | Prominent modification notices cover **eight C sources plus one header** (baseline **2026-09-15**, wolfSSH ordering **2026-09-16**), with original notices retained. Release packaging must still include them, archived patches/provenance, consolidated delta and reproducible build inputs. |
| Upstream clarification | Record/resolve wolfSSH 1.4.20 package LICENSE/README vs source-header mismatch without editing the managed package in place. GPLv3 is supported by the inspected headers and is also within the package prose's “or later” wording. | | Upstream clarification | Record/resolve wolfSSH 1.4.20 package LICENSE/README vs source-header mismatch without editing the managed package in place. GPLv3 is supported by the inspected headers and is also within the package prose's “or later” wording. |
| Release packaging verification | Archive exact corresponding source/build inputs and required asset preferred sources; validate source delivery/offer and any User Product installation information. Recheck bootloader, runtime objects and aggregation boundaries against the final release map. | | Release packaging verification | Archive exact corresponding source/build inputs and required asset preferred sources; validate source delivery/offer and any User Product installation information. Recheck bootloader, runtime objects and aggregation boundaries against the final release map. |
+117
View File
@@ -0,0 +1,117 @@
# Exact USB and Wi-Fi icon provenance
Reviewed 2026-09-16. This record resolves the identity of the **two retained
preferred-form SVG sources at Material Design Icons 7.4.47**, not all project
artwork, historical authorship of manual edits, or release compliance.
No firmware, mockup, web asset, or generated asset was changed or regenerated.
## Official pinned source and licenses
Official SVG distribution: <https://github.com/Templarian/MaterialDesign-SVG>.
Its upstream README identifies this as the production SVG distribution and
points to the main MaterialDesign repository for issues. The main repository
URL with tag `v7.4.47` returned 404; it is not used as version evidence.
- Distribution tag: `v7.4.47`.
- Annotated tag object: `5edde266e281d26a03dcfa89fb651183cbab0f2e`.
- Peeled commit: `9e04201d4557e729822fb57f62a316c3dea1d4a8`.
- Upstream `package.json`: `@mdi/svg`, version `7.4.47`, license `Apache-2.0`.
- Tag timestamp: `2023-12-26T23:33:26Z`; GitHub reports it **unsigned**.
HTTPS retrieval and content pins are evidence, not signature authentication.
Unmodified upstream SVGs, LICENSE, README, package metadata, complete `meta.json`,
and GitHub tag/tree responses are retained in
[`third_party/material-design-icons/upstream-7.4.47/`](../third_party/material-design-icons/upstream-7.4.47/).
`downloads.json` records exact retrieval URLs, sizes and SHA-256 hashes. Raw
source URLs use the immutable commit, not a moving branch or tag. API responses
are retained as fetched; future API formatting is not assumed stable.
The full metadata/tree files intentionally preserve the evidence behind the
per-icon selections and absence check, rather than only project-written claims.
The existing `third_party/material-design-icons/LICENSE` is byte-identical to
the pinned upstream Pictogrammers Free License summary and remains unchanged.
It distinguishes icon Apache-2.0/respective grants from code MIT terms. The
package declares Apache-2.0; the two metadata entries contain authors but no
per-icon alternate grant. This is the scoped upstream licensing evidence for
these two SVGs, not a blanket conclusion about every icon in the collection.
`upstream-7.4.47/Apache-2.0.txt` supplies the **full Apache-2.0 text**, fetched
from <https://www.apache.org/licenses/LICENSE-2.0.txt> (SHA-256
`cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30`).
It is a separately sourced license text, not a file falsely attributed to the
upstream icon tree. The retained non-truncated recursive tree has no path
containing `notice` (case-insensitive); no upstream NOTICE was found in this
pinned distribution and none is fabricated here. This does not audit unrelated
repositories or assert that a NOTICE is mandatory for every Apache work.
| Icon | Metadata attribution | Stable icon ID | First-version metadata | SVG SHA-256 |
| --- | --- | --- | --- | --- |
| `usb` | Google | `25033E0B-3AD4-414D-9972-559F2690FC1D` | `1.5.54` | `c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22` |
| `wifi-strength-4` | Simran | `41B86B22-7245-4A97-9BAA-3E9EBD44CEB0` | `2.3.50` | `89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f` |
The metadata `version` fields describe icon introduction versions, **not** a
contradiction of package 7.4.47. Matching these sources to that release does not
prove they originated in that release or were originally downloaded from it.
## Exact comparison to project derivatives
1. **Retained SVGs:** `third_party/material-design-icons/usb.svg` (403 bytes)
and `wifi-strength-4.svg` (219 bytes) are each byte-for-byte identical to the
pinned upstream originals, including every path command, coordinate, arc
flag and viewBox. Each has one path, `viewBox="0 0 24 24"`, and no transform
on the root or path. No coordinate rounding, normalization or visual-match
inference was used. The files remain unchanged.
2. **USB mockup:** `docs/phase7c_icon_mockup.svg` symbol `usb` has exactly the
upstream `d` string and 24-by-24 viewBox, without symbol/path transforms.
Its two direct use definitions are `(x,y,width,height)=(150,4,30,30)` inside
reusable `status`, and `(8,72,30,30)` on the broker page. These apply uniform
scale `30/24 = 1.25` and the stated translations. Status is instantiated in
page groups translated by `(62,98)`, `(592,98)`, `(62,438)`, `(592,438)`;
the broker use is in `(62,438)`. Thus status USB geometry maps as
`(X,Y)=(pageX+150+1.25*x, pageY+4+1.25*y)` and broker USB as
`(X,Y)=(62+8+1.25*x,438+72+1.25*y)`. CSS adds presentation fill/stroke;
this is path geometry equivalence, not pixel/rendering equivalence.
3. **Wi-Fi mockup:** symbol `wifi` in that same mockup uses a different,
segmented path starting `M1 8q11-9 22 0`. It is **not** an exact copy of
`wifi-strength-4` (which starts `M12,3C7.79,3`). No exact affine derivation
or upstream provenance for that distinct mockup path is established here.
4. **Actual firmware:** `src/local_status_ui.c` explicitly calls the USB mask
hand-rasterized and the Wi-Fi masks compact segmented adaptations. The exact
editable row bytes are:
```text
s_icon_usb: 18 3c 18 5a 3e 18 3c 18
s_icon_wifi_full: 7e 81 3c 42 18 24 00 18
s_icon_wifi_three: 00 00 3c 42 18 24 00 18
s_icon_wifi_two: 00 00 00 00 18 24 00 18
s_icon_wifi_one: 00 00 00 00 00 00 00 18
```
These manual 8-by-8 masks are not SVG coordinates or exact scaled vector
paths. No deterministic rasterizer, sampling/threshold rule or edit history
establishes an exact upstream-to-mask transform. Their declared design
provenance is supported by the now-verified retained sources, but **exact
mechanical derivation of the firmware masks remains unresolved**. Preserve
the C arrays as the preferred editable form of those manual modifications,
together with both original SVGs; do not substitute an invented generator.
The existing source comment is the adaptation notice. This dated record
documents the inspected modifications; it does not invent their edit date.
## Offline checks and release boundary
`python3 tests/release_notices/run.py` verifies the pinned source bytes and Git
blob identities, version/author metadata, catalog inclusion, exact SVG geometry,
USB mockup placement/ancestry, distinct Wi-Fi mockup path, and current manual
mask bytes. Negative checks reject coordinate and transform changes. Tests do
not regenerate artwork or claim raster equivalence.
The notice catalog retains all previous inputs and adds the two existing SVGs,
these source originals, licensing/metadata evidence and this record. The bundle
is still **not corresponding source or release clearance**. Firmware C arrays
and the full mockup remain in the project, not copied into this bounded notice
bundle; include them in a separately reviewed corresponding-source delivery
where required. Radio-blob/source-exception questions, wolfSSH packaging,
recipient notice/source delivery and other release gates remain open.
Older global inventory/packaging/memory documents describe the pre-verification
state and counts. They were intentionally not edited in this scoped task;
this record and the current catalog provide the narrower updated evidence.
+172
View File
@@ -0,0 +1,172 @@
# Phase 9 bounded host validation
`tools/validate_phase9.py` is a thin, sequential orchestrator for existing test
runners, not a new security test implementation or a Phase 9 acceptance gate.
See [security hardening](security_hardening.md) for scope, historical evidence,
and the deferred whole-phase target checklist.
## Usage
From the repository root (the script itself also resolves the root independently
of the caller's working directory):
```sh
python3 -B tools/validate_phase9.py --dry-run
python3 -B tools/validate_phase9.py
python3 -B tools/validate_phase9.py --fail-fast
python3 -B tools/validate_phase9.py --timeout 300
```
Build and OpenSSH interoperability are **independent explicit opt-ins**:
```sh
python3 -B tools/validate_phase9.py --build --build-timeout 600
python3 -B tools/validate_phase9.py --interop --timeout 300
python3 -B tools/validate_phase9.py --build --interop --dry-run
```
These examples are usage, not execution claims. `--build` runs exactly `pio run`
first; it does not upload, erase, monitor, or select another PlatformIO environment.
PlatformIO itself may download dependencies or write its normal external caches.
The caller/parent must choose whether to build and arrange any required permission
separately. No installer, permission grant, network retry, or sandbox escalation
is implemented. A failed/timed-out build skips every dependent host command to
avoid testing stale artifacts as if that build succeeded.
`--interop` adds only `--interop` to `tests/wolfssh_order_contract/run.py` (its
default single matrix). That runner uses OpenSSH and local AF_UNIX sockets, not
an IP host or device. Socket permissions and installed OpenSSH tooling must
already be available; denial is a failure, not a reason to grant permissions.
Neither option is enabled by default. No target address, credentials, arbitrary
command, or device-operation argument is accepted.
## Coverage and prerequisites
The fixed default plan contains **23 commands**; `--dry-run` prints their exact
argv vectors and timeouts without launching anything or checking prerequisites.
There is no discovery-time execution of runners (some run at import/top level).
Paths and options were inspected in their actual `run.py` implementations.
| Scope | Existing runners / modes |
|---|---|
| 9A effective crash policy | `security_build_policy --sdkconfig-header .pio/build/esp32-s3-devkitc-1-n16r8/config/sdkconfig.h` |
| 9B admission / credentials | `ssh_auth_policy`, `ssh_auth_transport`, `hidden_input` |
| 9C allocator | `ssh_memory` |
| Current seven-suite baseline | `sdk_security_overrides --build-dir .pio/build/esp32-s3-devkitc-1-n16r8`, `wolfssh_auth_contract`, `ssh_protocol_policy`, `wolf_crypto_policy`, `wolfssh_parser_contract`, `wolfssh_order_contract`, `release_notices` |
| Focused SSH/admin and HTTPS lifecycle regressions | `ssh_management`, `admin_console_boundary`, `admin_ssh_policy`, `web_admin_transport`, `web_admin_tickets`, `web_httpd_idle` |
| Web early admission, credentials and administrative lifecycle | `web_cookie_auth` default plus separate `--admin`, `--accounts`, `--ssh`, `--lifecycle` commands |
Every runner path is `tests/<name>/run.py`. Auth contract, protocol policy, and
crypto policy receive explicit `--compile-commands
.pio/build/esp32-s3-devkitc-1-n16r8/compile_commands.json` arguments. No
`--host-only`, candidate injection, or silent fallback is used. Default operation
requires an existing configured build, installed pinned SDK/managed sources,
the production toolchain and host compiler/libraries needed by these runners
(including OpenSSL development support for relevant tests). It **does not run
PlatformIO** to satisfy those requirements. Missing explicit files/executables
are `PREREQ` failures; deeper source/toolchain prerequisites are checked by the
existing runners and surface as nonzero `FAIL` results. Existing artifacts are
not proof that the current checkout has been freshly built.
The current cookie-auth runner has no `--admission` branch: the default exercises
early admission/wiping, and each selected domain mode repeats that baseline.
Unrelated display/network/UI/performance suites are intentionally excluded.
`ssh_memory` retains its documented optional installed-IDF extent-source check
as skipped (no `--idf-path` supplied); its normal allocator contracts still run.
The ordering runner's candidate `--target-contracts`, separate `--pio-adapter`
regression, and repeated interop matrices are not added implicitly. Run those
separately when their particular evidence is needed. This is a focused full
Phase 9 host regression set, not every test in the repository.
## Bounds, output, and result semantics
- Each host command has a 180-second wall-clock timeout by default; the optional
build gets 600 seconds. Both timeout flags accept finite values in `(0, 3600]`.
The fixed sequential plan bounds total child execution by the sum of its
timeouts (default 4,140 seconds), plus launch/reporting/cleanup overhead.
- POSIX process groups are required. Timeout or Ctrl-C kills the active process
group and reaps the runner; successful/failed exit also retires any remaining
group descendants. This covers normal compiler/test children, not deliberately
detached processes. Group reaping has a five-second wait bound.
- Commands use argv lists, no shell evaluation or interpolation, with stdin
closed. The child environment is copied intact except `CCACHE_DISABLE=1`;
arbitrary compiler, SDK, proxy and other caller environment settings are not
overwritten. The parent's environment is not mutated.
- stdout/stderr are inherited live. The orchestrator creates no persistent log,
JSON capture, environment dump, or secret artifact. Existing runners retain
their own temporary fixture/build behavior; forced termination can bypass
their temporary-directory cleanup. Console output is **not a redaction
guarantee**: use synthetic fixtures, review before sharing, and do not redirect
output into routine secret-bearing persistent captures. Build outputs remain
normal PlatformIO artifacts only when explicitly requested.
- `PASS` means the entire runner exited zero, not that an earlier printed PASS
line appeared. The final summary records each command's exit, timeout or
missing prerequisite. Defaults collect failures and continue independent
commands; `--fail-fast` reports remaining commands as `SKIP`. Build failure
always stops dependent commands. No selected suite is silently dropped.
- Exit 0 means all selected commands passed, or a dry-run plan was printed.
Dry-run uses `PLAN`, never `PASS`, and is not validation. Failures, timeouts,
prerequisites and dependent skips return 1; invalid CLI arguments return 2;
Ctrl-C returns 130. Optional build/interop omissions are announced separately
and do not turn a successful host run into failure.
## Orchestrator fixture tests
```sh
python3 -B tests/phase9_validation/run.py
```
Ten offline unittest groups check the exact plan/paths/strict arguments, independent
opt-ins, timeout configuration and invalid values, dry-run nonexecution, default
build/interop omission, failure collection, fail-fast and failed-build skips,
missing file/executable handling, literal argv/environment preservation,
timeout/descendant termination, and inherited streams/closed stdin. They execute
only small Python fixtures, never PlatformIO, interop, devices, or network.
## Execution record — 2026-09-16
Initial orchestrator-agent execution, under the existing sandbox without elevation (historical first run):
- `python3 -B tests/phase9_validation/run.py`: **10 tests PASS**.
- `python3 -B tools/validate_phase9.py --dry-run`: exit 0; **plan only**, no
prerequisite or suite validation.
- `python3 -B tools/validate_phase9.py`: **exit 1, 22 PASS / 1 FAIL**, no timeouts;
about 57 seconds of summed command time. Build and interop explicitly skipped.
- Direct rerun `CCACHE_DISABLE=1 python3 -B tests/admin_console_boundary/run.py`:
reproduced exit 1 at line 40, `ValueError: substring not found` for
`ssh.index("static void *ssh_malloc(")`. Earlier subtest PASS lines do not make
the runner pass. The existing runner is outside this change's ownership and
was not edited.
Passed commands: `security_build_policy`, `ssh_auth_policy`, `ssh_auth_transport`,
`hidden_input`, `ssh_memory`, **all seven current baseline suites listed above**,
`ssh_management`, `admin_ssh_policy`, `web_admin_transport`, `web_admin_tickets`,
`web_httpd_idle`, and all five selected `web_cookie_auth` modes.
Only `admin_console_boundary` failed.
No firmware build, interop, device, runtime reserve, hardware panic/recovery,
release delivery, or whole-Phase-9 acceptance result is claimed for this task.
### Follow-up supplied evidence
The owning agent corrected the stale `admin_console_boundary` source anchor;
its subsequent default orchestrator run reports **23/23 PASS**. This supersedes
the initial 22/23 host result above, without turning its early PASS lines into
a successful initial run. Final supplied parent execution now confirms:
- `CCACHE_DISABLE=1 python3 -B tools/validate_phase9.py`: **PASS 23/23**.
- `tests/phase9_validation/run.py`: **PASS 10 tests**.
No build or interop ran this turn; both remain separate opt-ins, not default
execution. Firmware source is unchanged. These are actual parent results supplied
for this record, not another execution by this documentation integration.
The supplied notice agent also reports **36 fixture tests PASS** and two actual
75-input bundles, each **77 files / 4,433,930 bytes**, verified deterministic; see
[packaging evidence](release_packaging.md). These are agent measurements, not a
new build or bundle measurement by this documentation integration.
The [finite advisory search](dependency_advisory_coverage.md) is complete for its
declared snapshot, but the [PMF-capable SoftAP blocker](wifi_security_update_plan.md)
is **not fixed**. Host success does not repair that vendor bundle, validate radio
behavior, clear distribution obligations or complete Phase 9.
+22 -7
View File
@@ -40,8 +40,10 @@ traversal, binary notice payloads and exhausted bounds fail closed. Symlinks in
input-root or output-parent ancestry are rejected too: pass real non-symlinked input-root or output-parent ancestry are rejected too: pass real non-symlinked
paths, not a convenience symlink. All input preflight completes before creating paths, not a convenience symlink. All input preflight completes before creating
output. The limits are 128 inputs, 4 MiB per input/catalog and 32 MiB cumulative output. The limits are 128 inputs, 4 MiB per input/catalog and 32 MiB cumulative
source bytes. The current catalog has 62 inputs (about 2.1 MB read and 0.51 MB source bytes. The current catalog has **75 inputs**, including the retained SVGs and pinned
copied before the generated manifest/introduction). [icon provenance evidence](icon_provenance.md). Overview documents edited in this
integration are not catalog inputs; `docs/icon_provenance.md` **is pinned**.
Coordinate any change to that record with the catalog owner; never silently repin.
An existing output file, directory (even empty) or dangling symlink is never An existing output file, directory (even empty) or dangling symlink is never
overwritten. Parent directories are not automatically created. Output uses overwritten. Parent directories are not automatically created. Output uses
@@ -58,7 +60,8 @@ checks prevent symlink traversal but are not isolation from the same OS user.
- `README.txt`: limitations and entry point for recipients. - `README.txt`: limitations and entry point for recipients.
- `inputs/project/…`: project GPL text, resolved lock, managed licenses and - `inputs/project/…`: project GPL text, resolved lock, managed licenses and
manifests, wolfSSL/wolfSSH README evidence, original wolfSSH header excerpts, manifests, wolfSSL/wolfSSH README evidence, original wolfSSH header excerpts,
xterm MIT texts and recorded provenance, icon summary, TLSF full rendering xterm MIT texts and recorded provenance, icon summary and official 7.4.47
SVG/license/metadata evidence, TLSF full rendering
and scope/provenance statement. and scope/provenance statement.
- `inputs/sdk/…`: complete scoped SDK license documents, mixed Newlib/argtable3 - `inputs/sdk/…`: complete scoped SDK license documents, mixed Newlib/argtable3
notices, radio license files, package/version identity and original source notices, radio license files, package/version identity and original source
@@ -122,15 +125,27 @@ catalog policy and test it. The runtime does not discover added notices or
packages outside its finite list; this limitation makes its reads bounded and packages outside its finite list; this limitation makes its reads bounded and
prevents opportunistic collection of user files. prevents opportunistic collection of user files.
## Supplied execution evidence — 2026-09-16
Agent results: **36 notice fixture tests PASS**, and **two actual 75-input
bundles verified deterministic**, each **77 files / 4,433,930 bytes**. These
replace the earlier 62-input / 64-file / 541,147-byte snapshot, not its historical
record. No parent rebuild or bundle reassembly was run in this documentation
turn; firmware source is unchanged. Assembly is not legal clearance or Phase 9
acceptance. The [unfixed Wi-Fi blocker](wifi_security_update_plan.md) also remains
a separate security gate; a future coherent vendor update requires catalog review.
## Separate work before distribution ## Separate work before distribution
1. Resolve or obtain qualified review of radio-blob corresponding-source or 1. Resolve or obtain qualified review of radio-blob corresponding-source or
exception basis for the actual linked firmware. Apache binary permissions exception basis for the actual linked firmware. Apache binary permissions
alone do not settle this question. No legal clearance is claimed. alone do not settle this question. No legal clearance is claimed.
2. Resolve the wolfSSH package/header discrepancy and verify exact two-icon 2. Resolve the wolfSSH package/header discrepancy and remaining icon derivative
provenance/licensing (recorded 7.4.47), including any applicable NOTICE. questions. [Exact retained SVG provenance](icon_provenance.md) is verified at
Supplying the full Apache text is not provenance verification. No icon official 7.4.47, commit `9e04201d4557e729822fb57f62a316c3dea1d4a8`: Google
assets or generated data were changed by this packaging work. USB and Simran Wi-Fi. Full Apache text is retained; no NOTICE was found in
that pinned distribution. Manual firmware bitmap derivation and the distinct
mockup Wi-Fi path remain unresolved. No artwork was regenerated.
3. Audit the final application/bootloader/runtime object set and aggregation 3. Audit the final application/bootloader/runtime object set and aggregation
boundaries. Full SDK/toolchain redistribution needs broader nested/tool/test boundaries. Full SDK/toolchain redistribution needs broader nested/tool/test
notice coverage; this is not an all-files license scanner. notice coverage; this is not an all-files license scanner.
+5 -3
View File
@@ -216,13 +216,15 @@ Staged work:
1. **9A — Crash/debug build policy and operational profiles — In progress; hardware pending.** `src/security_build_policy.c` requires `CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y` and `CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y`; rejects core-dump enable/flash/UART, panic print/halt/GDBstub, runtime GDBstub and ESP/FreeRTOS debugger-aware options. `sdkconfig.defaults` makes the baseline explicit. Development/test/production use the same build baseline, not separate PlatformIO environments. Host matrix (`python3 tests/security_build_policy/run.py`) compiles the actual guard: 17 cases plus the generated-header check passed on 2026-09-15. `pio run` passed (94,196 B linked RAM / 1,828,565 B flash); target panic/recovery tests have not run. Production readiness remains pending. 1. **9A — Crash/debug build policy and operational profiles — In progress; hardware pending.** `src/security_build_policy.c` requires `CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y` and `CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y`; rejects core-dump enable/flash/UART, panic print/halt/GDBstub, runtime GDBstub and ESP/FreeRTOS debugger-aware options. `sdkconfig.defaults` makes the baseline explicit. Development/test/production use the same build baseline, not separate PlatformIO environments. Host matrix (`python3 tests/security_build_policy/run.py`) compiles the actual guard: 17 cases plus the generated-header check passed on 2026-09-15. `pio run` passed (94,196 B linked RAM / 1,828,565 B flash); target panic/recovery tests have not run. Production readiness remains pending.
2. **9B — SSH admission and credential handling — Implemented; combined target validation deferred.** Boot-lifetime, owner-only token buckets independently bound handshakes, password/signed-key requests and unsigned probes; reconnect/restart/counter clearing do not replenish them. Existing per-slot attempt limits/currentness remain. Explicit keyboard-interactive rejection, pending-signature result fencing, secret-free admission counters, consumed admin-buffer wipes and fail-closed hidden-prompt overflow/unsupported-byte handling are implemented. Four focused suites (including 35 pinned-vendor control-flow cases), 11 related regressions and `pio run` passed on 2026-09-15: 94,340 B linked RAM / 1,829,925 B flash. Global-budget starvation remains a documented tradeoff, not a solved availability problem. 2. **9B — SSH admission and credential handling — Implemented; combined target validation deferred.** Boot-lifetime, owner-only token buckets independently bound handshakes, password/signed-key requests and unsigned probes; reconnect/restart/counter clearing do not replenish them. Existing per-slot attempt limits/currentness remain. Explicit keyboard-interactive rejection, pending-signature result fencing, secret-free admission counters, consumed admin-buffer wipes and fail-closed hidden-prompt overflow/unsupported-byte handling are implemented. Four focused suites (including 35 pinned-vendor control-flow cases), 11 related regressions and `pio run` passed on 2026-09-15: 94,340 B linked RAM / 1,829,925 B flash. Global-budget starvation remains a documented tradeoff, not a solved availability problem.
3. **9C — Library cleanup and protocol policy — Implemented; combined target validation deferred.** Exact-hash build-tree overrides correct HTTPS cleanup/leaks, HTTPD scratch failure/wiping/first-read handling, bounded SSH password parsing/wiping and server-local TLS policy without modifying installed dependencies. Secure wolfSSL allocation hooks and explicit SSH policy fail closed; early web quota probing avoids receiving already-throttled bodies. TLS1.2 ECDHE-ECDSA AES-GCM and SSH GCM/modern-KEX allowlists intentionally exclude legacy-only clients; no identity migration. Bounded password/certificate/header/destructor review is documented, not exhaustive zeroization. Final build PASS 94,340 B linked RAM / 1,831,309 B flash; focused and related host/source-contract tests passed. [Review and maintenance contract](security_library_review.md). 3. **9C — Library cleanup and protocol policy — Implemented; combined target validation deferred.** Exact-hash build-tree overrides correct HTTPS cleanup/leaks, HTTPD scratch failure/wiping/first-read handling, bounded SSH password parsing/wiping and server-local TLS policy without modifying installed dependencies. Secure wolfSSL allocation hooks and explicit SSH policy fail closed; early web quota probing avoids receiving already-throttled bodies. TLS1.2 ECDHE-ECDSA AES-GCM and SSH GCM/modern-KEX allowlists intentionally exclude legacy-only clients; no identity migration. Bounded password/certificate/header/destructor review is documented, not exhaustive zeroization. Final build PASS 94,340 B linked RAM / 1,831,309 B flash; focused and related host/source-contract tests passed. [Review and maintenance contract](security_library_review.md).
4. **9D — Maintenance and lifecycle — In progress; unresolved security and distribution questions.** [Security operations](security_operations.md) documents provisioning, explicit saves, rotation, recovery, reconstruction (no implemented backup/export) and approved destructive reset/decommissioning. The [wolfSSL/wolfSSH implementation addendum](wolf_security_review.md) records the implemented Xtensa small X25519/Ed25519 mitigation (CVE-2025-12888), with consistent library/consumer flags and a resolved-settings guard; small X25519 is not combined with blinding. Bounded IGNORE/service/string parsing, channel-window overflow, ECC/Ed25519 labels and exact signature framing are now corrected in the existing generated override. [P-256 import and X25519 all-zero-result checks](ssh_key_validation_review.md) are enabled with effective PUBLIC flags confirmed; the [finite remaining SSH parser/caller review](ssh_parser_remaining_review.md) is complete, not exhaustive safety. Exact CHANNEL_FAILURE recipient, `ssh-userauth` service and all nine channel-name checks are implemented; unknown/trailing-payload behavior is retained. PR899 client skips remain unchanged behind server ordering, forwarding is disabled, and the inspected generic caller trace has no short-digest/OID trigger; generic APIs are not globally fixed. **Restricted existing-profile ordering correction (CVE-2025-14942) is implemented**, using audited PR793/819/840/855/921 subsets plus local gates, not a full upstream backport. X25519/P-256 only, independent SELF/PEER bits, expected-message/authentication gates and queued NEWKEYS continuation handle nonblocking writes. **EXT_INFO is intentionally disabled; no `server-sig-algs` is advertised.** Eight C overrides plus one PUBLIC forced ABI header retain hash pins/notices; joined forced-header arguments fix PlatformIO sorting/deduplication. The review's misplaced EOF guard is corrected and verified with no scoped blocker. The [IDF implementation addendum](idf_security_review.md) records pinned DHCP (CVE-2026-45160), TLS 1.2 EMS (CVE-2026-50581) and X.509 allocation-failure (CVE-2026-34874) backports; historical research remains labeled and retained. The [finite IDF applicability completion](idf_security_review.md#finite-applicability-completion--2026-09-16) dispositions all six named findings: ECDH small-output, zero-length ECC PK parse, basicConstraints, server NewSessionTicket and stale ASN.1 length are not current paths/configurations for their documented reasons; optimized ECC reduction is active but its privileged-local/physical side-channel attacker model is excluded. No new current-path correction was established. Only the first advisory-index page was screened; unpatched primitives and broader coverage remain, not “all CVEs safe.” 4. **9D — Maintenance and lifecycle — In progress; unresolved security and distribution questions.** [Security operations](security_operations.md) documents provisioning, explicit saves, rotation, recovery, reconstruction (no implemented backup/export) and approved destructive reset/decommissioning. The [wolfSSL/wolfSSH implementation addendum](wolf_security_review.md) records the implemented Xtensa small X25519/Ed25519 mitigation (CVE-2025-12888), with consistent library/consumer flags and a resolved-settings guard; small X25519 is not combined with blinding. Bounded IGNORE/service/string parsing, channel-window overflow, ECC/Ed25519 labels and exact signature framing are now corrected in the existing generated override. [P-256 import and X25519 all-zero-result checks](ssh_key_validation_review.md) are enabled with effective PUBLIC flags confirmed; the [finite remaining SSH parser/caller review](ssh_parser_remaining_review.md) is complete, not exhaustive safety. Exact CHANNEL_FAILURE recipient, `ssh-userauth` service and all nine channel-name checks are implemented; unknown/trailing-payload behavior is retained. PR899 client skips remain unchanged behind server ordering, forwarding is disabled, and the inspected generic caller trace has no short-digest/OID trigger; generic APIs are not globally fixed. **Restricted existing-profile ordering correction (CVE-2025-14942) is implemented**, using audited PR793/819/840/855/921 subsets plus local gates, not a full upstream backport. X25519/P-256 only, independent SELF/PEER bits, expected-message/authentication gates and queued NEWKEYS continuation handle nonblocking writes. **EXT_INFO is intentionally disabled; no `server-sig-algs` is advertised.** Eight C overrides plus one PUBLIC forced ABI header retain hash pins/notices; joined forced-header arguments fix PlatformIO sorting/deduplication. The review's misplaced EOF guard is corrected and verified with no scoped blocker. The [IDF implementation addendum](idf_security_review.md) records pinned DHCP (CVE-2026-45160), TLS 1.2 EMS (CVE-2026-50581) and X.509 allocation-failure (CVE-2026-34874) backports; historical research remains labeled and retained. The [finite IDF applicability completion](idf_security_review.md#finite-applicability-completion--2026-09-16) dispositions all six named findings: ECDH small-output, zero-length ECC PK parse, basicConstraints, server NewSessionTicket and stale ASN.1 length are not current paths/configurations for their documented reasons; optimized ECC reduction is active but its privileged-local/physical side-channel attacker model is excluded. No new current-path correction was established. That earlier review screened only the first advisory-index page. The subsequent [finite dependency coverage](dependency_advisory_coverage.md) accounts for all **22 IDF entries across three pages**, plus named managed-component and browser publication channels. The declared dated search is complete, not exhaustive advisory clearance; unpatched primitives, inaccessible full-release databases and fresh findings remain.
**Latest integration evidence:** supplied parent build PASS: **94,340 B linked RAM / 1,768,901 B flash**, unchanged RAM / **+200 B flash** versus 1,768,701 B. Final parent **all seven suites PASS**: ordering `--interop` (8,028 checks, seven rejected mutations, 12 exact-256-KiB sessions with clean channel close/transport EOF), SDK overrides with actual `--build-dir` registration, auth (135), protocol, strict crypto, notices (30), and parser (3,258 × two modes plus channel profiles; 11 + 18 + 2 rejected mutations). Interop required unsandboxed approval only for local AF_UNIX sockets; no remote network/device operation. Agent ordering evidence: **8,028 checks / seven rejected mutations**. Initial interop failed a harness close race despite early PASS output; the corrected harness waits for peer close/transport EOF and independently reaps the server through an fd-passing proxy. Final agent repeated OpenSSH matrix: **36/36 sessions**, each exact **256 KiB**, **two or ten** completed key exchanges and clean client/server exits; see [evidence and limits](security_hardening.md#ordering-hostbuild-evidence--2026-09-16). **Latest integration evidence:** supplied parent build PASS: **94,340 B linked RAM / 1,768,901 B flash**, unchanged RAM / **+200 B flash** versus 1,768,701 B. Final parent **all seven suites PASS**: ordering `--interop` (8,028 checks, seven rejected mutations, 12 exact-256-KiB sessions with clean channel close/transport EOF), SDK overrides with actual `--build-dir` registration, auth (135), protocol, strict crypto, notices (30), and parser (3,258 × two modes plus channel profiles; 11 + 18 + 2 rejected mutations). Interop required unsandboxed approval only for local AF_UNIX sockets; no remote network/device operation. Agent ordering evidence: **8,028 checks / seven rejected mutations**. Initial interop failed a harness close race despite early PASS output; the corrected harness waits for peer close/transport EOF and independently reaps the server through an fd-passing proxy. Final agent repeated OpenSSH matrix: **36/36 sessions**, each exact **256 KiB**, **two or ten** completed key exchanges and clean client/server exits; see [evidence and limits](security_hardening.md#ordering-hostbuild-evidence--2026-09-16).
**Release status:** the [bounded license inventory](dependency_licenses.md) marks modification/date notices resolved for all eight generated C files plus one header (baseline 2026-09-15 and wolfSSH ordering 2026-09-16; upstream licenses retained), with archived patch hashes/commits and patch license context recorded, but radio-blob corresponding-source/exception, source/notice delivery and provenance questions remain open. [Offline notice assembly](release_packaging.md) is implemented by [tools/release_notices.py](../tools/release_notices.py): 62 mandatory hash/size-pinned inputs, deterministic bounded outputs, fail-closed preflight and no overwrite/fetch/build/device access. Parent notices suite: 30 PASS. Supplied independent review found no actionable scoped parser/bundle defects and verified two actual 62-input bundles were deterministic. The previously measured actual bundle was 64 files / 541,147 bytes; that is snapshot evidence, not a newly measured bundle size or legal clearance. **Release status:** the [bounded license inventory](dependency_licenses.md) marks modification/date notices resolved for all eight generated C files plus one header (baseline 2026-09-15 and wolfSSH ordering 2026-09-16; upstream licenses retained), with archived patch hashes/commits and patch license context recorded, but radio-blob corresponding-source/exception, source/notice delivery and provenance questions remain open. [Offline notice assembly](release_packaging.md) is implemented by [tools/release_notices.py](../tools/release_notices.py): 75 mandatory hash/size-pinned inputs, deterministic bounded outputs, fail-closed preflight and no overwrite/fetch/build/device access. Supplied agent evidence: **36 notice fixture tests PASS; two actual bundles verified deterministic, each 77 files / 4,433,930 bytes**. This includes retained SVGs and [exact icon provenance](icon_provenance.md), not corresponding-source delivery or legal clearance. These are agent measurements, not a parent rebuild or reassembly in this documentation turn.
**Remaining maintenance/target gates:** official registry wolfSSH 1.5.0 / wolfSSL 5.9.2 queries returned 404 on 2026-09-15; upstream tags exist but managed compatibility is not established. The [remaining ordering gates and immutable provenance](wolf_security_review.md#restricted-ordering-correction-and-remaining-gates) retain target cleanup during rekey, intended-client compatibility without EXT_INFO and whole-phase resource/timing validation. Future upstream adoption still requires isolated packaging/compatibility evaluation. Upgrades/backports require coherent source/header review, override rebasing and contract tests, not blind repinning. Broader dependency advisory coverage remains unfinished. No dependency upgrade was performed. **Phase 9 is not complete or production-ready; scoped mitigations do not establish full advisory closure, device validation or license/distribution clearance.** OTA signing trust remains separate Phase 10 work. **Remaining maintenance/target gates:** official registry wolfSSH 1.5.0 / wolfSSL 5.9.2 queries returned 404 on 2026-09-15; upstream tags exist but managed compatibility is not established. The [remaining ordering gates and immutable provenance](wolf_security_review.md#restricted-ordering-correction-and-remaining-gates) retain target cleanup during rekey, intended-client compatibility without EXT_INFO and whole-phase resource/timing validation. Future upstream adoption still requires isolated packaging/compatibility evaluation. Upgrades/backports require coherent source/header review, override rebasing and contract tests, not blind repinning. The [declared finite dependency search](dependency_advisory_coverage.md) is complete; fresh findings and explicit coverage gaps remain. **Current PMF-capable SoftAP security blocker: not fixed.** Follow the [Wi-Fi security update plan](wifi_security_update_plan.md): select a coherent vendor framework/toolchain and source/header/binary ABI bundle, rebase exact security overrides and validate on target; do not transplant one archive, edit only the callback signature or weaken PMF/WPA3. No dependency upgrade was performed. **Phase 9 is not complete or production-ready; scoped mitigations do not establish full advisory closure, device validation or license/distribution clearance.** OTA signing trust remains separate Phase 10 work.
**Bounded host validation:** [tools/validate_phase9.py](../tools/validate_phase9.py) orchestrates **23 commands** by default, with no build or OpenSSH interop unless separately opted in. The stale console-boundary anchor was fixed by its owning agent; supplied follow-up agent result is **23/23 PASS**. Final supplied parent execution: `CCACHE_DISABLE=1 python3 -B tools/validate_phase9.py` **PASS 23/23**; `tests/phase9_validation/run.py` **PASS 10 tests**. No build or interop ran this turn. See [usage and execution boundaries](phase9_validation.md). No parent rebuild this turn; firmware source is unchanged. Historical build/interop results above are not fresh target or release evidence.
At the user's request, hardware validation is deferred to **Phase 9 as a whole**, not required between implementation slices. [Security hardening](security_hardening.md) collects profiles, host evidence and the combined target checklist. Silent panic reboot removes useful crash diagnostics, not ordinary reset/boot/status information or every possible log disclosure. Raw flash/RAM/dumps remain secret-bearing, not routine diagnostic exports. Existing coredump bytes are not retroactively cleared; no secure erase is claimed. Isolated synthetic-secret debug builds require explicit reviewed source-policy changes, not a provided bypass flag. At the user's request, hardware validation is deferred to **Phase 9 as a whole**, not required between implementation slices. [Security hardening](security_hardening.md) collects profiles, host evidence and the combined target checklist. Silent panic reboot removes useful crash diagnostics, not ordinary reset/boot/status information or every possible log disclosure. Raw flash/RAM/dumps remain secret-bearing, not routine diagnostic exports. Existing coredump bytes are not retroactively cleared; no secure erase is claimed. Isolated synthetic-secret debug builds require explicit reviewed source-policy changes, not a provided bypass flag.
+7 -5
View File
@@ -106,8 +106,8 @@ The existing global five-verifications/60-second fixed window is unchanged: malf
- [Security operations](security_operations.md) supplies source-checked provisioning, explicit-save, account/key/identity rotation, recovery, reconstruction and approved erase/decommissioning procedures. There is no implemented configuration backup/export or private-identity restore workflow. Commands and checklists are not device execution evidence; the user will validate Phase 9 as a whole. - [Security operations](security_operations.md) supplies source-checked provisioning, explicit-save, account/key/identity rotation, recovery, reconstruction and approved erase/decommissioning procedures. There is no implemented configuration backup/export or private-identity restore workflow. Commands and checklists are not device execution evidence; the user will validate Phase 9 as a whole.
- [wolfSSL/wolfSSH review and implementation addendum](wolf_security_review.md): the **CVE-2025-12888** Xtensa mitigation now selects `CURVE25519_SMALL` and `ED25519_SMALL` consistently for wolfSSL and consumers. The PUBLIC forced-include resolved-settings guard rejects missing small implementations, X25519 blinding (incompatible with small in this pinned version), and unreviewed Curve448/Ed448 enablement. The existing generated wolfSSH override now bounds IGNORE/service strings, rejects zero-capacity string output and channel-window overflow, corrects ECC/Ed25519 key/signature labels, and enforces exact signature framing (ECC nested r/s bounds plus inner/outer consumption; Ed25519 outer consumption). These are PR892/881/880 subsets plus local framing corrections, not full backports; password wiping/async retention remain unchanged. PUBLIC `WOLFSSL_VALIDATE_ECC_IMPORT` and `WOLFSSL_ECDHX_SHARED_NOT_ZERO` now enable P-256 import validation and X25519 all-zero-result rejection, with effective production flags confirmed and fail-closed backend guards. See [key-validation evidence](ssh_key_validation_review.md) and [parser scope/limits](../tests/wolfssh_parser_contract/README.md). The restricted existing-profile correction for **CVE-2025-14942** is implemented as described below. The [finite remaining SSH review](ssh_parser_remaining_review.md) is complete: bounded exact CHANNEL_FAILURE recipient parsing (fatal policy retained), exact `ssh-userauth` service validation, and exact length/byte dispatch for all nine channel-request names are implemented. Unknown-request/trailing-payload behavior is preserved. PR899 client key skips are unchanged and blocked by current server role/ordering; PR918/919 forwarding is disabled. The inspected generic signature caller trace found no attacker-selected short-digest/OID path; generic APIs remain unpatched. These are profile-specific dispositions, not exhaustive parser/library safety; revisit on caller, feature, KEX or source changes. No exploit or whole-library clearance is demonstrated; added validation CPU/allocation cost and target interoperability remain unmeasured. - [wolfSSL/wolfSSH review and implementation addendum](wolf_security_review.md): the **CVE-2025-12888** Xtensa mitigation now selects `CURVE25519_SMALL` and `ED25519_SMALL` consistently for wolfSSL and consumers. The PUBLIC forced-include resolved-settings guard rejects missing small implementations, X25519 blinding (incompatible with small in this pinned version), and unreviewed Curve448/Ed448 enablement. The existing generated wolfSSH override now bounds IGNORE/service strings, rejects zero-capacity string output and channel-window overflow, corrects ECC/Ed25519 key/signature labels, and enforces exact signature framing (ECC nested r/s bounds plus inner/outer consumption; Ed25519 outer consumption). These are PR892/881/880 subsets plus local framing corrections, not full backports; password wiping/async retention remain unchanged. PUBLIC `WOLFSSL_VALIDATE_ECC_IMPORT` and `WOLFSSL_ECDHX_SHARED_NOT_ZERO` now enable P-256 import validation and X25519 all-zero-result rejection, with effective production flags confirmed and fail-closed backend guards. See [key-validation evidence](ssh_key_validation_review.md) and [parser scope/limits](../tests/wolfssh_parser_contract/README.md). The restricted existing-profile correction for **CVE-2025-14942** is implemented as described below. The [finite remaining SSH review](ssh_parser_remaining_review.md) is complete: bounded exact CHANNEL_FAILURE recipient parsing (fatal policy retained), exact `ssh-userauth` service validation, and exact length/byte dispatch for all nine channel-request names are implemented. Unknown-request/trailing-payload behavior is preserved. PR899 client key skips are unchanged and blocked by current server role/ordering; PR918/919 forwarding is disabled. The inspected generic signature caller trace found no attacker-selected short-digest/OID path; generic APIs remain unpatched. These are profile-specific dispositions, not exhaustive parser/library safety; revisit on caller, feature, KEX or source changes. No exploit or whole-library clearance is demonstrated; added validation CPU/allocation cost and target interoperability remain unmeasured.
- [Focused IDF review and implementation addendum](idf_security_review.md): pinned backports now implement DHCP option bounds (**CVE-2026-45160**), TLS 1.2 EMS failure return (**CVE-2026-50581**) and X.509 OID allocation-failure handling (**CVE-2026-34874**). Explicit nested-target validation places the mbedTLS edits on `mbedtls`/`mbedx509`, retaining source properties and exactly-one-source checks. WS negotiation **CVE-2026-45541** and ASN.1 named-data **CVE-2025-48965** remain unpatched with the review's qualified applicability, not blanket closure. The [finite IDF applicability completion](idf_security_review.md#finite-applicability-completion--2026-09-16) dispositions all six named findings: ECDH small-output, zero-length ECC PK parse, basicConstraints, server NewSessionTicket and stale ASN.1 length are not current paths/configurations for their documented reasons; optimized ECC reduction is active but its privileged-local/physical side-channel attacker model is excluded. No new current-path correction was established. Only the first advisory-index page was screened; unpatched primitives and broader coverage remain, not “all CVEs safe.” - [Focused IDF review and implementation addendum](idf_security_review.md): pinned backports now implement DHCP option bounds (**CVE-2026-45160**), TLS 1.2 EMS failure return (**CVE-2026-50581**) and X.509 OID allocation-failure handling (**CVE-2026-34874**). Explicit nested-target validation places the mbedTLS edits on `mbedtls`/`mbedx509`, retaining source properties and exactly-one-source checks. WS negotiation **CVE-2026-45541** and ASN.1 named-data **CVE-2025-48965** remain unpatched with the review's qualified applicability, not blanket closure. The [finite IDF applicability completion](idf_security_review.md#finite-applicability-completion--2026-09-16) dispositions all six named findings: ECDH small-output, zero-length ECC PK parse, basicConstraints, server NewSessionTicket and stale ASN.1 length are not current paths/configurations for their documented reasons; optimized ECC reduction is active but its privileged-local/physical side-channel attacker model is excluded. No new current-path correction was established. That earlier review screened only the first advisory-index page. The subsequent [finite dependency coverage](dependency_advisory_coverage.md) accounts for all **22 IDF entries across three pages**, plus named managed-component and browser publication channels. The declared dated search is complete, not exhaustive advisory clearance; unpatched primitives, inaccessible full-release databases and fresh findings remain.
- [Dependency license inventory](dependency_licenses.md) is a bounded engineering inventory, not legal or distribution clearance. All **eight generated C sources plus one header** carry prominent modification notices: the baseline **2026-09-15** notice plus **2026-09-16** ordering/provenance notices on wolfSSH outputs, with upstream notices retained, including both mbedTLS dual-license headers. That narrow finding is resolved. Radio-blob corresponding-source/exception questions, actual firmware/device/browser notice delivery, preferred-source packaging, wolfSSH package-license discrepancy and exact icon provenance and recipient license delivery remain open. Notice assembly does not prove recipient delivery. [Offline notice assembly](release_packaging.md) is implemented by [tools/release_notices.py](../tools/release_notices.py): 62 mandatory hash/size-pinned inputs, deterministic bounded outputs, fail-closed preflight and no overwrite/fetch/build/device access. Parent notices suite: 30 PASS. Supplied independent review found no actionable scoped parser/bundle defects and verified two actual 62-input bundles were deterministic. The previously measured actual bundle was 64 files / 541,147 bytes; that is snapshot evidence, not a newly measured bundle size or legal clearance. - [Dependency license inventory](dependency_licenses.md) is a bounded engineering inventory, not legal or distribution clearance. All **eight generated C sources plus one header** carry prominent modification notices: the baseline **2026-09-15** notice plus **2026-09-16** ordering/provenance notices on wolfSSH outputs, with upstream notices retained, including both mbedTLS dual-license headers. That narrow finding is resolved. Radio-blob corresponding-source/exception questions, actual firmware/device/browser notice delivery, preferred-source packaging, wolfSSH package-license discrepancy and manual bitmap derivation, the distinct mockup Wi-Fi path and recipient license delivery remain open; [exact retained SVG provenance](icon_provenance.md) is resolved. Notice assembly does not prove recipient delivery. [Offline notice assembly](release_packaging.md) is implemented by [tools/release_notices.py](../tools/release_notices.py): 75 mandatory hash/size-pinned inputs, deterministic bounded outputs, fail-closed preflight and no overwrite/fetch/build/device access. Supplied agent evidence: **36 notice fixture tests PASS; two actual bundles verified deterministic, each 77 files / 4,433,930 bytes**. This includes retained SVGs and [exact icon provenance](icon_provenance.md), not corresponding-source delivery or legal clearance. These are agent measurements, not a parent rebuild or reassembly in this documentation turn.
- **Restricted ordering correction implemented, not a full upstream backport or sign-off.** The [ordering review](wolf_security_review.md#restricted-ordering-correction-and-remaining-gates) and [provenance/prerequisite disposition](../tools/wolfssh_order/README.md) document the audited PR793/819/840/855/921 subsets plus local gates. Existing X25519/P-256 KEX only; independent SELF/PEER state, exact expected replies and authentication-phase checks cover both roles. Queued NEWKEYS survives WANT_WRITE without duplication. **EXT_INFO is deliberately disabled; no `server-sig-algs` is sent**, and `extInfoSent` stays zero. CMake applies the generated ABI header BEFORE PUBLIC and via a PUBLIC forced include; joined `-include/path` flags fix PlatformIO sorting/deduplication for ordering and crypto guards. Review's misplaced EOF guard is corrected before channel mutation; verification found no scoped blocker. Target cleanup during rekey and no-EXT_INFO client compatibility remain pending. - **Restricted ordering correction implemented, not a full upstream backport or sign-off.** The [ordering review](wolf_security_review.md#restricted-ordering-correction-and-remaining-gates) and [provenance/prerequisite disposition](../tools/wolfssh_order/README.md) document the audited PR793/819/840/855/921 subsets plus local gates. Existing X25519/P-256 KEX only; independent SELF/PEER state, exact expected replies and authentication-phase checks cover both roles. Queued NEWKEYS survives WANT_WRITE without duplication. **EXT_INFO is deliberately disabled; no `server-sig-algs` is sent**, and `extInfoSent` stays zero. CMake applies the generated ABI header BEFORE PUBLIC and via a PUBLIC forced include; joined `-include/path` flags fix PlatformIO sorting/deduplication for ordering and crypto guards. Review's misplaced EOF guard is corrected before channel mutation; verification found no scoped blocker. Target cleanup during rekey and no-EXT_INFO client compatibility remain pending.
- No dependency versions were upgraded. Beyond the implemented backports above, proposed upgrades/backports remain candidates, not approved compatible versions. Re-audit coherent source/header changes, effective compile policy, exact-hash overrides and callback/parser contracts, then obtain host/build and whole-phase target evidence. 9A9C passes below are historical scoped evidence, not closure of these newly recorded findings. - No dependency versions were upgraded. Beyond the implemented backports above, proposed upgrades/backports remain candidates, not approved compatible versions. Re-audit coherent source/header changes, effective compile policy, exact-hash overrides and callback/parser contracts, then obtain host/build and whole-phase target evidence. 9A9C passes below are historical scoped evidence, not closure of these newly recorded findings.
@@ -206,13 +206,15 @@ Retain these checks for the user's final whole-phase test session; do not stop i
4. Repeatedly start/stop HTTPS and SSH and stress header parsing/authentication under the full transport mix. Capture internal/DMA/PSRAM free/minimum/largest-block and stack margins alongside serial/broker loss counters. Specifically measure old-plus-new allocation peaks and secure-free CPU cost; previous very low internal minima remain important. 4. Repeatedly start/stop HTTPS and SSH and stress header parsing/authentication under the full transport mix. Capture internal/DMA/PSRAM free/minimum/largest-block and stack margins alongside serial/broker loss counters. Specifically measure old-plus-new allocation peaks and secure-free CPU cost; previous very low internal minima remain important.
5. Verify exhausted web login returns early without stalled-body work, clears the used pre-login challenge, and recovers after the documented window. Check malformed requests below quota and correct credentials for normal behavior; do not infer fairness from a rate-limit pass. 5. Verify exhausted web login returns early without stalled-body work, clears the used pre-login challenge, and recovers after the documented window. Check malformed requests below quota and correct credentials for normal behavior; do not infer fairness from a rate-limit pass.
**Bounded host validation:** [tools/validate_phase9.py](../tools/validate_phase9.py) orchestrates **23 commands** by default, with no build or OpenSSH interop unless separately opted in. The stale console-boundary anchor was fixed by its owning agent; supplied follow-up agent result is **23/23 PASS**. Final supplied parent execution: `CCACHE_DISABLE=1 python3 -B tools/validate_phase9.py` **PASS 23/23**; `tests/phase9_validation/run.py` **PASS 10 tests**. No build or interop ran this turn. See [usage and execution boundaries](phase9_validation.md). No parent rebuild this turn; firmware source is unchanged. Historical build/interop results above are not fresh target or release evidence.
## Staged next work ## Staged next work
- **Implementation/maintenance gate:** the finite SSH and six-finding IDF reviews are complete for their stated profiles; do not re-list them as unimplemented. Finish broader advisory coverage and resolve any newly established current-path findings with pinned changes and fresh production-source tests. Optional ASN.1/ECDH/basicConstraints defense-in-depth backports are not implemented or required by a demonstrated current-path finding. - **Implementation/maintenance gate:** the finite SSH and six-finding IDF reviews are complete for their stated profiles; do not re-list them as unimplemented. The [declared finite advisory search](dependency_advisory_coverage.md) is complete. Resolve the **unfixed PMF-capable SoftAP security blocker** through the [coherent vendor framework/ABI update plan](wifi_security_update_plan.md), retaining PMF/WPA3, exact override guards and fresh production-source/target tests. Residual direct-SDK AES-DMA applicability and publication-channel gaps remain; recheck the bounded snapshot before release. Optional ASN.1/ECDH/basicConstraints defense-in-depth backports are not implemented or required by a demonstrated current-path finding.
- **Release gate:** notice assembly is implemented; validate actual firmware/device/browser delivery, corresponding source and preferred asset sources, radio-blob legal basis, wolfSSH packaging clarification, exact icon provenance, final runtime/bootloader attribution and any Installation Information. See [packaging gates](release_packaging.md#separate-work-before-distribution). - **Release gate:** notice assembly is implemented; validate actual firmware/device/browser delivery, corresponding source and preferred asset sources, radio-blob legal basis, wolfSSH packaging clarification, remaining manual bitmap/mockup provenance, final runtime/bootloader attribution and any Installation Information. See [packaging gates](release_packaging.md#separate-work-before-distribution).
- **Target/acceptance gate:** rehearse operations and the combined target checklist above, including panic/recovery, abuse/isolation, cleanup during rekey, intended-client compatibility without EXT_INFO, loaded KEX/rekey and heap/stack/CPU timing. Obtain explicit whole-phase acceptance; no scoped reviewer or host PASS can substitute. - **Target/acceptance gate:** rehearse operations and the combined target checklist above, including panic/recovery, abuse/isolation, cleanup during rekey, intended-client compatibility without EXT_INFO, loaded KEX/rekey and heap/stack/CPU timing. Obtain explicit whole-phase acceptance; no scoped reviewer or host PASS can substitute.
- **Continue 9D maintenance and lifecycle.** Execute the [remaining ordering gates and advisory work](wolf_security_review.md#restricted-ordering-correction-and-remaining-gates), finish broader dependency coverage beyond the bounded IDF/mbedTLS review and three implemented backports, and address the [release source/notice work](dependency_licenses.md#actionable-release-work-not-performed). Runbooks are documented, not rehearsed; remaining mitigations/reviews, distribution clearance and whole-phase acceptance remain outstanding. - **Continue 9D maintenance and lifecycle.** Execute the [remaining ordering gates and advisory work](wolf_security_review.md#restricted-ordering-correction-and-remaining-gates), implement and validate the coherent Wi-Fi correction identified by the completed finite dependency search, and revisit its explicit residual questions, and address the [release source/notice work](dependency_licenses.md#actionable-release-work-not-performed). Runbooks are documented, not rehearsed; remaining mitigations/reviews, distribution clearance and whole-phase acceptance remain outstanding.
- **Retained evidence limits:** 9C completes a bounded cleanup/protocol review, not every-library-copy zeroization. Live inline residue, compaction tails, hardware/stack intermediates, global admission starvation and resource/interop measurements remain documented limitations or combined target gates. Any additional hardening must preserve owner lifetimes and bounded recovery. - **Retained evidence limits:** 9C completes a bounded cleanup/protocol review, not every-library-copy zeroization. Live inline residue, compaction tails, hardware/stack intermediates, global admission starvation and resource/interop measurements remain documented limitations or combined target gates. Any additional hardening must preserve owner lifetimes and bounded recovery.
- **Phase 10: OTA trust.** Define independent image-signature verification, trust-anchor provisioning, rotation/revocation, rollback/downgrade and recovery policy without secure boot. Authenticated transport alone is not image-signing policy, and OTA signature checks cannot prevent physical firmware replacement. - **Phase 10: OTA trust.** Define independent image-signature verification, trust-anchor provisioning, rotation/revocation, rollback/downgrade and recovery policy without secure boot. Authenticated transport alone is not image-signing policy, and OTA signature checks cannot prevent physical firmware replacement.
+129
View File
@@ -0,0 +1,129 @@
# Wi-Fi management-frame security update plan
Review date: **2026-09-16**. Focused documentation-only follow-up to [dependency advisory coverage](dependency_advisory_coverage.md#new-release-note-finding-wi-fi-management-frame-corruption). **No correction implemented, exploit reproduced, build run, device accessed, or upgrade approved.** This document is the only file owned/created by this review; existing concurrent work is untouched.
## Decision
**Prefer a complete, immutable Espressif IDF 5.5 maintenance-release bundle, integrated through a compatible pinned PlatformIO package/toolchain, over transplanting Wi-Fi archives into IDF 5.5.0.** IDF **5.5.3 is the verified fix-bearing reference candidate/minimum demonstrated release here**, not a recommendation to deploy it in preference to all later maintenance releases. The earlier coverage records 5.5.4/5.5.5; selecting a newer deployment candidate requires the same immutable provenance and compatibility gates below, not a repeat broad advisory audit.
Do not change PMF/WPA3 policy as an automatic mitigation. Do not replace only `libnet80211.a`, edit only a callback declaration, relax source guards, or overwrite the installed SDK. Current PMF-capable SoftAP exposure remains open pending implementation and target validation.
## Current applicability and trigger limits
Rechecked authoritative source `src/wifi_manager.c:315363`:
- SoftAP uses `WIFI_AUTH_WPA2_WPA3_PSK`, four clients, `pmf_cfg.capable=true`, `required=false`, `WPA3_SAE_PWE_BOTH`. AP/APSTA are real supported paths, including live fallback transitions (`set_runtime_ap_enabled`). Optional PMF is **not PMF disabled**.
- Station uses PMF capability in both profiles; mixed has WPA2 minimum/optional PMF, WPA3 requires PMF. Do not downgrade station profiles to address a demonstrated SoftAP trigger.
- Existing generated `sdkconfig.h` identifies ESP32-S3 and enables SoftAP, WPA3 SAE, SoftAP SAE, SAE H2E and SAE-PK support. This is build metadata, not proof of a running device's current mode or negotiated association.
- Architecture: the permanent Wi-Fi manager owns driver operations and bounded events; application NVS is authoritative, driver storage is RAM-only, AP policy is off/fallback/always. Working edits require explicit save. Preserve manager ownership, secret wiping and secret-free status. UART0 recovery and native USB UART1 access must remain independent of network success. Broker single-writer/multiple-isolated-observer behavior is unchanged.
The official contained fix says that when the supplicant sends an **authentication response for an already-connected station, with keys installed after a successful four-way handshake**, management encryption was selected from `bss->pmf_enable` without checking whether the frame was robust. The encryption code assumed header space that had not been allocated, causing memory corruption. The fix checks robust-management-frame status before encryption.
This supports a current-feature exposure candidate when SoftAP is active with the relevant station/key/PMF state. Radio delivery of the relevant management exchange, rather than application HTTPS/SSH authentication, is the pertinent access path (inference from the described Wi-Fi operation). The public text does **not** establish whether an attacker must know the PSK, personally complete association, or can spoof an existing station's exchange. It supplies no packet-level proof, CVSS, reliable arbitrary-code-execution claim, or exhaustive affected-mode matrix. Do not characterize this as proven unauthenticated remote exploitation, nor assume application login protects it. STA-only exclusion is limited to the described AP-response path, not a blanket clean bill for the opaque bundle.
The same vendor change also fixes an RSN-IE length/allocation mismatch, deauthentication-reason parsing, and default SAE PWE values. The project's short configured IE set has not been shown to trigger the allocation issue; do not conflate that uncertainty with the established old ABI/bundle identity.
## Official immutable provenance
Official sources fetched in this review:
1. [5.5.3 release](https://github.com/espressif/esp-idf/releases/tag/v5.5.3), also [release API](https://api.github.com/repos/espressif/esp-idf/releases/tags/v5.5.3): explicitly names the management-frame memory-corruption correction under `a3927641`.
2. [Merge commit](https://github.com/espressif/esp-idf/commit/a3927641bfd0aedfaab3514cba3d7fb01378ce4d), checked through its official commit API: **`a3927641bfd0aedfaab3514cba3d7fb01378ce4d`**. Its title emphasizes SAE defaults; the title alone omits the security detail.
3. [Contained fix patch](https://github.com/espressif/esp-idf/commit/caf4cad3b422be5c2f93afeff4cd07796a262b46.patch): **`caf4cad3b422be5c2f93afeff4cd07796a262b46`**, “Backport some wifi fixes,” with the trigger explanation. This is the merge's second parent, not a conflicting identification.
4. [Annotated release tag object](https://api.github.com/repos/espressif/esp-idf/git/tags/b31fcc7a314a44ad992b58f589f7d1d8a4fadff6): tag object **`b31fcc7a314a44ad992b58f589f7d1d8a4fadff6`** resolves to IDF commit **`2c211b236707889e8400c4dc5644dd5c4ee071e0`**. [Immutable comparison](https://api.github.com/repos/espressif/esp-idf/compare/a3927641bfd0aedfaab3514cba3d7fb01378ce4d...2c211b236707889e8400c4dc5644dd5c4ee071e0) reports ahead 195 / behind 0, establishing inclusion of the merge.
### Exact published source/ABI delta
The fix changes four paths:
| Path relative to IDF | Published change |
| --- | --- |
| `components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h` | `wpa_funcs.wpa_ap_get_wpa_ie`: `uint8_t *(*)(uint8_t *len)` becomes `uint8_t *(*)(size_t *len)` |
| `components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c` | Matching callback implementation takes `size_t *ie_len`; assignment from `hapd->wpa_auth->wpa_ie_len` remains |
| `components/esp_wifi/lib` | Submodule `d7373a90dc3f0be841b29911e33de5f99988dbff`**`a4e903fe43bf09a95022f9802db43d39740ccc0b`** |
| `components/esp_wifi/include/esp_wifi_types_generic.h` | Two SAE PWE documentation comments record default `WPA3_SAE_PWE_BOTH`; not structure-layout changes |
The installed header and callback still take `uint8_t *`; `esp_wpa_main.c` registers the callback for SoftAP. The callback slot/pointer size need not change for this to be an ABI break: the width and interpretation of the pointed-to output change (one byte versus a `size_t`, four bytes on ESP32-S3). Mixed old/new caller and callee can corrupt storage or leave an incorrect length. Casting the callback does not fix the contract. Both sides, including the opaque caller, must agree.
The visible C edits are the length correction/interface marker. **The management-encryption fix is in the vendor binary update, not a public C hunk that can be copied into this application.**
### Bundle identity: baseline, fix point, release point are different
- Installed baseline matches Wi-Fi submodule **`8a1b7bbc00e895d040c5c9a6fb9d1db2bbfc7958`** from IDF v5.5, not the fix's immediate predecessor `d7373a90…`.
- The exact fix-point bundle is **`a4e903fe43bf09a95022f9802db43d39740ccc0b`**.
- The complete 5.5.3 release points to **`e0befaa593277b4e80726079fbd521b4681754c2`**, verified again at the immutable release commit. [Wi-Fi comparison](https://api.github.com/repos/espressif/esp32-wifi-lib/compare/a4e903fe43bf09a95022f9802db43d39740ccc0b...e0befaa593277b4e80726079fbd521b4681754c2) reports ahead 3 / behind 0. Do not call the fix-point bundle the final 5.5.3 bundle.
Calculated Git blob SHA-1 (`blob <length>\0` plus bytes) of **all seven installed S3 archives** and compared against official metadata for [baseline](https://api.github.com/repos/espressif/esp32-wifi-lib/contents/esp32s3?ref=8a1b7bbc00e895d040c5c9a6fb9d1db2bbfc7958), [fix point](https://api.github.com/repos/espressif/esp32-wifi-lib/contents/esp32s3?ref=a4e903fe43bf09a95022f9802db43d39740ccc0b), and [release point](https://api.github.com/repos/espressif/esp32-wifi-lib/contents/esp32s3?ref=e0befaa593277b4e80726079fbd521b4681754c2):
| Archive | Installed = baseline Git blob | Fix-point Git blob | 5.5.3-release Git blob |
| --- | --- | --- | --- |
| `libcore.a` | `ec2e76caad4c29ee92ec45432e0dc3bf946ea4c7` | `af63b0f8254bde084b2f474cdba1c1d63b4ae750` | `9f7b14a8bf6eec64973da8adc65d35b5ba9bee49` |
| `libespnow.a` | `d4925dc7f73173077e8ed58abbbe5a59b5bb7be5` | `da0537c3f754a9d638fbecd4f4d806bfa66316b4` | `132b4f67e339ca2081d2add91c14eefa39476ff9` |
| `libmesh.a` | `5cd43bf5a0a0388fb6f093a154401f00227d9570` | `6ae30c90ba59ab949e98db89b6b51daab434a5a0` | `2e9dc1c8c7afbf033337b4175032e9b1161e3262` |
| `libnet80211.a` | `6ee20bec142638dc0a442b9642de9fa62db6ddd0` | `8ce8a2a6a9a753e31508bd609bf0a0d1d44c332f` | `2800d447ec385d33869373696ba8191292647694` |
| `libpp.a` | `c9fc98fe529c9ff2891839fdb9a41b1189c03c49` | `536fd25e30a1be76ff122d93e7481f1da22e6892` | `8944bcad7371621045f376cf74c62fde6f368cbb` |
| `libsmartconfig.a` | `31518eb9336f07de14b4a71c0389217a54ed3ec7` | `19e8274e0961fdf88351a0dec6e0d696b8ee2b94` | `4dc759e25617aa00b9e12887fd092a1d5780a170` |
| `libwapi.a` | `0604ff76aa9134b475daf08496e03350d5ef8f09` | `e43863a22e93990b8a4deb7c4efc8e4c27566789` | `65655b6feab0572a6e8a1200946d53a21f3f4722` |
All installed archives match baseline; all differ from both newer bundles. This is artifact identity, not proof that every archive is linked or contains the defect. Remote binaries were **not downloaded**. Git IDs are provenance identifiers, not independently measured remote SHA-256 digests or a vendor signature verification.
The release API advertises the submodule-inclusive `esp-idf-v5.5.3.zip`, asset ID **357881088**, SHA-256 **`d16e6b57b1df1a523aff6a1d0ef2f99cf058cb71e73f694429769eaaea171428`**. This is vendor-published metadata, not a locally verified download. The release is marked `immutable=false`; therefore pin the resolved commit/submodules and verify artifact hashes, not merely a tag URL. Espressif warns that GitHub's automatic source archives omit submodules; those are not complete SDK inputs.
## PMF/WPA3 mitigation assessment
Both the [v5.5 documentation source](https://raw.githubusercontent.com/espressif/esp-idf/v5.5/docs/en/api-guides/wifi-security.rst) and [immutable candidate documentation](https://raw.githubusercontent.com/espressif/esp-idf/2c211b236707889e8400c4dc5644dd5c4ee071e0/docs/en/api-guides/wifi-security.rst), plus the installed type header, establish:
- `pmf_cfg.capable` is deprecated, effectively true internally. Setting it false is **not a supported PMF-off mitigation**.
- `required=false` permits optional PMF; it does not disable it.
- `esp_wifi_disable_pmf_config()` is the documented optional-PMF disable API. Disabling PMF on WPA3 or WPA2/WPA3 mixed SoftAP returns an error.
- WPA3 mandates PMF. WPA2-only mode by itself still does not prove PMF is disabled.
**No issue-specific official workaround was found in the inspected release/fix text.** The API documentation explains general configuration, not an endorsement that disabling PMF safely mitigates all defects in this change. The trigger supplies a rationale that actually eliminating `bss->pmf_enable` could avoid the described encryption path; the opaque implementation and lifecycle have not been proved to honor that invariant across existing associations/restarts.
Consequently, a WPA2-only plus explicit PMF-disable implementation is at most an **unapproved conditional workaround candidate**. It would remove SAE benefits and management-frame protection, require explicit owner acceptance, documented threat trade-offs, correct manager-owned stop/reconfigure/start sequencing, checked API results, and target evidence that negotiated PMF cannot reappear across APSTA/fallback transitions. It would not repair the RSN-IE allocation defect. Do not implement it as a silent downgrade, global WPA3 Kconfig removal, or station-profile change.
If operational containment is urgently required before an update, the owner may explicitly choose existing AP-off policy (removes the described AP response path) or Wi-Fi-off (removes radio service), accepting lost network/fallback access. These are feature-withdrawal containment options, **not vendor-certified workarounds or a source fix**. Preserve and verify UART0/native USB access first; do not automatically persist policy changes. No containment action was taken here.
## What a coherent replacement entails
### Preferred: complete vendor maintenance release
Use all IDF source, private/public headers, Wi-Fi/PHY/coexistence libraries and other submodules from one resolved release, with its toolchain and Python/build requirements. Do not install final-release blobs alongside fix-point-only C edits or mix two release revisions. Preserve the application security policies separately through audited overrides.
Verified local integration constraints:
| Input | Current state | Required next action |
| --- | --- | --- |
| `platformio.ini` | `platformio/espressif32@6.12.0`, ESP-IDF, ESP32-S3 N16R8 | Select a supported pinned platform/framework/toolchain combination; no floating update |
| Installed platform `platform.json` | Framework range `~3.50500.0`; installed `framework-espidf/package.json` is `3.50500.0` | Does not select 5.5.3; establish package provenance and adapter support before proposing a package override |
| Installed Xtensa toolchain | `14.2.0+20241119` | Candidate's immutable [`tools/tools.json`](https://github.com/espressif/esp-idf/blob/2c211b236707889e8400c4dc5644dd5c4ee071e0/tools/tools.json) recommends **`esp-14.2.0_20251107`**; same GCC major/minor is not identical tooling or compatibility evidence |
| `tools/security_overrides.py` | `verify_version()` requires exactly **5.5.0**; each original source has an exact SHA-256 and executable edit contract | A full upgrade intentionally fails until semantic re-audit/rebase; never make the version range permissive just to build |
| `cmake/security_overrides.cmake` | Exact-once source replacement, nested mbedTLS ownership checks, source-property preservation, forced PUBLIC wolfSSH ABI overlay | Revalidate generated and actual compiler inputs, target identities and include order |
No known-good PlatformIO 6.12 + IDF 5.5.3 package combination was established here. The installed adapter was read only for package/version/toolchain selection references, not certified for the candidate. A raw IDF Git checkout is not automatically a PlatformIO framework package. Prefer a supported platform release carrying a suitable complete SDK; otherwise a maintained, exact-pinned framework/toolchain packaging effort is a separate explicit implementation deliverable.
Re-audit all existing corrections against candidate originals, not only Wi-Fi: HTTPS cleanup/private-key release, HTTPD scratch/null-read handling, server-local TLS policy, DHCP bounds, TLS EMS failure, X.509 allocation failure; retain/revalidate wolfSSH password/parser/ordering/ABI changes and wolfCrypt settings. Mark each correction **retained, rebased, or superseded with source/test evidence**. Upstream fixes do not automatically supersede local lifetime/policy additions in the same source. Also retain silent-panic/no-coredump and heap-wipe policy guards. The durable architecture's older four-correction summary is not the complete current inventory; the current generator and code map are authoritative.
### Contingency: vendor-supported backport onto 5.5.0
The smallest **published delta against the fix's own parent** is the four-path change above. The smallest **proven safe delta against this project's 5.5.0** is **not established**.
A candidate backport must at least pair both callback changes with one complete ESP32-S3 Wi-Fi archive set from the same vendor revision, retain the vendor patch/provenance, and establish compatibility with all private Wi-Fi headers, OS adapter tables, supplicant structures/callbacks, PHY/coexistence interfaces, configuration ABI and toolchain. All seven S3 archives form the conservative replacement set; do not mix old optional archives with new ones simply because current linking omits them. This minimum set is necessary for coherent provenance, **not sufficient proof** of cross-baseline compatibility.
Ask Espressif for a supported 5.5.0 backport bundle or an explicit compatibility statement with its required source/header/library/toolchain prerequisites, confirming both management-frame and IE-length corrections. The immediate-parent blob pointer differs from baseline; successful linking alone cannot establish binary layout/calling-contract compatibility. Without that evidence or a complete audited dependency closure, choose the full-release path rather than treating the two C signature edits plus blobs as approved.
## Bounded implementation and acceptance plan
1. **Compatibility/provenance gate first, no code change yet.** Resolve one deployment release and PlatformIO delivery combination. Record immutable SDK commit, recursive submodule pins, package/toolchain identities and SHA-256 manifests. Confirm vendor inclusion of the fix. Obtain missing packaging/ABI evidence; if unavailable, report the blocker instead of guessing a framework URL or transplanting archives.
2. **Prepare isolated inputs after approval.** Do not modify the user's shared installed SDK. Obtain complete vendor inputs in a dedicated location, verify provenance/hashes, and compare only relevant integration surfaces and protected-source entries. Keep existing managed components pinned where compatible; explicitly review any resolver-required changes. Review license/notice/source-delivery updates for new radio/SDK artifacts.
3. **Rebase security contracts.** Implement a reviewed per-entry disposition and exact new source pins, retain fail-closed guards, and verify every generated override/forced header reaches the actual targets. Add a bundle-consistency check for the selected SDK and archive identities so an old/new mixed bundle fails deterministically. Do not enable unrelated features, regenerate web assets, migrate credentials, or alter partitions.
4. **Build/host gates in the later implementation task only.** Clean candidate build with the selected toolchain; inspect linked archive paths/map, generated configuration and actual compilation inputs. Run SDK override, crypto, parser, ordering/interop, authentication/protocol, build-policy and notice validations as applicable to the resolved input changes. Record sizes and compare resource budgets; a host pass is not radio validation. Existing historical passes do not validate this candidate.
5. **Target gates under explicit device authorization.** Exercise WPA2 with/without negotiated PMF and WPA3 SoftAP; authenticate/reassociate after keys are installed; cover PMF optional/required behavior, four clients, disconnect/reconnect and AP/STA/APSTA/fallback transitions. Obtain vendor regression guidance or an authorized isolated-radio reproduction for the exact trigger; ordinary reconnect tests alone do not prove vulnerability closure. Stress concurrent HTTPS/WebSocket/SSH and verify bounded recovery, heap/stack reserve, queue behavior, no secret/crash-memory disclosure, and unchanged broker isolation. Verify UART0 recovery and native USB UART1 operation while Wi-Fi fails/stops/restarts. Include persisted-config reboot tests without erasure.
6. **Release gate.** Keep PMF/WPA3 security at least unchanged. Record exact artifacts and test evidence, retain a controlled recovery image and configuration backup procedure, and mark the old image as still exposed rather than calling rollback a security fix. No flash erase, upload, pin changes or deployment until separately authorized. Update durable project memory only when implemented contracts/ownership genuinely change.
## Open evidence and review boundary
- **Resolved:** official fix IDs/description; exact visible ABI delta; all seven installed S3 archives match baseline; distinct fix and final-release bundles; release/fix ancestry; current application configuration; PMF-disable restrictions; exact-IDF/hash guards; recommended versus installed toolchain mismatch.
- **Unresolved:** supported PlatformIO delivery for the chosen maintenance release; full private ABI prerequisite closure for a 5.5.0 transplant; exact PHY/coexistence submodule pins for the candidate in this review; complete tool/Python/managed-component compatibility; opaque binary implementation correctness; packet-level attacker requirements; target/runtime/resource evidence; latest deployment-release selection.
- A follow-up GitHub API request for candidate `components/esp_phy/lib` returned **HTTP 403 rate limit exceeded**. The sequential metadata query stopped there, so PHY/coexistence pins were not established; no inference was drawn from that failure. Already completed Wi-Fi/release/ancestry queries succeeded. Official raw documentation remained available. Do not treat this partial metadata boundary as a compatibility clearance.
- Validation performed here: read-only local source/package/config inspection; local seven-archive Git-blob hashing; official patch/release/tag/content/comparison/toolchain/documentation reads. No broad repeated dependency audit, binary download, PlatformIO invocation, build, test suite, device operation, configuration edit, or asset generation. Documentation links/provenance do not constitute signed-vendor attestation, exhaustive security certification, or Phase 9 sign-off.
+19 -2
View File
@@ -36,8 +36,25 @@ with tempfile.TemporaryDirectory(prefix="admin-console-boundary-") as directory:
"-o", str(path / "certificate")], check=True, timeout=30) "-o", str(path / "certificate")], check=True, timeout=30)
subprocess.run([str(path / "certificate")], check=True, timeout=10) subprocess.run([str(path / "certificate")], check=True, timeout=10)
ssh = (ROOT / "src/ssh_transport.c").read_text() ssh = (ROOT / "src/ssh_transport.c").read_text()
adapter = ssh[ssh.index("static admin_ssh_console_token_t admin_console_token("): # Bound the adapter by its own functions, not the allocator helpers now
ssh.index("static void *ssh_malloc(")] # owned by ssh_memory.c. Fail closed if the reviewed source layout changes.
adapter_markers = (
"static admin_ssh_console_token_t admin_console_token(",
"static void publish_slot(",
"static size_t admin_console_snapshot_index_locked(",
"static bool admin_console_is_current(",
"static bool admin_console_drained(",
"static esp_err_t admin_console_perform(",
"static const admin_console_owner_t s_admin_console_owner = {",
"static bool consume_external_close(",
)
positions = []
for marker in adapter_markers:
assert ssh.count(marker) == 1, f"SSH adapter marker missing/ambiguous: {marker}"
positions.append(ssh.index(marker))
assert positions == sorted(positions), "SSH adapter source order changed"
adapter_end = ssh.index("\n}", positions[-1]) + len("\n}")
adapter = ssh[positions[0]:adapter_end]
unit = ((ROOT / "tests/admin_console_boundary/fakes.h").read_text() unit = ((ROOT / "tests/admin_console_boundary/fakes.h").read_text()
+ strip_includes(header) + "\n" + strip_includes(source) + strip_includes(header) + "\n" + strip_includes(source)
+ (ROOT / "tests/admin_console_boundary/adapter.c").read_text() + (ROOT / "tests/admin_console_boundary/adapter.c").read_text()
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
"""Offline orchestrator fixtures only; never invokes pio or existing suites."""
import contextlib
import importlib.util
import io
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import time
import unittest
from unittest.mock import patch
sys.dont_write_bytecode = True
ROOT = Path(__file__).resolve().parents[2]
spec = importlib.util.spec_from_file_location('phase9', ROOT / 'tools/validate_phase9.py')
runner = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = runner
spec.loader.exec_module(runner)
class ValidationTests(unittest.TestCase):
def options(self, *args):
return runner.parser().parse_args(args)
def command(self, code, name='fixture', timeout=3, required=()):
return runner.Command(name, (sys.executable, '-c', code), timeout, required)
def execute(self, commands, **kwargs):
output = io.StringIO()
with contextlib.redirect_stdout(output):
code = runner.execute(commands, ROOT, **kwargs)
return code, output.getvalue()
def test_default_exact_scope_and_real_paths(self):
commands = runner.plan(self.options())
self.assertEqual(len(commands), 23)
self.assertEqual({c.name for c in commands}, {
'security_build_policy', 'ssh_auth_policy', 'ssh_auth_transport', 'hidden_input',
'ssh_memory', 'sdk_security_overrides', 'wolfssh_auth_contract', 'ssh_protocol_policy',
'wolf_crypto_policy', 'wolfssh_parser_contract', 'wolfssh_order_contract', 'release_notices',
'ssh_management', 'admin_console_boundary', 'admin_ssh_policy', 'web_admin_transport',
'web_admin_tickets', 'web_httpd_idle', 'web_cookie_auth:base', 'web_cookie_auth:admin',
'web_cookie_auth:accounts', 'web_cookie_auth:ssh', 'web_cookie_auth:lifecycle'})
for command in commands:
self.assertTrue((ROOT / command.argv[2]).is_file())
self.assertEqual(command.argv[:2], (sys.executable, '-B'))
self.assertEqual(command.timeout, 180)
self.assertFalse({'--interop', '--host-only', '--candidate', '--target-contracts',
'--pio-adapter', 'pio', '--admission'} & set(command.argv))
by_name = {c.name: c for c in commands}
database = str(runner.BUILD / 'compile_commands.json')
for name in ('wolfssh_auth_contract', 'ssh_protocol_policy', 'wolf_crypto_policy'):
self.assertEqual(by_name[name].argv[3:], ('--compile-commands', database))
self.assertEqual(by_name['sdk_security_overrides'].argv[3:], ('--build-dir', str(runner.BUILD)))
self.assertEqual(by_name['security_build_policy'].argv[3:],
('--sdkconfig-header', str(runner.BUILD / 'config/sdkconfig.h')))
def test_opt_ins_independent_and_timeout(self):
commands = runner.plan(self.options('--build', '--timeout', '4', '--build-timeout', '5'))
self.assertEqual(commands[0], runner.Command('build', ('pio', 'run'), 5))
self.assertTrue(all(c.timeout == 4 for c in commands[1:]))
self.assertFalse(any('--interop' in c.argv for c in commands))
commands = runner.plan(self.options('--interop'))
self.assertNotIn('build', [c.name for c in commands])
self.assertEqual([c.name for c in commands if '--interop' in c.argv], ['wolfssh_order_contract'])
def test_bad_timeout(self):
for value in ('0', '-1', 'nan', 'inf', '3601', 'junk'):
with contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit):
self.options('--timeout', value)
def test_dry_run_never_launches_or_checks_prerequisites(self):
with patch.object(runner, 'run_command', side_effect=AssertionError('executed')):
code, output = self.execute(runner.plan(self.options('--build', '--interop')), dry_run=True)
self.assertEqual(code, 0)
self.assertIn('PLAN build', output)
self.assertNotIn('PASS ', output)
with patch.object(runner, 'run_command', side_effect=AssertionError('executed')):
with contextlib.redirect_stdout(io.StringIO()) as output:
self.assertEqual(runner.main(['--dry-run']), 0)
self.assertIn('SKIP optional build', output.getvalue())
self.assertIn('SKIP optional interop', output.getvalue())
def test_collect_failure_and_failfast_skip(self):
commands = [self.command('raise SystemExit(7)', 'bad'), self.command('pass', 'good')]
code, output = self.execute(commands)
self.assertEqual(code, 1)
self.assertIn('FAIL bad: exit 7', output)
self.assertIn('PASS good', output)
code, output = self.execute(commands, fail_fast=True)
self.assertEqual(code, 1)
self.assertIn('SKIP good', output)
self.assertNotIn('PASS good', output)
def test_failed_build_blocks_stale_artifact_checks(self):
code, output = self.execute([self.command('raise SystemExit(1)', 'build'), self.command('pass', 'host')])
self.assertEqual(code, 1)
self.assertIn('SKIP host', output)
def test_prerequisites(self):
with tempfile.TemporaryDirectory() as tmp:
missing = Path(tmp) / 'missing'
commands = [runner.Command('missing-executable', (str(missing),), 1),
self.command('raise AssertionError()', 'missing-input', required=(missing,))]
code, output = self.execute(commands)
self.assertEqual(code, 1)
self.assertIn('PREREQ missing-executable', output)
self.assertIn('PREREQ missing-input', output)
def test_environment_and_literal_argv(self):
with tempfile.TemporaryDirectory(prefix='phase9 fixture ') as tmp:
script = Path(tmp) / 'fixture ; literal.py'
script.write_text('import os, sys\nassert os.environ["CCACHE_DISABLE"] == "1"\n'
'assert os.environ["PHASE9_FIXTURE"] == "preserved"\n'
'assert sys.argv[1] == "a ; $(not-a-command)"\n')
command = runner.Command('literal', (sys.executable, str(script), 'a ; $(not-a-command)'), 3)
with patch.dict(os.environ, {'PHASE9_FIXTURE': 'preserved', 'CCACHE_DISABLE': '0'}):
self.assertEqual(self.execute([command])[0], 0)
self.assertEqual(os.environ['CCACHE_DISABLE'], '0')
def test_timeout_kills_descendant_and_collects(self):
with tempfile.TemporaryDirectory() as tmp:
marker = Path(tmp) / 'should-not-exist'
child = f'import time; from pathlib import Path; time.sleep(1); Path({str(marker)!r}).touch()'
parent = f'import subprocess, sys, time; subprocess.Popen([sys.executable, "-c", {child!r}]); time.sleep(10)'
started = time.monotonic()
code, output = self.execute([self.command(parent, timeout=0.25), self.command('pass', 'next')])
self.assertLess(time.monotonic() - started, 4)
self.assertEqual(code, 1)
self.assertIn('TIMEOUT fixture', output)
self.assertIn('PASS next', output)
time.sleep(1.1)
self.assertFalse(marker.exists())
def test_streams_not_captured_and_stdin_closed(self):
with patch.object(runner.subprocess, 'Popen') as popen, patch.object(runner.os, 'killpg'):
popen.return_value.wait.return_value = 0
code, _ = self.execute([self.command('pass')])
self.assertEqual(code, 0)
kwargs = popen.call_args.kwargs
self.assertNotIn('stdout', kwargs)
self.assertNotIn('stderr', kwargs)
self.assertNotIn('shell', kwargs)
self.assertEqual(kwargs['stdin'], subprocess.DEVNULL)
self.assertTrue(kwargs['start_new_session'])
if __name__ == '__main__':
unittest.main()
+22 -5
View File
@@ -1,7 +1,7 @@
# Release notice tool tests # Release notice tool tests
Run `python3 tests/release_notices/run.py` from the repository root. Uses Python's Run `python3 tests/release_notices/run.py` from the repository root. Uses Python's
standard library and isolated temporary fixtures only; no managed package, standard library, isolated temporary fixtures and checked-in icon evidence; no managed package,
SDK, toolchain, PlatformIO, network, or device is required. Linux/POSIX path and SDK, toolchain, PlatformIO, network, or device is required. Linux/POSIX path and
descriptor semantics match the notice tool. descriptor semantics match the notice tool.
@@ -10,8 +10,25 @@ across moved roots/changed mtimes; missing, empty, changed and oversized inputs;
source body drift outside excerpts; bounds/schema; traversal and symlinks in source body drift outside excerpts; bounds/schema; traversal and symlinks in
input/output ancestry; FIFOs/directories; existing user-data preservation; input/output ancestry; FIFOs/directories; existing user-data preservation;
explicit output requirement; unlisted secret/config/build exclusion; incomplete explicit output requirement; unlisted secret/config/build exclusion; incomplete
write behavior; and success/failure CLI exits. write behavior; and success/failure CLI exits. Additional offline icon tests check
exact upstream SHA-256/Git blob identities, release and author metadata, absence
of NOTICE paths in the complete pinned tree, actual retained SVG coordinates,
USB mockup transforms, manual firmware row bytes, and catalog inclusion. A
changed coordinate or added transform is rejected; differing mockup Wi-Fi and
unproven manual rasterization are not described as exact upstream matches.
Real installed-input assembly and recipient delivery are separate checks; see Real installed-input assembly is an explicit, separate offline check:
`docs/release_packaging.md`. Passing these tests is not license clearance or
proof of corresponding-source compliance. ```sh
python3 tests/release_notices/actual_bundle.py \
--sdk-root /home/mscholz/.platformio/packages/framework-espidf \
--toolchain-root /home/mscholz/.platformio/packages/toolchain-xtensa-esp-elf
```
Use literal paths for the reviewed installed snapshot. This invokes the real
CLI twice with fresh temporary outputs outside input roots, verifies catalog
identity, every manifest entry and payload hash/size, absence of extra files,
and identical relative names/bytes across outputs. Temporary outputs are removed
after the check. No fetch, dependency installation, build or device access.
Recipient delivery remains separate; see `docs/release_packaging.md`. Passing
these tests is not license clearance or corresponding-source compliance.
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-3.0-only
"""Assemble two real bundles in temporary directories and verify every byte."""
import argparse
import hashlib
import json
from pathlib import Path
import subprocess
import sys
import tempfile
PROJECT = Path(__file__).absolute().parents[2]
def contents(root):
return {p.relative_to(root).as_posix(): p.read_bytes()
for p in root.rglob("*") if p.is_file()}
def validate(files, catalog_data):
manifest = json.loads(files["manifest.json"])
catalog = json.loads(catalog_data)
assert manifest["catalog_sha256"] == hashlib.sha256(catalog_data).hexdigest()
assert manifest["snapshot"] == catalog["snapshot"]
assert len(manifest["inputs"]) == len(catalog["inputs"])
expected_entries = {(x["root"], x["path"]): x for x in catalog["inputs"]}
expected_files = {"manifest.json"}
seen = set()
for entry in manifest["inputs"]:
key = (entry["root"], entry["path"])
assert key not in seen
seen.add(key)
original = expected_entries[key]
assert {k: entry[k] for k in original} == original
path = "inputs/" + entry["root"] + "/" + entry["path"]
if entry["range"] is not None:
path += ".notice.txt"
assert entry["output"] == path
expected_files.add(path)
data = files[path]
assert len(data) == entry["output_size"]
assert hashlib.sha256(data).hexdigest() == entry["output_sha256"]
assert seen == set(expected_entries)
assert len(manifest["generated"]) == 1
assert manifest["generated"][0]["path"] == "README.txt"
for entry in manifest["generated"]:
expected_files.add(entry["path"])
data = files[entry["path"]]
assert len(data) == entry["size"]
assert hashlib.sha256(data).hexdigest() == entry["sha256"]
assert set(files) == expected_files, "unexpected or missing bundle files"
return len(manifest["inputs"])
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--sdk-root", type=Path, required=True)
parser.add_argument("--toolchain-root", type=Path, required=True)
args = parser.parse_args()
catalog = (PROJECT / "third_party/release-notices/inputs.json").read_bytes()
with tempfile.TemporaryDirectory(prefix="actual-release-notices-") as temporary:
base = Path(temporary)
outputs = []
for name in ("first", "second"):
output = base / name
subprocess.run([
sys.executable, str(PROJECT / "tools/release_notices.py"),
"--sdk-root", str(args.sdk_root),
"--toolchain-root", str(args.toolchain_root), "--output", str(output),
], check=True, timeout=60)
files = contents(output)
count = validate(files, catalog)
outputs.append(files)
assert outputs[0] == outputs[1], "bundle names/bytes differ"
files = outputs[0]
print(f"PASS: two actual bundles; {count} inputs; {len(files)} files; "
f"{sum(map(len, files.values()))} bytes; all payloads verified and deterministic")
print("manifest SHA-256:", hashlib.sha256(files["manifest.json"]).hexdigest())
return 0
if __name__ == "__main__":
sys.exit(main())
+173
View File
@@ -0,0 +1,173 @@
# SPDX-License-Identifier: GPL-3.0-only
"""Offline checks of actual project icon derivatives, not a raster generator."""
import copy
import hashlib
import json
from pathlib import Path
import re
import unittest
import xml.etree.ElementTree as ET
PROJECT = Path(__file__).absolute().parents[2]
ICONS = PROJECT / "third_party/material-design-icons"
UPSTREAM = ICONS / "upstream-7.4.47"
COMMIT = "9e04201d4557e729822fb57f62a316c3dea1d4a8"
TAG = "5edde266e281d26a03dcfa89fb651183cbab0f2e"
SVG = "{http://www.w3.org/2000/svg}"
PINS = {
"usb.svg": "c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22",
"wifi-strength-4.svg": "89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f",
"LICENSE": "f3bc8715bad84b26396bb42d2abd11f919cf58163be158eab79ecbaabf84cdf2",
"package.json": "ffeb0e4cc17b4cb124408bd0068667b9a35e985971792978e40d4cd69c7ca8b7",
"README.md": "db5acca5eb4e2c9113c3408ed1ae7d17c76f653340a5d4e3f8a58d2bcdf50b7d",
"meta.json": "ed9d7c7a5ca3ce7dee023fb6c1d62715dbec5b27503d268cbc10b9c8894ef3e8",
"tag.json": "f02dc7fc1e862c344c66877828b1914543f0656db8544c05a1ed3b7d990b6d75",
"tree.json": "b75710c2b9ee4d0ad3f79016e9767a85103f16df6cbbe5f0629efc3b470d1569",
"Apache-2.0.txt": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
}
def load(name):
return json.loads((UPSTREAM / name).read_bytes())
def geometry(element):
"""Strict comparison: no coordinate normalization or hidden transforms."""
if set(element.attrib) != {"id", "viewBox"}:
raise ValueError("unexpected root/symbol geometry attributes")
if element.attrib["viewBox"] != "0 0 24 24":
raise ValueError("unexpected viewBox")
if len(element) != 1 or element[0].tag != SVG + "path":
raise ValueError("expected exactly one path")
if set(element[0].attrib) != {"d"}:
raise ValueError("unexpected path geometry attributes")
return element[0].attrib["d"]
class IconProvenanceTests(unittest.TestCase):
def test_download_pins_and_git_blobs(self):
records = load("downloads.json")
self.assertEqual({r["path"] for r in records}, set(PINS))
self.assertEqual(len(records), len(PINS))
tree = {x["path"]: x for x in load("tree.json")["tree"]}
for record in records:
name = record["path"]
with self.subTest(name=name):
data = (UPSTREAM / name).read_bytes()
self.assertEqual(len(data), record["size"])
self.assertEqual(hashlib.sha256(data).hexdigest(), PINS[name])
self.assertEqual(record["sha256"], PINS[name])
if name not in ("tag.json", "tree.json", "Apache-2.0.txt"):
path = "svg/" + name if name.endswith(".svg") else name
self.assertEqual(record["url"],
"https://raw.githubusercontent.com/Templarian/"
f"MaterialDesign-SVG/{COMMIT}/{path}")
self.assertEqual(tree[path]["size"], len(data))
blob = b"blob " + str(len(data)).encode() + b"\0" + data
self.assertEqual(hashlib.sha1(blob).hexdigest(), tree[path]["sha"])
for name in ("usb.svg", "wifi-strength-4.svg", "LICENSE"):
self.assertEqual((ICONS / name).read_bytes(), (UPSTREAM / name).read_bytes())
def test_release_license_authors_and_notice_scope(self):
tag = load("tag.json")
self.assertEqual(tag["sha"], TAG)
self.assertEqual(tag["tag"], "v7.4.47")
self.assertEqual(tag["object"]["sha"], COMMIT)
self.assertEqual(tag["object"]["type"], "commit")
self.assertFalse(tag["verification"]["verified"])
package = load("package.json")
self.assertEqual((package["name"], package["version"], package["license"]),
("@mdi/svg", "7.4.47", "Apache-2.0"))
expected = {
"usb": ("Google", "25033E0B-3AD4-414D-9972-559F2690FC1D", "1.5.54"),
"wifi-strength-4": ("Simran", "41B86B22-7245-4A97-9BAA-3E9EBD44CEB0", "2.3.50"),
}
selected = [x for x in load("meta.json") if x["name"] in expected]
self.assertEqual(len(selected), 2)
for icon in selected:
self.assertEqual((icon["author"], icon["id"], icon["version"]), expected[icon["name"]])
self.assertNotIn("license", icon)
tree = load("tree.json")
self.assertFalse(tree["truncated"])
self.assertFalse([x["path"] for x in tree["tree"] if "notice" in x["path"].lower()])
def test_exact_retained_geometry_and_negative_changes(self):
for name in ("usb.svg", "wifi-strength-4.svg"):
original = ET.parse(UPSTREAM / name).getroot()
local = ET.parse(ICONS / name).getroot()
self.assertEqual(geometry(local), geometry(original))
changed = copy.deepcopy(local)
changed[0].set("d", changed[0].get("d").replace("M", "M0,0L", 1))
self.assertNotEqual(geometry(changed), geometry(original))
for node in (0, None):
changed = copy.deepcopy(local)
(changed if node is None else changed[node]).set("transform", "translate(1 0)")
with self.assertRaises(ValueError):
geometry(changed)
def test_actual_mockup_paths_and_transforms(self):
root = ET.parse(PROJECT / "docs/phase7c_icon_mockup.svg").getroot()
parents = {child: parent for parent in root.iter() for child in parent}
symbols = {x.get("id"): x for x in root.iter(SVG + "symbol")}
self.assertEqual(geometry(symbols["usb"]), geometry(ET.parse(UPSTREAM / "usb.svg").getroot()))
self.assertNotEqual(geometry(symbols["wifi"]),
geometry(ET.parse(UPSTREAM / "wifi-strength-4.svg").getroot()))
uses = [x for x in root.iter(SVG + "use") if x.get("href") == "#usb"]
self.assertEqual([x.attrib for x in uses], [
{"href": "#usb", "x": "150", "y": "4", "width": "30", "height": "30"},
{"href": "#usb", "x": "8", "y": "72", "width": "30", "height": "30"},
])
def ancestry(node):
result = []
while node in parents:
node = parents[node]
if "transform" in node.attrib:
result.append(node.get("transform"))
# Nested SVG viewports would require additional mappings.
if node is not root:
self.assertNotEqual(node.tag, SVG + "svg")
return result
self.assertEqual(ancestry(uses[0]), [])
self.assertEqual(parents[parents[uses[0]]].get("id"), "status")
self.assertEqual(ancestry(uses[1]), ["translate(62 438)"])
status_uses = [x for x in root.iter(SVG + "use") if x.get("href") == "#status"]
self.assertEqual([x.attrib for x in status_uses], [{"href": "#status"}] * 4)
self.assertEqual([ancestry(x) for x in status_uses], [
["translate(62 98)"], ["translate(592 98)"],
["translate(62 438)"], ["translate(592 438)"],
])
def test_actual_manual_masks_not_inferred_rasterization(self):
source = (PROJECT / "src/local_status_ui.c").read_text()
self.assertIn("hand-rasterized 8x8 derivative", source)
self.assertIn('adaptations of "wifi-strength-4"', source)
masks = {
"usb": "18 3c 18 5a 3e 18 3c 18",
"wifi_full": "7e 81 3c 42 18 24 00 18",
"wifi_three": "00 00 3c 42 18 24 00 18",
"wifi_two": "00 00 00 00 18 24 00 18",
"wifi_one": "00 00 00 00 00 00 00 18",
}
for name, expected in masks.items():
match = re.search(r"s_icon_" + name + r"\[LOCAL_STATUS_UI_ICON_SIZE\]\s*=\s*\{([^}]+)\}", source)
self.assertIsNotNone(match)
actual = re.findall(r"0x([0-9a-fA-F]{2})U", match[1])
self.assertEqual(bytes.fromhex(" ".join(actual)), bytes.fromhex(expected))
def test_all_icon_evidence_is_pinned_in_catalog(self):
catalog = json.loads((PROJECT / "third_party/release-notices/inputs.json").read_bytes())
entries = {(x["root"], x["path"]): x for x in catalog["inputs"]}
paths = [UPSTREAM / name for name in (*PINS, "downloads.json")]
paths += [ICONS / name for name in ("LICENSE", "usb.svg", "wifi-strength-4.svg")]
paths += [PROJECT / "docs/icon_provenance.md"]
for path in paths:
with self.subTest(path=path.name):
entry = entries[("project", path.relative_to(PROJECT).as_posix())]
data = path.read_bytes()
self.assertIsNone(entry["range"])
self.assertEqual(entry["size"], len(data))
self.assertEqual(entry["sha256"], hashlib.sha256(data).hexdigest())
self.assertEqual(entry["output_sha256"], entry["sha256"])
+2
View File
@@ -14,6 +14,8 @@ import unittest
from unittest import mock from unittest import mock
sys.dont_write_bytecode = True sys.dont_write_bytecode = True
from icon_provenance import IconProvenanceTests
PROJECT = Path(__file__).absolute().parents[2] PROJECT = Path(__file__).absolute().parents[2]
SPEC = importlib.util.spec_from_file_location("release_notices", PROJECT / "tools/release_notices.py") SPEC = importlib.util.spec_from_file_location("release_notices", PROJECT / "tools/release_notices.py")
notices = importlib.util.module_from_spec(SPEC) notices = importlib.util.module_from_spec(SPEC)
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,20 @@
Pictogrammers Free License
--------------------------
This icon collection is released as free, open source, and GPL friendly by
the [Pictogrammers](http://pictogrammers.com/) icon group. You may use it
for commercial projects, open source projects, or anything really.
# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
Some of the icons are redistributed under the Apache 2.0 license. All other
icons are either redistributed under their respective licenses or are
distributed under the Apache 2.0 license.
# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
All web and desktop fonts are distributed under the Apache 2.0 license. Web
and desktop fonts contain some icons that are redistributed under the Apache
2.0 license. All other icons are either redistributed under their respective
licenses or are distributed under the Apache 2.0 license.
# Code: MIT (https://opensource.org/licenses/MIT)
The MIT license applies to all non-font and non-icon files.
@@ -0,0 +1,36 @@
> *Note:* Please use the main [MaterialDesign](https://github.com/Templarian/MaterialDesign/issues) repo to report issues. This repo is for distribution of the SVG files only.
# SVG - Material Design Icons
SVG distribution for the [Material Design Icons](https://materialdesignicons.com).
```
npm install @mdi/svg
```
> Versions prior to `2.2.43` can be accessed on npm via `mdi-svg`
## Related Packages
[NPM @MDI Organization](https://npmjs.com/org/mdi)
- JavaScript/Typescript: [MaterialDesign-JS](https://github.com/Templarian/MaterialDesign-JS)
- Webfont: [MaterialDesign-Webfont](https://github.com/Templarian/MaterialDesign-Webfont)
- Font-Build: [MaterialDesign-Font-Build](https://github.com/Templarian/MaterialDesign-Font-Build)
- Desktop Font: [MaterialDesign-Font](https://github.com/Templarian/MaterialDesign-Font)
## Third Party
For those developing third party scripts/programs/applications. Please use this repo to make sure you're using latest production ready icons.
Great uses of the SVG Icon distribution includes:
- Scripts to generate your own webfont.
- Writing addons/plugins to integrate with applications.
- Themes - Every theme needs icons.
- AngularJS/Angular/React Components to work with the icons.
## Learn More
- [MaterialDesignIcons.com](https://materialdesignicons.com)
- https://github.com/Templarian/MaterialDesign
@@ -0,0 +1,56 @@
[
{
"path": "usb.svg",
"url": "https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/9e04201d4557e729822fb57f62a316c3dea1d4a8/svg/usb.svg",
"size": 403,
"sha256": "c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22"
},
{
"path": "wifi-strength-4.svg",
"url": "https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/9e04201d4557e729822fb57f62a316c3dea1d4a8/svg/wifi-strength-4.svg",
"size": 219,
"sha256": "89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f"
},
{
"path": "LICENSE",
"url": "https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/9e04201d4557e729822fb57f62a316c3dea1d4a8/LICENSE",
"size": 1012,
"sha256": "f3bc8715bad84b26396bb42d2abd11f919cf58163be158eab79ecbaabf84cdf2"
},
{
"path": "package.json",
"url": "https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/9e04201d4557e729822fb57f62a316c3dea1d4a8/package.json",
"size": 587,
"sha256": "ffeb0e4cc17b4cb124408bd0068667b9a35e985971792978e40d4cd69c7ca8b7"
},
{
"path": "README.md",
"url": "https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/9e04201d4557e729822fb57f62a316c3dea1d4a8/README.md",
"size": 1399,
"sha256": "db5acca5eb4e2c9113c3408ed1ae7d17c76f653340a5d4e3f8a58d2bcdf50b7d"
},
{
"path": "meta.json",
"url": "https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/9e04201d4557e729822fb57f62a316c3dea1d4a8/meta.json",
"size": 2045073,
"sha256": "ed9d7c7a5ca3ce7dee023fb6c1d62715dbec5b27503d268cbc10b9c8894ef3e8"
},
{
"path": "tag.json",
"url": "https://api.github.com/repos/Templarian/MaterialDesign-SVG/git/tags/5edde266e281d26a03dcfa89fb651183cbab0f2e",
"size": 685,
"sha256": "f02dc7fc1e862c344c66877828b1914543f0656db8544c05a1ed3b7d990b6d75"
},
{
"path": "tree.json",
"url": "https://api.github.com/repos/Templarian/MaterialDesign-SVG/git/trees/9e04201d4557e729822fb57f62a316c3dea1d4a8?recursive=1",
"size": 1813728,
"sha256": "b75710c2b9ee4d0ad3f79016e9767a85103f16df6cbbe5f0629efc3b470d1569"
},
{
"path": "Apache-2.0.txt",
"url": "https://www.apache.org/licenses/LICENSE-2.0.txt",
"size": 11358,
"sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"
}
]
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
{
"name": "@mdi/svg",
"version": "7.4.47",
"description": "Material Design Icons SVG",
"scripts": {
"verify": "node scripts/verify.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Templarian/MaterialDesign-SVG.git"
},
"keywords": [
"material",
"design",
"icons",
"mdi"
],
"author": "Austin Andrews",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/Templarian/MaterialDesign/issues"
},
"homepage": "https://materialdesignicons.com/"
}
@@ -0,0 +1 @@
{"node_id":"TA_kwDOBVEjNNoAKDVlZGRlMjY2ZTI4MWQyNmEwM2RjZmE4OWZiNjUxMTgzY2JhYjBmMmU","sha":"5edde266e281d26a03dcfa89fb651183cbab0f2e","url":"https://api.github.com/repos/Templarian/MaterialDesign-SVG/git/tags/5edde266e281d26a03dcfa89fb651183cbab0f2e","tagger":{"name":"Austin Andrews","email":"admin@templarian.com","date":"2023-12-26T23:33:26Z"},"object":{"sha":"9e04201d4557e729822fb57f62a316c3dea1d4a8","type":"commit","url":"https://api.github.com/repos/Templarian/MaterialDesign-SVG/git/commits/9e04201d4557e729822fb57f62a316c3dea1d4a8"},"tag":"v7.4.47","message":"v7.4.47\n","verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="mdi-usb" viewBox="0 0 24 24"><path d="M15,7V11H16V13H13V5H15L12,1L9,5H11V13H8V10.93C8.7,10.56 9.2,9.85 9.2,9C9.2,7.78 8.21,6.8 7,6.8C5.78,6.8 4.8,7.78 4.8,9C4.8,9.85 5.3,10.56 6,10.93V13A2,2 0 0,0 8,15H11V18.05C10.29,18.41 9.8,19.15 9.8,20A2.2,2.2 0 0,0 12,22.2A2.2,2.2 0 0,0 14.2,20C14.2,19.15 13.71,18.41 13,18.05V15H16A2,2 0 0,0 18,13V11H19V7H15Z" /></svg>

After

Width:  |  Height:  |  Size: 403 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="mdi-wifi-strength-4" viewBox="0 0 24 24"><path d="M12,3C7.79,3 3.7,4.41 0.38,7C4.41,12.06 7.89,16.37 12,21.5C16.08,16.42 20.24,11.24 23.65,7C20.32,4.41 16.22,3 12,3Z" /></svg>

After

Width:  |  Height:  |  Size: 219 B

+19 -10
View File
@@ -25,8 +25,8 @@ contents. Versions: ESP-IDF 5.5.0 / package 3.50500.0, Xtensa package
TinyUSB 0.21.0~1, wolfSSL 5.8.2~1, wolfSSH 1.4.20. TinyUSB 0.21.0~1, wolfSSL 5.8.2~1, wolfSSH 1.4.20.
The scoped inventory covers the six managed packages, the SDK/runtime groups The scoped inventory covers the six managed packages, the SDK/runtime groups
in `docs/dependency_licenses.md`, two xterm packages, and the recorded icon in `docs/dependency_licenses.md`, two xterm packages, and the two verified icon
summary. It retains configured-but-not-observed-linked groups too; inclusion SVG sources with pinned upstream metadata and full Apache-2.0 text. It retains configured-but-not-observed-linked groups too; inclusion
is not a claim that each contributes to a release image. Full SDK/toolchain is not a claim that each contributes to a release image. Full SDK/toolchain
redistribution needs a broader review, including nested/test/tool licenses. redistribution needs a broader review, including nested/test/tool licenses.
No recursive license discovery is performed by the tool. Newly added files or No recursive license discovery is performed by the tool. Newly added files or
@@ -68,13 +68,21 @@ license grant or independent upstream authentication is claimed by assembly.
## Icons and browser notices ## Icons and browser notices
The existing Pictogrammers summary is retained unchanged. Full Apache-2.0 text The existing Pictogrammers summary is retained unchanged. Both retained SVGs
is supplied as `inputs/sdk/LICENSE`, the exact installed SDK copy; this is are byte-identical to official `@mdi/svg` 7.4.47 sources at commit
license text, **not proof of the individual icons' provenance or grant**. `9e04201d4557e729822fb57f62a316c3dea1d4a8`. The bundle now includes those SVGs,
The project records Material Design Icons 7.4.47 and adapted USB/Wi-Fi masks. unmodified upstream originals/license/package metadata, full author metadata,
Exact two-icon origin/version/licensing and any applicable upstream NOTICE unsigned tag and complete tree evidence, separately fetched full Apache-2.0
still need verification before distribution. No icon or web asset was changed text, and `inputs/project/docs/icon_provenance.md`. Metadata credits USB to
or regenerated, and no upstream icon provenance was authenticated here. Google and Wi-Fi to Simran; the package declares Apache-2.0. No NOTICE-named
path occurs in the pinned non-truncated distribution tree; none is invented.
See the included provenance record for exact coordinates and mockup transforms.
The USB mockup path matches; its Wi-Fi path differs. Firmware masks remain
manual adaptations with **no verified exact rasterization recipe**. Identity of
the preferred SVG sources is resolved, not the historical/mechanical derivation
of every adaptation. No existing icon, firmware or web asset was changed or
regenerated. Full license text alone is not provenance or release clearance.
Both xterm MIT notices and `web_assets/SOURCES.md` are retained. This does not Both xterm MIT notices and `web_assets/SOURCES.md` are retained. This does not
embed or serve notices in browser responses, authenticate preferred sources, embed or serve notices in browser responses, authenticate preferred sources,
@@ -105,5 +113,6 @@ proof of delivery.
Installation Information, and validate recipient access and source offers. Installation Information, and validate recipient access and source offers.
Do not publish keys, passwords, Wi-Fi secrets, tickets, verifiers, NVS/flash Do not publish keys, passwords, Wi-Fi secrets, tickets, verifiers, NVS/flash
images, credential backups, or secret-bearing build configurations. images, credential backups, or secret-bearing build configurations.
5. Resolve wolfSSH packaging and icon provenance questions above. Do not use a 5. Resolve wolfSSH packaging and the remaining manual-derivative provenance
limits above. Do not use a
successful hash check as legal sign-off or whole-Phase-9 acceptance. successful hash check as legal sign-off or whole-Phase-9 acceptance.
+120 -3
View File
@@ -199,13 +199,13 @@
"size": 1012 "size": 1012
}, },
{ {
"output_sha256": "9875d806c9437b5dbdd7ba341beac4772abd8da8e1d14c1a6279fe802b43208b", "output_sha256": "ceb91c094ca7413af406cf7d8a12dc5d113053e982beb611f9b055bf83d9b881",
"path": "third_party/release-notices/README.md", "path": "third_party/release-notices/README.md",
"purpose": "Scope, provenance, license choices and unresolved release gates", "purpose": "Scope, provenance, license choices and unresolved release gates",
"range": null, "range": null,
"root": "project", "root": "project",
"sha256": "9875d806c9437b5dbdd7ba341beac4772abd8da8e1d14c1a6279fe802b43208b", "sha256": "ceb91c094ca7413af406cf7d8a12dc5d113053e982beb611f9b055bf83d9b881",
"size": 6822 "size": 7458
}, },
{ {
"output_sha256": "8eb4021ed94ecea9bac60bda1a8be7bbc5ccbfe547196bb061dcbe29c01227de", "output_sha256": "8eb4021ed94ecea9bac60bda1a8be7bbc5ccbfe547196bb061dcbe29c01227de",
@@ -599,6 +599,123 @@
"root": "toolchain", "root": "toolchain",
"sha256": "422aa40293093fb54fc66e692a0d68fd0b24ed5602e5d1d33ad05ba3909057e9", "sha256": "422aa40293093fb54fc66e692a0d68fd0b24ed5602e5d1d33ad05ba3909057e9",
"size": 63318 "size": 63318
},
{
"output_sha256": "c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22",
"path": "third_party/material-design-icons/upstream-7.4.47/usb.svg",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22",
"size": 403
},
{
"output_sha256": "89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f",
"path": "third_party/material-design-icons/upstream-7.4.47/wifi-strength-4.svg",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f",
"size": 219
},
{
"output_sha256": "f3bc8715bad84b26396bb42d2abd11f919cf58163be158eab79ecbaabf84cdf2",
"path": "third_party/material-design-icons/upstream-7.4.47/LICENSE",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "f3bc8715bad84b26396bb42d2abd11f919cf58163be158eab79ecbaabf84cdf2",
"size": 1012
},
{
"output_sha256": "ffeb0e4cc17b4cb124408bd0068667b9a35e985971792978e40d4cd69c7ca8b7",
"path": "third_party/material-design-icons/upstream-7.4.47/package.json",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "ffeb0e4cc17b4cb124408bd0068667b9a35e985971792978e40d4cd69c7ca8b7",
"size": 587
},
{
"output_sha256": "db5acca5eb4e2c9113c3408ed1ae7d17c76f653340a5d4e3f8a58d2bcdf50b7d",
"path": "third_party/material-design-icons/upstream-7.4.47/README.md",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "db5acca5eb4e2c9113c3408ed1ae7d17c76f653340a5d4e3f8a58d2bcdf50b7d",
"size": 1399
},
{
"output_sha256": "ed9d7c7a5ca3ce7dee023fb6c1d62715dbec5b27503d268cbc10b9c8894ef3e8",
"path": "third_party/material-design-icons/upstream-7.4.47/meta.json",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "ed9d7c7a5ca3ce7dee023fb6c1d62715dbec5b27503d268cbc10b9c8894ef3e8",
"size": 2045073
},
{
"output_sha256": "f02dc7fc1e862c344c66877828b1914543f0656db8544c05a1ed3b7d990b6d75",
"path": "third_party/material-design-icons/upstream-7.4.47/tag.json",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "f02dc7fc1e862c344c66877828b1914543f0656db8544c05a1ed3b7d990b6d75",
"size": 685
},
{
"output_sha256": "b75710c2b9ee4d0ad3f79016e9767a85103f16df6cbbe5f0629efc3b470d1569",
"path": "third_party/material-design-icons/upstream-7.4.47/tree.json",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "b75710c2b9ee4d0ad3f79016e9767a85103f16df6cbbe5f0629efc3b470d1569",
"size": 1813728
},
{
"output_sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"path": "third_party/material-design-icons/upstream-7.4.47/Apache-2.0.txt",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"size": 11358
},
{
"output_sha256": "84408409a100b3eb5abd36c596a6539248d608b5c0cae463c60fd45506ff1eca",
"path": "third_party/material-design-icons/upstream-7.4.47/downloads.json",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "84408409a100b3eb5abd36c596a6539248d608b5c0cae463c60fd45506ff1eca",
"size": 2328
},
{
"output_sha256": "c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22",
"path": "third_party/material-design-icons/usb.svg",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "c9918e9a983fbd788378ca4c524e7a07a0d5eedcaeff73d19814e6f6ae221f22",
"size": 403
},
{
"output_sha256": "89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f",
"path": "third_party/material-design-icons/wifi-strength-4.svg",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "89d14daf863076b0f73c76d913212875f2e9bcddaaf49c9e5d1825e0b2dc2d5f",
"size": 219
},
{
"output_sha256": "e8ad06e9c8b8e1256b8d829436c50f57de35ad9e666d54b3ea5d93deea54fd6c",
"path": "docs/icon_provenance.md",
"purpose": "Exact two-icon source/license/provenance evidence; manual-derivative limits in docs/icon_provenance.md",
"range": null,
"root": "project",
"sha256": "e8ad06e9c8b8e1256b8d829436c50f57de35ad9e666d54b3ea5d93deea54fd6c",
"size": 7263
} }
], ],
"schema": 1, "schema": 1,
+3 -2
View File
@@ -28,8 +28,9 @@ verbatim, including mixed grants and the wolfSSH package/header discrepancy.
This is NOT corresponding source, a complete SBOM, an archive of the SDK/tools, This is NOT corresponding source, a complete SBOM, an archive of the SDK/tools,
or proof of notice delivery to firmware/device/browser recipients. Radio-blob or proof of notice delivery to firmware/device/browser recipients. Radio-blob
corresponding-source/System Library questions remain unresolved. Icon provenance, corresponding-source/System Library questions remain unresolved. Exact icon SVG
wolfSSH packaging clarification, bootloader/runtime attribution, source delivery source evidence and manual-derivative limits are in inputs/project/docs/icon_provenance.md.
WolfSSH packaging clarification, bootloader/runtime attribution, source delivery
and Installation Information still require release review. No legal clearance. and Installation Information still require release review. No legal clearance.
""".encode("utf-8") """.encode("utf-8")
+150
View File
@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""Bounded Phase 9 host validation; build and local interop are explicit opt-ins."""
import argparse
from dataclasses import dataclass
import math
import os
from pathlib import Path
import signal
import subprocess
import sys
import time
ROOT = Path(__file__).resolve().parents[1]
BUILD = Path('.pio/build/esp32-s3-devkitc-1-n16r8')
@dataclass(frozen=True)
class Command:
name: str
argv: tuple
timeout: float
required: tuple = ()
def positive_seconds(value):
seconds = float(value)
if not math.isfinite(seconds) or not 0 < seconds <= 3600:
raise argparse.ArgumentTypeError('timeout must be finite and in (0, 3600] seconds')
return seconds
def parser():
cli = argparse.ArgumentParser(description=__doc__)
cli.add_argument('--build', action='store_true', help='run pio run before host checks (may fetch dependencies)')
cli.add_argument('--interop', action='store_true', help='enable ordering OpenSSH local Unix-socket matrix')
cli.add_argument('--dry-run', action='store_true', help='print plan only; no execution or prerequisite validation')
cli.add_argument('--fail-fast', action='store_true', help='stop after first failure; default collects failures')
cli.add_argument('--timeout', type=positive_seconds, default=180, help='seconds per host command (default: 180, maximum: 3600)')
cli.add_argument('--build-timeout', type=positive_seconds, default=600, help='seconds for optional build (default: 600, maximum: 3600)')
return cli
def plan(options):
commands = []
if options.build:
commands.append(Command('build', ('pio', 'run'), options.build_timeout))
def suite(name, *args, required=(), label=None):
path = Path('tests') / name / 'run.py'
commands.append(Command(label or name, (sys.executable, '-B', str(path), *map(str, args)),
options.timeout, (path, *required)))
header = BUILD / 'config/sdkconfig.h'
database = BUILD / 'compile_commands.json'
suite('security_build_policy', '--sdkconfig-header', header, required=(header,))
for name in ('ssh_auth_policy', 'ssh_auth_transport', 'hidden_input', 'ssh_memory'):
suite(name)
suite('sdk_security_overrides', '--build-dir', BUILD, required=(database,))
for name in ('wolfssh_auth_contract', 'ssh_protocol_policy', 'wolf_crypto_policy'):
suite(name, '--compile-commands', database, required=(database,))
suite('wolfssh_parser_contract')
suite('wolfssh_order_contract', *(['--interop'] if options.interop else []))
suite('release_notices')
for name in ('ssh_management', 'admin_console_boundary', 'admin_ssh_policy',
'web_admin_transport', 'web_admin_tickets', 'web_httpd_idle'):
suite(name)
# The current runner has no --admission branch: its default covers admission.
for mode in ('base', 'admin', 'accounts', 'ssh', 'lifecycle'):
suite('web_cookie_auth', *([] if mode == 'base' else ['--' + mode]),
label='web_cookie_auth:' + mode)
return commands
def kill_group(process):
try:
os.killpg(process.pid, signal.SIGKILL)
except ProcessLookupError:
pass
process.wait(timeout=5)
def run_command(command, root, env):
missing = [str(path) for path in command.required if not (root / path).is_file()]
if missing:
return 'PREREQ', 'missing ' + ', '.join(missing)
try:
# Inherit stdout/stderr: no persistent captures or environment dumps.
process = subprocess.Popen(command.argv, cwd=root, env=env, stdin=subprocess.DEVNULL,
start_new_session=True)
except OSError as error:
return 'PREREQ', f'cannot launch command (errno {error.errno})'
try:
code = process.wait(timeout=command.timeout)
except subprocess.TimeoutExpired:
kill_group(process)
return 'TIMEOUT', f'exceeded {command.timeout:g}s; process group killed'
except KeyboardInterrupt:
kill_group(process)
raise
# Also retire any descendants left by a runner that exited early.
try:
os.killpg(process.pid, signal.SIGKILL)
except ProcessLookupError:
pass
return ('PASS', 'exit 0') if code == 0 else ('FAIL', f'exit {code}')
def execute(commands, root, *, dry_run=False, fail_fast=False):
if os.name != 'posix':
print('PREREQ: POSIX process groups required', flush=True)
return 1
env = os.environ.copy()
env['CCACHE_DISABLE'] = '1'
results = []
stopped = False
for command in commands:
print(f'COMMAND {command.name} timeout={command.timeout:g}s argv={list(command.argv)!r}', flush=True)
if dry_run:
status, detail = 'PLAN', 'not executed; prerequisites not checked'
elif stopped:
status, detail = 'SKIP', 'earlier failure (fail-fast or failed build)'
else:
started = time.monotonic()
try:
status, detail = run_command(command, root, env)
except KeyboardInterrupt:
print(f'INTERRUPTED {command.name}; process group killed', flush=True)
return 130
detail += f' ({time.monotonic() - started:.1f}s)'
if status != 'PASS' and (fail_fast or command.name == 'build'):
stopped = True
results.append((command.name, status, detail))
print(f'{status} {command.name}: {detail}', flush=True)
print('\nSUMMARY (command exits, not target validation):', flush=True)
for name, status, detail in results:
print(f'{status} {name}: {detail}', flush=True)
return int(any(status not in ('PASS', 'PLAN') for _, status, _ in results))
def main(argv=None):
options = parser().parse_args(argv)
if not options.build:
print('SKIP optional build: --build not requested; existing artifacts required', flush=True)
if not options.interop:
print('SKIP optional interop: --interop not requested', flush=True)
return execute(plan(options), ROOT, dry_run=options.dry_run, fail_fast=options.fail_fast)
if __name__ == '__main__':
sys.exit(main())