RepoPilotOpen in app →

espressif/arduino-esp32

Arduino core for the ESP32 family of SoCs

Healthy

Healthy across the board

worst of 4 axes
Use as dependencyConcerns

copyleft license (LGPL-2.1) — review compatibility

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1d ago
  • 32+ active contributors
  • Distributed ownership (top contributor 36% of recent commits)
Show 4 more →
  • LGPL-2.1 licensed
  • CI configured
  • Tests present
  • LGPL-2.1 is copyleft — check downstream compatibility
What would change the summary?
  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/espressif/arduino-esp32)](https://repopilot.app/r/espressif/arduino-esp32)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/espressif/arduino-esp32 on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: espressif/arduino-esp32

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/espressif/arduino-esp32 shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 1d ago
  • 32+ active contributors
  • Distributed ownership (top contributor 36% of recent commits)
  • LGPL-2.1 licensed
  • CI configured
  • Tests present
  • ⚠ LGPL-2.1 is copyleft — check downstream compatibility

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live espressif/arduino-esp32 repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/espressif/arduino-esp32.

What it runs against: a local clone of espressif/arduino-esp32 — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in espressif/arduino-esp32 | Confirms the artifact applies here, not a fork | | 2 | License is still LGPL-2.1 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>espressif/arduino-esp32</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of espressif/arduino-esp32. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/espressif/arduino-esp32.git
#   cd arduino-esp32
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of espressif/arduino-esp32 and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "espressif/arduino-esp32(\\.git)?\\b" \\
  && ok "origin remote is espressif/arduino-esp32" \\
  || miss "origin remote is not espressif/arduino-esp32 (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(LGPL-2\\.1)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"LGPL-2\\.1\"" package.json 2>/dev/null) \\
  && ok "license is LGPL-2.1" \\
  || miss "license drift — was LGPL-2.1 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "cores/esp32/Arduino.h" \\
  && ok "cores/esp32/Arduino.h" \\
  || miss "missing critical file: cores/esp32/Arduino.h"
test -f "cores/esp32/HardwareSerial.h" \\
  && ok "cores/esp32/HardwareSerial.h" \\
  || miss "missing critical file: cores/esp32/HardwareSerial.h"
test -f "cores/esp32/HardwareI2C.h" \\
  && ok "cores/esp32/HardwareI2C.h" \\
  || miss "missing critical file: cores/esp32/HardwareI2C.h"
test -f "boards.txt" \\
  && ok "boards.txt" \\
  || miss "missing critical file: boards.txt"
test -f "CMakeLists.txt" \\
  && ok "CMakeLists.txt" \\
  || miss "missing critical file: CMakeLists.txt"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/espressif/arduino-esp32"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Arduino core that brings the familiar Arduino API and IDE workflow to ESP32 microcontrollers (and their variants like ESP32-S3, ESP32-C3). It translates Arduino sketches into native ESP-IDF binaries, letting developers write IoT firmware in the simplified Arduino language while accessing the full power of Espressif's ESP32 SoC family. Monorepo structure: cores/esp32/ contains the Arduino core implementation (pins, peripherals, SDK glue code), tools/ holds build scripts and utilities (including .github/scripts/ for CI), variants/ defines board-specific configurations (chip-specific pinouts and capabilities), libraries/ bundles common peripheral drivers (WiFi, BLE, SPIFFS). Python dominates CI tooling (.github/scripts/*.py), while the core is C/C++.

👥Who it's for

Embedded systems developers and hobbyists who want to prototype IoT/embedded projects on ESP32 chips using the Arduino ecosystem, without learning the lower-level ESP-IDF C SDK. Arduino users migrating from AVR boards to more powerful WiFi-enabled microcontrollers.

🌱Maturity & risk

Production-ready and actively maintained. The repo shows consistent activity via GitHub Actions workflows (.github/workflows/ contains allboards.yml, boards.yml, push.yml), extensive CI/CD infrastructure, multiple release branches, and a public roadmap (github.com/orgs/espressif/projects/3). The codebase is 5.3M+ LOC in C++, indicating a mature, substantial project with professional tooling (clang-format, CodeQL, code owners).

Standard open source risks apply.

