fix: firmware cluster — wasm3 IDF v6.0 build (#946) + swarm TLS stack… #94
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: wifi-densepose sensing-server → Docker Hub + ghcr.io | |
| # Build + publish the `wifi-densepose` sensing-server image to both Docker Hub | |
| # (`ruvnet/wifi-densepose`) and ghcr.io (`ghcr.io/ruvnet/wifi-densepose`) on: | |
| # - push to main affecting the Dockerfile, the server crate, the UI assets, | |
| # or this workflow itself, | |
| # - tag push matching v* (release builds), | |
| # - manual workflow_dispatch. | |
| # | |
| # Closes #520 and #514: the stale `:latest` is rebuilt and pushed automatically | |
| # whenever the surface that produces it changes, and the Dockerfile fails the | |
| # build if the observatory/pose-fusion UI assets ever go missing again. | |
| # | |
| # Secrets: | |
| # DOCKERHUB_USERNAME — `ruvnet` (Docker Hub login name) | |
| # DOCKERHUB_TOKEN — Docker Hub access token with read/write/delete scope | |
| # (ghcr.io uses the workflow's GITHUB_TOKEN — no secret needed.) | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'docker/Dockerfile.rust' | |
| - 'docker/docker-entrypoint.sh' | |
| - 'v2/crates/wifi-densepose-sensing-server/**' | |
| - 'v2/crates/wifi-densepose-signal/**' | |
| - 'v2/crates/wifi-densepose-vitals/**' | |
| - 'v2/crates/wifi-densepose-wifiscan/**' | |
| - 'v2/crates/wifi-densepose-bfld/**' | |
| - 'v2/crates/cog-ha-matter/**' | |
| - 'v2/Cargo.toml' | |
| - 'v2/Cargo.lock' | |
| - 'ui/**' | |
| - '.github/workflows/sensing-server-docker.yml' | |
| tags: ['v*'] | |
| workflow_dispatch: {} | |
| permissions: | |
| contents: read | |
| packages: write | |
| concurrency: | |
| group: sensing-server-docker-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-publish: | |
| name: build · push · smoke-test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| # QEMU is required so the amd64 GitHub runner can cross-build the | |
| # linux/arm64 layer below (Dockerfile.rust is arch-agnostic — no `--target` | |
| # flag — so buildx + QEMU is all that's needed; arm64 builds are emulated | |
| # by the runner, not built on a separate arm64 host). | |
| - uses: docker/setup-qemu-action@v3 | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Docker Hub | |
| # Bypassing docker/login-action@v3: the action kept emitting | |
| # "malformed HTTP Authorization header" against a known-good | |
| # dckr_pat_* token (verified by direct curl against the Hub API). | |
| # `docker login --password-stdin` is the documented credential | |
| # path and avoids whatever encoding step the action injects. | |
| env: | |
| DH_USER: ${{ secrets.DOCKERHUB_USERNAME }} | |
| DH_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} | |
| run: | | |
| printf '%s' "$DH_TOKEN" | docker login docker.io -u "$DH_USER" --password-stdin | |
| - name: Log in to ghcr.io | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Compute tags | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: | | |
| docker.io/ruvnet/wifi-densepose | |
| ghcr.io/ruvnet/wifi-densepose | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=tag | |
| type=sha,format=short | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build + push | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: docker/Dockerfile.rust | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # README badge advertises `amd64 + arm64`, and #547 promised multi-arch | |
| # as part of the docker publish refresh; arm64 was never actually wired | |
| # in, so Apple Silicon Macs hit `no matching manifest for linux/arm64/v8` | |
| # on `docker pull ruvnet/wifi-densepose:latest` (#136, #625). Build both. | |
| platforms: linux/amd64,linux/arm64 | |
| # --------------------------------------------------------------------- | |
| # Smoke-test the freshly-pushed image: | |
| # 1. UI assets that closed #520 are inside `/app/ui` (the Dockerfile's | |
| # RUN guard catches missing ones at build time, this re-checks the | |
| # pushed artifact post-hoc as belt-and-braces). | |
| # 2. /health is up. | |
| # 3. /api/v1/info returns 200 with no auth (LAN-mode default). | |
| # 4. With RUVIEW_API_TOKEN set, /api/v1/info returns 401 without a | |
| # Bearer header, 200 with the correct one (the #443 auth middleware). | |
| # --------------------------------------------------------------------- | |
| - name: Smoke-test image assets + LAN-mode HTTP | |
| run: | | |
| set -euo pipefail | |
| IMAGE="ghcr.io/ruvnet/wifi-densepose:sha-${GITHUB_SHA::7}" | |
| docker pull "$IMAGE" | |
| docker run --rm "$IMAGE" sh -c \ | |
| 'ls /app/ui/observatory.html /app/ui/pose-fusion.html /app/ui/index.html /app/ui/viz.html >/dev/null' | |
| docker run --rm "$IMAGE" sh -c 'ls -d /app/ui/observatory /app/ui/pose-fusion >/dev/null' | |
| docker run -d --name sm -p 3000:3000 -e CSI_SOURCE=simulated "$IMAGE" | |
| # Wait up to 30 s for /health. | |
| for _ in $(seq 1 30); do | |
| if curl -fsS http://127.0.0.1:3000/health >/dev/null 2>&1; then break; fi | |
| sleep 1 | |
| done | |
| curl -fsS http://127.0.0.1:3000/health | |
| curl -fsS http://127.0.0.1:3000/api/v1/info >/dev/null | |
| curl -fsS http://127.0.0.1:3000/ui/observatory.html >/dev/null | |
| curl -fsS http://127.0.0.1:3000/ui/pose-fusion.html >/dev/null | |
| docker stop sm | |
| - name: Smoke-test the bearer-token auth path | |
| run: | | |
| set -euo pipefail | |
| IMAGE="ghcr.io/ruvnet/wifi-densepose:sha-${GITHUB_SHA::7}" | |
| docker run -d --name auth \ | |
| -p 3000:3000 \ | |
| -e CSI_SOURCE=simulated \ | |
| -e RUVIEW_API_TOKEN=smoke-test-token-do-not-use \ | |
| "$IMAGE" | |
| for _ in $(seq 1 30); do | |
| if curl -fsS http://127.0.0.1:3000/health >/dev/null 2>&1; then break; fi | |
| sleep 1 | |
| done | |
| # /health stays unauthenticated. | |
| curl -fsS http://127.0.0.1:3000/health >/dev/null | |
| # /api/v1/info without a bearer → 401. | |
| code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/api/v1/info) | |
| test "$code" = "401" || { echo "expected 401, got $code"; exit 1; } | |
| # Wrong bearer → 401. | |
| code=$(curl -s -o /dev/null -w '%{http_code}' -H 'Authorization: Bearer wrong' http://127.0.0.1:3000/api/v1/info) | |
| test "$code" = "401" || { echo "expected 401 (wrong token), got $code"; exit 1; } | |
| # Correct bearer → 200. | |
| curl -fsS -H 'Authorization: Bearer smoke-test-token-do-not-use' http://127.0.0.1:3000/api/v1/info >/dev/null | |
| docker stop auth | |
| - name: Summary | |
| if: always() | |
| run: | | |
| { | |
| echo "## sensing-server image published" | |
| echo | |
| echo "Tags:" | |
| echo '```' | |
| echo "${{ steps.meta.outputs.tags }}" | |
| echo '```' | |
| echo | |
| echo "Closes #520 (missing observatory/pose-fusion UI assets) and #514 (stale `:latest` for the v0.6+ packet format)." | |
| echo "The Dockerfile fails the build if those UI assets ever disappear again, and this workflow rebuilds + pushes automatically on every change to the surface." | |
| } >> "$GITHUB_STEP_SUMMARY" |