Some checks failed
Lint & Build / C/C++ Static Analysis (push) Failing after 37s
Lint & Build / Security Flaw Analysis (push) Successful in 21s
Lint & Build / Secret Scanning (push) Successful in 5s
Lint & Build / Shell Script Analysis (push) Successful in 6s
Lint & Build / Build Firmware (push) Successful in 2m12s
Lint & Build / Deploy to ESP Fleet (push) Successful in 4m19s
Instead of having ESP devices download from Gitea (TLS cert issues), the runner now serves firmware via local HTTP server and triggers OTA with the local URL.
227 lines
7.2 KiB
YAML
227 lines
7.2 KiB
YAML
name: Lint & Build
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags: ['v*']
|
|
pull_request:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
inputs:
|
|
deploy:
|
|
description: 'Deploy to ESP fleet after build'
|
|
required: false
|
|
default: 'false'
|
|
type: choice
|
|
options:
|
|
- 'false'
|
|
- 'true'
|
|
|
|
jobs:
|
|
build:
|
|
name: Build Firmware
|
|
runs-on: anvil
|
|
container:
|
|
image: docker.io/espressif/idf:v5.3
|
|
steps:
|
|
- name: Checkout
|
|
run: |
|
|
git clone --depth=1 --branch=${{ github.ref_name }} \
|
|
https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git .
|
|
|
|
- name: Build firmware
|
|
run: |
|
|
. /opt/esp/idf/export.sh
|
|
cd get-started/csi_recv_router
|
|
idf.py build
|
|
|
|
- name: Show binary size
|
|
run: |
|
|
ls -lh get-started/csi_recv_router/build/*.bin
|
|
|
|
- name: Upload firmware artifact
|
|
run: |
|
|
mkdir -p /tmp/artifacts
|
|
cp get-started/csi_recv_router/build/csi_recv_router.bin /tmp/artifacts/
|
|
cp get-started/csi_recv_router/build/bootloader/bootloader.bin /tmp/artifacts/
|
|
cp get-started/csi_recv_router/build/partition_table/partition-table.bin /tmp/artifacts/
|
|
cp get-started/csi_recv_router/build/ota_data_initial.bin /tmp/artifacts/
|
|
echo "Artifacts ready in /tmp/artifacts"
|
|
ls -la /tmp/artifacts/
|
|
|
|
deploy:
|
|
name: Deploy to ESP Fleet
|
|
runs-on: anvil
|
|
needs: build
|
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.deploy == 'true' || startsWith(github.ref, 'refs/tags/v')
|
|
container:
|
|
image: docker.io/espressif/idf:v5.3
|
|
steps:
|
|
- name: Install tools
|
|
run: |
|
|
apt-get update && apt-get install -y --no-install-recommends netcat-openbsd curl jq
|
|
|
|
- name: Checkout
|
|
run: |
|
|
git clone --depth=1 --branch=${{ github.ref_name }} \
|
|
https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git .
|
|
|
|
- name: Build firmware
|
|
run: |
|
|
. /opt/esp/idf/export.sh
|
|
cd get-started/csi_recv_router
|
|
idf.py build
|
|
|
|
- name: Create release and upload firmware
|
|
env:
|
|
GITEA_TOKEN: ${{ github.token }}
|
|
run: |
|
|
TAG="${{ github.ref_name }}"
|
|
REPO="${{ github.repository }}"
|
|
API_URL="https://git.mymx.me/api/v1"
|
|
|
|
echo "Creating release for tag: $TAG"
|
|
|
|
# Check if release exists
|
|
RELEASE=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
|
"$API_URL/repos/$REPO/releases/tags/$TAG")
|
|
|
|
RELEASE_ID=$(echo "$RELEASE" | jq -r '.id // empty')
|
|
|
|
if [ -z "$RELEASE_ID" ]; then
|
|
# Create new release
|
|
RELEASE=$(curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"tag_name\": \"$TAG\", \"name\": \"$TAG\", \"body\": \"Automated release from CI\"}" \
|
|
"$API_URL/repos/$REPO/releases")
|
|
RELEASE_ID=$(echo "$RELEASE" | jq -r '.id')
|
|
echo "Created release ID: $RELEASE_ID"
|
|
else
|
|
echo "Release exists with ID: $RELEASE_ID"
|
|
fi
|
|
|
|
# Upload firmware binary
|
|
echo "Uploading firmware..."
|
|
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
|
|
-F "attachment=@get-started/csi_recv_router/build/csi_recv_router.bin" \
|
|
"$API_URL/repos/$REPO/releases/$RELEASE_ID/assets?name=csi_recv_router.bin"
|
|
|
|
- name: Deploy via OTA
|
|
run: |
|
|
SENSORS="muddy-storm:192.168.129.29 amber-maple:192.168.129.30 hollow-acorn:192.168.129.31"
|
|
FIRMWARE_PATH="get-started/csi_recv_router/build/csi_recv_router.bin"
|
|
OTA_PORT=8899
|
|
|
|
# Get runner IP (first non-loopback interface)
|
|
RUNNER_IP=$(hostname -I | awk '{print $1}')
|
|
echo "Runner IP: $RUNNER_IP"
|
|
|
|
# Start HTTP server to serve firmware
|
|
cd get-started/csi_recv_router/build
|
|
python3 -m http.server $OTA_PORT &
|
|
HTTP_PID=$!
|
|
sleep 2
|
|
|
|
FIRMWARE_URL="http://${RUNNER_IP}:${OTA_PORT}/csi_recv_router.bin"
|
|
echo "Firmware URL: $FIRMWARE_URL"
|
|
|
|
# Verify server is running
|
|
curl -sI "http://localhost:${OTA_PORT}/csi_recv_router.bin" | head -1
|
|
|
|
# Deploy to each sensor
|
|
for entry in $SENSORS; do
|
|
NAME="${entry%%:*}"
|
|
IP="${entry##*:}"
|
|
echo "=== Deploying to $NAME ($IP) ==="
|
|
echo "OTA $FIRMWARE_URL" | nc -u -w 2 "$IP" 5501 || true
|
|
sleep 45
|
|
done
|
|
|
|
# Stop HTTP server
|
|
kill $HTTP_PID 2>/dev/null || true
|
|
|
|
echo "=== Deployment complete ==="
|
|
|
|
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
|
|
|
|
shellcheck:
|
|
name: Shell Script Analysis
|
|
runs-on: anvil
|
|
container:
|
|
image: docker.io/koalaman/shellcheck-alpine:stable
|
|
steps:
|
|
- name: Install git
|
|
run: apk add --no-cache git
|
|
|
|
- name: Checkout
|
|
run: |
|
|
git clone --depth=1 --branch=${{ github.ref_name }} \
|
|
https://oauth2:${{ github.token }}@git.mymx.me/${{ github.repository }}.git .
|
|
|
|
- name: Find and check shell scripts
|
|
run: |
|
|
SCRIPTS=$(find . -name "*.sh" -type f 2>/dev/null || true)
|
|
if [ -n "$SCRIPTS" ]; then
|
|
echo "Checking: $SCRIPTS"
|
|
echo "$SCRIPTS" | xargs shellcheck --severity=warning
|
|
else
|
|
echo "No shell scripts found, skipping"
|
|
fi
|