Active areas of work

Active development tracked on the public roadmap; CI pipelines validate against all supported variants (allboards.yml suggests comprehensive board matrix testing). Runtime tests produce results published to gh-pages (runtime-test-results/). Version management is automated (update-version.sh), and the project regularly integrates upstream ESP-IDF changes (on-push-idf.sh visible in scripts).

🚀Get running

git clone https://github.com/espressif/arduino-esp32.git
cd arduino-esp32
# Install via Arduino IDE: Sketch > Include Library > Manage Libraries, search 'esp32'
# Or via Arduino CLI: arduino-cli core install esp32:esp32

For development: review the .github/scripts/install-arduino-core-esp32.sh for full development environment setup.

Daily commands: This is not a runnable project—it's a build system. To compile sketches: install the core via Arduino IDE or arduino-cli, select an ESP32 board variant from Tools > Board, write your sketch, and click Upload. Use .github/scripts/tests_build.sh to validate compilation across all board variants programmatically.

🗺️Map of the codebase

  • cores/esp32/Arduino.h — Main Arduino API header for ESP32; defines all core interfaces and entry points that all sketches depend on.
  • cores/esp32/HardwareSerial.h — Serial communication abstraction; foundational I/O interface used by nearly every ESP32 sketch and library.
  • cores/esp32/HardwareI2C.h — I2C/TWI interface abstraction; critical for sensor and peripheral integration, widely used in the ecosystem.
  • boards.txt — Board definitions and build flags; every contributor adding board support or modifying compiler behavior must understand this.
  • CMakeLists.txt — Build system configuration; defines how the Arduino core is compiled and linked into sketches.
  • .github/workflows/push.yml — CI/CD pipeline for compilation tests; validates that changes don't break the build across all supported boards.
  • cores/esp32/Esp.h — ESP32-specific APIs and chip utilities; encapsulates hardware-specific functionality beyond standard Arduino.

🛠️How to make changes

Add a new board variant

  1. Define board metadata and pins in boards.txt (tool.name, tool.arch, build.board, build.mcu, etc.) (boards.txt)
  2. Create board-specific variant directory under variants/{board_name}/ with pins_arduino.h if custom pinouts required (variants/)
  3. Add upload and compiler flags specific to the board variant in boards.txt (boards.txt)
  4. Validate using script; verify in CI workflow (.github/scripts/validate_board.sh)

Add a new hardware interface (e.g., SPI driver)

  1. Create new header file in cores/esp32/ defining the public API (e.g., HardwareSPI.h) (cores/esp32/HardwareSPI.h)
  2. Implement the driver in cores/esp32/HardwareSPI.cpp with ESP-IDF SPI driver calls (cores/esp32/HardwareSPI.cpp)
  3. Include the header in cores/esp32/Arduino.h so it's available to all sketches (cores/esp32/Arduino.h)
  4. Add example sketches and update documentation (libraries/)

Add a new ESP32-specific feature (chip utility)

  1. Add function declaration in cores/esp32/Esp.h within the Esp class (cores/esp32/Esp.h)
  2. Implement the feature in cores/esp32/Esp.cpp using ESP-IDF APIs (cores/esp32/Esp.cpp)
  3. Add a test sketch in examples/ or tests/ directory to validate behavior (tests/)
  4. Update CI configuration to compile and optionally run the test (.github/workflows/tests.yml)

Fix a cross-board compatibility issue

  1. Identify affected boards in boards.txt and check variant-specific pins_arduino.h files (boards.txt)
  2. Update the core abstraction (e.g., HardwareSerial.cpp) to handle variant differences (cores/esp32/HardwareSerial.cpp)
  3. Add conditional compilation guards using build variables (e.g., ARDUINO_VARIANT macros) (cores/esp32/Arduino.h)
  4. Run full compilation matrix through CI to verify fix across all boards (.github/workflows/allboards.yml)

