name: Lint & Build on: push: branches: [main] tags: ['v*'] pull_request: branches: [main] workflow_dispatch: jobs: build: name: Build Firmware needs: [cppcheck, flawfinder, gitleaks] runs-on: anvil container: image: docker.io/espressif/idf:v5.5 volumes: - /var/cache/ccache:/ccache env: CCACHE_DIR: /ccache IDF_CCACHE_ENABLE: 1 IDF_PATH: /opt/esp/idf IDF_PATH_FORCE: 1 steps: - name: Checkout run: | git clone --depth=1 --branch=${{ github.ref_name }} \ https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git . - name: Setup ccache run: | apt-get update && apt-get install -y --no-install-recommends ccache ccache --zero-stats ccache --show-config | grep -E "(cache_dir|max_size)" - name: Build firmware run: | . /opt/esp/idf/export.sh cd get-started/csi_recv_router idf.py build - name: Show ccache stats run: ccache --show-stats - name: Show binary size run: | ls -lh get-started/csi_recv_router/build/*.bin - name: Check firmware size run: | BIN="get-started/csi_recv_router/build/csi_recv_router.bin" MAX_SIZE=1966080 # 0x1E0000 = 1920 KB partition WARN_PERCENT=85 SIZE=$(stat -c%s "$BIN") PERCENT=$((SIZE * 100 / MAX_SIZE)) echo "Firmware: $((SIZE/1024)) KB / $((MAX_SIZE/1024)) KB ($PERCENT%)" if [ $SIZE -gt $MAX_SIZE ]; then echo "::error::Firmware exceeds partition size!" exit 1 fi if [ $PERCENT -gt $WARN_PERCENT ]; then echo "::warning::Firmware using $PERCENT% of partition" fi - name: Security checks run: | BIN="get-started/csi_recv_router/build/csi_recv_router.bin" CFG="get-started/csi_recv_router/sdkconfig" echo "=== Checking for hardcoded secrets ===" if strings "$BIN" | grep -iE '(password|secret|api_key|apikey)=' \ | grep -ivE '(auth_secret|secret=%s|secret=\$)'; then echo "::error::Potential hardcoded secret found in binary" exit 1 fi echo "No hardcoded secrets detected" echo "=== Checking release configuration ===" LOG_LEVEL=$(grep 'CONFIG_LOG_DEFAULT_LEVEL=' "$CFG" | cut -d= -f2) if [ "$LOG_LEVEL" -gt 3 ]; then echo "::warning::Debug/verbose logging enabled (level $LOG_LEVEL)" else echo "Log level OK ($LOG_LEVEL)" fi echo "=== Component size breakdown ===" . /opt/esp/idf/export.sh cd get-started/csi_recv_router idf.py size-components 2>/dev/null | head -30 - name: Push to Harbor run: | CRANE_VERSION="v0.20.3" curl -sL "https://github.com/google/go-containerregistry/releases/download/${CRANE_VERSION}/go-containerregistry_Linux_x86_64.tar.gz" \ | tar xz -C /usr/local/bin crane BIN="get-started/csi_recv_router/build/csi_recv_router.bin" TAG=$(echo "${{ github.sha }}" | cut -c1-7) IMAGE="harbor.mymx.me/library/firmware" crane auth login harbor.mymx.me \ -u "${{ secrets.HARBOR_USER }}" \ -p "${{ secrets.HARBOR_PASS }}" tar cf /tmp/firmware.tar -C "$(dirname "$BIN")" "$(basename "$BIN")" crane append -f /tmp/firmware.tar -t "$IMAGE:$TAG" if [ "${{ github.ref_type }}" = "tag" ]; then crane tag "$IMAGE:$TAG" "${{ github.ref_name }}" fi echo "Pushed $IMAGE:$TAG" - name: Create release if: startsWith(github.ref, 'refs/tags/v') run: | BIN="get-started/csi_recv_router/build/csi_recv_router.bin" TAG="${{ github.ref_name }}" API="https://git.mymx.me/api/v1/repos/${{ github.repository }}" TOKEN="${{ github.token }}" SIZE=$(stat -c%s "$BIN") RELEASE_ID=$(curl -sS -f -X POST "$API/releases" \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"tag_name\": \"$TAG\", \"name\": \"$TAG\", \"body\": \"Firmware $TAG — $((SIZE / 1024)) KB\" }" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])") echo "Release $RELEASE_ID created for $TAG" curl -sS -f -X POST \ "$API/releases/$RELEASE_ID/assets?name=csi_recv_router.bin" \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary @"$BIN" echo "Uploaded csi_recv_router.bin ($((SIZE / 1024)) KB)" cppcheck: name: C/C++ Static Analysis runs-on: anvil container: image: docker.io/library/debian:bookworm-slim steps: - name: Install tools run: | apt-get update && apt-get install -y --no-install-recommends git cppcheck ca-certificates - name: Checkout run: | git clone --depth=1 --branch=${{ github.ref_name }} \ https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git . - name: Run cppcheck run: | cppcheck --enable=warning,style,performance,portability \ --suppress=missingIncludeSystem \ --error-exitcode=1 \ --inline-suppr \ -I get-started/csi_recv_router/main \ get-started/csi_recv_router/main/*.c flawfinder: name: Security Flaw Analysis runs-on: anvil container: image: docker.io/library/python:3.12-slim steps: - name: Install tools run: | apt-get update && apt-get install -y --no-install-recommends git ca-certificates pip install --no-cache-dir flawfinder - name: Checkout run: | git clone --depth=1 --branch=${{ github.ref_name }} \ https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git . - name: Run flawfinder run: | flawfinder --minlevel=2 --error-level=4 \ get-started/csi_recv_router/main/ gitleaks: name: Secret Scanning runs-on: anvil container: image: docker.io/zricethezav/gitleaks:latest steps: - name: Checkout run: | git clone --branch=${{ github.ref_name }} \ https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git . - name: Run gitleaks run: gitleaks detect --source . --verbose --redact