🔧Why these technologies

  • ESP-IDF (Espressif IoT Development Framework) — Deep hardware abstraction for ESP32 chip features (GPIO, SPI, I2C, USB, BLE, WiFi); Arduino core wraps it to provide familiar Arduino API.
  • CMake + Build system integration — Bridges Arduino IDE/CLI build tools with ESP-IDF's component system; enables modular, incremental compilation.
  • GitHub Actions + GitLab CI — Comprehensive matrix testing across 50+ board variants and configurations; ensures regression detection before merge.
  • Sphinx documentation + ReadTheDocs — Auto-generated HTML docs from inline comments and markdown; keeps API documentation in sync with code changes.

⚖️Trade-offs already made

  • Wrapping ESP-IDF rather than implementing drivers from scratch

    • Why: ESP-IDF provides battle-tested, optimized HAL for all ESP32 variants; reinventing would waste effort.
    • Consequence: Tight coupling to ESP-IDF version; not portable to other architectures; requires IDF knowledge for advanced features.
  • Board variant system (pins_arduino.h per board) instead of dynamic pin detection

    • Why: Compile-time constants and optimization; allows linker to remove unused code.
    • Consequence: New boards require manual variant definitions; risk of pin conflicts if variants not carefully maintained.
  • Pure C/C++ core without Rust or type-safe abstractions

    • Why: Maximum compatibility with Arduino ecosystem and existing libraries; minimal barrier to entry.
    • Consequence: More potential for memory bugs and unsafe abstractions; relies on developer discipline.
  • Central boards.txt for all board definitions instead of plugin system

    • Why: Simple, single source of truth; easier to audit and version control.
    • Consequence: Core repository becomes bottleneck for new board support; scaling challenge as board count grows.

🚫Non-goals (don't propose these)

  • Does not implement real-time operating system scheduling—relies on FreeRTOS from ESP-IDF
  • Does not provide network stack (WiFi/BLE/Ethernet drivers)—uses IDF network components
  • Not a simulator—requires actual hardware or QEMU/Wokwi for testing
  • Does not guarantee thread safety or memory safety—developer responsibility
  • Not cross-platform to ARM, RISC-V, or other architectures—ESP32-only

🪤Traps & gotchas

ESP-IDF version pinning: The core is tightly coupled to a specific ESP-IDF version (check CMakeLists.txt for IDF_VERSION); mismatched versions cause cryptic build failures. Variant-specific behavior: GPIO pin capabilities vary by chip (ESP32 vs ESP32-S3 have different ADC/touch/PWM layouts); code must check chip ID at runtime. Compiler flags in platform.txt: Custom -ffunction-sections and memory layout flags are critical and easy to break when modifying. Board definition format: boards.txt uses a quirky Arduino .properties format with dot-notation nesting; mistakes silently fail. Upload tools: esptool.py is bundled; PATH issues or wrong Python version can cause upload to fail mysteriously.

🏗️Architecture

💡Concepts to learn

  • Hardware Abstraction Layer (HAL) — The entire esp32-hal-*.c/h stack abstracts chip-specific register access behind Arduino-compatible function signatures; understanding HAL design is key to extending the core
  • Pin Multiplexing / GPIO Matrix — ESP32's GPIO matrix allows any peripheral (SPI, I2C, UART) to connect to any pin; variants must define this mapping in pins_*.h, and the core must handle dynamic pin assignment unlike simpler AVR boards
  • Memory Sections and Linker Scripts — ESP32 has multiple memory pools (IRAM, DRAM, PSRAM); the core must carefully section code/data to avoid crashes; linker script configuration in platform.txt is critical
  • Dual-Core Architecture & Task Scheduling — ESP32 runs FreeRTOS on dual cores by default; Arduino sketches run on one core while WiFi/BLE run on another; understanding task priorities and core affinity prevents mysterious hangs
  • Board Variant System — Arduino's variant pattern (variants/ folder) lets a single core support many chip models by parameterizing pin assignments and feature flags; critical for scaling to ESP32 family diversity
  • USB-to-Serial Bridge vs Native USB — Older ESP32 boards use CP2104/CH340 USB-UART bridges; newer ESP32-S3 have native USB; the core must detect which and configure upload tools accordingly (see platform.txt upload.use_1200bps_touch)
  • OTA (Over-The-Air) Firmware Updates — libraries/Update/ implements secure firmware partitioning and rollback; understanding partition tables and signing is essential for production ESP32 deployments
  • espressif/esp-idf — The official Espressif IoT Development Framework; arduino-esp32 is a wrapper around this lower-level C SDK
  • espressif/esptool — Firmware flashing tool bundled with arduino-esp32; handles serial upload and chip communication
  • arduino/Arduino — The canonical Arduino IDE and core architecture that esp32 adapts; defines the API contract and build system patterns
  • arduino/ArduinoCore-SAMD — Arduino core for ARM-based Atmel chips; structurally similar reference implementation for how to wrap a non-AVR SoC
  • adafruit/Adafruit_nRF52_Arduino — Arduino core for Nordic Semiconductor nRF52 BLE chips; parallel ecosystem showing alternative SoC integration patterns

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Create a comprehensive CI workflow for validating CMakeLists.txt consistency across all board variants

The repo has a script .github/scripts/check-cmakelists.sh and .github/scripts/validate_board.sh but no dedicated GitHub Actions workflow to automatically validate CMakeLists.txt files on every PR. Given the complexity of supporting multiple ESP32 SoCs and variants, a dedicated workflow would catch configuration errors early. This would prevent merge conflicts and inconsistencies in build configurations.

  • [ ] Create .github/workflows/validate-cmakelists.yml that runs check-cmakelists.sh and validate_board.sh on PR changes
  • [ ] Integrate the validation to run on modifications to any CMakeLists.txt files or board definition files
  • [ ] Add step to verify all boards listed in .github/scripts/find_all_boards.sh have valid configurations
  • [ ] Document the validation process in .github/CI_README.md

Add unit tests for the Python build toolchain scripts (.github/scripts/*.py)

The repo contains multiple critical Python scripts like merge_packages.py, get_affected.py, include_checker.py, and process_sarif.py that have no visible test coverage. These scripts are core to the CI/CD pipeline but lack validation. Adding pytest-based tests would prevent regressions and make contributions to these tools safer.

  • [ ] Create .github/tests/unit/ directory structure for Python script tests
  • [ ] Add unit tests for merge_packages.py covering package merging logic
  • [ ] Add unit tests for get_affected.py covering file change detection logic
  • [ ] Add unit tests for process_sarif.py covering SARIF report processing
  • [ ] Create .github/workflows/test-python-scripts.yml to run pytest on .github/scripts/*.py files
  • [ ] Add pytest and coverage to CI dependencies

Create missing documentation for board variant configuration system

The repo has .github/scripts/find_all_boards.sh, .github/scripts/check_official_variants.sh, and .github/scripts/validate_board.sh suggesting a complex board variant system, but there's no dedicated documentation explaining how to add new board variants or configure them. This creates a high barrier for new contributors wanting to add support for new ESP32 boards.

  • [ ] Create docs/source/contributing/board_variants.md documenting the board variant system
  • [ ] Document the structure and requirements for board definition files
  • [ ] Provide step-by-step guide for adding a new ESP32 variant using the scripts in .github/scripts/
  • [ ] Link this documentation from main CONTRIBUTING.md
  • [ ] Include examples showing output of find_all_boards.sh and expected format

🌿Good first issues

  • Add missing example sketches demonstrating ESP32-C3's RISC-V core differences (QEMU timer, interrupt handling). The examples/ directory shows most features but C3-specific gotchas are underdocumented.
  • Write unit tests for cores/esp32/esp32-hal-gpio.c (GPIO mode switching, level setting, interrupt attachment). The core is sparsely tested; adding basic unit tests via the CI framework (see tests_run.sh) would catch regressions early.
  • Create a variant porting guide document in docs/ with a checklist for adding a new ESP32 SoC (pinout template, memory sections, clock tree configuration). Currently there's no step-by-step reference; contributors reverse-engineer from existing variants/.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 9c72f8c — fix(ci): prevent compile_commands filename collisions from duplicate sketch basenames (#12576) (Copilot)
  • 975fc7b — fix(matter): BLE memory releasing model adjustment (#12515) (SuGlider)
  • 2b43e5b — fix(uart): solves pinSet order with UART begin (#12569) (SuGlider)
  • 65c5136 — fix(zigbee): Time cluster - Epoch starts from year 2000 (#12547) (P-R-O-C-H-Y)
  • e9afc63 — SPI ETH drivers do not compile with C2 under IDF 6.0 (#12559) (Jason2866)
  • 8018845 — ESP_I2S: Add configurable I2S port selection (#12557) (ai-hpc)
  • e4d54ae — ci(compilation): Add label to force compilation of all sketches (#12560) (lucasssvaz)
  • e8324e5 — fix(spi): use spi_ll bus/reset clock on IDF ≥ 6 for required socs (#12552) (P-R-O-C-H-Y)
  • 332a9ac — fix(idf6): Fix examples for ESP-IDF 6 (#12548) (me-no-dev)
  • 926d881 — test(ota): Add OTA and Hash tests (#12505) (lucasssvaz)

🔒Security observations

The espressif/arduino-esp32 repository demonstrates good security practices with proper use of GitHub Actions, CI/CD automation, and code organization. However, there are moderate concerns regarding dependency management and potential CI/CD security risks. The main issues are: (1) outdated dependencies that should be regularly updated, (2) potential credential exposure risks in workflows and PowerShell signing scripts, and (3) lack of visible security-focused linting rules. The codebase follows established conventions but would benefit from implementing automated security scanning tools (SAST), regular dependency audits, and explicit secret management practices. No critical injection vulnerabilities, exposed credentials, or Docker misconfiguration issues are apparent from the visible file structure.

  • Medium · Outdated Sphinx Documentation Dependencies — dependencies/requirements.txt (sphinx==7.1.2). The requirements file specifies sphinx==7.1.2 which is not the latest stable version. Sphinx 7.1.2 was released in September 2023 and may contain known vulnerabilities that have been patched in newer versions. Regular dependency updates are essential for security. Fix: Update to the latest stable version of Sphinx (currently 7.x or later). Use pip list --outdated to identify outdated packages and establish a regular dependency update schedule.
  • Medium · Unspecified Minor Versions in Dependencies — dependencies/requirements.txt (all dependencies). Dependencies like 'numpydoc==1.10.0' and other packages lack comprehensive upper version bounds. While pinned, this could allow patch-level updates that might introduce breaking changes or security issues without explicit review. Fix: Implement a dependency management strategy using tools like pip-audit or safety to regularly scan for known vulnerabilities. Consider using version constraints like '>=1.10.0,<2.0.0' for better control.
  • Low · Potential Credential Exposure in GitHub Workflows — .github/workflows/ (all YAML files, especially sign-related scripts like Sign-File.ps1). Multiple GitHub workflow files (.github/workflows/*.yml) exist that may contain hardcoded secrets or expose sensitive information through CI/CD logs. While not directly visible in the file listing, this is a common risk in Arduino/IoT projects. Fix: Audit all workflow files to ensure secrets are managed via GitHub Secrets. Never commit API keys, tokens, or credentials. Use git-secrets or pre-commit hooks to prevent accidental commits.
  • Low · Custom PowerShell Script for File Signing — .github/pytools/Sign-File.ps1. The presence of '.github/pytools/Sign-File.ps1' suggests custom cryptographic operations. PowerShell scripts, if not properly reviewed, can be vectors for supply chain attacks. Fix: Conduct a security audit of this script. Ensure it uses proper cryptographic libraries, validates inputs, and doesn't execute untrusted code. Consider using established signing tools from trusted sources.
  • Low · Python Script Execution in CI/CD Without Version Pinning — .github/scripts/*.py files. Multiple Python scripts in .github/scripts/*.py are executed in CI/CD workflows without explicit Python version constraints or dependency isolation visible in the file structure. Fix: Specify Python version requirements in workflows (e.g., 'python-version: 3.11'). Create a separate requirements.txt for script dependencies and use virtual environments in workflows.
  • Low · Code Style Tools Configuration Without Security Review — .clang-format, .flake8, .prettierignore. Configuration files like .clang-format, .flake8, and .prettierignore are present but may not enforce security-related linting rules (e.g., bandit for Python security checks). Fix: Integrate security linters into the codebase: use 'bandit' for Python security checks and 'clang-analyzer' for C/C++ code. Update CI/CD workflows to enforce security checks.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · espressif/arduino-esp32 — RepoPilot